Fix CLI encode format detection and jpegtran -trim bug
CLI encode: - Auto-detect output format from extension (.jpg → DCT mode, .png → LSB) - Default to JPEG output for JPEG carriers (preserves DCT benefits) - Pass embed_mode and dct_output_format to encode function jpegtran fix (critical for rotation fallback): - Remove -trim flag which was dropping edge blocks and destroying stego data - Remove -perfect flag which fails on non-MCU-aligned images - Plain jpegtran without flags works correctly for lossless rotation This enables: encode → external rotation → decode to work correctly. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2136,7 +2136,7 @@ def api_tools_rotate():
|
||||
output_path = tempfile.mktemp(suffix=".jpg")
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["jpegtran", "-rotate", str(rotation), "-copy", "all", "-trim",
|
||||
["jpegtran", "-rotate", str(rotation), "-copy", "all",
|
||||
"-outfile", output_path, input_path],
|
||||
capture_output=True, timeout=30
|
||||
)
|
||||
@@ -2158,7 +2158,7 @@ def api_tools_rotate():
|
||||
output_path = tempfile.mktemp(suffix=".jpg")
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["jpegtran", "-flip", "horizontal", "-copy", "all", "-trim",
|
||||
["jpegtran", "-flip", "horizontal", "-copy", "all",
|
||||
"-outfile", output_path, input_path],
|
||||
capture_output=True, timeout=30
|
||||
)
|
||||
@@ -2180,7 +2180,7 @@ def api_tools_rotate():
|
||||
output_path = tempfile.mktemp(suffix=".jpg")
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["jpegtran", "-flip", "vertical", "-copy", "all", "-trim",
|
||||
["jpegtran", "-flip", "vertical", "-copy", "all",
|
||||
"-outfile", output_path, input_path],
|
||||
capture_output=True, timeout=30
|
||||
)
|
||||
|
||||
@@ -241,8 +241,20 @@ def encode(
|
||||
with open(carrier, "rb") as f:
|
||||
carrier_data = f.read()
|
||||
|
||||
# Determine output path
|
||||
output = output or f"{Path(carrier).stem}_encoded.png"
|
||||
# Determine output path and format
|
||||
# Default to JPEG for JPEG carriers (preserves DCT mode benefits)
|
||||
carrier_ext = Path(carrier).suffix.lower()
|
||||
if not output:
|
||||
if carrier_ext in ('.jpg', '.jpeg'):
|
||||
output = f"{Path(carrier).stem}_encoded.jpg"
|
||||
else:
|
||||
output = f"{Path(carrier).stem}_encoded.png"
|
||||
|
||||
# Detect output format from extension
|
||||
output_ext = Path(output).suffix.lower()
|
||||
use_dct = output_ext in ('.jpg', '.jpeg')
|
||||
|
||||
from .steganography import EMBED_MODE_DCT, EMBED_MODE_LSB
|
||||
|
||||
try:
|
||||
if file_payload:
|
||||
@@ -253,6 +265,8 @@ def encode(
|
||||
carrier_image=carrier_data,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
embed_mode=EMBED_MODE_DCT if use_dct else EMBED_MODE_LSB,
|
||||
dct_output_format="jpeg" if use_dct else "png",
|
||||
)
|
||||
else:
|
||||
# Encode message
|
||||
@@ -262,6 +276,8 @@ def encode(
|
||||
carrier_image=carrier_data,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
embed_mode=EMBED_MODE_DCT if use_dct else EMBED_MODE_LSB,
|
||||
dct_output_format="jpeg" if use_dct else "png",
|
||||
)
|
||||
|
||||
# Write output
|
||||
|
||||
@@ -1252,20 +1252,12 @@ def _jpegtran_rotate(image_data: bytes, rotation: int) -> bytes:
|
||||
output_path = tempfile.mktemp(suffix=".jpg")
|
||||
|
||||
try:
|
||||
# jpegtran -rotate 90|180|270 -copy all -perfect
|
||||
# jpegtran -rotate 90|180|270 -copy all
|
||||
# -copy all: preserve all metadata
|
||||
# -perfect: fail if there are non-transformable edge blocks (rare)
|
||||
# NOTE: Don't use -trim as it drops edge blocks and destroys stego data
|
||||
# NOTE: Don't use -perfect as it fails on images with non-MCU-aligned edges
|
||||
result = subprocess.run(
|
||||
["jpegtran", "-rotate", str(rotation), "-copy", "all", "-perfect",
|
||||
"-outfile", output_path, input_path],
|
||||
capture_output=True,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
# If -perfect fails (edge blocks), retry without it
|
||||
if result.returncode != 0:
|
||||
result = subprocess.run(
|
||||
["jpegtran", "-rotate", str(rotation), "-copy", "all", "-trim",
|
||||
["jpegtran", "-rotate", str(rotation), "-copy", "all",
|
||||
"-outfile", output_path, input_path],
|
||||
capture_output=True,
|
||||
timeout=30
|
||||
|
||||
Reference in New Issue
Block a user