问题描述
信息来源 -
在 GIF 图片中,存储实际图片大小(宽度,高度)在图像块中。据我所知,图像块是标题中包含的第一个块。
在实际块开始之前,有一个名为全局颜色表(0..255 x 3字节)的内存分配(从现在开始 GCT )。如果我知道为 GCT 保留的字节数,我可以从图像块中提取字节5-9并具有实际图像大小。
In GIF images the actual image size (width, height) is stored in Image Block. To my best understanding Image Block is the very first block included in header.Before the actual blocks begin, there is a memory allocation called Global Color Table(0..255 x 3 bytes)(from now-on GCT). If I can know the byte count reserved for GCT I can extract bytes 5-9 from Image Block and have the actual image size.
问题:
我如何知道/了解 GCT 的大小?
或
GCT 在哪里结束?
或
图像阻止从哪里开始?
或
图像阻止在哪里结束?
推荐答案
gif enc / dec所需的一切,你可以在这里找到
All you need for gif enc/dec you will find here 3MF Project GIF
-
GCT
此块是可选的,并不总是出现在 GIF 文件中。大小由 GIF 标题中的颜色数和位宽决定。我像这样解码/加载它:
this block is optional and not always present in a GIF file. Size is determined by number of colors and bit wide from GIF header. I decode/load it like this:
struct _hdr
{
// Header
BYTE Signature[3]; /* Header Signature (always "GIF") */
BYTE Version[3]; /* GIF format version("87a" or "89a") */
// Logical Screen Descriptor
WORD xs;
WORD ys;
BYTE Packed; /* Screen and Color Map Information */
BYTE BackgroundColor; /* Background Color Index */
BYTE AspectRatio; /* Pixel Aspect Ratio */
} hdr;
gcolor_bits= (hdr.Packed &7)+1; // global pallete
scolor_bits=((hdr.Packed>>4)&7)+1; // screen
_gcolor_sorted =hdr.Packed&8;
_gcolor_table =hdr.Packed&128;
scolors=1<<scolor_bits;
gcolors=1<<gcolor_bits;
- 如果
_gcolor_table
是真的然后 GCT 存在 - GCT 尺寸
3 * gcolors
[字节]按顺序存储R,G,B
- if
_gcolor_table
is true then GCT is present - GCT size is
3*gcolors
[Bytes] stored in orderR,G,B
图像开始
这个有点棘手,因为 GIF89a 文件可能包含许多可选块。您需要执行解码循环检测块类型并根据其目的解码/跳过它。我是这样做的:
This one is a bit tricky because GIF89a files may contain many optional blocks. You need to do a decoding loop detecting type of block and decoding/skipping it according its purpose. I do it like this:
struct _gfxext
{
BYTE Introducer; /* Extension Introducer (always 21h) */
BYTE Label; /* Graphic Control Label (always F9h) */
BYTE BlockSize; /* Size of remaining fields (always 04h) */
BYTE Packed; /* Method of graphics disposal to use */
WORD DelayTime; /* Hundredths of seconds to wait */
BYTE ColorIndex; /* Transparent Color Index */
BYTE Terminator; /* Block Terminator (always 0) */
} gfx;
struct _txtext
{
BYTE Introducer; /* Extension Introducer (always 21h) */
BYTE Label; /* Extension Label (always 01h) */
BYTE BlockSize; /* Size of Extension Block (always 0Ch) */
WORD TextGridLeft; /* X position of text grid in pixels */
WORD TextGridTop; /* Y position of text grid in pixels */
WORD TextGridWidth; /* Width of the text grid in pixels */
WORD TextGridHeight; /* Height of the text grid in pixels */
BYTE CellWidth; /* Width of a grid cell in pixels */
BYTE CellHeight; /* Height of a grid cell in pixels */
BYTE TextFgColorIndex; /* Text foreground color index value */
BYTE TextBgColorIndex; /* Text background color index value */
// BYTE *PlainTextData; /* The Plain Text data */
// BYTE Terminator; /* Block Terminator (always 0) */
};
struct _remext
{
BYTE Introducer; /* Extension Introducer (always 21h) */
BYTE Label; /* Comment Label (always FEh) */
// BYTE *CommentData; /* Pointer to Comment Data sub-blocks */
// BYTE Terminator; /* Block Terminator (always 0) */
};
struct _appext
{
BYTE Introducer; /* Extension Introducer (always 21h) */
BYTE Label; /* Extension Label (always FFh) */
BYTE BlockSize; /* Size of Extension Block (always 0Bh) */
CHAR Identifier[8]; /* Application Identifier */
BYTE AuthentCode[3]; /* Application Authentication Code */
// BYTE *ApplicationData; /* Point to Application Data sub-blocks */
// BYTE Terminator; /* Block Terminator (always 0) */
};
// handle 89a extensions blocks
_gfxext gfxext; gfxext.Introducer=0;
_txtext txtext; txtext.Introducer=0;
_remext remext; remext.Introducer=0;
_appext appext; appext.Introducer=0;
if((hdr.Version[0]=='8')
&&(hdr.Version[1]=='9')
&&(hdr.Version[2]=='a')) _89a=true; else _89a=false;
if (_89a)
for (;!f.eof;)
{
f.peek((BYTE*)&dw,2);
if (dw==0xF921) { f.read((BYTE*)&gfxext,sizeof(_gfxext)); }
else if (dw==0x0121) { f.read((BYTE*)&txtext,sizeof(_txtext)); for (;!f.eof;) { f.read(&db,1); if (!db) break; f.read(dat,DWORD(db)); } }
else if (dw==0xFE21) { f.read((BYTE*)&remext,sizeof(_remext)); for (;!f.eof;) { f.read(&db,1); if (!db) break; f.read(dat,DWORD(db)); } }
else if (dw==0xFF21) { f.read((BYTE*)&appext,sizeof(_appext)); for (;!f.eof;) { f.read(&db,1); if (!db) break; f.read(dat,DWORD(db)); } }
else if ((dw&0x00FF)==0x0021) return; // corrupted file
else break; // no extension found
}
-
db
是BYTE变量 -
dw
是WORD变量 -
f
是我的文件缓存类成员是自我解释我希望无论如何: -
f.read (&数据,大小)
读取大小
BYTES进入数据
-
f.peek(& data,size)
执行相同但不更新文件中的位置 -
f.eof
表示已到达文件结尾 db
is BYTE variabledw
is WORD variablef
is my file cache class the members are self explanatory I hope anyway:f.read(&data,size)
readsize
BYTES intodata
f.peek(&data,size)
do the same but do not update position in filef.eof
indicates end of file reached
这必须为所有此图片标题开始后的每一帧。
this has to be done for each frame after all this image header starts.
图片结束
图像块以终止符结束。所有图像块都以 BYTE
计数开头。如果它是零
,它是一个终结符块。通常在图像之后,很少 BYTES
没有被 LZW 数据使用,因此在填充整个图像区域后跳过所有块直到达到零大小的块然后停止那是图像结束。如果 BYTE
之后 0x3B
hex,则到达 GIF 文件的末尾
Image block ends with terminator. All the chunks of image start with BYTE
count. If it is zero
it is a terminator block. Usually after the image there are few BYTES
not used by LZW data so after you fill the whole image area skip all blocks until hit the zero sized block and then stop that is image end. If BYTE
after this is 0x3B
hex you reached the end of GIF file
[注释]
不要忘记通过 #pragma pack(1)
和 #pragma pack()
封装struct或手动设置对齐到 1 BYTE
。注意有符号数据类型的问题( LZW 数据是无符号的)所以在你可以避免问题或仅使用无符号变量(具有足够的位宽)进行解码时的改写
Do not forget to encapsulate struct by #pragma pack(1)
and #pragma pack()
or manually set align to 1 BYTE
. Beware problems with signed data types (LZW data is unsigned) so overtype where you can to avoid problems or use just unsigned variables (with enough bit-width) for decoding
这篇关于如何找到图像块在GIF图像中的起始位置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!