GIF palettes
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:
/**************************************************************************** 2005/02/25 Miguel de Benito <nonick AT 8027 DOT org>** Extracts info from GIF87a files.* WARNING: this should work on GIF89a headers up to the first extended field,* so it most probably WON'T WORK with image color tables. I'll just stick* with the global one.** More info on http://www.fileformat.info/format/gif/***************************************************************************/#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h> /* read() / write() */#include <stdarg.h> /* va_start(), etc. */#include <stdlib.h> /* malloc() *//*** GIF header*/struct gif_header{u_int8_t signature[3]; /* Header Signature (always "GIF") */u_int8_t version[3]; /* GIF format version("87a" or "89a") */} __attribute__((packed));/*** Logical screen descriptor. This appears once, just after the header,* and is followed by the global color table, if there is any.*/struct gif_screen_descriptor{u_int16_t s_width; /* Width of Display Screen in Pixels */u_int16_t s_height; /* Height of Display Screen in Pixels */u_int8_t packed; /* Screen and Color Map Information */u_int8_t background_color; /* Background Color Index */u_int8_t aspect_ratio; /* Pixel Aspect Ratio */} __attribute__((packed));/*** Header for each one of the images in the GIF*/struct gif_image_descriptor{u_int8_t separator; /* Image Descriptor identifier */u_int16_t left; /* X position of image on the display */u_int16_t top; /* Y position of image on the display */u_int16_t width; /* Width of the image in pixels */u_int16_t height; /* Height of the image in pixels */u_int8_t packed; /* Image and Color Table Data Information */} __attribute__((packed));/*** The information found in a Graphics Control block is used to modify the* data in the Graphical Rendering block that immediately follows it. A* Graphics Control block may modify either bitmap or plain-text data. It* must also occur in the GIF stream before the data it modifies, and only* one Graphics Control block may appear per Graphics Rendering block.*/struct gif_graphcontrol_ext{u_int8_t introducer; /* Extension Introducer (always 21h) */u_int8_t label; /* Graphic Control Label (always F9h) */u_int8_t block_size; /* Size of remaining fields (always 04h) */u_int8_t packed; /* Method of graphics disposal to use */u_int16_t delay; /* Hundredths of seconds to wait */u_int8_t color_index; /* Transparent Color Index */u_int8_t terminator; /* Block Terminator (always 0) */} __attribute__((packed));/*** Any number of Plain Text Extension blocks may appear in a GIF file.* To display plain-text data, a grid is described that contains the data.* The height, width, and position of the grid on the display screen are* specified. The size of each cell in the grid is also described, and one* character is displayed per cell. The foreground and background color of* the text are taken from the Global Color Table and are also described in* the Plain Text Extension block. The actual Plain Text data is a simple* string of ASCII characters.*/struct gif_plaintext_ext{u_int8_t Introducer; /* Extension Introducer (always 21h) */u_int8_t Label; /* Extension Label (always 01h) */u_int8_t BlockSize; /* Size of Extension Block (always 0Ch) */u_int16_t TextGridLeft; /* X position of text grid in pixels */u_int16_t TextGridTop; /* Y position of text grid in pixels */u_int16_t TextGridWidth; /* Width of the text grid in pixels */u_int16_t TextGridHeight; /* Height of the text grid in pixels */u_int8_t CellWidth; /* Width of a grid cell in pixels */u_int8_t CellHeight; /* Height of a grid cell in pixels */u_int8_t TextFgColorIndex; /* Text foreground color index value */u_int8_t TextBgColorIndex; /* Text background color index value */u_int8_t *PlainTextData; /* The Plain Text data */u_int8_t Terminator; /* Block Terminator (always 0) */} __attribute__((packed));/*** Each color in the color table is defined by three bytes.*/struct gif_rgb{u_int8_t red;u_int8_t green;u_int8_t blue;} __attribute__((packed));/*** Bit masks for logical screen descriptor packed bit field.* bits 0-2 number of bits in each color entry minus one (???)* bit 3 Is the global color table sorted by relevance?* bits 4-6 Number of colors bits (see dump_color_table())* bit 7 Is there a global color table?*/#define SCR_CTABLE_SIZE ((1 << 0) | (1 << 1) | (1 << 2))#define SCR_CTABLE_SORT ((1 << 3))#define SCR_CRESOLUTION ((1 << 4) | (1 << 5) | (1 << 6))#define SCR_CTABLE_FLAG ((1 << 7))/*** Bit masks for logical image descriptor packed bit field.* bit 0 Is there a global color table?* bit 1 Is the image interlaced.* bit 2 Is the global color table sorted by relevance?* bits 3-4 Reserved* bits 5-7 Number of colors bits (see dump_color_table())*/#define IMG_CTABLE_FLAG ((1 << 0))#define IMG_INTERLACED ((1 << 1))#define IMG_CTABLE_SORT ((1 << 2))#define IMG_RESERVED ((1 << 3) | (1 << 4))#define IMG_CTABLE_SIZE ((1 << 5) | (1 << 6) | (1 << 7))/*** This otherwise unnecessary declaration is needed for __attribute__* to work. This __attribute__ tells the compiler that this is a* printf-like function*/void error(char *fmt, ...) __attribute__((format(printf, 1, 2)));/****/void error(char *fmt, ...){va_list args;va_start(args, fmt);printf ("\nERROR: ");vprintf (fmt, args);printf ("\n\nUsage:\n\tgif [filename.gif] [output.pal]\n");printf ("\nWARNING: this is incomplete work. It may not work for you!\n");va_end(args);exit(1);}/****/int get_screen_info(int fd){struct gif_header hdr;struct gif_screen_descriptor dsc;if (! read(fd, &hdr, sizeof(struct gif_header)))error ("Error reading gif header. Tryed to read %d bytes.",sizeof(struct gif_header));if (! read(fd, &dsc, sizeof(struct gif_screen_descriptor) ))error ("Error reading gif header. Tryed to read %d bytes.",sizeof(struct gif_screen_descriptor));u_int16_t color_table_size, color_resolution, pixel_aspect_ratio;color_table_size = (u_int16_t)(1 << ((dsc.packed & SCR_CTABLE_SIZE) + 1));color_resolution = (u_int16_t)(1 << ((dsc.packed & SCR_CRESOLUTION) + 1));pixel_aspect_ratio = (dsc.aspect_ratio + 15) / 64;printf ("Signature: %c%c%c\nVersion: %c%c%c\n",hdr.signature[0], hdr.signature[1], hdr.signature[2],hdr.version[0], hdr.version[1], hdr.version[2]);printf ("Screen width: %d\nScreen height: %d\n", dsc.s_width, dsc.s_height);printf ("Color table size: %d\nColor resolution: %d\n",color_table_size, color_resolution);printf ("Color table is sorted: %s\n",(dsc.packed & SCR_CTABLE_SORT) ? "yes" : "no");printf ("There is a global color table: %s\n",(dsc.packed & SCR_CTABLE_FLAG) ? "yes" : "no");printf ("Background color index: %d\n", dsc.background_color);printf ("Pixel aspect ratio: %d\n", pixel_aspect_ratio);return (dsc.packed & SCR_CTABLE_FLAG) ? color_table_size : 0;}/****/void get_image_info(int fd){struct gif_image_descriptor img;u_int16_t ctable_entry_size;if (! read(fd, &img, sizeof(struct gif_image_descriptor) ))error ("Error reading image info.");ctable_entry_size = (u_int16_t)(1 << ((img.packed & IMG_CTABLE_SIZE)+ 1));printf ("-------------Image info-------------\n");printf ("There is an image color table: %s\n",(img.packed & IMG_CTABLE_FLAG) ? "yes" : "no");printf ("Image is interlaced: %s\n",(img.packed & IMG_INTERLACED) ? "yes" : "no");printf ("Color table is sorted: %s\n",(img.packed & IMG_CTABLE_SORT) ? "yes" : "no");printf ("Color table entry size: %d\n", ctable_entry_size);return;}/****/int dump_color_table(int fd, u_int16_t numcolors){u_int16_t i;size_t size = sizeof(struct gif_rgb) * numcolors;struct gif_rgb *pal;if ((pal = (struct gif_rgb *)malloc(size)) == NULL)error ("Not enough memory?? I tryed to allocate %d bytes", size);if (! read(fd, pal, size))error ("Error reading gif color table. Not enough input while trying to read %d bytes.", size);for (i = 0; i < numcolors ;i++)printf ("Color %03d: #%02X%02X%02X\n", i, pal[i].red, pal[i].green, pal[i].blue);return i;}/****/int main (int argc, char **argv){int fd;u_int16_t numcolors;if (argc < 2)error ("No gif file specified.");/*if (argc < 3)error ("No ouput file specified.");*/if ((fd = open(argv[1], O_RDONLY)) == -1)error ("Could not open input file %s for reading.", argv[1]);/*if ((fd = open(argv[2], O_WRONLY | O_CREAT)) == -1)error ("Could not open output file %s for writing.", argv[2]);*/if (! (numcolors = get_screen_info(fd)))error("This image lacks a global color table.");elsedump_color_table(fd, numcolors);get_image_info(fd);return 0;}- Download this code: gifreader.c

