Optimize analyzer resize, Bump python version, Change compose name

This commit is contained in:
Zeecka
2025-12-09 18:24:15 +01:00
parent b97a66d072
commit e271c15b56
5 changed files with 48 additions and 43 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
FROM python:3.11-slim AS build FROM python:3.14-slim AS build
WORKDIR / WORKDIR /
+2 -3
View File
@@ -73,13 +73,13 @@ Here is a batch of usefull commands.
```bash ```bash
docker compose down -v # Remove volume containings results docker compose down -v # Remove volume containings results
docker compose -f docker-compose-dev.yml up # Start application in developpement mode docker compose -f compose.dev.yml up # Start application in developpement mode
rm -rf aperisolve/results # Remove results from developpement mode rm -rf aperisolve/results # Remove results from developpement mode
docker exec -it postgres psql -U aperiuser -d aperisolve # Get postgresql shell docker exec -it postgres psql -U aperiuser -d aperisolve # Get postgresql shell
docker exec -it aperisolve-web bash # Get shell in running web app docker exec -it aperisolve-web bash # Get shell in running web app
``` ```
> Note, if you used [docker-compose-dev.yml](docker-compose-dev.yml), you must remove "results" when switching to [production docker](docker-compose.yml). > Note, if you used [compose.dev.yml](compose.dev.yml), you must remove "results" when switching to [production docker](compose.yml).
### Code quality ### Code quality
@@ -94,7 +94,6 @@ GitHub CI will alert in case of failure.
## Roadmap ## Roadmap
- [x] PngCheck
- [ ] Zsteg extract / --all --> **Download `zsteg` files** such as mp3 encoded on LSB - [ ] Zsteg extract / --all --> **Download `zsteg` files** such as mp3 encoded on LSB
- [ ] Test on mobile - [ ] Test on mobile
- [ ] i18n - [ ] i18n
+45 -39
View File
@@ -1,6 +1,7 @@
"""Image size bruteforcer for common PNG sizes.""" """Image size bruteforcer for common PNG sizes."""
import zlib import zlib
import shutil
from pathlib import Path from pathlib import Path
from .utils import update_data from .utils import update_data
@@ -116,74 +117,79 @@ def analyze_image_resize(input_img: Path, output_dir: Path) -> None:
# 3. Initialize Logs # 3. Initialize Logs
logs = [] logs = []
recovered_images = [] recovered_image = None
try: try:
with open(input_img, "rb") as image: with open(input_img, "rb") as image:
f = image.read() f = image.read()
b = bytearray(f)
# Find IHDR start b = bytearray(f)
IHDR = b.find(b'\x49\x48\x44\x52')
if IHDR == -1:
logs.append("Failure: PNG header (IHDR) not found.")
update_data(output_dir, {"image_resize": {"status": "error", "error": "PNG header not found."}})
return
# Calculate Chunk Length (The 4 bytes BEFORE IHDR tag) # Find IHDR start
chunk_length = int.from_bytes((b[IHDR- 4: IHDR]), byteorder="big") + 4 IHDR = b.find(b'\x49\x48\x44\x52')
if IHDR == -1:
logs.append("Failure: PNG header (IHDR) not found.")
update_data(output_dir, {"image_resize": {"status": "error", "error": "PNG header not found."}})
if extracted_dir.exists():
shutil.rmtree(extracted_dir, ignore_errors=True)
return
# Extract Target CRC (The 4 bytes AFTER the chunk data) # Calculate Chunk Length (The 4 bytes BEFORE IHDR tag)
target_crc = b[IHDR + chunk_length:IHDR + chunk_length + 4] chunk_length = int.from_bytes((b[IHDR- 4: IHDR]), byteorder="big") + 4
# Isolate the header chunk (Type + Data) # Extract Target CRC (The 4 bytes AFTER the chunk data)
header_chunk = b[IHDR:IHDR + chunk_length] target_crc = b[IHDR + chunk_length:IHDR + chunk_length + 4]
logs.append(f"Target CRC found: 0x{target_crc.hex()}") # Isolate the header chunk (Type + Data)
header_chunk = b[IHDR:IHDR + chunk_length]
match_found = False logs.append(f"Target CRC found: 0x{target_crc.hex()}")
# Brute-force Loop match_found = False
for size in EXPECTED_SIZES:
width, height = size
# Convert dimensions to 4-byte Big Endian arrays # Brute-force Loop
width_bytes = bytearray(width.to_bytes(4, byteorder='big')) for size in EXPECTED_SIZES:
height_bytes = bytearray(height.to_bytes(4, byteorder='big')) width, height = size
# Check if this size matches the file's CRC # Convert dimensions to 4-byte Big Endian arrays
if target_crc == calc_checksum(header_chunk, width_bytes, height_bytes): width_bytes = bytearray(width.to_bytes(4, byteorder='big'))
match_found = True height_bytes = bytearray(height.to_bytes(4, byteorder='big'))
logs.append(f"Success: Match found! Dimensions: {width}x{height}")
# Create Output Filename # Check if this size matches the file's CRC
output_filename = f"recovered_{width}x{height}.png" if target_crc == calc_checksum(header_chunk, width_bytes, height_bytes):
output_path = extracted_dir / output_filename match_found = True
logs.append(f"Success: Match found! Dimensions: {width}x{height}")
# Splicing: [Start...IHDR+4] + [W] + [H] + [IHDR+12...End] # Create Output Filename
full_png_data = b[:IHDR+4] + width_bytes + height_bytes + b[IHDR+12:] output_filename = f"recovered_{width}x{height}.png"
output_path = extracted_dir / output_filename
# Write the recovered file to disk # Splicing: [Start...IHDR+4] + [W] + [H] + [IHDR+12...End]
with open(output_path, "wb") as out_f: full_png_data = b[:IHDR+4] + width_bytes + height_bytes + b[IHDR+12:]
out_f.write(full_png_data)
recovered_images.append(output_filename) # Write the recovered file to disk
break # Stop looking after finding the match with output_path.open("wb") as out_f:
out_f.write(full_png_data)
if not match_found: recovered_image = output_filename
logs.append("Failure: No matching dimensions found.") break # Stop looking after finding the match
if not match_found:
logs.append("Failure: No matching dimensions found.")
# 4. Final Data Update # 4. Final Data Update
output_data = { output_data = {
"image_resize": { # Key name must match your module name in AperiSolve "image_resize": { # Key name must match your module name in AperiSolve
"status": "ok", "status": "ok",
"output": logs, "output": logs,
"images": recovered_images, # Tells frontend to display the image "images": recovered_image, # Tells frontend to display the image
} }
} }
update_data(output_dir, output_data) update_data(output_dir, output_data)
except Exception as e: except Exception as e:
update_data(output_dir, {"image_resize": {"status": "error", "error": str(e)}}) update_data(output_dir, {"image_resize": {"status": "error", "error": str(e)}})
if extracted_dir.exists():
shutil.rmtree(extracted_dir, ignore_errors=True)
return None return None
View File