Created
December 6, 2020 12:15
-
-
Save GMMan/c1f0b516afdbb71769752ee06adbbd9a to your computer and use it in GitHub Desktop.
Game & Watch splash converter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
namespace GameAndWatchBackdropToGif | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
if (args.Length != 2) | |
{ | |
Console.WriteLine("Usage: GameAndWatchBackdropToGif <decrypted_flash_path> <output_path>"); | |
return; | |
} | |
int[] offsets = new int[] | |
{ | |
0xcd858, | |
0xc58f8, | |
0xec318, | |
0xe16f8, | |
0xd6c78 | |
}; | |
using FileStream ifs = File.OpenRead(args[0]); | |
BinaryReader br = new BinaryReader(ifs); | |
Directory.CreateDirectory(args[1]); | |
for (int i = 0; i < offsets.Length; ++i) | |
{ | |
ifs.Seek(offsets[i], SeekOrigin.Begin); | |
Convert(br, Path.Combine(args[1], i + ".gif")); | |
} | |
} | |
static void Rgb565ToRgba32(ushort pix, out byte r, out byte g, out byte b) | |
{ | |
r = (byte)(((pix >> 11) * 255 + 15) / 31); | |
g = (byte)((((pix >> 5) & 0x3f) * 255 + 31) / 63); | |
b = (byte)(((pix & 0x1f) * 255 + 15) / 31); | |
} | |
static void Convert(BinaryReader br, string path) | |
{ | |
using FileStream ofs = File.Create(path); | |
BinaryWriter bw = new BinaryWriter(ofs); | |
// Header | |
bw.Write("GIF".ToCharArray()); | |
bw.Write("89a".ToCharArray()); | |
// Logical screen descriptor | |
ushort width = br.ReadUInt16(); | |
ushort height = br.ReadUInt16(); | |
byte paletteSize = br.ReadByte(); | |
br.ReadByte(); // padding | |
ushort[] palette = new ushort[paletteSize]; | |
for (int i = 0; i < palette.Length; ++i) | |
{ | |
palette[i] = br.ReadUInt16(); | |
} | |
int gctSize = 0; | |
int calcGctSize = 2; | |
while (calcGctSize < paletteSize) | |
{ | |
++gctSize; | |
calcGctSize <<= 1; | |
} | |
bw.Write(width); | |
bw.Write(height); | |
bw.Write((byte)((1 << 7) | gctSize)); | |
bw.Write((byte)0); | |
bw.Write((byte)0); | |
// Global color table | |
for (int i = 0; i < calcGctSize; ++i) | |
{ | |
if (i < palette.Length) | |
{ | |
Rgb565ToRgba32(palette[i], out byte r, out byte g, out byte b); | |
bw.Write(r); | |
bw.Write(g); | |
bw.Write(b); | |
} | |
else | |
{ | |
bw.Write((byte)0); | |
bw.Write((byte)0); | |
bw.Write((byte)0); | |
} | |
} | |
// Image descriptor | |
bw.Write((byte)0x2c); | |
bw.Write((ushort)0); // x | |
bw.Write((ushort)0); // y | |
bw.Write(width); | |
bw.Write(height); | |
bw.Write((byte)0); // no flags | |
// Frame | |
byte minCodeSize = br.ReadByte(); | |
bw.Write(minCodeSize); | |
while (true) | |
{ | |
byte blockSize = br.ReadByte(); | |
bw.Write(blockSize); | |
if (blockSize == 0) break; | |
byte[] block = br.ReadBytes(blockSize); | |
bw.Write(block); | |
} | |
byte trailer = br.ReadByte(); | |
if (trailer != 0x3b) throw new InvalidDataException("Invalid GIF trailer"); | |
bw.Write(trailer); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment