diff --git a/analyze_text.py b/analyze_text.py new file mode 100644 index 0000000..a735717 --- /dev/null +++ b/analyze_text.py @@ -0,0 +1,53 @@ +""" +Final analysis: Search for any readable content in the decoded text. +Look for patterns that might indicate it's a screenshot from an Android device. +""" +import sys +import re + +path = r"D:\Yuzu-GCA\screen.png" + +with open(path, 'rb') as f: + raw = f.read() + +text = raw.decode('utf-16-le') + +# Save full text for manual inspection +with open(r"D:\Yuzu-GCA\screen_full_text.txt", 'w', encoding='utf-8') as f: + f.write(text) +print("Full text written to screen_full_text.txt") + +# Search for any CJK character sequences (potential readable Chinese text) +# Chinese characters are in range U+4E00 to U+9FFF +cjk_pattern = re.compile(r'[\u4e00-\u9fff]{3,}') +cjk_matches = cjk_pattern.findall(text) +print(f"\nChinese character sequences (>=3 chars): {len(cjk_matches)}") +# Show unique ones +unique_cjk = list(set(cjk_matches)) +print(f"Unique sequences: {len(unique_cjk)}") +for seq in sorted(unique_cjk, key=len, reverse=True)[:30]: + print(f" '{seq}' (len={len(seq)})") + +# Search for any ASCII word sequences (potential English words) +# Words of length >= 4 made of letters only +word_pattern = re.compile(r'[A-Za-z]{4,}') +word_matches = word_pattern.findall(text) +print(f"\nEnglish word-like sequences (>=4 chars): {len(word_matches)}") +unique_words = list(set(word_matches)) +print(f"Unique: {len(unique_words)}") +for w in sorted(unique_words, key=len, reverse=True)[:40]: + print(f" '{w}'") + +# Also search for numbers that look like versions +version_pattern = re.compile(r'\d+\.\d+(\.\d+)?') +version_matches = version_pattern.findall(text) +print(f"\nVersion-like patterns: {len(version_matches)}") +for v in version_matches[:20]: + print(f" '{v}'") + +# Search for URLs or file paths +path_pattern = re.compile(r'[/\\][A-Za-z0-9_./\\-]{5,}') +path_matches = path_pattern.findall(text) +print(f"\nPath-like patterns: {len(path_matches)}") +for p in path_matches[:20]: + print(f" '{p}'") diff --git a/check_files.py b/check_files.py new file mode 100644 index 0000000..24332ad --- /dev/null +++ b/check_files.py @@ -0,0 +1,17 @@ +import sys +import io +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') + +# Check screen2.png +data = open(r"D:\Yuzu-GCA\screen2.png", 'rb').read() +print(f"screen2.png: Size={len(data)}") +print(f"First 20 bytes: {' '.join(f'{b:02X}' for b in data[:20])}") +print(f"Is valid PNG: {data[:8] == b'\x89PNG\r\n\x1a\n'}") + +# Also check the fixed files +for fname in ['screen_fixed.png', 'screen_fixed2.png']: + try: + d = open(r"D:\\Yuzu-GCA\\" + fname, 'rb').read() + print(f"\n{fname}: Size={len(d)}") + except: + print(f"\n{fname}: NOT FOUND") diff --git a/check_header.py b/check_header.py new file mode 100644 index 0000000..c1d4a4a --- /dev/null +++ b/check_header.py @@ -0,0 +1,36 @@ +import sys + +image_path = r"D:\Yuzu-GCA\screen.png" + +with open(image_path, 'rb') as f: + header = f.read(32) + +print(f"File size check: first 32 bytes hex:") +print(' '.join(f'{b:02X}' for b in header)) +print() +print(f"ASCII representation: {header}") + +# Check known magic numbers +if header[:8] == b'\x89PNG\r\n\x1a\n': + print("✓ Valid PNG header detected") +elif header[:2] == b'\xff\xd8': + print("✓ JPEG header detected") +elif header[:4] == b'BM': + print("✓ BMP header detected") +elif header[:4] == b'RIFF': + print("✓ WEBP header detected") +else: + print("⚠ Unknown image format") + +# Also check if it might be an Android screencap (could be raw) +# Try to detect if it's a PNG embedded in a wrapper +print() + +# Check if file is actually a text-based format +with open(image_path, 'rb') as f: + content = f.read(200) + # Check if mostly printable ASCII + printable = sum(1 for b in content if 32 <= b <= 126 or b in (9, 10, 13)) + if printable > len(content) * 0.8: + print("Note: File appears to be mostly text!") + print(content.decode('utf-8', errors='replace')) diff --git a/check_png.py b/check_png.py new file mode 100644 index 0000000..1297e8e --- /dev/null +++ b/check_png.py @@ -0,0 +1,74 @@ +import sys +import io + +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') + +with open(r"D:\Yuzu-GCA\screen_fixed.png", 'rb') as f: + data = f.read() + +print(f"Total size: {len(data)}") + +# Check PNG structure +# Signature: 8 bytes +# Then chunks: each chunk has 4-byte length, 4-byte type, data, 4-byte CRC + +offset = 8 # skip signature + +while offset < len(data): + if offset + 8 > len(data): + break + length = int.from_bytes(data[offset:offset+4], 'big') + chunk_type = data[offset+4:offset+8].decode('ascii', errors='replace') + print(f"Chunk at offset {offset}: type='{chunk_type}', length={length}") + + if chunk_type == 'IHDR': + w = int.from_bytes(data[offset+8:offset+12], 'big') + h = int.from_bytes(data[offset+12:offset+16], 'big') + bit_depth = data[offset+16] + color_type = data[offset+17] + print(f" Width={w}, Height={h}, BitDepth={bit_depth}, ColorType={color_type}") + # Height seems wrong (854591). Expected ~1920 or ~2340 + # 0x000D0A3F: maybe it was 0x00000780 (1920) or 0x00000924 (2340)? + # Let me look at the raw bytes around height + print(f" Raw height bytes: {' '.join(f'{b:02X}' for b in data[offset+12:offset+16])}") + # Expected height around 1920 = 0x780, or 2340 = 0x924 + # What we have: 00 0D 0A 3F = 0x000D0A3F + # Could it be that 0D 0A is an inserted CR LF? + # If we remove 0D 0A: remaining would be 00 3F... but that's only 2 bytes + # Actually: 00 [0D 0A] 3F -> 00 3F? That's too short. + # Maybe: 00 [0D] 0A 3F, and 0D was inserted? Then original: 00 0A 3F = 2623 pixels? + # Or maybe: 00 00 0A 3F was original? No. + + # Let me check: common heights: 1920=0x780, 2000=0x7D0, 2340=0x924 + # 0x0A3F = 2623 (close to nothing standard) + # What if the actual height bytes are 00 00 0A 3F? That's still 2623. + # What about 00 00 07 80 (1920)? Then 0D 0A replaced 00 07 somehow? + + offset += 12 + length + + if offset > 200: + break + +# Let me search for CR LF (0D 0A) in the PNG data +crlf_count = 0 +for i in range(len(data) - 1): + if data[i] == 0x0D and data[i+1] == 0x0A: + crlf_count += 1 + if crlf_count <= 10: + print(f"CR LF at offset {i}: context: {' '.join(f'{b:02X}' for b in data[max(0,i-4):i+6])}") + +print(f"\nTotal CR LF sequences: {crlf_count}") + +# Also count lone 0A +lone_lf = 0 +for i in range(len(data)): + if data[i] == 0x0A and (i == 0 or data[i-1] != 0x0D): + lone_lf += 1 +print(f"Lone LF: {lone_lf}") + +# Count lone 0D +lone_cr = 0 +for i in range(len(data)): + if data[i] == 0x0D and (i == len(data)-1 or data[i+1] != 0x0A): + lone_cr += 1 +print(f"Lone CR: {lone_cr}") diff --git a/chi_sim.traineddata b/chi_sim.traineddata new file mode 100644 index 0000000..16fa167 --- /dev/null +++ b/chi_sim.traineddata @@ -0,0 +1 @@ +File size exceeded the configured limit of 20 MB. \ No newline at end of file diff --git a/debug_png.py b/debug_png.py new file mode 100644 index 0000000..0913889 --- /dev/null +++ b/debug_png.py @@ -0,0 +1,82 @@ +""" +Debug: compare raw bytes and re-encoded bytes. +Also try to interpret the file as a regular PNG by skipping the BOM. +""" +import sys + +path = r"D:\Yuzu-GCA\screen.png" + +with open(path, 'rb') as f: + raw = f.read() + +print(f"Total size: {len(raw)} bytes") + +# Decode as UTF-16 LE +text = raw.decode('utf-16-le') +print(f"Decoded text length: {len(text)} chars") + +# Re-encode +reencoded = text.encode('utf-16-le') +print(f"Re-encoded size: {len(reencoded)} bytes") + +# Compare +if raw == reencoded: + print("raw == reencoded: EXACT MATCH") +else: + print(f"raw == reencoded: DIFFER") + # Find first difference + for i in range(min(len(raw), len(reencoded))): + if raw[i] != reencoded[i]: + print(f"First diff at byte {i}: raw={raw[i]:02x}, reencoded={reencoded[i]:02x}") + print(f" Context raw: {raw[max(0,i-5):i+10].hex(' ')}") + print(f" Context re: {reencoded[max(0,i-5):i+10].hex(' ')}") + break + +# Check if raw starts with BOM +if raw[:2] == b'\xff\xfe': + print("\nFile starts with UTF-16 LE BOM") +elif raw[:2] == b'\xfe\xff': + print("\nFile starts with UTF-16 BE BOM") + +# Check reencoded start +if reencoded[:2] == b'\xff\xfe': + print("Re-encoded starts with UTF-16 LE BOM") +elif reencoded[:2] == b'\xfe\xff': + print("Re-encoded starts with UTF-16 BE BOM") + +# Try: what if we treat raw[2:] as the UTF-16 LE data (without the BOM)? +# This would be the case if the file had BOM added later +print(f"\nraw[2:4] = {raw[2:4].hex(' ')}") +text2 = raw[2:].decode('utf-16-le') +print(f"Decoded text2 (skipping BOM) length: {len(text2)} chars") +print(f"text2 first 50 chars: {text2[:50]}") + +# Try: what if the entire file is just raw PNG with a bogus BOM? +# PNG magic: 89 50 4E 47 0D 0A 1A 0A +# Our file: ff fe 52 58 4e 00 47 00 0d 00 0a 00 ... +# Maybe each byte X became X*256 + something? +# Or maybe the file is a hex dump? +print("\n=== Trying hex dump interpretation ===") +# Check if the text looks like a hex dump (pairs of hex digits) +hex_pattern = all(c in '0123456789abcdefABCDEF \n\r\t' for c in text[:1000]) +print(f"First 1000 chars look like hex dump: {hex_pattern}") + +# Final: Is there any actual readable content? +# Let's look for sequences of Latin chars that might form words +import re +# Words with 5+ letters +real_words = re.findall(r'[A-Za-z]{5,}', text) +# Filter out those that look like random binary +likely_real = [w for w in real_words if w.lower() in [ + 'update', 'download', 'install', 'error', 'success', 'failed', + 'system', 'android', 'version', 'checking', 'package', 'verify' +] or w in ['IHDR', 'IDAT', 'IEND', 'sRGB', 'sBIT', 'pHYs', 'iTXt', 'tEXt', 'zTXt']] +print(f"\nKnown words found: {likely_real}") + +# Check for PNG chunk names +png_chunks = ['IHDR', 'PLTE', 'IDAT', 'IEND', 'cHRM', 'gAMA', 'iCCP', 'sBIT', 'sRGB', + 'bKGD', 'hIST', 'tRNS', 'pHYs', 'sPLT', 'tIME', 'iTXt', 'tEXt', 'zTXt'] +for chunk in png_chunks: + cnt = text.count(chunk) + if cnt > 0: + print(f" PNG chunk '{chunk}': {cnt} times") diff --git a/decode_png.py b/decode_png.py new file mode 100644 index 0000000..9d5bc38 --- /dev/null +++ b/decode_png.py @@ -0,0 +1,15 @@ +import sys +import io + +# Set stdout to UTF-8 +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') + +with open(r"D:\Yuzu-GCA\screen.png", 'rb') as f: + data = f.read() + +print(f"Total bytes: {len(data)}") + +# Try UTF-16 LE decode +text = data.decode('utf-16-le', errors='replace') +print("=== Decoded as UTF-16 LE (first 10000 chars) ===") +print(text[:10000]) diff --git a/fix_png.py b/fix_png.py new file mode 100644 index 0000000..6eb9fbf --- /dev/null +++ b/fix_png.py @@ -0,0 +1,129 @@ +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}") diff --git a/fix_png2.py b/fix_png2.py new file mode 100644 index 0000000..084883c --- /dev/null +++ b/fix_png2.py @@ -0,0 +1,66 @@ +import sys +import io + +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') + +with open(r"D:\Yuzu-GCA\screen_fixed.png", 'rb') as f: + data = f.read() + +print(f"Original size: {len(data)}") + +# The file has been corrupted by text-mode LF->CRLF conversion. +# Every 0x0A byte in the original PNG has been changed to 0x0D 0x0A. +# We need to revert this: change 0x0D 0x0A back to 0x0A. +# But the PNG signature contains a legitimate 0x0D 0x0A (at offset 4-5), +# which should remain as-is. + +# Strategy: replace 0D 0A -> 0A, EXCEPT for the known legitimate ones +# Legitimate: offset 4-5 (PNG signature "\r\n") + +# Actually, let's just do the replacement everywhere and then fix the signature +fixed = bytearray() +i = 0 +while i < len(data): + if i < len(data) - 1 and data[i] == 0x0D and data[i+1] == 0x0A: + # CR LF found - replace with just LF + fixed.append(0x0A) + i += 2 + else: + fixed.append(data[i]) + i += 1 + +fixed = bytes(fixed) +print(f"After CRLF->LF fix: {len(fixed)}") + +# Now fix the PNG signature (offset 4-5 should be 0D 0A, but we changed it to 0A) +# The correct PNG signature: 89 50 4E 47 0D 0A 1A 0A +# We need to fix offset 4 to be 0D again +if fixed[4] == 0x0A: # Should be 0x0D + fixed = fixed[:4] + b'\x0D' + fixed[5:] + print("Fixed PNG signature byte 4 (0D)") + +print(f"First 16 bytes: {' '.join(f'{b:02X}' for b in fixed[:16])}") + +# Check IHDR +offset = 8 +length = int.from_bytes(fixed[offset:offset+4], 'big') +chunk_type = fixed[offset+4:offset+8].decode('ascii', errors='replace') +print(f"IHDR: type={chunk_type}, length={length}") +w = int.from_bytes(fixed[offset+8:offset+12], 'big') +h = int.from_bytes(fixed[offset+12:offset+16], 'big') +bit_depth = fixed[offset+16] +color_type = fixed[offset+17] +print(f" Width={w}, Height={h}, BitDepth={bit_depth}, ColorType={color_type}") + +# Save +with open(r"D:\Yuzu-GCA\screen_fixed2.png", 'wb') as f: + f.write(fixed) +print("Saved screen_fixed2.png") + +# Try to open with PIL +from PIL import Image +try: + img = Image.open(r"D:\Yuzu-GCA\screen_fixed2.png") + print(f"Success! Format={img.format}, Size={img.size}, Mode={img.mode}") +except Exception as e: + print(f"PIL error: {e}") diff --git a/ocr_fixed.py b/ocr_fixed.py new file mode 100644 index 0000000..254362a --- /dev/null +++ b/ocr_fixed.py @@ -0,0 +1,48 @@ +import sys +import io + +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') + +from PIL import Image + +img = Image.open(r"D:\Yuzu-GCA\screen_fixed.png") +print(f"Format: {img.format}") +print(f"Size: {img.size}") +print(f"Mode: {img.mode}") + +# Try OCR +try: + import pytesseract + text = pytesseract.image_to_string(img, lang='eng+chi_sim') + print("\n=== pytesseract OCR result ===") + print(text) +except ImportError: + print("pytesseract not available") + +# Also try Windows OCR +try: + import asyncio + from winsdk.windows.media.ocr import OcrEngine + from winsdk.windows.graphics.imaging import BitmapDecoder, SoftwareBitmap + from winsdk.windows.storage.streams import RandomAccessStreamReference + from winsdk.windows.globalization import Language + import os + + async def ocr_windows(): + engine = OcrEngine.try_create_from_user_profile_languages() + if not engine: + engine = OcrEngine.try_create_from_language(Language("en")) + + path = os.path.abspath(r"D:\Yuzu-GCA\screen_fixed.png") + file_stream = await RandomAccessStreamReference.create_from_file(path).open_read_async() + decoder = await BitmapDecoder.create_async(file_stream) + bitmap = await decoder.get_software_bitmap_async() + + result = await engine.recognize_async(bitmap) + print("\n=== Windows OCR result ===") + for line in result.lines: + print(line.text) + + asyncio.run(ocr_windows()) +except Exception as e: + print(f"Windows OCR failed: {e}") diff --git a/ocr_screen.py b/ocr_screen.py new file mode 100644 index 0000000..4903963 --- /dev/null +++ b/ocr_screen.py @@ -0,0 +1,55 @@ +""" +OCR script to extract text from screen.png +Attempts to use pytesseract if available, otherwise falls back to basic image info. +""" +import sys +import os + +image_path = r"D:\Yuzu-GCA\screen.png" + +# First, try to get basic image info +try: + from PIL import Image + img = Image.open(image_path) + print(f"Image size: {img.size}") + print(f"Image mode: {img.mode}") + print(f"Image format: {img.format}") + print("---") +except ImportError: + print("Pillow not available, trying basic file read...") + # Can't do much without PIL + +# Try pytesseract +try: + import pytesseract + text = pytesseract.image_to_string(img, lang='chi_sim+eng') + print("OCR Result (pytesseract):") + print(text) +except ImportError: + print("pytesseract not available") + # Try subprocess call to system tesseract + import subprocess + try: + result = subprocess.run( + ['tesseract', image_path, 'stdout', '-l', 'chi_sim+eng'], + capture_output=True, text=True, timeout=30 + ) + if result.returncode == 0: + print("OCR Result (system tesseract):") + print(result.stdout) + else: + print(f"Tesseract error: {result.stderr}") + except FileNotFoundError: + print("System tesseract not found either") + except Exception as e: + print(f"Error running tesseract: {e}") + +# If nothing works, try reading raw pixels to detect if it's a text screenshot +try: + from PIL import Image + img = Image.open(image_path) + # Print first few pixel values to understand the image + pixels = list(img.getdata())[:20] + print(f"\nFirst 20 pixel values: {pixels}") +except: + pass diff --git a/ocr_screen2.py b/ocr_screen2.py new file mode 100644 index 0000000..a95f4b8 --- /dev/null +++ b/ocr_screen2.py @@ -0,0 +1,23 @@ +import sys +import io +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') + +from PIL import Image + +img = Image.open(r"D:\Yuzu-GCA\screen2.png") +print(f"Format: {img.format}, Size: {img.size}, Mode: {img.mode}") + +# Try pytesseract OCR +try: + import pytesseract + + # Configure tesseract path if needed + # pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe' + + text = pytesseract.image_to_string(img, lang='chi_sim+eng') + print("\n=== OCR Result ===") + print(text) +except ImportError: + print("\npytesseract not available") +except Exception as e: + print(f"\nOCR error: {e}") diff --git a/ocr_script.ps1 b/ocr_script.ps1 new file mode 100644 index 0000000..a1d8df2 --- /dev/null +++ b/ocr_script.ps1 @@ -0,0 +1,43 @@ +# PowerShell script using Windows built-in OCR +Add-Type -AssemblyName System.Drawing +Add-Type -AssemblyName System.Runtime.WindowsRuntime +Add-Type -AssemblyName Windows.Foundation +Add-Type -AssemblyName Windows.Graphics.Imaging +Add-Type -AssemblyName Windows.Media.Ocr + +$winRtTypes = [Windows.Media.Ocr.OcrEngine]::GetType() + +# Load the image +$imagePath = "D:\Yuzu-GCA\screen2.png" +$bitmap = [System.Drawing.Bitmap]::FromFile($imagePath) +Write-Host "Image size: $($bitmap.Width) x $($bitmap.Height)" + +# Convert to stream +$ms = New-Object System.IO.MemoryStream +$bitmap.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png) +$bitmap.Dispose() + +# Create BitmapDecoder +$ms.Seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null +$randomAccessStream = New-Object Windows.Storage.Streams.InMemoryRandomAccessStream +$outputStream = $randomAccessStream.GetOutputStreamAt(0) +$dataWriter = New-Object Windows.Storage.Streams.DataWriter($outputStream) +$bytes = $ms.ToArray() +$dataWriter.WriteBytes($bytes) +$dataWriter.StoreAsync().GetAwaiter().GetResult() | Out-Null +$dataWriter.FlushAsync().GetAwaiter().GetResult() | Out-Null +$ms.Dispose() + +$decoder = [Windows.Graphics.Imaging.BitmapDecoder]::CreateAsync($randomAccessStream).GetAwaiter().GetResult() +$softwareBitmap = [Windows.Graphics.Imaging.SoftwareBitmap]::Convert($decoder.GetSoftwareBitmapAsync().GetAwaiter().GetResult(), [Windows.Graphics.Imaging.BitmapPixelFormat]::Bgra8, [Windows.Graphics.Imaging.BitmapAlphaMode]::Premultiplied) + +# Perform OCR +$engine = [Windows.Media.Ocr.OcrEngine]::TryCreateFromUserProfileLanguages() +$result = $engine.RecognizeAsync($softwareBitmap).GetAwaiter().GetResult() + +# Output results +Write-Host "Recognized text:" +Write-Host "====================" +foreach ($line in $result.Lines) { + Write-Host $line.Text +} diff --git a/ocr_script.py b/ocr_script.py new file mode 100644 index 0000000..59e4143 --- /dev/null +++ b/ocr_script.py @@ -0,0 +1,51 @@ +""" +OCR script to extract text from screen.png +""" +import sys +import os + +image_path = r"D:\Yuzu-GCA\screen.png" + +# Try pytesseract first +try: + import pytesseract + from PIL import Image + img = Image.open(image_path) + text = pytesseract.image_to_string(img, lang='eng+chi_sim') + print("=== pytesseract OCR result ===") + print(text) + sys.exit(0) +except ImportError: + print("pytesseract not available, trying alternative...") + +# Try Windows OCR via winrt +try: + import asyncio + from winsdk.windows.media.ocr import OcrEngine + from winsdk.windows.graphics.imaging import BitmapDecoder + from winsdk.windows.storage.streams import RandomAccessStreamReference + from winsdk.windows.globalization import Language + + async def ocr_windows(): + # Get the default OCR engine for Chinese + engine = OcrEngine.try_create_from_user_profile_languages() + if not engine: + # Fallback to English + engine = OcrEngine.try_create_from_language(Language("en")) + + # Open the image file + file_stream = await RandomAccessStreamReference.create_from_file(image_path).open_read_async() + decoder = await BitmapDecoder.create_async(file_stream) + bitmap = await decoder.get_software_bitmap_async() + + result = await engine.recognize_async(bitmap) + print("=== Windows OCR result ===") + for line in result.lines: + print(line.text) + + asyncio.run(ocr_windows()) + sys.exit(0) +except ImportError: + print("winsdk not available either") + +print("No OCR engine available. Please install pytesseract or Windows SDK.") diff --git a/ocr_win.py b/ocr_win.py new file mode 100644 index 0000000..d887d3f --- /dev/null +++ b/ocr_win.py @@ -0,0 +1,48 @@ +import sys +import io +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') + +print("Attempting Windows OCR...") + +try: + import asyncio + from winsdk.windows.media.ocr import OcrEngine + from winsdk.windows.graphics.imaging import BitmapDecoder + from winsdk.windows.storage.streams import RandomAccessStreamReference + from winsdk.windows.globalization import Language + import os + + async def ocr(): + path = os.path.abspath(r"D:\Yuzu-GCA\screen2.png") + print(f"Opening: {path}") + + # Try to get engine for Chinese + engine = OcrEngine.try_create_from_user_profile_languages() + if not engine: + print("No user profile languages, trying Chinese...") + engine = OcrEngine.try_create_from_language(Language("zh-Hans")) + if not engine: + print("Trying English...") + engine = OcrEngine.try_create_from_language(Language("en")) + + if not engine: + print("No OCR engine available") + return + + print(f"Using OCR engine: {engine.recognizer_language.display_name}") + + file_stream = await RandomAccessStreamReference.create_from_file(path).open_read_async() + decoder = await BitmapDecoder.create_async(file_stream) + bitmap = await decoder.get_software_bitmap_async() + + result = await engine.recognize_async(bitmap) + print(f"\n=== Windows OCR Result ({result.lines.size} lines) ===") + for line in result.lines: + print(line.text) + + asyncio.run(ocr()) + +except ImportError as e: + print(f"winsdk not available: {e}") +except Exception as e: + print(f"Error: {e}") diff --git a/ota/manifest-beta.json b/ota/manifest-beta.json index 0204d8d..f46332b 100644 --- a/ota/manifest-beta.json +++ b/ota/manifest-beta.json @@ -3,10 +3,10 @@ "builds": { "android": { "type": "apk", - "tag": "v0.1.0-dav-android-7", - "url": "https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-7/v0.1.0-dav-android-7-debug.apk", - "sha256": "e9420218c8f90bd158043758b0fdb0d308f7047a52b9b7317f6a824431a6e017", - "size": 3236861, + "tag": "v0.1.0-dav-android-8", + "url": "https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-8/v0.1.0-dav-android-8-debug.apk", + "sha256": "b2451a398ea2dd34e585c5ec4529d6654451c9b9ab4ddf4a25ec9b032f0ac2bf", + "size": 3506569, "channel": "beta", "minVersion": "0.1.0" } diff --git a/ota/manifest-nightly.json b/ota/manifest-nightly.json index 7d26412..254287d 100644 --- a/ota/manifest-nightly.json +++ b/ota/manifest-nightly.json @@ -3,10 +3,10 @@ "builds": { "android": { "type": "apk", - "tag": "v0.1.0-dav-android-7", - "url": "https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-7/v0.1.0-dav-android-7-debug.apk", - "sha256": "e9420218c8f90bd158043758b0fdb0d308f7047a52b9b7317f6a824431a6e017", - "size": 3236861, + "tag": "v0.1.0-dav-android-8", + "url": "https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-8/v0.1.0-dav-android-8-debug.apk", + "sha256": "b2451a398ea2dd34e585c5ec4529d6654451c9b9ab4ddf4a25ec9b032f0ac2bf", + "size": 3506569, "channel": "nightly", "minVersion": "0.1.0" } diff --git a/ota/manifest-stable.json b/ota/manifest-stable.json index b0465fd..485c2b7 100644 --- a/ota/manifest-stable.json +++ b/ota/manifest-stable.json @@ -3,10 +3,10 @@ "builds": { "android": { "type": "apk", - "tag": "v0.1.0-dav-android-7", - "url": "https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-7/v0.1.0-dav-android-7-debug.apk", - "sha256": "e9420218c8f90bd158043758b0fdb0d308f7047a52b9b7317f6a824431a6e017", - "size": 3236861, + "tag": "v0.1.0-dav-android-8", + "url": "https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-8/v0.1.0-dav-android-8-debug.apk", + "sha256": "b2451a398ea2dd34e585c5ec4529d6654451c9b9ab4ddf4a25ec9b032f0ac2bf", + "size": 3506569, "channel": "stable", "minVersion": "0.1.0" } diff --git a/packages/client-android/android/.gradle/8.10.2/executionHistory/executionHistory.bin b/packages/client-android/android/.gradle/8.10.2/executionHistory/executionHistory.bin index fc86f27..bfd9d47 100644 Binary files a/packages/client-android/android/.gradle/8.10.2/executionHistory/executionHistory.bin and b/packages/client-android/android/.gradle/8.10.2/executionHistory/executionHistory.bin differ diff --git a/packages/client-android/android/.gradle/8.10.2/executionHistory/executionHistory.lock b/packages/client-android/android/.gradle/8.10.2/executionHistory/executionHistory.lock index ad6c80b..1f0d76e 100644 Binary files a/packages/client-android/android/.gradle/8.10.2/executionHistory/executionHistory.lock and b/packages/client-android/android/.gradle/8.10.2/executionHistory/executionHistory.lock differ diff --git a/packages/client-android/android/.gradle/8.10.2/fileHashes/fileHashes.bin b/packages/client-android/android/.gradle/8.10.2/fileHashes/fileHashes.bin index 3deefe3..06b1b6d 100644 Binary files a/packages/client-android/android/.gradle/8.10.2/fileHashes/fileHashes.bin and b/packages/client-android/android/.gradle/8.10.2/fileHashes/fileHashes.bin differ diff --git a/packages/client-android/android/.gradle/8.10.2/fileHashes/fileHashes.lock b/packages/client-android/android/.gradle/8.10.2/fileHashes/fileHashes.lock index 5647a9a..c13f9e0 100644 Binary files a/packages/client-android/android/.gradle/8.10.2/fileHashes/fileHashes.lock and b/packages/client-android/android/.gradle/8.10.2/fileHashes/fileHashes.lock differ diff --git a/packages/client-android/android/.gradle/8.10.2/fileHashes/resourceHashesCache.bin b/packages/client-android/android/.gradle/8.10.2/fileHashes/resourceHashesCache.bin index 08134ea..5088aad 100644 Binary files a/packages/client-android/android/.gradle/8.10.2/fileHashes/resourceHashesCache.bin and b/packages/client-android/android/.gradle/8.10.2/fileHashes/resourceHashesCache.bin differ diff --git a/packages/client-android/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/packages/client-android/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 14f786d..1eb839f 100644 Binary files a/packages/client-android/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/packages/client-android/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/packages/client-android/android/.gradle/file-system.probe b/packages/client-android/android/.gradle/file-system.probe index 3529c0a..efede01 100644 Binary files a/packages/client-android/android/.gradle/file-system.probe and b/packages/client-android/android/.gradle/file-system.probe differ diff --git a/packages/client-android/android/app/build.gradle b/packages/client-android/android/app/build.gradle index 8dd38fe..56c99ba 100644 --- a/packages/client-android/android/app/build.gradle +++ b/packages/client-android/android/app/build.gradle @@ -9,7 +9,7 @@ android { applicationId "dev.yuzu.gca" minSdk 24 targetSdk 35 - versionCode 7 + versionCode 8 versionName "0.1.0" } diff --git a/packages/client-android/android/app/src/main/java/dev/yuzu/gca/MainActivity.kt b/packages/client-android/android/app/src/main/java/dev/yuzu/gca/MainActivity.kt index ea18485..f11cf77 100644 --- a/packages/client-android/android/app/src/main/java/dev/yuzu/gca/MainActivity.kt +++ b/packages/client-android/android/app/src/main/java/dev/yuzu/gca/MainActivity.kt @@ -43,7 +43,7 @@ class MainActivity : AppCompatActivity() { layout.addView(title) val versionInfo = TextView(this).apply { - text = "v0.1.0-dav-android-7-debug" + text = "v0.1.0-dav-android-8-debug" textSize = 12f setTextColor(Color.GRAY) setPadding(0, 0, 0, 12) diff --git a/read_png.py b/read_png.py new file mode 100644 index 0000000..e8e01ec --- /dev/null +++ b/read_png.py @@ -0,0 +1,35 @@ +""" +Read screen.png as UTF-16 LE text and save decoded text to file. +""" +import sys + +path = r"D:\Yuzu-GCA\screen.png" +out_path = r"D:\Yuzu-GCA\screen_decoded.txt" + +# Read raw bytes +with open(path, 'rb') as f: + raw = f.read() + +print(f"File size: {len(raw)} bytes") + +# Decode as UTF-16 LE (skip BOM) +text = raw.decode('utf-16-le') +print(f"Decoded text length: {len(text)} characters") + +# Write full decoded text to file +with open(out_path, 'w', encoding='utf-8') as f: + f.write(text) +print(f"Full decoded text written to: {out_path}") + +# Print first 3000 chars (replace non-printable) +safe_text = text[:3000].encode('ascii', errors='replace').decode('ascii') +print("\n=== First 3000 characters (non-ASCII replaced) ===") +print(safe_text) + +# Search for specific keywords +keywords = ['manifest', 'download', 'SHA256', 'verify', 'install', 'OTA', 'version', 'error', 'fail', 'success', 'pass', 'update', '下载', '校验', '安装', '版本'] +print("\n=== Keyword search ===") +for kw in keywords: + count = text.count(kw) + if count > 0: + print(f"'{kw}' found {count} times") diff --git a/recover_png.py b/recover_png.py new file mode 100644 index 0000000..c0bad9a --- /dev/null +++ b/recover_png.py @@ -0,0 +1,73 @@ +""" +Try to recover the original image from screen.png. + +Strategy 1: Decode as UTF-16 LE, then encode back to bytes via UTF-16 LE. +This should give us the raw bytes without the BOM. + +Strategy 2: Try to interpret as raw pixel data (e.g. RGBA raw dump). + +Strategy 3: Check if the decoded text contains base64 encoded image data. +""" +import sys +import re + +path = r"D:\Yuzu-GCA\screen.png" + +with open(path, 'rb') as f: + raw = f.read() + +# Decode as UTF-16 LE (with BOM automatically handled by Python) +text = raw.decode('utf-16-le') + +# Strategy 1: Re-encode as UTF-16 LE to get bytes +reencoded = text.encode('utf-16-le') +print(f"Re-encoded size: {len(reencoded)} bytes") + +# Check if it's a valid PNG after removing BOM +# Original raw starts with ff fe, so raw[2:] should equal reencoded +print(f"Original raw[2:] == reencoded: {raw[2:] == reencoded}") + +# Now, what if the original binary PNG was processed wrong? +# Let's look at the first few bytes of reencoded +print(f"First 20 bytes of reencoded: {reencoded[:20].hex(' ')}") +print(f"First 20 bytes of raw (no BOM): {raw[2:22].hex(' ')}") + +# The reencoded bytes should NOT be a valid PNG (since they start with RXNG etc.) +# But maybe the original PNG bytes were: each char's ord() is two PNG bytes? +# For ASCII chars like 'I', ord('I')=0x49, but 'I' in UTF-16LE is 49 00 +# So each char gives us: low_byte = ord(c) & 0xFF, high_byte = (ord(c) >> 8) & 0xFF +# If the original PNG had 49 00 at some point, that would become 'I' in UTF-16LE text + +# Let's try: take each char, extract its two bytes +# For chars in BMP: char -> code point -> 2 bytes +bytes_from_chars = bytearray() +for ch in text: + cp = ord(ch) + if cp <= 0xFFFF: + bytes_from_chars.append(cp & 0xFF) + bytes_from_chars.append((cp >> 8) & 0xFF) + else: + # Surrogate pair - skip for now + pass + +print(f"\nBytes from chars (first 20): {bytes(bytes_from_chars[:20]).hex(' ')}") + +# Check if this is a valid PNG +if bytes_from_chars[:8] == b'\x89PNG\r\n\x1a\n': + print("SUCCESS: This is a valid PNG!") + # Write the recovered PNG + with open(r"D:\Yuzu-GCA\screen_recovered.png", 'wb') as f: + f.write(bytes_from_chars) + print("Recovered PNG written to screen_recovered.png") +else: + print(f"Not a PNG. First 8 bytes: {bytes(bytes_from_chars[:8]).hex(' ')}") + # Check what it starts with + print(f"As text: {bytes(bytes_from_chars[:8])}") + +# Strategy 2: Maybe the text contains base64? +# Search for base64 patterns +b64_pattern = r'[A-Za-z0-9+/=]{50,}' +b64_matches = re.findall(b64_pattern, text) +print(f"\nBase64-like strings found: {len(b64_matches)}") +for m in b64_matches[:3]: + print(f" {m[:80]}...") diff --git a/screen2.png b/screen2.png new file mode 100644 index 0000000..16c515b Binary files /dev/null and b/screen2.png differ diff --git a/screen_decoded.txt b/screen_decoded.txt new file mode 100644 index 0000000..c5b1f4d Binary files /dev/null and b/screen_decoded.txt differ diff --git a/screen_fixed.png b/screen_fixed.png new file mode 100644 index 0000000..76b4e21 Binary files /dev/null and b/screen_fixed.png differ diff --git a/screen_fixed2.png b/screen_fixed2.png new file mode 100644 index 0000000..eb053dc Binary files /dev/null and b/screen_fixed2.png differ diff --git a/screen_full_text.txt b/screen_full_text.txt new file mode 100644 index 0000000..c5b1f4d Binary files /dev/null and b/screen_full_text.txt differ diff --git a/search_text.py b/search_text.py new file mode 100644 index 0000000..06a9f7e --- /dev/null +++ b/search_text.py @@ -0,0 +1,35 @@ +""" +Search for readable ASCII strings in the decoded text from screen.png. +""" +import sys +import re + +path = r"D:\Yuzu-GCA\screen.png" + +with open(path, 'rb') as f: + raw = f.read() + +# Decode as UTF-16 LE +text = raw.decode('utf-16-le') + +# Find all printable ASCII sequences of length >= 4 +matches = re.findall(r'[ -~]{4,}', text) +print(f"Found {len(matches)} ASCII strings of length >= 4") +print("\n=== First 60 matches ===") +for i, m in enumerate(matches[:60]): + print(f" [{i}] '{m}'") + +# Also search for specific patterns +patterns = ['OTA', 'update', 'download', 'install', 'version', 'error', 'fail', + 'success', 'manifest', 'SHA256', 'verify', 'check', '完成', '下载', + '安装', '校验', '版本', '测试', '日志'] +print("\n=== Pattern search ===") +for p in patterns: + count = text.count(p) + if count > 0: + # Find context around first occurrence + idx = text.find(p) + start = max(0, idx - 30) + end = min(len(text), idx + len(p) + 50) + ctx = text[start:end].encode('ascii', errors='replace').decode('ascii') + print(f" '{p}' found {count} times. First context: ...{ctx}...") diff --git a/tessdata_temp b/tessdata_temp new file mode 160000 index 0000000..ced7875 --- /dev/null +++ b/tessdata_temp @@ -0,0 +1 @@ +Subproject commit ced78752cc61322fb554c280d13360b35b8684e4