• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*****************************************************************************
2 
3 gifecho - generate a GIF from ASCII text
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 "gifecho"
19 
20 #define MAX_NUM_TEXT_LINES 100 /* Maximum number of lines in file. */
21 
22 #define LINE_LEN 256 /* Maximum length of one text line. */
23 
24 #define DEFAULT_FG_INDEX 1 /* Text foreground index. */
25 
26 #define DEFAULT_COLOR_RED 255 /* Text foreground color. */
27 #define DEFAULT_COLOR_GREEN 255
28 #define DEFAULT_COLOR_BLUE 255
29 
30 static char *VersionStr = PROGRAM_NAME VERSION_COOKIE
31     "	Gershon Elber,	" __DATE__ ",   " __TIME__ "\n"
32     "(C) Copyright 1989 Gershon Elber.\n";
33 static char *CtrlStr = PROGRAM_NAME
34     " v%- s%-ClrMapSize!d f%-FGClr!d c%-R|G|B!d!d!d t%-\"Text\"!s h%-";
35 
36 static unsigned int RedColor = DEFAULT_COLOR_RED,
37                     GreenColor = DEFAULT_COLOR_GREEN,
38                     BlueColor = DEFAULT_COLOR_BLUE;
39 
40 static void QuitGifError(GifFileType *GifFile);
41 static void GenRasterTextLine(GifRowType *RasterBuffer, char *TextLine,
42                               int BufferWidth, int ForeGroundIndex);
43 
44 /******************************************************************************
45  Interpret the command line and generate the given GIF file.
46 ******************************************************************************/
main(int argc,char ** argv)47 int main(int argc, char **argv) {
48 	int i, j, l, ImageWidth, ImageHeight, NumOfLines, LogNumLevels,
49 	    ErrorCode, NumLevels, ColorMapSize = 1,
50 	                          ForeGroundIndex = DEFAULT_FG_INDEX;
51 	bool Error, ClrMapSizeFlag = false, ForeGroundFlag = false,
52 	            TextLineFlag = false, HelpFlag = false, ColorFlag = false,
53 	            GifNoisyPrint = false;
54 	char *TextLines[MAX_NUM_TEXT_LINES];
55 	GifRowType RasterBuffer[GIF_FONT_HEIGHT];
56 	ColorMapObject *ColorMap;
57 	GifFileType *GifFile;
58 
59 	if ((Error =
60 	         GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint, &ClrMapSizeFlag,
61 	                   &ColorMapSize, &ForeGroundFlag, &ForeGroundIndex,
62 	                   &ColorFlag, &RedColor, &GreenColor, &BlueColor,
63 	                   &TextLineFlag, &TextLines[0], &HelpFlag)) != false) {
64 		GAPrintErrMsg(Error);
65 		GAPrintHowTo(CtrlStr);
66 		exit(EXIT_FAILURE);
67 	}
68 
69 	if (HelpFlag) {
70 		(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
71 		GAPrintHowTo(CtrlStr);
72 		exit(EXIT_SUCCESS);
73 	}
74 
75 	if (ForeGroundIndex > 255 || ForeGroundIndex < 1) {
76 		GIF_EXIT(
77 		    "Foregound (-f) should be in the range 1..255, aborted.");
78 	}
79 
80 	if (ColorMapSize > 8 || ColorMapSize < 1) {
81 		GIF_EXIT(
82 		    "ColorMapSize (-s) should be in the range 1..8, aborted.");
83 	}
84 
85 	if (TextLineFlag) {
86 		NumOfLines = 1;
87 		ImageHeight = GIF_FONT_HEIGHT;
88 		ImageWidth = GIF_FONT_WIDTH * strlen(TextLines[0]);
89 	} else {
90 		char Line[LINE_LEN];
91 		NumOfLines = l = 0;
92 		while (fgets(Line, LINE_LEN - 1, stdin)) {
93 			for (i = strlen(Line); i > 0 && Line[i - 1] <= ' ';
94 			     i--) {
95 				;
96 			}
97 			Line[i] = 0;
98 			if (l < i) {
99 				l = i;
100 			}
101 			TextLines[NumOfLines++] = strdup(Line);
102 			if (NumOfLines == MAX_NUM_TEXT_LINES) {
103 				GIF_EXIT(
104 				    "Input file has too many lines, aborted.");
105 			}
106 		}
107 		if (NumOfLines == 0) {
108 			GIF_EXIT("No input text, aborted.");
109 		}
110 		ImageHeight = GIF_FONT_HEIGHT * NumOfLines;
111 		ImageWidth = GIF_FONT_WIDTH * l;
112 	}
113 
114 	/* Allocate the raster buffer for GIF_FONT_HEIGHT scan lines (one text
115 	 * line). */
116 	for (i = 0; i < GIF_FONT_HEIGHT; i++) {
117 		if ((RasterBuffer[i] = (GifRowType)malloc(
118 		         sizeof(GifPixelType) * ImageWidth)) == NULL) {
119 			GIF_EXIT(
120 			    "Failed to allocate memory required, aborted.");
121 		}
122 	}
123 
124 	/* Open stdout for the output file: */
125 	if ((GifFile = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
126 		PrintGifError(ErrorCode);
127 		exit(EXIT_FAILURE);
128 	}
129 
130 	/* Dump out screen description with given size and generated color map:
131 	 */
132 	for (LogNumLevels = 1, NumLevels = 2; NumLevels < ForeGroundIndex;
133 	     LogNumLevels++, NumLevels <<= 1) {
134 		;
135 	}
136 	if (NumLevels < (1 << ColorMapSize)) {
137 		NumLevels = (1 << ColorMapSize);
138 		LogNumLevels = ColorMapSize;
139 	}
140 
141 	if ((ColorMap = GifMakeMapObject(NumLevels, NULL)) == NULL) {
142 		GIF_EXIT("Failed to allocate memory required, aborted.");
143 	}
144 
145 	for (i = 0; i < NumLevels; i++) {
146 		ColorMap->Colors[i].Red = ColorMap->Colors[i].Green =
147 		    ColorMap->Colors[i].Blue = 0;
148 	}
149 	ColorMap->Colors[ForeGroundIndex].Red = RedColor;
150 	ColorMap->Colors[ForeGroundIndex].Green = GreenColor;
151 	ColorMap->Colors[ForeGroundIndex].Blue = BlueColor;
152 
153 	if (EGifPutScreenDesc(GifFile, ImageWidth, ImageHeight, LogNumLevels, 0,
154 	                      ColorMap) == GIF_ERROR) {
155 		QuitGifError(GifFile);
156 	}
157 
158 	/* Dump out the image descriptor: */
159 	if (EGifPutImageDesc(GifFile, 0, 0, ImageWidth, ImageHeight, false,
160 	                     NULL) == GIF_ERROR) {
161 		QuitGifError(GifFile);
162 	}
163 
164 	GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]:     ", PROGRAM_NAME,
165 	           GifFile->Image.Left, GifFile->Image.Top,
166 	           GifFile->Image.Width, GifFile->Image.Height);
167 
168 	for (i = l = 0; i < NumOfLines; i++) {
169 		GenRasterTextLine(RasterBuffer, TextLines[i], ImageWidth,
170 		                  ForeGroundIndex);
171 		for (j = 0; j < GIF_FONT_HEIGHT; j++) {
172 			if (EGifPutLine(GifFile, RasterBuffer[j], ImageWidth) ==
173 			    GIF_ERROR) {
174 				QuitGifError(GifFile);
175 			}
176 			GifQprintf("\b\b\b\b%-4d", l++);
177 		}
178 	}
179 
180 	if (EGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR) {
181 		PrintGifError(ErrorCode);
182 		exit(EXIT_FAILURE);
183 	}
184 
185 	return 0;
186 }
187 
188 /******************************************************************************
189  Generate raster bits corresponding to given text
190 ******************************************************************************/
GenRasterTextLine(GifRowType * RasterBuffer,char * TextLine,int BufferWidth,int ForeGroundIndex)191 static void GenRasterTextLine(GifRowType *RasterBuffer, char *TextLine,
192                               int BufferWidth, int ForeGroundIndex) {
193 	unsigned char Byte, Mask;
194 	int i, j, k, CharPosX, Len = strlen(TextLine);
195 
196 	for (i = 0; i < BufferWidth; i++) {
197 		for (j = 0; j < GIF_FONT_HEIGHT; j++) {
198 			RasterBuffer[j][i] = 0;
199 		}
200 	}
201 
202 	for (i = CharPosX = 0; i < Len; i++, CharPosX += GIF_FONT_WIDTH) {
203 		unsigned char c = TextLine[i];
204 		for (j = 0; j < GIF_FONT_HEIGHT; j++) {
205 			Byte = GifAsciiTable8x8[(unsigned short)c][j];
206 			for (k = 0, Mask = 128; k < GIF_FONT_WIDTH;
207 			     k++, Mask >>= 1) {
208 				if (Byte & Mask) {
209 					RasterBuffer[j][CharPosX + k] =
210 					    ForeGroundIndex;
211 				}
212 			}
213 		}
214 	}
215 }
216 
217 /******************************************************************************
218  * Close output file (if open), and exit.
219  ******************************************************************************/
QuitGifError(GifFileType * GifFile)220 static void QuitGifError(GifFileType *GifFile) {
221 	if (GifFile != NULL) {
222 		PrintGifError(GifFile->Error);
223 		EGifCloseFile(GifFile, NULL);
224 	}
225 	exit(EXIT_FAILURE);
226 }
227 
228 /* end */
229