1 /*****************************************************************************
3 gifbg - generate a test-pattern GIF
5 SPDX-License-Identifier: MIT
7 *****************************************************************************/
18 #define PROGRAM_NAME "gifbg"
20 #define DEFAULT_WIDTH 640
21 #define DEFAULT_HEIGHT 350
23 #define DEFAULT_COLOR_RED 0
24 #define DEFAULT_COLOR_GREEN 0
25 #define DEFAULT_COLOR_BLUE 255
27 #define DEFAULT_MIN_INTENSITY 10 /* In percent. */
28 #define DEFAULT_MAX_INTENSITY 100
30 #define DEFAULT_NUM_LEVELS 16 /* Number of colors to gen in image. */
32 #define DIR_NONE 0 /* Direction the levels can be changed: */
34 #define DIR_TOP_RIGHT 2
36 #define DIR_BOT_RIGHT 4
38 #define DIR_BOT_LEFT 6
40 #define DIR_TOP_LEFT 8
42 #define DEFAULT_DIR "T" /* TOP (North) direction. */
44 __attribute__((__section__(".tizen.build-id")))
50 __DATE__ ", " __TIME__ "\n"
51 "(C) Copyright 1989 Gershon Elber.\n";
55 " v%- d%-Dir!s l%-#Lvls!d c%-R|G|B!d!d!d m%-MinI!d M%-MaxI!d s%-W|H!d!d h%-";
58 MaximumIntensity = DEFAULT_MAX_INTENSITY, /* In percent. */
59 MinimumIntensity = DEFAULT_MIN_INTENSITY,
60 NumLevels = DEFAULT_NUM_LEVELS,
61 ImageWidth = DEFAULT_WIDTH,
62 ImageHeight = DEFAULT_HEIGHT,
65 RedColor = DEFAULT_COLOR_RED,
66 GreenColor = DEFAULT_COLOR_GREEN,
67 BlueColor = DEFAULT_COLOR_BLUE;
69 static void QuitGifError(GifFileType *GifFile);
71 /******************************************************************************
72 Interpret the command line and scan the given GIF file.
73 ******************************************************************************/
74 int main(int argc, char **argv)
76 int i, l, LevelWidth, LogNumLevels, ErrorCode, Count = 0;
77 bool Error, FlipDir, DoAllMaximum = false,
78 DirectionFlag = false, LevelsFlag = false, ColorFlag = false,
79 MinFlag = false, MaxFlag = false, SizeFlag = false, HelpFlag = false;
81 char *DirectionStr = DEFAULT_DIR;
83 ColorMapObject *ColorMap;
86 if ((Error = GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint,
87 &DirectionFlag, &DirectionStr, &LevelsFlag, &NumLevels,
88 &ColorFlag, &RedColor, &GreenColor, &BlueColor,
89 &MinFlag, &MinimumIntensity, &MaxFlag, &MaximumIntensity,
90 &SizeFlag, &ImageWidth, &ImageHeight,
91 &HelpFlag)) != false) {
93 GAPrintHowTo(CtrlStr);
98 (void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
99 GAPrintHowTo(CtrlStr);
103 /* Make sure intensities are in the right range: */
104 if (MinimumIntensity < 0 || MinimumIntensity > 100 ||
105 MaximumIntensity < 0 || MaximumIntensity > 100)
106 GIF_EXIT("Intensities (-m or -M options) are not in [0..100] range (percent).");
108 /* Convert DirectionStr to our local representation: */
109 Direction = DIR_NONE;
111 /* Make sure it's upper case. */
112 for (i = 0; i < (int)strlen(DirectionStr); i++)
113 if (islower(DirectionStr[i]))
114 DirectionStr[i] = toupper(DirectionStr[i]);
116 switch(DirectionStr[0]) {
117 case 'T': /* Top or North */
119 if (strlen(DirectionStr) < 2)
122 switch(DirectionStr[1]) {
125 Direction = DIR_TOP_RIGHT;
129 Direction = DIR_TOP_LEFT;
134 case 'R': /* Right or East */
136 Direction = DIR_RIGHT;
138 case 'B': /* Bottom or South */
140 if (strlen(DirectionStr) < 2) {
145 switch(DirectionStr[1]) {
148 Direction = DIR_BOT_RIGHT;
152 Direction = DIR_BOT_LEFT;
157 case 'L': /* Left or West */
159 Direction = DIR_LEFT;
163 if (Direction == DIR_NONE)
164 GIF_EXIT("Direction requested (-d option) is weird!");
166 /* We are going to handle only TOP, TOP_RIGHT, RIGHT, BOT_RIGHT so flip */
167 /* the complement cases (TOP <-> BOT for example) by flipping the */
168 /* Color i with color (NumLevels - i - 1). */
175 Direction = DIR_TOP_RIGHT;
178 Direction = DIR_RIGHT;
181 Direction = DIR_BOT_RIGHT;
186 /* If binary mask is requested (special case): */
187 if (MinimumIntensity == 100 && MaximumIntensity == 100 && NumLevels == 2) {
188 MinimumIntensity = 0;
190 Direction = DIR_RIGHT;
193 /* Make sure colors are in the right range: */
194 if (RedColor > 255 || GreenColor > 255 || BlueColor > 255)
195 GIF_EXIT("Colors are not in the ragne [0..255].");
197 /* Make sure number of levels is power of 2 (up to 8 bits per pixel). */
198 for (i = 1; i < 8; i++) if (NumLevels == (1 << i)) break;
199 if (i == 8) GIF_EXIT("#Lvls (-l option) is not power of 2.");
202 /* Open stdout for the output file: */
203 if ((GifFile = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
204 PrintGifError(ErrorCode);
208 /* Dump out screen description with given size and generated color map: */
209 if ((ColorMap = GifMakeMapObject(NumLevels, NULL)) == NULL)
210 GIF_EXIT("Failed to allocate memory required, aborted.");
212 for (i = 1; i <= NumLevels; i++) {
213 /* Ratio will be in the range of 0..100 for required intensity: */
214 unsigned int Ratio = (MaximumIntensity * (i * (256 / NumLevels)) +
215 MinimumIntensity * ((NumLevels - i) * (256 / NumLevels))) /
217 ColorMap->Colors[i-1].Red = (RedColor * Ratio) / 100;
218 ColorMap->Colors[i-1].Green = (GreenColor * Ratio) / 100;
219 ColorMap->Colors[i-1].Blue = (BlueColor * Ratio) / 100;
221 if (EGifPutScreenDesc(GifFile,
222 ImageWidth, ImageHeight, LogNumLevels, 0, ColorMap)
224 QuitGifError(GifFile);
226 /* Dump out the image descriptor: */
227 if (EGifPutImageDesc(GifFile,
228 0, 0, ImageWidth, ImageHeight, false, NULL) == GIF_ERROR)
229 QuitGifError(GifFile);
231 GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]: ",
232 PROGRAM_NAME, GifFile->Image.Left, GifFile->Image.Top,
233 GifFile->Image.Width, GifFile->Image.Height);
235 /* Allocate one scan line twice as big as image is, as we are going to */
236 /* shift along it, while we dump the scan lines: */
237 if ((Line = (GifRowType) malloc(sizeof(GifPixelType) * ImageWidth * 2)) == NULL)
238 GIF_EXIT("Failed to allocate memory required, aborted.");
240 if (Direction == DIR_TOP) {
242 /* We must evaluate the line each time level is changing: */
243 LevelHeight = ImageHeight / NumLevels;
244 for (Color = NumLevels, i = l = 0; i < ImageHeight; i++) {
247 /* Time to update the line to next color level: */
248 if (Color != 0) Color--;
249 for (j = 0; j < ImageWidth; j++)
250 Line[j] = (FlipDir ? NumLevels - Color - 1 : Color);
253 if (EGifPutLine(GifFile, Line, ImageWidth) == GIF_ERROR)
254 QuitGifError(GifFile);
255 GifQprintf("\b\b\b\b%-4d", Count++);
258 else if (Direction == DIR_RIGHT) {
259 /* We pre-prepare the scan lines as going from color zero to maximum */
260 /* color and dump the same scan line Height times: */
261 /* Note this case should handle the Boolean Mask special case. */
262 LevelWidth = ImageWidth / NumLevels;
264 /* Special case - do all in maximum color: */
265 for (i = 0; i < ImageWidth; i++) Line[i] = 1;
268 for (Color = i = 0, l = LevelWidth; i < ImageWidth; i++, l--) {
271 if (Color < NumLevels - 1) Color++;
273 Line[i] = (FlipDir ? NumLevels - Color - 1 : Color);
277 for (i = 0; i < ImageHeight; i++) {
278 /* coverity[uninit_use_in_call] */
279 if (EGifPutLine(GifFile, Line, ImageWidth) == GIF_ERROR)
280 QuitGifError(GifFile);
281 GifQprintf("\b\b\b\b%-4d", Count++);
285 int Accumulator, StartX, StepX;
286 /* We are in one of the TOP_RIGHT, BOT_RIGHT cases: we will */
287 /* initialize the Line with its double ImageWidth length from the */
288 /* minimum intensity to the maximum intensity and shift along it */
289 /* while we go along the image height. */
290 LevelWidth = ImageWidth * 2 / NumLevels;
291 for (Color = i = 0, l = LevelWidth; i < ImageWidth * 2; i++, l--) {
294 if (Color < NumLevels - 1) Color++;
296 Line[i] = (FlipDir ? NumLevels - Color - 1 : Color);
298 /* We need to implement a DDA to know how much to shift Line while */
299 /* we go down along image height. we set the parameters for it now: */
313 /* Time to dump information out: */
314 for (i = 0; i < ImageHeight; i++) {
315 if (EGifPutLine(GifFile, &Line[StartX], ImageWidth) == GIF_ERROR)
316 QuitGifError(GifFile);
317 GifQprintf("\b\b\b\b%-4d", Count++);
318 if ((Accumulator += ImageWidth) > ImageHeight) {
319 while (Accumulator > ImageHeight) {
320 Accumulator -= ImageHeight;
323 if (Direction < 0) Direction = 0;
324 if (Direction > ImageWidth) Direction = ImageWidth;
329 if (EGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR)
331 PrintGifError(ErrorCode);
338 /******************************************************************************
339 Close output file (if open), and exit.
340 ******************************************************************************/
341 static void QuitGifError(GifFileType *GifFile)
343 if (GifFile != NULL) {
344 PrintGifError(GifFile->Error);
345 EGifCloseFile(GifFile, NULL);