Files
Yuzu-GCA/fix_png.py
2026-07-19 22:57:19 +08:00

130 lines
4.4 KiB
Python

import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
with open(r"D:\Yuzu-GCA\screen.png", 'rb') as f:
data = f.read()
# The file is UTF-16 LE encoded with some corruption.
# Let's fix the known issues:
# 1. Replace the corrupted first char (U+5852 from bytes 52 58)
# with correct U+0089 (89 00) + U+0050 (50 00)
# But wait - in UTF-16 LE, each char takes 2 bytes.
# We need to replace 2 bytes (52 58) with 4 bytes (89 00 50 00)
# Actually, let's approach differently:
# Convert the whole thing from UTF-16 LE to raw bytes,
# but fix the known corruptions.
# Step 1: parse as UTF-16 LE (skip BOM)
raw = data[2:]
# Each 2 bytes is one UTF-16 LE char
chars = []
for i in range(0, len(raw), 2):
if i + 1 < len(raw):
ch = raw[i] | (raw[i+1] << 8)
chars.append(ch)
print(f"Total chars: {len(chars)}")
# Step 2: Fix corruptions in the char array
# Char 0: U+5852 -> should be U+0089 (first PNG byte)
# But U+0089 is one char, and we also need U+0050 for 'P'
# So we need to insert a char
# The corruption pattern:
# - Char 0 (U+5852) replaces two chars: U+0089 and U+0050
# - Char 6 (U+000D) should be U+000A
# - Char 7 (U+000A) is extra, should be removed
# - Char 12 (U+000A) is extra, should be removed
# Let's verify by looking at what we expect:
# Expected chars for correct PNG:
# [0]=0x0089, [1]=0x0050('P'), [2]=0x004E('N'), [3]=0x0047('G'),
# [4]=0x000D, [5]=0x000A, [6]=0x001A, [7]=0x000A (signature end)
# [8]=0x0000, [9]=0x0000, [10]=0x0000, [11]=0x000D (IHDR length=13)
# [12]=0x0049('I'), [13]=0x0048('H'), [14]=0x0044('D'), [15]=0x0052('R')
# Actual chars:
# [0]=0x5852, [1]=0x004E, [2]=0x0047, [3]=0x000D, [4]=0x000A,
# [5]=0x001A, [6]=0x000D, [7]=0x000A, [8]=0x0000, [9]=0x0000,
# [10]=0x0000, [11]=0x000D, [12]=0x000A, [13]=0x0049, [14]=0x0048, ...
# Fix:
# Replace char 0 (U+5852) with U+0089
# Insert U+0050 at position 1
# Change char 6 from 0x0D to 0x0A
# Delete char 7 (extra 0x0A)
# Delete char 12 (extra 0x0A) - wait, this is after IHDR length
fixed_chars = []
# Fix char 0: split U+5852 -> U+0089, U+0050
fixed_chars.append(0x0089) # PNG first byte
fixed_chars.append(0x0050) # 'P'
# Copy chars 1-5 normally (but adjust indices)
# Original char 1 (U+004E='N') -> fixed index 2
# Original char 2 (U+0047='G') -> fixed index 3
# Original char 3 (U+000D) -> fixed index 4
# Original char 4 (U+000A) -> fixed index 5
# Original char 5 (U+001A) -> fixed index 6
fixed_chars.append(chars[1]) # 'N'
fixed_chars.append(chars[2]) # 'G'
fixed_chars.append(chars[3]) # '\r'
fixed_chars.append(chars[4]) # '\n'
fixed_chars.append(chars[5]) # '\x1a'
# Fix char 6: change from 0x0D to 0x0A
fixed_chars.append(0x000A) # Should be '\n' instead of '\r'
# Skip char 7 (extra 0x0A) - don't add it
# Add chars 8-11 (IHDR length = 0x0000000D)
fixed_chars.append(chars[8]) # 0x0000
fixed_chars.append(chars[9]) # 0x0000
fixed_chars.append(chars[10]) # 0x0000
fixed_chars.append(chars[11]) # 0x000D
# Skip char 12 (extra 0x0A) - don't add it
# Add the rest from char 13 onwards
for i in range(13, len(chars)):
fixed_chars.append(chars[i])
print(f"Fixed chars: {len(fixed_chars)}")
# Step 3: Convert fixed chars back to UTF-16 LE bytes
fixed_bytes = bytearray()
for ch in fixed_chars:
fixed_bytes.append(ch & 0xFF) # low byte
fixed_bytes.append((ch >> 8) & 0xFF) # high byte
print(f"Fixed bytes: {len(fixed_bytes)}")
# Step 4: Extract original PNG bytes (every other byte, starting from first)
# In UTF-16 LE, for ASCII chars (< 0x80), the low byte is the char and high byte is 00
# But for non-ASCII chars like U+0089, the low byte is 0x89 and high byte is 0x00
# So we take the low byte of each char
png_bytes = bytearray()
for ch in fixed_chars:
png_bytes.append(ch & 0xFF)
print(f"PNG bytes: {len(png_bytes)}")
print(f"First 32 PNG bytes: {' '.join(f'{b:02X}' for b in png_bytes[:32])}")
# Check PNG signature
if png_bytes[:8] == b'\x89PNG\r\n\x1a\n':
print("✓ Valid PNG signature!")
with open(r"D:\Yuzu-GCA\screen_fixed.png", 'wb') as f:
f.write(png_bytes)
print("Saved screen_fixed.png")
else:
print(f"✗ Invalid signature: {' '.join(f'{b:02X}' for b in png_bytes[:8])}")
# Try to see if we can find where it goes wrong
expected = b'\x89PNG\r\n\x1a\n'
for i in range(8):
if png_bytes[i] != expected[i]:
print(f" Mismatch at byte {i}: got {png_bytes[i]:02X}, expected {expected[i]:02X}")