Fix decode progress - add Argon2 phase tracking
- decode.py now writes 20% "initializing" before Argon2 - decode.py writes 25% "extracting" after Argon2 completes - DCT extraction scales from 25-70% (was 5-70%) - Removed duplicate "loading" writes that caused backwards jumps Progress flow: 15% reading -> 20% initializing (Argon2) -> 25-70% extracting -> 75-95% decoding -> 100% complete Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1198,7 +1198,7 @@ def _extract_scipy_dct_safe(
|
||||
progress_file: str | None = None,
|
||||
) -> bytes:
|
||||
"""Extract using safe DCT operations with vectorized processing."""
|
||||
_write_progress(progress_file, 0, 100, "loading")
|
||||
# Progress starts at 25% (decode.py writes 20% for Argon2, 25% before extraction)
|
||||
|
||||
img = Image.open(io.BytesIO(stego_image))
|
||||
width, height = img.size
|
||||
@@ -1264,9 +1264,10 @@ def _extract_scipy_dct_safe(
|
||||
del blocks, dct_blocks, coeffs, quantized
|
||||
block_idx = batch_end
|
||||
|
||||
# Report progress (scale to 5-70% range, RS decode gets 70-100%)
|
||||
# Report progress (scale to 25-70% range, RS decode gets 70-100%)
|
||||
# Starts at 25% because decode.py writes 25% before calling extraction
|
||||
if progress_file and block_idx % PROGRESS_INTERVAL < BATCH_SIZE:
|
||||
extract_pct = 5 + int(65 * block_idx / num_blocks)
|
||||
extract_pct = 25 + int(45 * block_idx / num_blocks)
|
||||
_write_progress(progress_file, extract_pct, 100, "extracting")
|
||||
|
||||
# Check if we have enough bits (early exit)
|
||||
@@ -1382,7 +1383,7 @@ def _extract_jpegio(
|
||||
"""Extract using jpegio for JPEG images."""
|
||||
import os
|
||||
|
||||
_write_progress(progress_file, 0, 100, "loading")
|
||||
# Progress starts at 25% (decode.py writes 20% for Argon2, 25% before extraction)
|
||||
|
||||
# Normalize JPEG to avoid crashes with quality=100 images
|
||||
# (shouldn't happen with stego images, but be defensive)
|
||||
@@ -1397,7 +1398,7 @@ def _extract_jpegio(
|
||||
all_positions = _jpegio_get_usable_positions(coef_array)
|
||||
order = _jpegio_generate_order(len(all_positions), seed)
|
||||
|
||||
_write_progress(progress_file, 20, 100, "extracting")
|
||||
_write_progress(progress_file, 30, 100, "extracting")
|
||||
|
||||
# Try RS-protected format first (has 24-byte length prefix: 3 copies for majority voting)
|
||||
if HAS_REEDSOLO and len(all_positions) >= RS_LENGTH_PREFIX_SIZE * 8:
|
||||
|
||||
@@ -8,6 +8,7 @@ Changes in v4.0.0:
|
||||
- Improved error messages for channel key mismatches
|
||||
"""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from .constants import EMBED_MODE_AUTO
|
||||
@@ -24,6 +25,22 @@ from .validation import (
|
||||
)
|
||||
|
||||
|
||||
def _write_progress(progress_file: str | None, current: int, total: int, phase: str) -> None:
|
||||
"""Write progress to file for UI polling."""
|
||||
if progress_file is None:
|
||||
return
|
||||
try:
|
||||
with open(progress_file, "w") as f:
|
||||
json.dump({
|
||||
"current": current,
|
||||
"total": total,
|
||||
"percent": (current / total * 100) if total > 0 else 0,
|
||||
"phase": phase,
|
||||
}, f)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def decode(
|
||||
stego_image: bytes,
|
||||
reference_photo: bytes,
|
||||
@@ -93,11 +110,17 @@ def decode(
|
||||
if rsa_key_data:
|
||||
require_valid_rsa_key(rsa_key_data, rsa_password)
|
||||
|
||||
# Progress: starting key derivation (Argon2 - slow on Pi)
|
||||
_write_progress(progress_file, 20, 100, "initializing")
|
||||
|
||||
# Derive pixel/coefficient selection key (with channel key)
|
||||
from .crypto import derive_pixel_key
|
||||
|
||||
pixel_key = derive_pixel_key(reference_photo, passphrase, pin, rsa_key_data, channel_key)
|
||||
|
||||
# Progress: key derivation done, starting extraction
|
||||
_write_progress(progress_file, 25, 100, "extracting")
|
||||
|
||||
# Extract encrypted data
|
||||
encrypted = extract_from_image(
|
||||
stego_image,
|
||||
|
||||
Reference in New Issue
Block a user