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 处. ",ftell(fp) -1);
  assert(0);
 }
 size_t buffer[8] = {0};
 fread(buffer,1,1,fp);
 printf("下一个图像块使用的处置方式为:%u. ",(1+2+4)&(*(char*)buffer >> 2));
 printf("下一个图像块%s用户输入。 ",(2&*(char*)buffer)?"期待":"不期待");
 int enabledTransparent = 0;
 printf("在下一个图像块中%s透明色。 ",(1&*(char*)buffer)?
 enabledTransparent = 1,"使用":"不使用");
 printf("读取到了文件偏移:0x%04X. ",ftell(fp));
 memset(buffer,0,sizeof buffer);
 fread(buffer,2,1,fp);
 printf("延迟时间:%.2lf秒。 ",0.01 * *(int*)buffer);
 fread(buffer,1,1,fp);
 if(enabledTransparent){
  printf("透明颜色索引为:%u. ",*(unsigned char*)buffer);
 }
 if(fgetc(fp) == 0)puts("正确的块终结器.");
 else{
  fprintf(stderr,"错误的块终结器%u. ",(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 ",ftell(fp));
#endif
 int i = 0;
 for(;sizeColorTable > 0; -- sizeColorTable){
  fread(rgb, sizeof rgb, 1, fp);
  //printf("#%02d RGB( %u , %u , %u ) ",++i,*red,*green,*blue);
 }
 puts("color table 读取完毕.");
 printf("读取到了文件偏移:0x%04X. ",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大小的数据块。 ",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(' ');
  }
 }
}
void parseImageData(FILE *fp){
 long loc = ftell(fp);
 printf("下面准备从0x%04X处开始处理图像数据. ",loc);
 fseek(fp,0,SEEK_END);
 printf("还差%d字节的数据未处理. ",ftell(fp) - loc);
 fseek(fp,loc,SEEK_SET);
 printf("此图像块的LZW编码长度为%u. ",(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. ",*(int*)buffer);
 fread(buffer,2,1,fp);
 printf("图像宽度为%u. ",*(int*)buffer);
 fread(buffer,2,1,fp);
 printf("图像高度为%u. ",*(int*)buffer);
 fread(buffer,1,1,fp);
#ifdef DEBUG
 fprintf(stderr,"reading 0x%04X. ",ftell(fp) -1);
#endif
 int enabledLocalColor = 0;
 printf("%s使用局部颜色. ",
 (0x80 & *(char*)buffer)?enabledLocalColor = 1,"":"不");
 printf("%s使用交织方式排列. ",(0x40 & *(char*)buffer)?"":"不");
 printf("分类标志%s. ",(0x20&*(int*)buffer)?"被置位":"未置位");
 int sizeLocalColorTable = 0;
 if(!enabledLocalColor){
  puts("禁用了局部颜色.");
 }
 else{
  printf("局部颜色列表列表大小为%d。 ",(
  ({
  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('' == strcmp(buffer,signature)){
  puts("good signature found.");
 }
 else if('' == strcmp("GIF87a",buffer)){
  puts("Version 87a.");
 }
 else{
  fputs("bad signature. ",stderr);
  fprintf(stderr,"expecting %s while meet %s. ",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). ",*(int*)buffer);

 fread(buffer,1,1,fp);
 int enabledGCT = 0;
 printf("Global Color Table %s. ",
 (0x80 & *(char*)buffer)?
 (enabledGCT = 1, "enabled"): "disabled");
 
 printf("Color Resolution: %d bit. ",1+((1+2+4)&(*(char*)buffer >> 4)));
 
 printf("Sort Flag %s. ",
 (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. ", sizeGCT);
 }
 fread(buffer,1,1,fp);
 printf("background color : %u. ",*(unsigned char*)buffer);
 fread(buffer,1,1,fp);
 printf("Pixel Aspect Ratio : %u. ",*(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. ",ftell(fp) -1);
   parseImageDescriptor(fp);
  }
  else if(ch == ';'){
   puts("遇到了文档的结束标志;。");
   long loc = ftell(fp);
   fseek(fp,0,SEEK_END),
   printf("距离文件流的结尾还有%u个字节。 ",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. ",ch);
    puts("还未能处理这种扩展块");
    assert(0);
   }
  }
  else{
   fputs("遇到了未预期的字符.现在退出程序。",stderr);
   fprintf(stderr,"在0x%04X处. ",ftell(fp));
   exit(-1);
  }
 }
 return 0;
}

原文地址:https://www.cnblogs.com/renhl/p/3336207.html