Files
ImHex-Patterns/patterns/gif.hexpat
paxcut 5b32941801 patterns: Added visualizers to image patterns (#117)
* Added image visualizers to image patterns that were supported

* missing include files

* Small style fixes

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2023-06-04 22:38:25 +02:00

183 lines
5.1 KiB
Rust

#pragma MIME image/gif
// Extension Labels
#define LABEL_GC 0xF9
#define LABEL_COMMENT 0xFE
#define LABEL_APPLICATION 0xFF
#define LABEL_PLAINTEXT 0x01
// Indentifier Magics
#define IMAGE_SEPERATOR_MAGIC 0x2C
#define EXTENSION_INTRODUCER_MAGIC 0x21
#define GIF_TRAILER_MAGIC 0x3B
#include <std/io.pat>
#include <std/core.pat>
#include <std/mem.pat>
#include <std/string.pat>
#include <std/math.pat>
#include <type/magic.pat>
bitfield GCT_Flags {
size : 3 [[comment("physical size = 2^(flags.size + 1)")]];
sort : 1 [[comment("Indicates if the table is sorted by importance")]];
colorRes : 3 [[comment("Indicates the richness of the original pallet")]];
enabled : 1;
};
bitfield ImageDescriptorFlags {
lctSize: 3;
reserved: 2;
lctSort: 1;
interlaceFlag: 1;
lctEnable: 1;
};
bitfield GCE_Flags {
transparent : 1;
userInput : 1;
disposalMode : 3 [[format("format::dispose_enum")]];
reserved : 3;
};
struct Color {
u8 red;
u8 green;
u8 blue;
} [[color(std::format("{:02X}{:02X}{:02X}", red, green, blue))]];
struct _SubBlocks {
u8 data_size;
u8 data[data_size];
};
struct DataSubBlocks {
_SubBlocks subBlocks[while(std::mem::read_unsigned($, 1) != 0)];
};
struct Header {
type::Magic<"GIF"> magic;
char version[3];
};
struct LogicalScreenDescriptor {
u16 width;
u16 height;
GCT_Flags gctFlags;
u8 bgColorIndex;
u8 pixelAscpet;
if (gctFlags.enabled) {
Color gct[std::math::pow(2, gctFlags.size + 1)];
}
};
struct ImageDescriptor {
u16 imageLeftPosition;
u16 imageTopPosition;
u16 imageWidth;
u16 imageHeight;
ImageDescriptorFlags flags;
if(flags.lctEnable) {
Color lct[std::math::pow(2, flags.lctSize + 1)];
}
u8 lzwMinCode [[comment("This byte determines the initial number of bits used for LZW codes in the image data")]];
DataSubBlocks lzwCompressedData [[comment("Data is pallet indecies either into current LDC or GCT and is compressed using LZW")]];
};
struct CommentExtension {
DataSubBlocks commentData;
};
struct ApplicationExtension {
u8 blockSize;
char identifier[8];
char authenticationCode[3];
DataSubBlocks applicationData;
};
struct PlainTextExtension {
u8 blockSize;
u16 textGridLeftPos;
u16 textGridTopPos;
u16 textGridWidth;
u16 textGridHeight;
u8 charCellWidth;
u8 charCellHeight;
u8 textForegroundColorIndex;
u8 textBackgroundColorIndex;
DataSubBlocks plainTextData;
};
struct GraphicControlExtension {
u8 blockSize;
std::assert_warn(blockSize == 4, "Unexpected GCE block size");
GCE_Flags flags;
u16 delay [[format("format::delay")]];
u8 transparentColorIndex;
};
struct Extension {
u8 label [[format("format::extension_name")]];
if(label == LABEL_GC) GraphicControlExtension gce [[inline]];
if(label == LABEL_COMMENT) CommentExtension c [[inline]];
if(label == LABEL_APPLICATION) ApplicationExtension a [[inline]];
if(label == LABEL_PLAINTEXT) PlainTextExtension p [[inline]];
};
struct Block {
u8 identifier [[format("format::identifier_name")]];
if(identifier == IMAGE_SEPERATOR_MAGIC) ImageDescriptor i [[inline]];
if(identifier == EXTENSION_INTRODUCER_MAGIC) Extension e [[inline]];
if(identifier == GIF_TRAILER_MAGIC) break;
u8 blockTerminator;
} [[format("format::block_name")]];
namespace format {
fn dispose_enum(u8 value) {
if(value == 0x00) return "Do nothing";
if(value == 0x01) return "Do not remove pixels";
if(value == 0x02) return "Restore background pixels";
if(value == 0x03) return "Restore previous pixels";
};
fn extension_name(u8 label) {
if(label == LABEL_GC) return "Graphical Control Extension";
if(label == LABEL_COMMENT) return "Comment Extension";
if(label == LABEL_APPLICATION) return "Application Extension";
if(label == LABEL_PLAINTEXT) return "Plaintext Extension";
return "Unknown Extension";
};
fn block_name(ref Block b) {
if(b.identifier == IMAGE_SEPERATOR_MAGIC) return "Image Descriptor";
if(b.identifier == EXTENSION_INTRODUCER_MAGIC) return "Extension";
if(b.identifier == GIF_TRAILER_MAGIC) return "Trailer";
return "Unknown Block Type";
};
fn identifier_name(u8 identifier) {
if(identifier == IMAGE_SEPERATOR_MAGIC) return "Image Separator";
if(identifier == EXTENSION_INTRODUCER_MAGIC) return "Extension Introducer";
if(identifier == GIF_TRAILER_MAGIC) return "GIF Trailer";
return "Unknown Identifier";
};
fn delay(u16 delay) {
if(delay == -1) return "forever";
else if(delay < 2) return "100ms";
else return std::string::to_string(delay * 10) + "ms";
return "notime";
};
}
struct Gif {
u8 data[std::mem::size()] [[no_unique_address, hidden]];
Header header;
std::assert_warn(header.version == "89a" || header.version == "87a", "Unsupported format version");
LogicalScreenDescriptor logicalScreenDescriptor;
Block blocks[while(!std::mem::eof())];
} [[hex::visualize("image", this.data)]];
Gif gif @ 0x00;