GIF palettes

Friday, February 25th, 2005 - Español English

Today at my work I had to extract some palette information from gif files as part of a project’s build process. I needed some command line tool wich did this as well as conveniently format the output and did not think of the (quite obvious, I must admit) giflib. With it comes a tool called gifclrmp which enables you to extract the color table from gif files.

But I didn’t know that at the moment and wrote a little program to do it. It reads global color tables from gif files (a palette for all images in the file) and might be able to read the first per-image color table of a multiple-image gif file.

You can get all the info you want and more about gif files and many other formats at File Format. Here you can read the code:

  1. /***************************************************************************
  2. * 2005/02/25 Miguel de Benito <nonick AT 8027 DOT org>
  3. *
  4. * Extracts info from GIF87a files.
  5. * WARNING: this should work on GIF89a headers up to the first extended field,
  6. * so it most probably WON'T WORK with image color tables. I'll just stick
  7. * with the global one.
  8. *
  9. * More info on http://www.fileformat.info/format/gif/
  10. ***************************************************************************/
  11.  
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <fcntl.h>
  15. #include <unistd.h> /* read() / write() */
  16. #include <stdarg.h> /* va_start(), etc. */
  17. #include <stdlib.h> /* malloc() */
  18.  
  19. /**
  20. * GIF header
  21. */
  22. struct gif_header
  23. {
  24. u_int8_t signature[3]; /* Header Signature (always "GIF") */
  25. u_int8_t version[3]; /* GIF format version("87a" or "89a") */
  26. } __attribute__((packed));
  27.  
  28. /**
  29. * Logical screen descriptor. This appears once, just after the header,
  30. * and is followed by the global color table, if there is any.
  31. */
  32. struct gif_screen_descriptor
  33. {
  34. u_int16_t s_width; /* Width of Display Screen in Pixels */
  35. u_int16_t s_height; /* Height of Display Screen in Pixels */
  36. u_int8_t packed; /* Screen and Color Map Information */
  37. u_int8_t background_color; /* Background Color Index */
  38. u_int8_t aspect_ratio; /* Pixel Aspect Ratio */
  39. } __attribute__((packed));
  40.  
  41.  
  42. /**
  43. * Header for each one of the images in the GIF
  44. */
  45. struct gif_image_descriptor
  46. {
  47. u_int8_t separator; /* Image Descriptor identifier */
  48. u_int16_t left; /* X position of image on the display */
  49. u_int16_t top; /* Y position of image on the display */
  50. u_int16_t width; /* Width of the image in pixels */
  51. u_int16_t height; /* Height of the image in pixels */
  52. u_int8_t packed; /* Image and Color Table Data Information */
  53. } __attribute__((packed));
  54.  
  55. /**
  56. * The information found in a Graphics Control block is used to modify the
  57. * data in the Graphical Rendering block that immediately follows it. A
  58. * Graphics Control block may modify either bitmap or plain-text data. It
  59. * must also occur in the GIF stream before the data it modifies, and only
  60. * one Graphics Control block may appear per Graphics Rendering block.
  61. */
  62. struct gif_graphcontrol_ext
  63. {
  64. u_int8_t introducer; /* Extension Introducer (always 21h) */
  65. u_int8_t label; /* Graphic Control Label (always F9h) */
  66. u_int8_t block_size; /* Size of remaining fields (always 04h) */
  67. u_int8_t packed; /* Method of graphics disposal to use */
  68. u_int16_t delay; /* Hundredths of seconds to wait */
  69. u_int8_t color_index; /* Transparent Color Index */
  70. u_int8_t terminator; /* Block Terminator (always 0) */
  71. } __attribute__((packed));
  72.  
  73. /**
  74. * Any number of Plain Text Extension blocks may appear in a GIF file.
  75. * To display plain-text data, a grid is described that contains the data.
  76. * The height, width, and position of the grid on the display screen are
  77. * specified. The size of each cell in the grid is also described, and one
  78. * character is displayed per cell. The foreground and background color of
  79. * the text are taken from the Global Color Table and are also described in
  80. * the Plain Text Extension block. The actual Plain Text data is a simple
  81. * string of ASCII characters.
  82. */
  83. struct gif_plaintext_ext
  84. {
  85. u_int8_t Introducer; /* Extension Introducer (always 21h) */
  86. u_int8_t Label; /* Extension Label (always 01h) */
  87. u_int8_t BlockSize; /* Size of Extension Block (always 0Ch) */
  88. u_int16_t TextGridLeft; /* X position of text grid in pixels */
  89. u_int16_t TextGridTop; /* Y position of text grid in pixels */
  90. u_int16_t TextGridWidth; /* Width of the text grid in pixels */
  91. u_int16_t TextGridHeight; /* Height of the text grid in pixels */
  92. u_int8_t CellWidth; /* Width of a grid cell in pixels */
  93. u_int8_t CellHeight; /* Height of a grid cell in pixels */
  94. u_int8_t TextFgColorIndex; /* Text foreground color index value */
  95. u_int8_t TextBgColorIndex; /* Text background color index value */
  96. u_int8_t *PlainTextData; /* The Plain Text data */
  97. u_int8_t Terminator; /* Block Terminator (always 0) */
  98. } __attribute__((packed));
  99.  
  100.  
  101. /**
  102. * Each color in the color table is defined by three bytes.
  103. */
  104. struct gif_rgb
  105. {
  106. u_int8_t red;
  107. u_int8_t green;
  108. u_int8_t blue;
  109. } __attribute__((packed));
  110.  
  111.  
  112. /**
  113. * Bit masks for logical screen descriptor packed bit field.
  114. * bits 0-2 number of bits in each color entry minus one (???)
  115. * bit 3 Is the global color table sorted by relevance?
  116. * bits 4-6 Number of colors bits (see dump_color_table())
  117. * bit 7 Is there a global color table?
  118. */
  119. #define SCR_CTABLE_SIZE ((1 << 0) | (1 << 1) | (1 << 2))
  120. #define SCR_CTABLE_SORT ((1 << 3))
  121. #define SCR_CRESOLUTION ((1 << 4) | (1 << 5) | (1 << 6))
  122. #define SCR_CTABLE_FLAG ((1 << 7))
  123.  
  124. /**
  125. * Bit masks for logical image descriptor packed bit field.
  126. * bit 0 Is there a global color table?
  127. * bit 1 Is the image interlaced.
  128. * bit 2 Is the global color table sorted by relevance?
  129. * bits 3-4 Reserved
  130. * bits 5-7 Number of colors bits (see dump_color_table())
  131. */
  132. #define IMG_CTABLE_FLAG ((1 << 0))
  133. #define IMG_INTERLACED ((1 << 1))
  134. #define IMG_CTABLE_SORT ((1 << 2))
  135. #define IMG_RESERVED ((1 << 3) | (1 << 4))
  136. #define IMG_CTABLE_SIZE ((1 << 5) | (1 << 6) | (1 << 7))
  137.  
  138.  
  139. /**
  140. * This otherwise unnecessary declaration is needed for __attribute__
  141. * to work. This __attribute__ tells the compiler that this is a
  142. * printf-like function
  143. */
  144. void error(char *fmt, ...) __attribute__((format(printf, 1, 2)));
  145.  
  146. /**
  147. *
  148. */
  149. void error(char *fmt, ...)
  150. {
  151. va_list args;
  152. va_start(args, fmt);
  153. printf ("\nERROR: ");
  154. vprintf (fmt, args);
  155. printf ("\n\nUsage:\n\tgif [filename.gif] [output.pal]\n");
  156. printf ("\nWARNING: this is incomplete work. It may not work for you!\n");
  157. va_end(args);
  158.  
  159. exit(1);
  160. }
  161.  
  162. /**
  163. *
  164. */
  165. int get_screen_info(int fd)
  166. {
  167. struct gif_header hdr;
  168. struct gif_screen_descriptor dsc;
  169.  
  170. if (! read(fd, &hdr, sizeof(struct gif_header)))
  171. error ("Error reading gif header. Tryed to read %d bytes.",
  172. sizeof(struct gif_header));
  173.  
  174. if (! read(fd, &dsc, sizeof(struct gif_screen_descriptor) ))
  175. error ("Error reading gif header. Tryed to read %d bytes.",
  176. sizeof(struct gif_screen_descriptor));
  177.  
  178. u_int16_t color_table_size, color_resolution, pixel_aspect_ratio;
  179.  
  180. color_table_size = (u_int16_t)(1 << ((dsc.packed & SCR_CTABLE_SIZE) + 1));
  181. color_resolution = (u_int16_t)(1 << ((dsc.packed & SCR_CRESOLUTION) + 1));
  182. pixel_aspect_ratio = (dsc.aspect_ratio + 15) / 64;
  183.  
  184. printf ("Signature: %c%c%c\nVersion: %c%c%c\n",
  185. hdr.signature[0], hdr.signature[1], hdr.signature[2],
  186. hdr.version[0], hdr.version[1], hdr.version[2]);
  187. printf ("Screen width: %d\nScreen height: %d\n", dsc.s_width, dsc.s_height);
  188. printf ("Color table size: %d\nColor resolution: %d\n",
  189. color_table_size, color_resolution);
  190. printf ("Color table is sorted: %s\n",
  191. (dsc.packed & SCR_CTABLE_SORT) ? "yes" : "no");
  192. printf ("There is a global color table: %s\n",
  193. (dsc.packed & SCR_CTABLE_FLAG) ? "yes" : "no");
  194. printf ("Background color index: %d\n", dsc.background_color);
  195. printf ("Pixel aspect ratio: %d\n", pixel_aspect_ratio);
  196.  
  197. return (dsc.packed & SCR_CTABLE_FLAG) ? color_table_size : 0;
  198. }
  199.  
  200.  
  201. /**
  202. *
  203. */
  204. void get_image_info(int fd)
  205. {
  206. struct gif_image_descriptor img;
  207.  
  208. u_int16_t ctable_entry_size;
  209.  
  210. if (! read(fd, &img, sizeof(struct gif_image_descriptor) ))
  211. error ("Error reading image info.");
  212.  
  213. ctable_entry_size = (u_int16_t)(1 << ((img.packed & IMG_CTABLE_SIZE)+ 1));
  214.  
  215. printf ("-------------Image info-------------\n");
  216. printf ("There is an image color table: %s\n",
  217. (img.packed & IMG_CTABLE_FLAG) ? "yes" : "no");
  218. printf ("Image is interlaced: %s\n",
  219. (img.packed & IMG_INTERLACED) ? "yes" : "no");
  220. printf ("Color table is sorted: %s\n",
  221. (img.packed & IMG_CTABLE_SORT) ? "yes" : "no");
  222. printf ("Color table entry size: %d\n", ctable_entry_size);
  223.  
  224. return;
  225. }
  226.  
  227. /**
  228. *
  229. */
  230. int dump_color_table(int fd, u_int16_t numcolors)
  231. {
  232. u_int16_t i;
  233. size_t size = sizeof(struct gif_rgb) * numcolors;
  234. struct gif_rgb *pal;
  235.  
  236. if ((pal = (struct gif_rgb *)malloc(size)) == NULL)
  237. error ("Not enough memory?? I tryed to allocate %d bytes", size);
  238.  
  239. if (! read(fd, pal, size))
  240. error ("Error reading gif color table. Not enough input while trying to read %d bytes.", size);
  241.  
  242. for (i = 0; i < numcolors ;i++)
  243. printf ("Color %03d: #%02X%02X%02X\n", i, pal[i].red, pal[i].green, pal[i].blue);
  244.  
  245. return i;
  246. }
  247.  
  248. /**
  249. *
  250. */
  251. int main (int argc, char **argv)
  252. {
  253. int fd;
  254. u_int16_t numcolors;
  255.  
  256. if (argc < 2)
  257. error ("No gif file specified.");
  258.  
  259. /*
  260. if (argc < 3)
  261. error ("No ouput file specified.");
  262. */
  263. if ((fd = open(argv[1], O_RDONLY)) == -1)
  264. error ("Could not open input file %s for reading.", argv[1]);
  265. /*
  266. if ((fd = open(argv[2], O_WRONLY | O_CREAT)) == -1)
  267. error ("Could not open output file %s for writing.", argv[2]);
  268. */
  269. if (! (numcolors = get_screen_info(fd)))
  270. error("This image lacks a global color table.");
  271. else
  272. dump_color_table(fd, numcolors);
  273.  
  274. get_image_info(fd);
  275.  
  276. return 0;
  277. }

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>