您所需的gif enc/dec您可以在这里找到3MF项目GIF
- GCT
此块是可选的,并不总是出现在GIF文件中。大小由颜色数决定,并从GIF标头中变宽。我像这样解码/加载它:
结构化_hdr { //头字节Signature3;/*头签名(总是" GIF ") */字节Version3;/* GIF格式版本(“87a”或"89a") * / /逻辑屏幕描述符词xs;WORD ys;字节打包;/*屏幕和彩色地图信息*/字节BackgroundColor;/*背景颜色索引*/字节AspectRatio;/*像素长径比*/ } hdr;gcolor_bits= (hdr.Packed &7)+1;//全球托盘scolor_bits=((hdr.Packed>>4)&7)+1;// screen _gcolor_sorted =hdr.Packed&8;_gcolor_table =hdr.Packed&128;scolors=1<
- if `_gcolor_table` is true then **GCT** is present
- **GCT** size is `3*gcolors` [Bytes] stored in order `R,G,B`
- 启动图像
这个问题有点棘手,因为GIF89a文件可能包含许多可选块。您需要执行解码循环,检测块的类型,并根据其目的对其进行解码/跳过。我这样做:
struct _gfxext {字节导入器;/*扩展导入器(总是21h) */字节标签;/*图形控制标签(总是F9h) */字节BlockSize;剩余字段的/*大小(总是04h) */字节填充;/*图形处理方法使用*/ WORD DelayTime;/*百分之一秒等待*/字节ColorIndex;/*透明颜色索引*/字节终止符;/*块终止符(总是0) */ } gfx;结构_txtext {字节导入器;/*扩展导入器(总是21h) */字节标签;/*扩展标签(总是01h) */字节BlockSize;扩展块的/*大小(总是0Ch) */ WORD TextGridLeft;以像素*/ WORD TextGridTop为单位的文本网格的TextGridTop X位置;以像素*/ WORD TextGridWidth为单位的文本网格的/* Y位置;以像素*/ WORD TextGridHeight为单位的文本网格的/*宽度;以像素*/字节CellWidth为单位的文本网格的/*高度;以像素*/字节CellHeight为单位的网格单元格的/*宽度;以像素*/字节为单位的网格单元格的/*高度;以像素*/字节为单位的/*文本前景颜色索引值*/字节TextFgColorIndex;/*文本背景色索引值* / /字节*PlainTextData;/*纯文本数据* / /字节终止符;/*块终止符(总是0) */ };struct _remext {字节导入器;/*扩展导入器(总是21h) */字节标签;/*注释标签(总是FEh) * / /字节*CommentData;/*指针,用于注释数据子块* / /字节终止符;/*块终止符(总是0) */ };结构_appext {字节导入器;/*扩展导入器(总是21h) */字节标签;/*扩展标签(总是FFh) */字节BlockSize;扩展块的/*大小(总是0 0Bh) */ CHAR Identifier8;/*应用程序标识符*/ AuthentCode3;/*应用程序身份验证代码* / /字节*ApplicationData;/*指向应用程序数据子块* / /字节终止符;/*块终止符(始终为0) */ };// Handl89a扩展阻止_gfxext gfxext;gfxext.Introducer=0;_txtext txtext;txtext.Introducer=0;_remext remext;remext.Introducer=0;_appext;appext.Introducer=0;if ((hdr.version=‘8’)&&(hdr.Version 1=‘9’)和(hdr.Version 2=‘a’) _89a=true;else _89a=false;if (_89a) for (;!f.eof;) {f.peek(字节*)&dw,2;if (dw==0xF921) {f.read(字节*)&gfxext,相当大的(_gfxext);} if (dw==0x0121) {f.read((字节*)&txtext,sizeof(_txtext));for (;!f.eof;) { f.read(&db,1);if (!db)断开;f.read(dat,DWORD(db));} if (dw==0xFE21) {f.read(字节*&remext,sizeof(_remext));for (;!f.eof;) { f.read(&db,1);if (!db)中断;f.read(dat,DWORD(db));} else (dw==0xFF21) {f.read((字节*)&appext,sizeof(_appext));for (;!f.eof;) { f.read(&db,1);if (!db)断开;f.read(dat,DWORD(db));}} if (dw&0x00ff)==0x0021)返回;//损坏的文件其他中断;//无延期}
- `db` is BYTE variable
- `dw` is WORD variable
- `f` is my file cache class the members are self explanatory I hope anyway:
- `f.read(&data,size)` read `size` BYTES into `data`
- `f.peek(&data,size)` do the same but do not update position in file
- `f.eof` indicates end of file reached
在所有这些图像头开始后,必须对每个帧执行此操作。
- 图像端
图像块以终止符结束。所有的图像块都以
BYTE计数开始。如果是zero,则为终止符块。通常在图像之后,很少有BYTES不被、LZW、数据使用,所以在填充整个图像区域之后,跳过所有块,直到点击零大小的块,然后停止,即图像结束。如果BYTE之后是0x3B十六进制,则到达GIF文件的末尾。
注意到
不要忘记通过#pragma pack(1)和#pragma pack()封装结构,或者手动将对齐设置为1 BYTE。注意有符号数据类型的问题(LZW数据是无符号的),所以在可以避免问题的地方过度类型,或者只使用无符号变量(有足够的位宽)来解码。