1 /*****************************************************************************
3 gifclrmap - extract colormaps from GIF images
5 *****************************************************************************/
18 #define PROGRAM_NAME "gifclrmp"
25 __DATE__ ", " __TIME__ "\n"
26 "(C) Copyright 1989 Gershon Elber.\n";
30 " v%- s%- t%-TranslationFile!s l%-ColorMapFile!s g%-Gamma!F i%-Image#!d h%- GifFile!*s";
34 TranslateFlag = false,
40 FILE *ColorFile = NULL;
41 FILE *TranslateFile = NULL;
43 GifPixelType Translation[256];
45 static ColorMapObject *ModifyColorMap(ColorMapObject *ColorMap);
46 static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut);
48 /******************************************************************************
49 Interpret the command line and scan the given GIF file.
50 ******************************************************************************/
51 int main(int argc, char **argv)
53 int NumFiles, ExtCode, CodeSize, ImageNum = 0,
54 ImageN, HasGIFOutput, ErrorCode;
55 bool Error, ImageNFlag = false, HelpFlag = false;
56 GifRecordType RecordType;
57 GifByteType *Extension, *CodeBlock;
58 char **FileName = NULL, *ColorFileName, *TranslateFileName;
59 GifFileType *GifFileIn = NULL, *GifFileOut = NULL;
61 if ((Error = GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint, &SaveFlag,
62 &TranslateFlag, &TranslateFileName,
63 &LoadFlag, &ColorFileName,
64 &GammaFlag, &Gamma, &ImageNFlag, &ImageN,
65 &HelpFlag, &NumFiles, &FileName)) != false ||
66 (NumFiles > 1 && !HelpFlag)) {
69 else if (NumFiles > 1)
70 GIF_MESSAGE("Error in command line parsing - one GIF file please.");
71 GAPrintHowTo(CtrlStr);
76 (void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
77 GAPrintHowTo(CtrlStr);
81 if (SaveFlag + LoadFlag + GammaFlag + TranslateFlag > 1)
82 GIF_EXIT("Can not handle more than one of -s -l, -t, or -g at the same time.");
84 /* Default action is to dump colormaps */
85 if (!SaveFlag && !LoadFlag && !GammaFlag && !TranslateFlag)
89 if ((GifFileIn = DGifOpenFileName(*FileName, &ErrorCode)) == NULL) {
90 PrintGifError(ErrorCode);
95 /* Use stdin instead: */
96 if ((GifFileIn = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
97 PrintGifError(ErrorCode);
103 /* We are dumping out the color map as text file to stdout: */
108 /* We are loading new color map from specified file: */
109 if ((TranslateFile = fopen(TranslateFileName, "rt")) == NULL)
110 GIF_EXIT("Failed to open specified color translation file.");
114 /* We are loading new color map from specified file: */
115 if ((ColorFile = fopen(ColorFileName, "rt")) == NULL)
116 GIF_EXIT("Failed to open specified color map file.");
120 if ((HasGIFOutput = (LoadFlag || TranslateFlag || GammaFlag)) != 0) {
121 /* Open stdout for GIF output file: */
122 if ((GifFileOut = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
123 PrintGifError(ErrorCode);
129 /* We are supposed to modify the screen color map, so do it: */
130 if (!GifFileIn->SColorMap)
131 GIF_EXIT("No colormap to modify");
132 GifFileIn->SColorMap = ModifyColorMap(GifFileIn->SColorMap);
134 /* We can quit here, as we have the color map: */
135 DGifCloseFile(GifFileIn, NULL);
140 /* And dump out its new possible repositioned screen information: */
142 if (EGifPutScreenDesc(GifFileOut,
143 GifFileIn->SWidth, GifFileIn->SHeight,
144 GifFileIn->SColorResolution, GifFileIn->SBackGroundColor,
145 GifFileIn->SColorMap) == GIF_ERROR)
146 QuitGifError(GifFileIn, GifFileOut);
148 /* Scan the content of the GIF file and load the image(s) in: */
150 if (DGifGetRecordType(GifFileIn, &RecordType) == GIF_ERROR)
151 QuitGifError(GifFileIn, GifFileOut);
153 switch (RecordType) {
154 case IMAGE_DESC_RECORD_TYPE:
155 if (DGifGetImageDesc(GifFileIn) == GIF_ERROR)
156 QuitGifError(GifFileIn, GifFileOut);
157 if ((++ImageNum == ImageN) && ImageNFlag) {
158 /* We are suppose to modify this image color map, do it: */
159 GifFileIn->SColorMap =ModifyColorMap(GifFileIn->SColorMap);
161 /* We can quit here, as we have the color map: */
162 DGifCloseFile(GifFileIn, NULL);
168 if (EGifPutImageDesc(GifFileOut,
169 GifFileIn->Image.Left, GifFileIn->Image.Top,
170 GifFileIn->Image.Width, GifFileIn->Image.Height,
171 GifFileIn->Image.Interlace,
172 GifFileIn->Image.ColorMap) == GIF_ERROR)
173 QuitGifError(GifFileIn, GifFileOut);
175 if (!TranslateFlag || (ImageNFlag && (ImageN != ImageNum)))
177 /* Now read image itself in decoded form as we don't */
178 /* really care what we have there, and this is much */
180 if (DGifGetCode(GifFileIn, &CodeSize, &CodeBlock) == GIF_ERROR)
181 QuitGifError(GifFileIn, GifFileOut);
183 if (EGifPutCode(GifFileOut, CodeSize, CodeBlock) == GIF_ERROR)
184 QuitGifError(GifFileIn, GifFileOut);
185 while (CodeBlock != NULL) {
186 if (DGifGetCodeNext(GifFileIn, &CodeBlock) == GIF_ERROR)
187 QuitGifError(GifFileIn, GifFileOut);
189 if (EGifPutCodeNext(GifFileOut, CodeBlock) == GIF_ERROR)
190 QuitGifError(GifFileIn, GifFileOut);
193 else /* we need to mung pixels intices */
196 register GifPixelType *cp;
199 = (GifPixelType *) malloc(GifFileIn->Image.Width *
200 sizeof(GifPixelType));
201 for (i = 0; i < GifFileIn->Image.Height; i++) {
202 if (DGifGetLine(GifFileIn, Line,GifFileIn->Image.Width)
204 QuitGifError(GifFileIn, GifFileOut);
207 /* translation step goes here */
208 for (cp = Line; cp < Line+GifFileIn->Image.Width; cp++)
209 *cp = Translation[*cp];
211 if (EGifPutLine(GifFileOut,
212 Line, GifFileIn->Image.Width)
214 QuitGifError(GifFileIn, GifFileOut);
220 case EXTENSION_RECORD_TYPE:
221 assert(GifFileOut != NULL); /* might pacify Coverity */
222 /* pass through extension records */
223 if (DGifGetExtension(GifFileIn, &ExtCode, &Extension) == GIF_ERROR)
224 QuitGifError(GifFileIn, GifFileOut);
225 if (Extension == NULL)
227 if (EGifPutExtensionLeader(GifFileOut, ExtCode) == GIF_ERROR)
228 QuitGifError(GifFileIn, GifFileOut);
229 if (EGifPutExtensionBlock(GifFileOut,
231 Extension + 1) == GIF_ERROR)
232 QuitGifError(GifFileIn, GifFileOut);
233 while (Extension != NULL) {
234 if (DGifGetExtensionNext(GifFileIn, &Extension)==GIF_ERROR)
235 QuitGifError(GifFileIn, GifFileOut);
236 if (Extension != NULL)
237 if (EGifPutExtensionBlock(GifFileOut,
239 Extension + 1) == GIF_ERROR)
240 QuitGifError(GifFileIn, GifFileOut);
242 if (EGifPutExtensionTrailer(GifFileOut) == GIF_ERROR)
243 QuitGifError(GifFileIn, GifFileOut);
245 case TERMINATE_RECORD_TYPE:
247 default: /* Should be trapped by DGifGetRecordType. */
251 while (RecordType != TERMINATE_RECORD_TYPE);
253 if (DGifCloseFile(GifFileIn, &ErrorCode) == GIF_ERROR)
255 PrintGifError(ErrorCode);
259 if (EGifCloseFile(GifFileOut, &ErrorCode) == GIF_ERROR)
261 PrintGifError(ErrorCode);
268 /******************************************************************************
269 Modify the given colormap according to global variables setting.
270 ******************************************************************************/
271 static ColorMapObject *ModifyColorMap(ColorMapObject *ColorMap)
273 int i, Dummy, Red, Green, Blue;
276 /* Save this color map to ColorFile: */
277 for (i = 0; i < ColorMap->ColorCount; i++)
278 fprintf(ColorFile, "%3d %3d %3d %3d\n", i,
279 ColorMap->Colors[i].Red,
280 ColorMap->Colors[i].Green,
281 ColorMap->Colors[i].Blue);
285 /* Read the color map in ColorFile into this color map: */
286 for (i = 0; i < ColorMap->ColorCount; i++) {
288 GIF_EXIT("Color file to load color map from, too small.");
289 if (fscanf(ColorFile, "%3d %3d %3d %3d\n", &Dummy, &Red, &Green, &Blue) == 4) {
290 ColorMap->Colors[i].Red = Red;
291 ColorMap->Colors[i].Green = Green;
292 ColorMap->Colors[i].Blue = Blue;
297 else if (GammaFlag) {
298 /* Apply gamma correction to this color map: */
299 double Gamma1 = 1.0 / Gamma;
300 for (i = 0; i < ColorMap->ColorCount; i++) {
301 ColorMap->Colors[i].Red =
302 ((int) (255 * pow(ColorMap->Colors[i].Red / 255.0, Gamma1)));
303 ColorMap->Colors[i].Green =
304 ((int) (255 * pow(ColorMap->Colors[i].Green / 255.0, Gamma1)));
305 ColorMap->Colors[i].Blue =
306 ((int) (255 * pow(ColorMap->Colors[i].Blue / 255.0, Gamma1)));
310 else if (TranslateFlag) {
311 ColorMapObject *NewMap;
314 /* Read the translation table in TranslateFile: */
315 for (i = 0; i < ColorMap->ColorCount; i++) {
317 if (feof(TranslateFile))
318 GIF_EXIT("Color file to load color map from, too small.");
319 if (fscanf(TranslateFile, "%3d %3d\n", &Dummy, &tmp) == 2) {
320 Translation[i] = tmp & 0xff;
321 if (Translation[i] > Max)
322 Max = Translation[i];
326 if ((NewMap = GifMakeMapObject(1 << GifBitSize(Max+1), NULL)) == NULL)
327 GIF_EXIT("Out of memory while allocating color map!");
329 /* Apply the translation; we'll do it to the pixels, too */
330 for (i = 0; i < ColorMap->ColorCount; i++) {
331 NewMap->Colors[i] = ColorMap->Colors[Translation[i]];
338 GIF_EXIT("Nothing to do!");
343 /******************************************************************************
344 Close both input and output file (if open), and exit.
345 ******************************************************************************/
346 static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut)
348 if (GifFileIn != NULL) {
349 PrintGifError(GifFileIn->Error);
350 EGifCloseFile(GifFileIn, NULL);
352 if (GifFileOut != NULL) {
353 PrintGifError(GifFileOut->Error);
354 EGifCloseFile(GifFileOut, NULL);