This commit is contained in:
Zeecka
2025-12-10 22:23:54 +01:00
parent 83bce75b2f
commit d1fb8b3760
2 changed files with 117 additions and 57 deletions
+111 -51
View File
@@ -1,7 +1,6 @@
"""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
@@ -10,75 +9,128 @@ EXPECTED_SIZES = [
# ------------------------- # -------------------------
# ICONS (Square) # ICONS (Square)
# ------------------------- # -------------------------
(16, 16), (20, 20), (24, 24), (28, 28), (16, 16),
(32, 32), (48, 48), (64, 64), (72, 72), (20, 20),
(96, 96), (128, 128), (192, 192), (256, 256), (24, 24),
(384, 384), (512, 512), (768, 768), (1024, 1024), (28, 28),
(1536, 1536), (2048, 2048), (4096, 4096), (32, 32),
(48, 48),
(64, 64),
(72, 72),
(96, 96),
(128, 128),
(192, 192),
(256, 256),
(384, 384),
(512, 512),
(768, 768),
(1024, 1024),
(1536, 1536),
(2048, 2048),
(4096, 4096),
# ------------------------- # -------------------------
# 1:1 Square (General) # 1:1 Square (General)
# ------------------------- # -------------------------
(300, 300), (500, 500), (800, 800), (1000, 1000), (300, 300),
(1500, 1500), (2000, 2000), (2500, 2500), (3000, 3000), (500, 500),
(800, 800),
(1000, 1000),
(1500, 1500),
(2000, 2000),
(2500, 2500),
(3000, 3000),
# ------------------------- # -------------------------
# 4:3 Aspect (Classic Screens) # 4:3 Aspect (Classic Screens)
# ------------------------- # -------------------------
(320, 240), (640, 480), (800, 600), (960, 720), (320, 240),
(1024, 768), (1280, 960), (1600, 1200), (2048, 1536), (640, 480),
(2560, 1920), (3200, 2400), (4096, 3072), (800, 600),
(960, 720),
(1024, 768),
(1280, 960),
(1600, 1200),
(2048, 1536),
(2560, 1920),
(3200, 2400),
(4096, 3072),
# ------------------------- # -------------------------
# 3:2 Aspect (Photography) # 3:2 Aspect (Photography)
# ------------------------- # -------------------------
(600, 400), (900, 600), (1200, 800), (1500, 1000), (600, 400),
(1800, 1200), (2400, 1600), (3000, 2000), (3600, 2400), (900, 600),
(4500, 3000), (6000, 4000), (1200, 800),
(1500, 1000),
(1800, 1200),
(2400, 1600),
(3000, 2000),
(3600, 2400),
(4500, 3000),
(6000, 4000),
# ------------------------- # -------------------------
# 16:9 Aspect (Video / Web) # 16:9 Aspect (Video / Web)
# ------------------------- # -------------------------
(426, 240), (640, 360), (854, 480), (960, 540), (426, 240),
(1280, 720), (1366, 768), (1600, 900), (1920, 1080), (640, 360),
(2560, 1440), (3200, 1800), (3440, 1935), (3840, 2160), (854, 480),
(5120, 2880), (7680, 4320), (10240, 5760), (960, 540),
(1280, 720),
(1366, 768),
(1600, 900),
(1920, 1080),
(2560, 1440),
(3200, 1800),
(3440, 1935),
(3840, 2160),
(5120, 2880),
(7680, 4320),
(10240, 5760),
# ------------------------- # -------------------------
# 16:10 Aspect (Laptops) # 16:10 Aspect (Laptops)
# ------------------------- # -------------------------
(1280, 800), (1440, 900), (1680, 1050), (1280, 800),
(1920, 1200), (2560, 1600), (2880, 1800), (1440, 900),
(3840, 2400), (5120, 3200), (1680, 1050),
(1920, 1200),
(2560, 1600),
(2880, 1800),
(3840, 2400),
(5120, 3200),
# ------------------------- # -------------------------
# Mobile Portrait (9:16) # Mobile Portrait (9:16)
# ------------------------- # -------------------------
(720, 1280), (1080, 1920), (1440, 2560), (720, 1280),
(2160, 3840), (1440, 2960), (1080, 2400), (1080, 1920),
(1170, 2532), (1284, 2778), (1290, 2796), (1440, 2560),
(2160, 3840),
(1440, 2960),
(1080, 2400),
(1170, 2532),
(1284, 2778),
(1290, 2796),
# ------------------------- # -------------------------
# Social Media Sizes # Social Media Sizes
# ------------------------- # -------------------------
# Instagram # Instagram
(1080, 1080), (1080, 1350), (1080, 1920), (1080, 1080),
(1080, 1350),
(1080, 1920),
# Facebook # Facebook
(1200, 628), (1200, 1200), (1200, 628),
(1200, 1200),
# Twitter/X # Twitter/X
(1200, 675), (1500, 500), (1200, 675),
(1500, 500),
# YouTube Thumbnails # YouTube Thumbnails
(1280, 720), (1920, 1080), (1280, 720),
(1920, 1080),
# ------------------------- # -------------------------
# Banners / Headers # Banners / Headers
# ------------------------- # -------------------------
(1600, 500), (1920, 500), (2560, 700), (1600, 500),
(3000, 1000), (3840, 1200), (1920, 500),
(2560, 700),
(3000, 1000),
(3840, 1200),
# ------------------------- # -------------------------
# Print-like Digital Sizes # Print-like Digital Sizes
# ------------------------- # -------------------------
@@ -87,10 +139,12 @@ EXPECTED_SIZES = [
(3508, 4961), # A3 @ 300 DPI (3508, 4961), # A3 @ 300 DPI
(4961, 7016), # A2 @ 300 DPI (4961, 7016), # A2 @ 300 DPI
(7016, 9933), # A1 @ 300 DPI (7016, 9933), # A1 @ 300 DPI
] ]
def calc_checksum(header_chunk, width_bytes, height_bytes):
def calc_checksum(
header_chunk: bytearray, width_bytes: bytearray, height_bytes: bytearray
) -> bytearray:
""" """
Calculates the CRC32 of the IHDR chunk with new dimensions. Calculates the CRC32 of the IHDR chunk with new dimensions.
header_chunk: The full IHDR chunk (Type + Data). header_chunk: The full IHDR chunk (Type + Data).
@@ -99,7 +153,8 @@ def calc_checksum(header_chunk, width_bytes, height_bytes):
new_header = header_chunk[:4] + width_bytes + height_bytes + header_chunk[12:] new_header = header_chunk[:4] + width_bytes + height_bytes + header_chunk[12:]
# Calculate CRC and return as 4 bytes (Big Endian) # Calculate CRC and return as 4 bytes (Big Endian)
return bytearray((zlib.crc32(new_header) & 0xffffffff).to_bytes(4, byteorder='big')) return bytearray((zlib.crc32(new_header) & 0xFFFFFFFF).to_bytes(4, byteorder="big"))
def analyze_image_resize(input_img: Path, output_dir: Path) -> None: def analyze_image_resize(input_img: Path, output_dir: Path) -> None:
""" """
@@ -122,10 +177,13 @@ def analyze_image_resize(input_img: Path, output_dir: Path) -> None:
b = bytearray(f) b = bytearray(f)
# Find IHDR start # Find IHDR start
IHDR = b.find(b'\x49\x48\x44\x52') IHDR = b.find(b"\x49\x48\x44\x52")
if IHDR == -1: if IHDR == -1:
logs.append("Failure: PNG header (IHDR) not found.") logs.append("Failure: PNG header (IHDR) not found.")
update_data(output_dir, {"image_resize": {"status": "error", "error": "PNG header not found."}}) update_data(
output_dir,
{"image_resize": {"status": "error", "error": "PNG header not found."}},
)
return return
# Calculate Chunk Length (The 4 bytes BEFORE IHDR tag) # Calculate Chunk Length (The 4 bytes BEFORE IHDR tag)
@@ -146,8 +204,8 @@ def analyze_image_resize(input_img: Path, output_dir: Path) -> None:
width, height = size width, height = size
# Convert dimensions to 4-byte Big Endian arrays # Convert dimensions to 4-byte Big Endian arrays
width_bytes = bytearray(width.to_bytes(4, byteorder='big')) width_bytes = bytearray(width.to_bytes(4, byteorder="big"))
height_bytes = bytearray(height.to_bytes(4, byteorder='big')) height_bytes = bytearray(height.to_bytes(4, byteorder="big"))
# Check if this size matches the file's CRC # Check if this size matches the file's CRC
if target_crc == calc_checksum(header_chunk, width_bytes, height_bytes): if target_crc == calc_checksum(header_chunk, width_bytes, height_bytes):
@@ -162,7 +220,9 @@ def analyze_image_resize(input_img: Path, output_dir: Path) -> None:
output_path = output_dir / img_name output_path = output_dir / img_name
# Splicing: [Start...IHDR+4] + [W] + [H] + [IHDR+12...End] # Splicing: [Start...IHDR+4] + [W] + [H] + [IHDR+12...End]
full_png_data = b[:IHDR+4] + width_bytes + height_bytes + b[IHDR+12:] full_png_data = (
b[: IHDR + 4] + width_bytes + height_bytes + b[IHDR + 12 :]
)
# Write the recovered file to disk # Write the recovered file to disk
with output_path.open("wb") as out_f: with output_path.open("wb") as out_f:
@@ -178,7 +238,7 @@ def analyze_image_resize(input_img: Path, output_dir: Path) -> None:
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,
} }
} }
if recovered_image: if recovered_image: