1 /******************************************************************************
2
3 giffilter.c - skeleton file for generic GIF `filter' program
4
5 Sequentially read GIF records from stdin, process them, send them out.
6 Most of the junk above `int main' isn't needed for the skeleton, but
7 is likely to be for what you'll do with it.
8
9 If you compile this, it will turn into an expensive GIF copying routine;
10 stdin to stdout with no changes and minimal validation. Well, it's a
11 decent test of the low-level routines, anyway.
12
13 Note: due to the vicissitudes of Lempel-Ziv compression, the output of this
14 copier may not be bitwise identical to its input. This can happen if you
15 copy an image from a much more (or much *less*) memory-limited system; your
16 compression may use more (or fewer) bits. The uncompressed rasters should,
17 however, be identical (you can check this with gifbuild -d).
18
19 SPDX-License-Identifier: MIT
20
21 ******************************************************************************/
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <fcntl.h>
27
28 #include "gif_lib.h"
29 #include "getarg.h"
30
31 #define PROGRAM_NAME "giffilter"
32
33 /******************************************************************************
34 Close both input and output file (if open), and exit.
35 ******************************************************************************/
QuitGifError(GifFileType * GifFileIn,GifFileType * GifFileOut)36 static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut)
37 {
38 if (GifFileIn != NULL) {
39 PrintGifError(GifFileIn->Error);
40 EGifCloseFile(GifFileIn, NULL);
41 }
42 if (GifFileOut != NULL) {
43 PrintGifError(GifFileOut->Error);
44 EGifCloseFile(GifFileOut, NULL);
45 }
46 exit(EXIT_FAILURE);
47 }
48
49 /******************************************************************************
50 Main sequence
51 ******************************************************************************/
main(int argc,char ** argv)52 int main(int argc, char **argv)
53 {
54 GifFileType *GifFileIn = NULL, *GifFileOut = NULL;
55 GifRecordType RecordType;
56 int CodeSize, ExtCode, ErrorCode;
57 GifByteType *CodeBlock, *Extension;
58
59 /*
60 * Command-line processing goes here.
61 */
62
63 /* Use stdin as input (note this also read screen descriptor in: */
64 if ((GifFileIn = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
65 PrintGifError(ErrorCode);
66 exit(EXIT_FAILURE);
67 }
68
69 /* Use the stdout as output: */
70 if ((GifFileOut = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
71 PrintGifError(ErrorCode);
72 exit(EXIT_FAILURE);
73 }
74
75 /* And dump out its screen information: */
76 if (EGifPutScreenDesc(GifFileOut,
77 GifFileIn->SWidth, GifFileIn->SHeight,
78 GifFileIn->SColorResolution, GifFileIn->SBackGroundColor,
79 GifFileIn->SColorMap) == GIF_ERROR)
80 QuitGifError(GifFileIn, GifFileOut);
81
82 /* Scan the content of the input GIF file and load the image(s) in: */
83 do {
84 if (DGifGetRecordType(GifFileIn, &RecordType) == GIF_ERROR)
85 QuitGifError(GifFileIn, GifFileOut);
86
87 switch (RecordType) {
88 case IMAGE_DESC_RECORD_TYPE:
89 if (DGifGetImageDesc(GifFileIn) == GIF_ERROR)
90 QuitGifError(GifFileIn, GifFileOut);
91 /* Put image descriptor to out file: */
92 if (EGifPutImageDesc(GifFileOut,
93 GifFileIn->Image.Left, GifFileIn->Image.Top,
94 GifFileIn->Image.Width, GifFileIn->Image.Height,
95 GifFileIn->Image.Interlace,
96 GifFileIn->Image.ColorMap) == GIF_ERROR)
97 QuitGifError(GifFileIn, GifFileOut);
98
99 /* Now read image itself in decoded form as we dont really */
100 /* care what we have there, and this is much faster. */
101 if (DGifGetCode(GifFileIn, &CodeSize, &CodeBlock) == GIF_ERROR ||
102 EGifPutCode(GifFileOut, CodeSize, CodeBlock) == GIF_ERROR)
103 QuitGifError(GifFileIn, GifFileOut);
104 while (CodeBlock != NULL) {
105 if (DGifGetCodeNext(GifFileIn, &CodeBlock) == GIF_ERROR ||
106 EGifPutCodeNext(GifFileOut, CodeBlock) == GIF_ERROR)
107 QuitGifError(GifFileIn, GifFileOut);
108 }
109 break;
110 case EXTENSION_RECORD_TYPE:
111 /* pass through extension records */
112 if (DGifGetExtension(GifFileIn, &ExtCode, &Extension) == GIF_ERROR || Extension == NULL)
113 QuitGifError(GifFileIn, GifFileOut);
114 if (EGifPutExtensionLeader(GifFileOut, ExtCode) == GIF_ERROR)
115 QuitGifError(GifFileIn, GifFileOut);
116 if (EGifPutExtensionBlock(GifFileOut,
117 Extension[0],
118 Extension + 1) == GIF_ERROR)
119 QuitGifError(GifFileIn, GifFileOut);
120 while (Extension != NULL) {
121 if (DGifGetExtensionNext(GifFileIn, &Extension)==GIF_ERROR)
122 QuitGifError(GifFileIn, GifFileOut);
123 if (Extension != NULL)
124 if (EGifPutExtensionBlock(GifFileOut,
125 Extension[0],
126 Extension + 1) == GIF_ERROR)
127 QuitGifError(GifFileIn, GifFileOut);
128 }
129 if (EGifPutExtensionTrailer(GifFileOut) == GIF_ERROR)
130 QuitGifError(GifFileIn, GifFileOut);
131 break;
132 case TERMINATE_RECORD_TYPE:
133 break;
134 default: /* Should be trapped by DGifGetRecordType */
135 break;
136 }
137 }
138 while (RecordType != TERMINATE_RECORD_TYPE);
139
140 if (DGifCloseFile(GifFileIn, &ErrorCode) == GIF_ERROR)
141 {
142 PrintGifError(ErrorCode);
143 exit(EXIT_FAILURE);
144 }
145 if (EGifCloseFile(GifFileOut, &ErrorCode) == GIF_ERROR)
146 {
147 PrintGifError(ErrorCode);
148 exit(EXIT_FAILURE);
149 }
150
151 return 0;
152 }
153
154 /* end */
155