Compare commits
4 Commits
3e4230e46f
...
354155db20
Author | SHA1 | Date |
---|---|---|
Jarrod Doyle | 354155db20 | |
Jarrod Doyle | f6e35f5b7a | |
Jarrod Doyle | fbec9db3f6 | |
Jarrod Doyle | a9a16f88e9 |
|
@ -35,11 +35,9 @@ public class GifDecoder
|
||||||
LogicalScreenHeight = reader.ReadUInt16();
|
LogicalScreenHeight = reader.ReadUInt16();
|
||||||
var flags = reader.ReadByte();
|
var flags = reader.ReadByte();
|
||||||
HasGlobalColorTable = ((flags >> 7) & 0x1) != 0;
|
HasGlobalColorTable = ((flags >> 7) & 0x1) != 0;
|
||||||
// Godot.GD.Print($"HALLO WE HAVE GLOBAL TABLE? {HasGlobalColorTable}");
|
|
||||||
BitsPerColorChannel = (byte)(((flags >> 4) & 0x7) + 1);
|
BitsPerColorChannel = (byte)(((flags >> 4) & 0x7) + 1);
|
||||||
IsGlobalColorTableSorted = ((flags >> 3) & 0x1) != 0;
|
IsGlobalColorTableSorted = ((flags >> 3) & 0x1) != 0;
|
||||||
GlobalColorTableSize = (int)Math.Pow(2, (flags & 0x7) + 1);
|
GlobalColorTableSize = (int)Math.Pow(2, (flags & 0x7) + 1);
|
||||||
// Godot.GD.Print($"Global colour size? {GlobalColorTableSize}");
|
|
||||||
BackgroundColorIndex = reader.ReadByte();
|
BackgroundColorIndex = reader.ReadByte();
|
||||||
var rawAspectRatio = reader.ReadByte();
|
var rawAspectRatio = reader.ReadByte();
|
||||||
if (rawAspectRatio == 0)
|
if (rawAspectRatio == 0)
|
||||||
|
@ -86,6 +84,7 @@ public class GifDecoder
|
||||||
private byte[] _colors;
|
private byte[] _colors;
|
||||||
private byte[] _pixelIndices;
|
private byte[] _pixelIndices;
|
||||||
private int _transparentIndex;
|
private int _transparentIndex;
|
||||||
|
private readonly bool _interlaced;
|
||||||
|
|
||||||
public ImageData(BinaryReader reader, byte[] globalColors, int transparentIndex)
|
public ImageData(BinaryReader reader, byte[] globalColors, int transparentIndex)
|
||||||
{
|
{
|
||||||
|
@ -95,7 +94,7 @@ public class GifDecoder
|
||||||
var height = reader.ReadUInt16();
|
var height = reader.ReadUInt16();
|
||||||
var flags = reader.ReadByte();
|
var flags = reader.ReadByte();
|
||||||
var hasLocalColorTable = ((flags >> 7) & 0x1) != 0;
|
var hasLocalColorTable = ((flags >> 7) & 0x1) != 0;
|
||||||
var interlaced = ((flags >> 6) & 0x1) != 0; // See appendix E for interlacing
|
_interlaced = ((flags >> 6) & 0x1) != 0; // See appendix E for interlacing
|
||||||
var isLocalColorTableSorted = ((flags >> 5) & 0x1) != 0;
|
var isLocalColorTableSorted = ((flags >> 5) & 0x1) != 0;
|
||||||
var sizeOfLocalColorTable = (byte)Math.Pow(2, (flags & 0x7) + 1);
|
var sizeOfLocalColorTable = (byte)Math.Pow(2, (flags & 0x7) + 1);
|
||||||
byte[] colors;
|
byte[] colors;
|
||||||
|
@ -140,7 +139,6 @@ public class GifDecoder
|
||||||
compressedBytes.AddRange(bytes);
|
compressedBytes.AddRange(bytes);
|
||||||
blockSize = reader.ReadByte();
|
blockSize = reader.ReadByte();
|
||||||
}
|
}
|
||||||
// Godot.GD.Print($"End of image data: {reader.BaseStream.Position}");
|
|
||||||
|
|
||||||
using MemoryStream compressedStream = new(compressedBytes.ToArray());
|
using MemoryStream compressedStream = new(compressedBytes.ToArray());
|
||||||
using BinaryReader compressedReader = new(compressedStream, Encoding.UTF8, false);
|
using BinaryReader compressedReader = new(compressedStream, Encoding.UTF8, false);
|
||||||
|
@ -180,7 +178,6 @@ public class GifDecoder
|
||||||
}
|
}
|
||||||
else if (code == endCode)
|
else if (code == endCode)
|
||||||
{
|
{
|
||||||
// Godot.GD.Print($"CompressedBytesLeft: {compressedReader.BaseStream.Length - compressedReader.BaseStream.Position}");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (code < codeCount)
|
else if (code < codeCount)
|
||||||
|
@ -256,17 +253,49 @@ public class GifDecoder
|
||||||
{
|
{
|
||||||
var bytesIdx = 0;
|
var bytesIdx = 0;
|
||||||
var bytes = new byte[Width * Height * 4];
|
var bytes = new byte[Width * Height * 4];
|
||||||
|
|
||||||
|
void WritePixelBytes(int bytesOffset, int colorIndex)
|
||||||
|
{
|
||||||
|
bytes[bytesOffset] = _colors[colorIndex * 3];
|
||||||
|
bytes[bytesOffset + 1] = _colors[colorIndex * 3 + 1];
|
||||||
|
bytes[bytesOffset + 2] = _colors[colorIndex * 3 + 2];
|
||||||
|
bytes[bytesOffset + 3] = (byte)((colorIndex == _transparentIndex) ? 0 : 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_interlaced)
|
||||||
|
{
|
||||||
foreach (var colorIndex in _pixelIndices)
|
foreach (var colorIndex in _pixelIndices)
|
||||||
{
|
{
|
||||||
bytes[bytesIdx++] = _colors[colorIndex * 3];
|
WritePixelBytes(bytesIdx, colorIndex);
|
||||||
bytes[bytesIdx++] = _colors[colorIndex * 3 + 1];
|
bytesIdx += 4;
|
||||||
bytes[bytesIdx++] = _colors[colorIndex * 3 + 2];
|
|
||||||
// Fuck you LGS hardcoding the transparent index suck my balls
|
|
||||||
// bytes[bytesIdx++] = (byte)((colorIndex == _transparentIndex) ? 0 : 255);
|
|
||||||
bytes[bytesIdx++] = (byte)((colorIndex == 0) ? 0 : 255);
|
|
||||||
}
|
}
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pass = 0;
|
||||||
|
var inc = 8;
|
||||||
|
var y = 0;
|
||||||
|
var indicesOffset = 0;
|
||||||
|
var bytesPerRow = Width * 4;
|
||||||
|
for (var i = 0; i < Height; i++)
|
||||||
|
{
|
||||||
|
bytesIdx = y * bytesPerRow;
|
||||||
|
for (var x = 0; x < Width; x++)
|
||||||
|
{
|
||||||
|
WritePixelBytes(bytesIdx + x * 4, _pixelIndices[indicesOffset++]);
|
||||||
|
}
|
||||||
|
|
||||||
|
y += inc;
|
||||||
|
if (y >= Height)
|
||||||
|
{
|
||||||
|
pass += 1;
|
||||||
|
y = (int)(8 / Math.Pow(2, pass));
|
||||||
|
inc = y * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Header _header;
|
Header _header;
|
||||||
|
@ -280,15 +309,12 @@ public class GifDecoder
|
||||||
throw new FileNotFoundException();
|
throw new FileNotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Godot.GD.Print($"Decoding image at: {path}");
|
|
||||||
|
|
||||||
using MemoryStream stream = new(File.ReadAllBytes(path));
|
using MemoryStream stream = new(File.ReadAllBytes(path));
|
||||||
using BinaryReader reader = new(stream, Encoding.UTF8, false);
|
using BinaryReader reader = new(stream, Encoding.UTF8, false);
|
||||||
|
|
||||||
_header = new Header(reader);
|
_header = new Header(reader);
|
||||||
_globalColors = ReadColorTable(reader, _header.HasGlobalColorTable ? _header.GlobalColorTableSize : 0);
|
_globalColors = ReadColorTable(reader, _header.HasGlobalColorTable ? _header.GlobalColorTableSize : 0);
|
||||||
var images = new List<ImageData>();
|
var images = new List<ImageData>();
|
||||||
var transparentIndex = -1;
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var id = reader.ReadByte();
|
var id = reader.ReadByte();
|
||||||
|
@ -296,22 +322,18 @@ public class GifDecoder
|
||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
case 0x2C: // Image
|
case 0x2C: // Image
|
||||||
// Godot.GD.Print("Adding new image!!");
|
images.Add(new ImageData(reader, _globalColors, 0));
|
||||||
images.Add(new ImageData(reader, _globalColors, transparentIndex));
|
|
||||||
transparentIndex = -1;
|
|
||||||
break;
|
break;
|
||||||
case 0x21: // Extension
|
case 0x21: // Extension
|
||||||
var extId = reader.ReadByte();
|
// We don't need to actually handle any extensions. The only one that's
|
||||||
if (extId == 0xF9)
|
// potentially relevant is GraphicsControl, but Dark uses a hardcoded
|
||||||
|
// transparency palette index and doesn't use multi-frame GIFs with timing.
|
||||||
|
reader.ReadByte();
|
||||||
|
var blockSize = reader.ReadByte();
|
||||||
|
while (blockSize != 0)
|
||||||
{
|
{
|
||||||
var graphicsControl = new GraphicsControl(reader);
|
reader.ReadBytes(blockSize);
|
||||||
transparentIndex = graphicsControl.TransparencyIndex;
|
blockSize = reader.ReadByte();
|
||||||
// Godot.GD.Print($"We set the transparent index: {transparentIndex} for {path}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We don't support Comment (0xFE), Text (0x01), or Application (0xFF) extensions
|
|
||||||
throw new InvalidDataException($"Unknown or unsupported extension identifier in GIF file: {extId}");
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x3B:
|
case 0x3B:
|
||||||
|
|
Loading…
Reference in New Issue