gif解析
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
//#define DEBUG
void parseControlExtension(FILE *fp){
if(fgetc(fp) != 4){
printf("错误的块大小在偏移 %u 处.\n",ftell(fp) -1);
assert(0);
}
size_t buffer[8] = {0};
fread(buffer,1,1,fp);
printf("下一个图像块使用的处置方式为:%u.\n",(1+2+4)&(*(char*)buffer >> 2));
printf("下一个图像块%s用户输入。\n",(2&*(char*)buffer)?"期待":"不期待");
int enabledTransparent = 0;
printf("在下一个图像块中%s透明色。\n",(1&*(char*)buffer)?
enabledTransparent = 1,"使用":"不使用");
printf("读取到了文件偏移:0x%04X.\n",ftell(fp));
memset(buffer,0,sizeof buffer);
fread(buffer,2,1,fp);
printf("延迟时间:%.2lf秒。\n",0.01 * *(int*)buffer);
fread(buffer,1,1,fp);
if(enabledTransparent){
printf("透明颜色索引为:%u.\n",*(unsigned char*)buffer);
}
if(fgetc(fp) == 0)puts("正确的块终结器.");
else{
fprintf(stderr,"错误的块终结器%u.\n",(fseek(fp,-1,SEEK_CUR),fgetc(fp)));
exit(-1);
}
}
void parseColorTable(int sizeColorTable, FILE *fp){
unsigned char rgb[3];
const unsigned char *red = &rgb[0];
const unsigned char *green = &rgb[1];
const unsigned char *blue = &rgb[2];
puts("Color Table found.");
#ifdef DEBUG
printf("开始于0x%04X\n",ftell(fp));
#endif
int i = 0;
for(;sizeColorTable > 0; -- sizeColorTable){
fread(rgb, sizeof rgb, 1, fp);
//printf("#%02d RGB( %u , %u , %u )\n",++i,*red,*green,*blue);
}
puts("color table 读取完毕.");
printf("读取到了文件偏移:0x%04X.\n",ftell(fp));
}
void showSubBlocks(FILE *fp){
size_t buffer[8];
int sizeBlock = 0;
for(;;){
memset(buffer,0,sizeof buffer);
fread(buffer,1,1,fp);
printf("遇到了一个%u大小的数据块。\n",sizeBlock = *(int*)buffer);
if(sizeBlock == 0)break;
else if(sizeBlock > 8){
fseek(fp,sizeBlock,SEEK_CUR);
}
else{
unsigned char buf[512];
for(;sizeBlock > 0; --sizeBlock){
char c;
printf("0x%02X ",(unsigned char)(c = fgetc(fp)));
if(c >= 0x20)printf("(%c)",c);
}
putchar('\n');
}
}
}
void parseImageData(FILE *fp){
long loc = ftell(fp);
printf("下面准备从0x%04X处开始处理图像数据.\n",loc);
fseek(fp,0,SEEK_END);
printf("还差%d字节的数据未处理.\n",ftell(fp) - loc);
fseek(fp,loc,SEEK_SET);
printf("此图像块的LZW编码长度为%u.\n",(unsigned char)fgetc(fp));
showSubBlocks(fp);
}
void parseImageDescriptor(FILE *fp){
size_t buffer[8] = {0};
fread(buffer,2,1,fp);
printf("x方向偏移量为%u,",*(int*)buffer);
fread(buffer,2,1,fp);
printf("y方向偏移量为%u.\n",*(int*)buffer);
fread(buffer,2,1,fp);
printf("图像宽度为%u.\n",*(int*)buffer);
fread(buffer,2,1,fp);
printf("图像高度为%u.\n",*(int*)buffer);
fread(buffer,1,1,fp);
#ifdef DEBUG
fprintf(stderr,"reading 0x%04X.\n",ftell(fp) -1);
#endif
int enabledLocalColor = 0;
printf("%s使用局部颜色.\n",
(0x80 & *(char*)buffer)?enabledLocalColor = 1,"":"不");
printf("%s使用交织方式排列.\n",(0x40 & *(char*)buffer)?"":"不");
printf("分类标志%s.\n",(0x20&*(int*)buffer)?"被置位":"未置位");
int sizeLocalColorTable = 0;
if(!enabledLocalColor){
puts("禁用了局部颜色.");
}
else{
printf("局部颜色列表列表大小为%d。\n",(
({
int i = 1 + ((1+2+4)&(*(char*)buffer));
//后面这个大括号很重要,血泪的教训啊!
//否则加号的优先级比与号要高!想不到吧!
sizeLocalColorTable = 1;
for(;i>0;--i){
sizeLocalColorTable *= 2;
}
}),sizeLocalColorTable));
}
if(enabledLocalColor){
parseColorTable(sizeLocalColorTable,fp);
parseImageData(fp);
}
else{
parseImageData(fp);
}
}
void parseApplicationExtension(FILE *fp){
size_t buffer[16] = {0};
fread(buffer,1,1,fp);
if(11 == *(char*)buffer){
puts("正确的应用程序控制块大小.");
}
else{
fprintf(stderr,"错误的应用程序控制块大小在0x%04X.",ftell(fp));
assert(0);
}
memset(buffer,0,sizeof buffer);
fread(buffer,8,1,fp);
puts((char*)buffer);
memset(buffer,0,sizeof buffer);
fread(buffer,3,1,fp);
puts((char*)buffer);
showSubBlocks(fp);
}
int main(int argc,char *argv[]){
FILE *fp = NULL;
if(argc != 2){
fputs("bad command line.input filename expected.",stderr);
exit(0);
}
fp = fopen(argv[1],"rb");
char *signature = "GIF89a";
char buffer[8] = {0};
int i;
for(i = 0; i < strlen(signature); ++i){
if(feof(fp)){
fputs("file size too small.",stderr);
exit(0);
}
buffer[i] = fgetc(fp);
}
if('\0' == strcmp(buffer,signature)){
puts("good signature found.");
}
else if('\0' == strcmp("GIF87a",buffer)){
puts("Version 87a.");
}
else{
fputs("bad signature.\n",stderr);
fprintf(stderr,"expecting %s while meet %s.\n",signature,buffer);
exit(0);
}
memset(buffer,0,sizeof buffer);
fread(buffer,2,1,fp);
printf("image width : %d pixel(s), ",*(int*)buffer);
fread(buffer,2,1,fp);
printf("image height : %d pixel(s).\n",*(int*)buffer);
fread(buffer,1,1,fp);
int enabledGCT = 0;
printf("Global Color Table %s.\n",
(0x80 & *(char*)buffer)?
(enabledGCT = 1, "enabled"): "disabled");
printf("Color Resolution: %d bit.\n",1+((1+2+4)&(*(char*)buffer >> 4)));
printf("Sort Flag %s.\n",
(0x08 & *(char*)buffer)?
({
fputs("Meet Sort Flag which is not supported...exiting.",stderr);
exit(0);
}),
"enabled"/*null string for syntax*/:"disabled");
int sizeGCT;
{
int i;
for(i = 0, sizeGCT = 1; i < 1+(*(char*)buffer & (1+2+4)); ++i){
sizeGCT *= 2;
}
printf("The size of Global Color Table: %d.\n", sizeGCT);
}
fread(buffer,1,1,fp);
printf("background color : %u.\n",*(unsigned char*)buffer);
fread(buffer,1,1,fp);
printf("Pixel Aspect Ratio : %u.\n",*(unsigned char*)buffer);
if(enabledGCT){
puts("parsing global color table...");
parseColorTable(sizeGCT, fp);
}
while(!feof(fp)){
unsigned char ch = fgetc(fp);
if(ch == ','){
printf("读取到一个图像标识符','在0x%04X.\n",ftell(fp) -1);
parseImageDescriptor(fp);
}
else if(ch == ';'){
puts("遇到了文档的结束标志;。");
long loc = ftell(fp);
fseek(fp,0,SEEK_END),
printf("距离文件流的结尾还有%u个字节。\n",ftell(fp) - loc);
exit(0);
}
else if(ch == '!'){
puts("读取到一个扩展块标识符'!'");
ch = fgetc(fp);
if(ch == 0xF9){
puts("读取到一个图像控制扩展标签.");
parseControlExtension(fp);
}
else if(ch == 0xFF){
parseApplicationExtension(fp);
}
else{
printf("读取到0x%02X.\n",ch);
puts("还未能处理这种扩展块");
assert(0);
}
}
else{
fputs("遇到了未预期的字符.现在退出程序。",stderr);
fprintf(stderr,"在0x%04X处.\n",ftell(fp));
exit(-1);
}
}
return 0;
}