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