1 /*****************************************************************************
2 
3 gifcolor - generate color test-pattern GIFs
4 
5 SPDX-License-Identifier: MIT
6 
7 *****************************************************************************/
8 
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <ctype.h>
12 #include <string.h>
13 #include <stdbool.h>
14 
15 #include "gif_lib.h"
16 #include "getarg.h"
17 
18 #define PROGRAM_NAME	"gifcolor"
19 
20 #define LINE_LEN		40
21 #define IMAGEWIDTH		LINE_LEN*GIF_FONT_WIDTH
22 
23 static char
24     *VersionStr =
25 	PROGRAM_NAME
26 	VERSION_COOKIE
27 	"	Gershon Elber,	"
28 	__DATE__ ",   " __TIME__ "\n"
29 	"(C) Copyright 1989 Gershon Elber.\n";
30 static char
31     *CtrlStr = PROGRAM_NAME " v%- b%-Background!d h%-";
32 
33 static int BackGround = 0;
34 static void QuitGifError(GifFileType *GifFile);
35 static void GenRasterTextLine(GifRowType *RasterBuffer, char *TextLine,
36 					int BufferWidth, int ForeGroundIndex);
37 
38 /******************************************************************************
39  Interpret the command line and generate the given GIF file.
40 ******************************************************************************/
main(int argc,char ** argv)41 int main(int argc, char **argv)
42 {
43     int	i, j, l, GifNoisyPrint, ColorMapSize, ErrorCode;
44     bool Error, BackGroundFlag = false, HelpFlag = false;
45     char Line[LINE_LEN];
46     GifRowType RasterBuffer[GIF_FONT_HEIGHT];
47     ColorMapObject *ColorMap;
48     GifFileType *GifFile;
49     GifColorType	ScratchMap[256];
50     int red, green, blue;
51 
52     if ((Error = GAGetArgs(argc, argv, CtrlStr,
53 			   &GifNoisyPrint,
54 			   &BackGroundFlag, &BackGround,
55 			   &HelpFlag)) != false) {
56 	GAPrintErrMsg(Error);
57 	GAPrintHowTo(CtrlStr);
58 	exit(EXIT_FAILURE);
59     }
60 
61     if (HelpFlag) {
62 	(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
63 	GAPrintHowTo(CtrlStr);
64 	exit(EXIT_SUCCESS);
65     }
66 
67     /* Allocate the raster buffer for GIF_FONT_HEIGHT scan lines. */
68     for (i = 0; i < GIF_FONT_HEIGHT; i++)
69     {
70 	if ((RasterBuffer[i] = (GifRowType) malloc(sizeof(GifPixelType) *
71 						   IMAGEWIDTH)) == NULL)
72 	    GIF_EXIT("Failed to allocate memory required, aborted.");
73     }
74 
75     /* Open stdout for the output file: */
76     if ((GifFile = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
77 	PrintGifError(ErrorCode);
78 	exit(EXIT_FAILURE);
79     }
80 
81     /* Read the color map in ColorFile into this color map: */
82     ColorMapSize = 0;
83     while (fscanf(stdin,
84 		  "%*3d %3d %3d %3d\n",
85 		  &red, &green, &blue) == 3) {
86 	if (ColorMapSize < 256) {
87 		ScratchMap[ColorMapSize].Red = red;
88 		ScratchMap[ColorMapSize].Green = green;
89 		ScratchMap[ColorMapSize].Blue = blue;
90 		ColorMapSize++;
91 	} else {
92 	    GIF_EXIT("Too many color map triples, aborting.");
93 	}
94     }
95 
96     if ((ColorMap = GifMakeMapObject(1 << GifBitSize(ColorMapSize), ScratchMap)) == NULL)
97 	GIF_EXIT("Failed to allocate memory required, aborted.");
98 
99     if (EGifPutScreenDesc(GifFile,
100 			  IMAGEWIDTH, ColorMapSize * GIF_FONT_HEIGHT,
101 			  GifBitSize(ColorMapSize),
102 			  BackGround, ColorMap) == GIF_ERROR)
103 	QuitGifError(GifFile);
104 
105     /* Dump out the image descriptor: */
106     if (EGifPutImageDesc(GifFile,
107 			 0, 0, IMAGEWIDTH, ColorMapSize * GIF_FONT_HEIGHT, false, NULL) == GIF_ERROR)
108 	QuitGifError(GifFile);
109 
110     GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]:     ",
111 	       PROGRAM_NAME, GifFile->Image.Left, GifFile->Image.Top,
112 	       GifFile->Image.Width, GifFile->Image.Height);
113 
114     for (i = l = 0; i < ColorMap->ColorCount; i++) {
115 	(void)snprintf(Line, sizeof(Line),
116 		       "Color %-3d: [%-3d, %-3d, %-3d] ", i,
117 		       ColorMap->Colors[i].Red,
118 		       ColorMap->Colors[i].Green,
119 		       ColorMap->Colors[i].Blue);
120 	GenRasterTextLine(RasterBuffer, Line, IMAGEWIDTH, i);
121 	for (j = 0; j < GIF_FONT_HEIGHT; j++) {
122 	    if (EGifPutLine(GifFile, RasterBuffer[j], IMAGEWIDTH) == GIF_ERROR)
123 		QuitGifError(GifFile);
124 	    GifQprintf("\b\b\b\b%-4d", l++);
125 	}
126     }
127 
128     if (EGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR)
129     {
130 	PrintGifError(ErrorCode);
131 	exit(EXIT_FAILURE);
132     }
133 
134     return 0;
135 }
136 
137 /******************************************************************************
138  Close output file (if open), and exit.
139 ******************************************************************************/
GenRasterTextLine(GifRowType * RasterBuffer,char * TextLine,int BufferWidth,int ForeGroundIndex)140 static void GenRasterTextLine(GifRowType *RasterBuffer, char *TextLine,
141 					int BufferWidth, int ForeGroundIndex)
142 {
143     unsigned char Byte, Mask;
144     int i, j, k, CharPosX, Len = strlen(TextLine);
145 
146     for (i = 0; i < BufferWidth; i++)
147         for (j = 0; j < GIF_FONT_HEIGHT; j++) RasterBuffer[j][i] = BackGround;
148 
149     for (i = CharPosX = 0; i < Len; i++, CharPosX += GIF_FONT_WIDTH) {
150 	unsigned char c = TextLine[i];
151 	for (j = 0; j < GIF_FONT_HEIGHT; j++) {
152 	    Byte = GifAsciiTable8x8[(unsigned short)c][j];
153 	    for (k = 0, Mask = 128; k < GIF_FONT_WIDTH; k++, Mask >>= 1)
154 		if (Byte & Mask)
155 		    RasterBuffer[j][CharPosX + k] = ForeGroundIndex;
156 	}
157     }
158 }
159 
160 /******************************************************************************
161  Close output file (if open), and exit.
162 ******************************************************************************/
QuitGifError(GifFileType * GifFile)163 static void QuitGifError(GifFileType *GifFile)
164 {
165     if (GifFile != NULL) {
166 	PrintGifError(GifFile->Error);
167 	EGifCloseFile(GifFile, NULL);
168     }
169     exit(EXIT_FAILURE);
170 }
171