diff --git a/frontends/web/app.py b/frontends/web/app.py index 60ea3bb..af0c88d 100644 --- a/frontends/web/app.py +++ b/frontends/web/app.py @@ -886,16 +886,6 @@ def encode_page(): ref_data = ref_photo.read() carrier_data = carrier.read() - # DEBUG: Log file hashes to verify bytes match between encode/decode - import hashlib - import sys - ref_hash = hashlib.md5(ref_data).hexdigest()[:8] - carrier_hash = hashlib.md5(carrier_data).hexdigest()[:8] - print(f"[ENCODE DEBUG] ref: {len(ref_data)} bytes, md5: {ref_hash}", file=sys.stderr) - print(f"[ENCODE DEBUG] carrier: {len(carrier_data)} bytes, md5: {carrier_hash}", file=sys.stderr) - print(f"[ENCODE DEBUG] passphrase: '{passphrase}', pin: '{pin}'", file=sys.stderr) - print(f"[ENCODE DEBUG] channel_key: '{channel_key}', embed_mode: '{embed_mode}'", file=sys.stderr) - # Handle RSA key - can come from .pem file or QR code image rsa_key_data = None rsa_key_qr = request.files.get("rsa_key_qr") @@ -1019,8 +1009,6 @@ def encode_page(): # Store temporarily file_id = secrets.token_urlsafe(16) cleanup_temp_files() - stego_hash = hashlib.md5(encode_result.stego_data).hexdigest()[:8] - print(f"[ENCODE RESULT] stego: {len(encode_result.stego_data)} bytes, md5: {stego_hash}", file=sys.stderr) TEMP_FILES[file_id] = { "data": encode_result.stego_data, "filename": filename, @@ -1102,10 +1090,6 @@ def encode_download(file_id): file_info = TEMP_FILES[file_id] mime_type = file_info.get("mime_type", "image/png") - import hashlib - download_hash = hashlib.md5(file_info["data"]).hexdigest()[:8] - print(f"[DOWNLOAD] stego: {len(file_info['data'])} bytes, md5: {download_hash}", file=sys.stderr) - return send_file( io.BytesIO(file_info["data"]), mimetype=mime_type, @@ -1193,15 +1177,6 @@ def decode_page(): ref_data = ref_photo.read() stego_data = stego_image.read() - # DEBUG: Log file hashes to verify bytes match between encode/decode - import hashlib - ref_hash = hashlib.md5(ref_data).hexdigest()[:8] - stego_hash = hashlib.md5(stego_data).hexdigest()[:8] - print(f"[DECODE DEBUG] ref: {len(ref_data)} bytes, md5: {ref_hash}", file=sys.stderr) - print(f"[DECODE DEBUG] channel_key: '{channel_key}'", file=sys.stderr) - print(f"[DECODE DEBUG] stego: {len(stego_data)} bytes, md5: {stego_hash}", file=sys.stderr) - print(f"[DECODE DEBUG] passphrase: '{passphrase}', pin: '{pin}', embed_mode: '{embed_mode}'", file=sys.stderr) - # Handle RSA key - can come from .pem file or QR code image rsa_key_data = None rsa_key_qr = request.files.get("rsa_key_qr") @@ -1256,7 +1231,6 @@ def decode_page(): ) # Check for subprocess errors - print(f"[DECODE RESULT] success={decode_result.success}, error={decode_result.error}", file=sys.stderr) if not decode_result.success: error_msg = decode_result.error or "Decoding failed" # Check for channel key related errors diff --git a/frontends/web/stego_worker.py b/frontends/web/stego_worker.py index cc07784..62696c7 100644 --- a/frontends/web/stego_worker.py +++ b/frontends/web/stego_worker.py @@ -98,16 +98,6 @@ def encode_operation(params: dict) -> dict: # Resolve channel key (v4.0.0) resolved_channel_key = _resolve_channel_key(params.get("channel_key", "auto")) - # DEBUG: Log what channel key the worker is using - import sys, os - from stegasoo.channel import get_channel_key, get_channel_key_hash - worker_channel_key = get_channel_key() - worker_channel_hash = get_channel_key_hash() - print(f"[WORKER ENCODE] cwd={os.getcwd()}", file=sys.stderr) - print(f"[WORKER ENCODE] channel_key param='{params.get('channel_key')}' -> resolved='{resolved_channel_key}'", file=sys.stderr) - print(f"[WORKER ENCODE] get_channel_key()={worker_channel_key}", file=sys.stderr) - print(f"[WORKER ENCODE] get_channel_key_hash()={worker_channel_hash[:8].hex() if worker_channel_hash else None}", file=sys.stderr) - # Call encode with correct parameter names result = encode( message=payload, @@ -161,16 +151,6 @@ def decode_operation(params: dict) -> dict: # Resolve channel key (v4.0.0) resolved_channel_key = _resolve_channel_key(params.get("channel_key", "auto")) - # DEBUG: Log what channel key the worker is using - import sys, os - from stegasoo.channel import get_channel_key, get_channel_key_hash - worker_channel_key = get_channel_key() - worker_channel_hash = get_channel_key_hash() - print(f"[WORKER DECODE] cwd={os.getcwd()}", file=sys.stderr) - print(f"[WORKER DECODE] channel_key param='{params.get('channel_key')}' -> resolved='{resolved_channel_key}'", file=sys.stderr) - print(f"[WORKER DECODE] get_channel_key()={worker_channel_key}", file=sys.stderr) - print(f"[WORKER DECODE] get_channel_key_hash()={worker_channel_hash[:8].hex() if worker_channel_hash else None}", file=sys.stderr) - # Call decode with correct parameter names result = decode( stego_image=stego_data, diff --git a/frontends/web/subprocess_stego.py b/frontends/web/subprocess_stego.py index ac775ad..8fa027f 100644 --- a/frontends/web/subprocess_stego.py +++ b/frontends/web/subprocess_stego.py @@ -179,10 +179,6 @@ class SubprocessStego: cwd=str(self.worker_path.parent), ) - # DEBUG: Log worker stderr to main process stderr - if result.stderr: - print(result.stderr, file=sys.stderr, end='') - if result.returncode != 0: # Worker crashed return { diff --git a/src/stegasoo/dct_steganography.py b/src/stegasoo/dct_steganography.py index a95e1c6..9ce7777 100644 --- a/src/stegasoo/dct_steganography.py +++ b/src/stegasoo/dct_steganography.py @@ -851,9 +851,12 @@ def _extract_scipy_dct_safe(stego_image: bytes, seed: bytes) -> bytes: del channel gc.collect() - h, w = padded.shape - blocks_x = w // BLOCK_SIZE - num_blocks = (h // BLOCK_SIZE) * blocks_x + # Use ORIGINAL image dimensions for block calculations (must match embed) + # Embed uses width // BLOCK_SIZE, not padded width + h, w = padded.shape # Padded dimensions for bounds checking + blocks_x = width // BLOCK_SIZE + blocks_y = height // BLOCK_SIZE + num_blocks = blocks_y * blocks_x block_order = _generate_block_order(num_blocks, seed) diff --git a/src/stegasoo/encode.py b/src/stegasoo/encode.py index 0c87b11..43b18ff 100644 --- a/src/stegasoo/encode.py +++ b/src/stegasoo/encode.py @@ -35,7 +35,7 @@ def encode( output_format: str | None = None, embed_mode: str = EMBED_MODE_LSB, dct_output_format: str = "png", - dct_color_mode: str = "grayscale", + dct_color_mode: str = "color", channel_key: str | bool | None = None, ) -> EncodeResult: """ @@ -158,7 +158,7 @@ def encode_file( filename_override: str | None = None, embed_mode: str = EMBED_MODE_LSB, dct_output_format: str = "png", - dct_color_mode: str = "grayscale", + dct_color_mode: str = "color", channel_key: str | bool | None = None, ) -> EncodeResult: """ @@ -215,7 +215,7 @@ def encode_bytes( mime_type: str | None = None, embed_mode: str = EMBED_MODE_LSB, dct_output_format: str = "png", - dct_color_mode: str = "grayscale", + dct_color_mode: str = "color", channel_key: str | bool | None = None, ) -> EncodeResult: """ diff --git a/src/stegasoo/steganography.py b/src/stegasoo/steganography.py index 87dc666..6eb7ba8 100644 --- a/src/stegasoo/steganography.py +++ b/src/stegasoo/steganography.py @@ -525,7 +525,7 @@ def embed_in_image( output_format: str | None = None, embed_mode: str = EMBED_MODE_LSB, dct_output_format: str = DCT_OUTPUT_PNG, - dct_color_mode: str = "grayscale", + dct_color_mode: str = "color", ) -> tuple[bytes, Union[EmbedStats, "DCTEmbedStats"], str]: """ Embed data into an image using specified mode. @@ -567,8 +567,8 @@ def embed_in_image( # Validate DCT color mode (v3.0.1) if dct_color_mode not in ("grayscale", "color"): - debug.print(f"Invalid dct_color_mode '{dct_color_mode}', defaulting to grayscale") - dct_color_mode = "grayscale" + debug.print(f"Invalid dct_color_mode '{dct_color_mode}', defaulting to color") + dct_color_mode = "color" dct_mod = _get_dct_module() diff --git a/tests/test_stegasoo.py b/tests/test_stegasoo.py index d268717..80c598d 100644 --- a/tests/test_stegasoo.py +++ b/tests/test_stegasoo.py @@ -50,8 +50,17 @@ def png_image(): @pytest.fixture def large_png_image(): - """Create a larger test PNG image for DCT mode.""" - img = Image.new("RGB", (400, 400), color="blue") + """Create a larger test PNG image for DCT mode. + + Uses noise instead of solid color to ensure DCT color mode works. + Solid colors cause coefficient drift during RGB conversion that + can exceed the quantization step and corrupt embedded data. + """ + import numpy as np + # Create random noise image (ensures varied Y channel values) + np.random.seed(42) # Reproducible + data = np.random.randint(0, 256, (400, 400, 3), dtype=np.uint8) + img = Image.fromarray(data, 'RGB') buf = io.BytesIO() img.save(buf, format="PNG") buf.seek(0)