patterns: Added new WebP and VGM patterns (#294)

* README: fix square bracket

* patterns: add WebP pattern

* patterns/dds: add x-dds mimetype

* patterns: add vgm pattern

* patterns/vgm: remove old pointer

* patterns/protobuf: fix field number handling

* patterns/protobuf: add .pb file extension

* patterns/uf2: updating the family IDs again

* patterns/png: add cHRM and tIME chunks

* patterns/png: whoops, old description snuck back in

* new quantized-mesh pattern

* add quantized-mesh to README, implement oct16 decoding
This commit is contained in:
applecuckoo
2024-11-18 01:53:18 +13:00
committed by GitHub
parent 6697fc23a4
commit bf94cb7243
9 changed files with 604 additions and 15 deletions

View File

@@ -25,7 +25,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
|------|------|------|-------------| |------|------|------|-------------|
| 3DS | | [`patterns/3ds.hexpat`](patterns/3ds.hexpat) | Autodesk 3DS Max Model file | | 3DS | | [`patterns/3ds.hexpat`](patterns/3ds.hexpat) | Autodesk 3DS Max Model file |
| 7Z | | [`patterns/7z.hexpat`](patterns/7z.hexpat) | 7z File Format | | 7Z | | [`patterns/7z.hexpat`](patterns/7z.hexpat) | 7z File Format |
| ADTS | | [`patterns/adts.hexpat`(patterns/adts.hexpat) | ADTS/AAC audio files | | ADTS | | [`patterns/adts.hexpat`](patterns/adts.hexpat) | ADTS/AAC audio files |
| AFE2 | | [`patterns/afe2.hexpat`](patterns/afe2.hexpat) | Nintendo Switch Atmosphère CFW Fatal Error log | | AFE2 | | [`patterns/afe2.hexpat`](patterns/afe2.hexpat) | Nintendo Switch Atmosphère CFW Fatal Error log |
| ANI | `application/x-navi-animation` | [`patterns/ani.hexpat`](patterns/ani.hexpat) | Windows Animated Cursor file | | ANI | `application/x-navi-animation` | [`patterns/ani.hexpat`](patterns/ani.hexpat) | Windows Animated Cursor file |
| AR | `application/x-archive` | [`patterns/ar.hexpat`](patterns/ar.hexpat) | Static library archive files | | AR | `application/x-archive` | [`patterns/ar.hexpat`](patterns/ar.hexpat) | Static library archive files |
@@ -115,6 +115,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
| PYC | | [`patterns/pyc.hexpat`](patterns/pyc.hexpat) | Python bytecode files | | PYC | | [`patterns/pyc.hexpat`](patterns/pyc.hexpat) | Python bytecode files |
| QBCL | | [`patterns/qbcl.hexpat`](patterns/qbcl.hexpat) | Qubicle voxel scene project file | | QBCL | | [`patterns/qbcl.hexpat`](patterns/qbcl.hexpat) | Qubicle voxel scene project file |
| QOI | `image/qoi` | [`patterns/qoi.hexpat`](patterns/qoi.hexpat) | QOI image files | | QOI | `image/qoi` | [`patterns/qoi.hexpat`](patterns/qoi.hexpat) | QOI image files |
| quantized-mesh | | [`patterns/quantized-mesh.hexpat`](patterns/quantized-mesh.hexpat) | Cesium quantized-mesh terrain |
| RAS | `image/x-sun-raster` | [`patterns/ras.hexpat`](patterns/ras.hexpat) | RAS image files | | RAS | `image/x-sun-raster` | [`patterns/ras.hexpat`](patterns/ras.hexpat) | RAS image files |
| ReFS | | [`patterns/refs.hexpat`](patterns/refs.hexpat) | Microsoft Resilient File System | | ReFS | | [`patterns/refs.hexpat`](patterns/refs.hexpat) | Microsoft Resilient File System |
| RGBDS | | [`patterns/rgbds.hexpat`](patterns/rgbds.hexpat) | [RGBDS](https://rgbds.gbdev.io) object file format | | RGBDS | | [`patterns/rgbds.hexpat`](patterns/rgbds.hexpat) | [RGBDS](https://rgbds.gbdev.io) object file format |
@@ -136,10 +137,12 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
| UF2 | | [`patterns/uf2.hexpat`](patterns/uf2.hexpat) | [USB Flashing Format](https://github.com/microsoft/uf2) | | UF2 | | [`patterns/uf2.hexpat`](patterns/uf2.hexpat) | [USB Flashing Format](https://github.com/microsoft/uf2) |
| VBMeta | | [`patterns/vbmeta.hexpat`](patterns/vbmeta.hexpat) | Android VBMeta image | | VBMeta | | [`patterns/vbmeta.hexpat`](patterns/vbmeta.hexpat) | Android VBMeta image |
| VDF | | [`patterns/vdf.hexpat`](patterns/vdf.hexpat) | Binary Value Data Format (.vdf) files | | VDF | | [`patterns/vdf.hexpat`](patterns/vdf.hexpat) | Binary Value Data Format (.vdf) files |
| VGM | | [`patterns/vgm.hexpat`](patterns/vgm.hexpat) | VGM (Video Game Music) sound log |
| VHDX | | [`patterns/vhdx.hexpat`](patterns/vhdx.hexpat) | Microsoft Hyper-V Virtual Hard Disk format | | VHDX | | [`patterns/vhdx.hexpat`](patterns/vhdx.hexpat) | Microsoft Hyper-V Virtual Hard Disk format |
| WAV | `audio/x-wav` | [`patterns/wav.hexpat`](patterns/wav.hexpat) | RIFF header, WAVE header, PCM header | | WAV | `audio/x-wav` | [`patterns/wav.hexpat`](patterns/wav.hexpat) | RIFF header, WAVE header, PCM header |
| WAS | | [`patterns\was_oskasoftware.hexpat`](patterns\was_oskasoftware.hexpat) | Oska Software DeskMates WAS/WA3 (WAVE/MP3 Set) file | WAS | | [`patterns\was_oskasoftware.hexpat`](patterns\was_oskasoftware.hexpat) | Oska Software DeskMates WAS/WA3 (WAVE/MP3 Set) file
| WAD | | [`patterns/wad.hexpat`](patterns/wad.hexpat) | DOOM WAD Archive | | WAD | | [`patterns/wad.hexpat`](patterns/wad.hexpat) | DOOM WAD Archive |
| WebP | `image/webp` | [`patterns/webp.hexpat`](patterns/webp.hexpat) | Google WebP image |
| XBEH | `audio/x-xbox-executable` | [`patterns/xbeh.hexpat`](patterns/xbeh.hexpat) | Xbox executable | | XBEH | `audio/x-xbox-executable` | [`patterns/xbeh.hexpat`](patterns/xbeh.hexpat) | Xbox executable |
| XCI | | [`patterns/xci.hexpat`](patterns/xci.hexpat) | Nintendo Switch XCI cartridge ROM | | XCI | | [`patterns/xci.hexpat`](patterns/xci.hexpat) | Nintendo Switch XCI cartridge ROM |
| XGT | | [`patterns/xgt.hexpat`](patterns/xgstexture.hexpat) | Exient XGS Engine Texture | | XGT | | [`patterns/xgt.hexpat`](patterns/xgstexture.hexpat) | Exient XGS Engine Texture |

View File

@@ -1,6 +1,7 @@
#pragma description DirectDraw Surface #pragma description DirectDraw Surface
#pragma MIME image/vnd-ms.dds #pragma MIME image/vnd-ms.dds
#pragma MIME image/x-dds
#pragma endian little #pragma endian little
enum DXGI_FORMAT : u32 { enum DXGI_FORMAT : u32 {

View File

@@ -1,4 +1,4 @@
#pragma description PNG image #pragma description PNG image
#pragma MIME image/png #pragma MIME image/png
#pragma endian big #pragma endian big
@@ -121,6 +121,26 @@ struct palette_entry_t {
u24 color; u24 color;
} [[inline]]; } [[inline]];
struct chrm_t {
u32 white_point_x;
u32 white_point_y;
u32 red_x;
u32 red_y;
u32 green_x;
u32 green_y;
u32 blue_x;
u32 blue_y;
};
struct time_t {
u16 year;
u8 month;
u8 day;
u8 hour;
u8 minute;
u8 second;
};
struct chunk_t { struct chunk_t {
u32 length [[color("17BECF")]]; u32 length [[color("17BECF")]];
char name[4]; char name[4];
@@ -139,6 +159,8 @@ struct chunk_t {
#define acTL_k "acTL" #define acTL_k "acTL"
#define fdAT_k "fdAT" #define fdAT_k "fdAT"
#define fcTL_k "fcTL" #define fcTL_k "fcTL"
#define cHRM_k "cHRM"
#define tIME_k "tIME"
if (name == IHDR_k) { if (name == IHDR_k) {
ihdr_t ihdr [[comment("Image Header chunk"), name("IHDR")]]; ihdr_t ihdr [[comment("Image Header chunk"), name("IHDR")]];
@@ -167,6 +189,10 @@ struct chunk_t {
} else if (name == fdAT_k) { } else if (name == fdAT_k) {
fdat_t fdat [[comment("Frame data chunk")]]; fdat_t fdat [[comment("Frame data chunk")]];
u8 data[length-sizeof(u32)]; u8 data[length-sizeof(u32)];
} else if (name == cHRM_k) {
chrm_t chrm;
} else if (name == tIME_k) {
time_t time;
} else { } else {
u8 data[length]; u8 data[length];
} }

View File

@@ -1,7 +1,8 @@
#pragma author WerWolv #pragma author WerWolv
#pragma description Google Protobuf #pragma description Google Protobuf wire encoding (.pb)
import std.core; import std.core;
import std.io;
import std.mem; import std.mem;
import type.leb128; import type.leb128;
@@ -31,10 +32,19 @@ enum WireType : u8 {
_32Bit = 5 _32Bit = 5
}; };
bitfield Key { WireType wire_type;
field_number : 5; u32 tag;
wire_type : 3; u32 field_number;
} [[bitfield_order(std::core::BitfieldOrder::MostToLeastSignificant, 8)]];
struct Key {
type::uLEB128 keyDec;
field_number = u32(keyDec) >> 3;
wire_type = u32(keyDec) & 7;
}[[sealed, format("format_key")]];
fn format_key(Key keyObject) {
return std::format("{} with field number {}", wire_type, field_number);
};
union _64Bit { union _64Bit {
u64 fixed64; u64 fixed64;
@@ -49,22 +59,22 @@ union _32Bit {
}; };
struct LengthDelimited { struct LengthDelimited {
type::LEB128 length; type::uLEB128 length;
char data[length]; char data[length];
}; };
struct Entry { struct Entry {
Key key; Key key;
if (key.wire_type == WireType::Varint) if (wire_type == WireType::Varint)
type::LEB128 value; type::uLEB128 value;
else if (key.wire_type == WireType::_64Bit) else if (wire_type == WireType::_64Bit)
_64Bit value; _64Bit value;
else if (key.wire_type == WireType::LengthDelimited) else if (wire_type == WireType::LengthDelimited)
LengthDelimited value; LengthDelimited value;
else if (key.wire_type == WireType::_32Bit) else if (wire_type == WireType::_32Bit)
_32Bit value; _32Bit value;
}; };
Entry entries[while(!std::mem::eof())] @ 0x00; Entry entries[while(!std::mem::eof())] @ 0x00;

View File

@@ -0,0 +1,169 @@
#pragma author applecuckoo
#pragma description Cesium quantized-mesh terrain
#pragma endian little
// based on https://github.com/CesiumGS/quantized-mesh
// potential improvements: figure out high water mark encoding for indices
import std.math;
import std.io;
u8 extensionCount;
extensionCount = 0; // NOTE: set this to the amount of extensions in your terrain.
// ZigZag decoder based on protobuf.hexpat by WerWolv
struct ZigZag16 {
u16 value;
} [[sealed, format("format_zigzag16")]];
fn format_zigzag16(ZigZag16 zigzag) {
return s16((s16(zigzag.value) << 1) ^ (s16(zigzag.value) >> 15));
};
struct QuantizedMeshHeader {
double CenterX;
double CenterY;
double CenterZ;
float MinimumHeight;
float MaximumHeight;
double BoundingSphereCenterX;
double BoundingSphereCenterY;
double BoundingSphereCenterZ;
double BoundingSphereRadius;
double HorizonOcclusionPointX;
double HorizonOcclusionPointY;
double HorizonOcclusionPointZ;
};
struct VertexData {
u32 vertexCount;
ZigZag16 u[vertexCount];
ZigZag16 v[vertexCount];
ZigZag16 height[vertexCount];
};
struct IndexData16 {
u32 triangleCount;
u16 indices[triangleCount * 3];
};
struct IndexData32 {
u32 triangleCount;
u32 indices[triangleCount * 3];
};
struct EdgeIndices16 {
u32 westVertexCount;
u16 westIndices[westVertexCount];
u32 southVertexCount;
u16 southIndices[southVertexCount];
u32 eastVertexCount;
u16 eastIndices[eastVertexCount];
u32 northVertexCount;
u16 northIndices[northVertexCount];
};
struct EdgeIndices32 {
u32 westVertexCount;
u32 westIndices[westVertexCount];
u32 southVertexCount;
u32 southIndices[southVertexCount];
u32 eastVertexCount;
u32 eastIndices[eastVertexCount];
u32 northVertexCount;
u32 northIndices[northVertexCount];
};
enum ExtensionTypes : u8 {
OctEncodedVertexNormals = 0x1,
WaterMask,
Metadata = 0x4,
};
// Oct16 decode based on https://github.com/loicgasser/quantized-mesh-tile/blob/master/quantized_mesh_tile/utils.py
fn signNotZero(float v) {
if (v < 0.0)
return -1.0;
else
return 1.0;
};
fn fromSnorm(u8 value) {
return float(std::math::clamp(value, 0.0, 255.0) / 255.0 * 2.0 - 1.0);
};
struct Oct16 {
u8 x;
u8 y;
}[[sealed, format("format_oct16")]];
fn format_oct16(Oct16 oct) {
float xOut;
float yOut;
float zOut;
xOut = fromSnorm(oct.x);
yOut = fromSnorm(oct.y);
zOut = 1.0 - (std::math::abs(xOut) + std::math::abs(yOut));
if (zOut < 0.0) {
float oldX;
oldX = xOut;
xOut = (1.0 - std::math::abs(yOut)) * signNotZero(oldX);
yOut = (1.0 - std::math::abs(oldX)) * signNotZero(yOut);
}
return std::format("{}, {}, {}", xOut, yOut, zOut);
};
struct OctEncodedVertexNormals {
Oct16 xy[parent.parent.vertdata.vertexCount];
};
struct WaterMask {
u8 mask[parent.extensionLength];
};
struct Metadata {
u32 jsonLength;
char json[jsonLength];
};
struct ExtensionHeader {
u8 extensionId;
u32 extensionLength;
match (extensionId) {
(ExtensionTypes::OctEncodedVertexNormals): OctEncodedVertexNormals octVertNormals;
(ExtensionTypes::WaterMask): WaterMask maskData;
(ExtensionTypes::Metadata): Metadata metadata;
}
};
struct QuantizedMesh {
QuantizedMeshHeader header;
VertexData vertdata;
if (vertdata.vertexCount > 65536) {
IndexData32 indexdata;
EdgeIndices32 edgeindices;
} else {
IndexData16 indexdata;
EdgeIndices16 edgeindices;
}
ExtensionHeader extensions[extensionCount];
};
QuantizedMesh mesh @ 0x00;

View File

@@ -98,6 +98,16 @@ enum UF2_FamilyID : u32 {
NRF52832xxAB = 0x6f752678, NRF52832xxAB = 0x6f752678,
AT32F415 = 0xa0c97b8e, AT32F415 = 0xa0c97b8e,
CH32V = 0x699b62ec, CH32V = 0x699b62ec,
RA4M1 = 0x7be8976d,
RTL8710A = 0x9fffd543,
RTL8710B = 0x22e0d6fc,
RTL8720C = 0xe08f7564,
RTL8720D = 0x3379CFE2,
XR809 = 0x51e903a8,
BK7231U = 0x675a40b0,
BK7251 = 0x6a82cc42,
BK7231N = 0x7b3ef230,
BL602 = 0xde1270b7,
}; };
fn formatTagType(UF2_TagType type) { fn formatTagType(UF2_TagType type) {

248
patterns/vgm.hexpat Normal file
View File

@@ -0,0 +1,248 @@
#pragma author applecuckoo
#pragma description VGM (Video Game Music) sound log
#pragma endian little
import type.magic;
import std.string;
import std.io;
u32 versionValue;
u32 gd3TagPos;
u32 chpClkBase;
u32 chpVolBase;
// note: the versionValue variable exists to help check which fields exist and which don't, otherwise the actual log data would show up as part of the header.
bitfield VGMVersion {
bugfix : 4;
minor : 4;
major : 24;
versionValue = major * 100 + minor * 10 + bugfix;
} [[format("format_VGMVersion")]];
fn format_VGMVersion(auto version) {
return std::format("{}.{}{}", version.major, version.minor, version.bugfix);
};
bitfield SN76489Flags {
frequency : 1;
negateOutput : 1;
GameGearStereo : 1;
clockDiv : 1;
XNORNoiseMode : 1;
padding : 3;
};
bitfield AY8910Flags {
legacyOutput : 1;
singleOutput : 1;
discreteOutput : 1;
RAWOutput : 1;
YMclockDivLow : 1;
padding : 3;
};
bitfield OKIM6258Flags {
clockDiv : 2;
ADPCMsel : 1;
outputBitDepth : 1;
padding : 4;
};
bitfield K054539Flags {
reverseStereo : 1;
disableReverb : 1;
KeyOnUpdate : 1;
padding : 5;
};
enum AY8190Type : u8 {
AY8910,
AY8912,
AY8913,
AY8914,
YM2149 = 0x10,
YM3439,
YMZ284,
YMZ294,
};
enum C140Type : u8 {
C140_NamcoSystem2,
C140_NamcoSystem21,
ASIC219_NamcoNA,
};
struct Gd3 {
type::Magic<"Gd3 "> ident;
VGMVersion version;
u32 Gd3Length;
std::string::NullString16 trackNameEng;
std::string::NullString16 trackNameOriginal;
std::string::NullString16 gameNameEng;
std::string::NullString16 gameNameOriginal;
std::string::NullString16 sysNameEng;
std::string::NullString16 sysNameOriginal;
std::string::NullString16 trackAuthorEnglish;
std::string::NullString16 trackAuthorOriginal;
std::string::NullString16 gameReleaseDate;
std::string::NullString16 VGMConverter;
std::string::NullString16 Notes;
};
struct baseHeader {
type::Magic<"Vgm "> ident;
u32 eofOffset;
VGMVersion version;
u32 SN76489_clk;
u32 YM2413_clk;
gd3TagPos = $;
u32 Gd3Offset;
u32 sampleCount;
u32 loopOffset;
u32 loopSamples;
};
struct Header : baseHeader {
if (versionValue >= 101) {
u32 rate;
} if (versionValue >= 110) {
u16 SN76489_feedback;
u8 SN76489_shift_width;
} if (versionValue >= 151) {
SN76489Flags snflags;
} else {
padding[1];
} if (versionValue >= 110) {
u32 YM2612_clk;
u32 YM2151_clk;
} if (versionValue >= 150) {
u32 VGMOffset;
} if (versionValue >= 151) {
u32 SegaPCM_clk;
u32 SegaPCM_reg;
u32 RF5C68_clk;
u32 YM2203_clk;
u32 YM2608_clk;
u32 YM2610_clk;
u32 YM3812_clk;
u32 YM3526_clk;
u32 Y8950_clk;
u32 YMF262_clk;
u32 YMF278B_clk;
u32 YMF271_clk;
u32 YMZ280B_clk;
u32 RF5C164_clk;
u32 PWM_clk;
u32 AY8910_clk;
AY8190Type AY8910_type;
AY8910Flags AY8910_flags;
u8 YM2203_flags;
u8 YM2608_flags;
} if (versionValue >= 160) {
u8 volumeMod;
padding[1];
u8 loopBase;
} else {
padding[3];
} if (versionValue >= 151) {
u8 loopMod;
} if (versionValue >= 161) {
u32 DMG_clk;
u32 APU_clk;
u32 MultiPCM_clk;
u32 uPD7759_clk;
u32 OKIM6258_clk;
OKIM6258Flags OKIM6258_flags;
K054539Flags K054539_flags;
C140Type C140_type;
padding[1];
u32 OKIM6295_clk;
u32 K051649_clk;
u32 K054539_clk;
u32 HuC6280_clk;
u32 C140_clk;
u32 K053260_clk;
u32 Pokey_clk;
u32 QSound_clk;
} if (versionValue >= 171) {
u32 SCSP_clk;
} else {
padding[4];
} if (versionValue >= 170) {
u32 extraHeaderOffset;
} if (versionValue >= 171) {
u32 WonderSwan_clk;
u32 VSU_clk;
u32 SAA1099_clk;
u32 ES5503_clk;
u32 ES5005_clk;
u8 ES5503_ch;
u8 ES5505_ch;
u8 C352_clockDiv;
padding[1];
u32 X1_010_clk;
u32 C352_clk;
u32 GA20_clk;
} if (versionValue > 172) {
u32 Mikey_clk;
}
};
struct chpClkEntry {
u8 chpID;
u32 chpClk;
};
struct chpClkHeader {
u8 entryCount;
chpClkEntry entries[entryCount];
};
bitfield chpVolume {
volume : 15;
absoluteRelative : 1;
};
struct chpVolEntry {
u8 chpID;
u8 flags;
chpVolume chpVol;
};
struct chpVolHeader {
u8 entryCount;
chpVolEntry entries[entryCount];
};
struct ExtraHeader {
u32 headerSize;
chpClkBase = $;
u32 chpClkOffset;
chpVolBase = $;
u32 chpVolOffset;
if (chpClkOffset > 0) {
$ = chpClkBase + chpClkOffset;
chpClkHeader chpClk;
} if (chpVolOffset > 0) {
$ = chpVolBase + chpVolOffset;
chpVolHeader chpVol;
}
};
struct VGM {
Header header;
if (versionValue >= 170) {
if (header.extraHeaderOffset > 0) {
ExtraHeader extraHeader;
}
}
Gd3 tag @ (gd3TagPos + header.Gd3Offset);
};
VGM vgm @ 0x00;

122
patterns/webp.hexpat Normal file
View File

@@ -0,0 +1,122 @@
#pragma author applecuckoo
#pragma description Google WebP
#pragma endian little
#pragma MIME image/webp
// based off of ttf.hexpat by Rebuild and wav.hexpat by WerWolv
import std.mem;
import std.core;
import type.magic;
struct RiffHeader {
char ckID[4] [[comment("Container Signature"), name("RIFF Header Signature")]];
u32 ckSize [[comment("Size of RIFF Header"), name("RIFF Chunk Size")]];
char format[4] [[comment("RIFF format"), name("WAVE Header Signature")]];
};
struct WebPChunk {
char chunkId[4];
u32 chunkSize;
};
bitfield VP8XFlags {
padding : 1;
A : 1;
X : 1;
E : 1;
L : 1;
I : 1;
padding : 2;
};
struct OneBase {
u24 value;
} [[sealed, format("format_onebase")]];
fn format_onebase(OneBase onebase) {
return onebase.value + 1;
};
struct WebPVP8XData {
VP8XFlags flags;
padding[3];
OneBase canvasWidth;
OneBase canvasHeight;
};
struct WebPANIMData {
u32 backgroundColor;
u16 loopCount;
};
bitfield ANMFFlags {
D : 1;
B : 1;
padding : 6;
};
bitfield WebPVP8LHeader {
widthMinusOne : 14;
heightMinusOne : 14;
alphaUsed : 1;
version : 3;
};
struct WebPVP8LData {
type::Magic<"\x2f"> id;
WebPVP8LHeader header;
};
u32 frameSize;
struct WebPANMFData {
u24 frameX;
u24 frameY;
OneBase frameWidth;
OneBase frameHeight;
u24 frameDuration;
ANMFFlags flags;
u8 data[parent.chunkHeader.chunkSize - 16]; // lazy fix - can't be bothered implementing subchunks
};
bitfield ALPHFlags {
C : 2;
F : 2;
P : 2;
padding : 2;
};
u32 paddedChunkSize;
struct WebPData {
WebPChunk chunkHeader;
paddedChunkSize = (chunkHeader.chunkSize + 1) >> 1 << 1;
match (chunkHeader.chunkId) {
("VP8X"): WebPVP8XData VP8XData;
("ANIM"): WebPANIMData ANIMData;
("ANMF"): {
WebPANMFData ANMFData;
padding[paddedChunkSize - sizeof(ANMFData)];
}
("VP8L"): {
WebPVP8LHeader VP8LData;
u8 image[chunkHeader.chunkSize-3];
padding[paddedChunkSize - sizeof(VP8LData) - sizeof(image)];
}
("ALPH"): {
ALPHFlags flags;
u8 ALPHData[chunkHeader.chunkSize-1];
padding[paddedChunkSize - sizeof(ALPHData) - sizeof(flags)];
}
(_): {
u8 data[chunkHeader.chunkSize];
padding[paddedChunkSize - sizeof(data)];
}
}
} [[name(std::format("Chunk ({})", chunkHeader.chunkId))]];;
RiffHeader header @0x00;
WebPData data[while (!std::mem::eof())] @ $;

Binary file not shown.

After

Width:  |  Height:  |  Size: 934 B