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 <fcntl.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "getarg.h"
29 #include "gif_lib.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 if (GifFileIn != NULL) {
38 PrintGifError(GifFileIn->Error);
39 EGifCloseFile(GifFileIn, NULL);
40 }
41 if (GifFileOut != NULL) {
42 PrintGifError(GifFileOut->Error);
43 EGifCloseFile(GifFileOut, NULL);
44 }
45 exit(EXIT_FAILURE);
46 }
47
48 /******************************************************************************
49 Main sequence
50 ******************************************************************************/
main(int argc,char ** argv)51 int main(int argc, char **argv) {
52 GifFileType *GifFileIn = NULL, *GifFileOut = NULL;
53 GifRecordType RecordType;
54 int CodeSize, ExtCode, ErrorCode;
55 GifByteType *CodeBlock, *Extension;
56
57 /*
58 * Command-line processing goes here.
59 */
60
61 /* Use stdin as input (note this also read screen descriptor in: */
62 if ((GifFileIn = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
63 PrintGifError(ErrorCode);
64 exit(EXIT_FAILURE);
65 }
66
67 /* Use the stdout as output: */
68 if ((GifFileOut = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
69 PrintGifError(ErrorCode);
70 exit(EXIT_FAILURE);
71 }
72
73 /* And dump out its screen information: */
74 if (EGifPutScreenDesc(GifFileOut, GifFileIn->SWidth, GifFileIn->SHeight,
75 GifFileIn->SColorResolution,
76 GifFileIn->SBackGroundColor,
77 GifFileIn->SColorMap) == GIF_ERROR) {
78 QuitGifError(GifFileIn, GifFileOut);
79 }
80
81 /* Scan the content of the input GIF file and load the image(s) in: */
82 do {
83 if (DGifGetRecordType(GifFileIn, &RecordType) == GIF_ERROR) {
84 QuitGifError(GifFileIn, GifFileOut);
85 }
86
87 switch (RecordType) {
88 case IMAGE_DESC_RECORD_TYPE:
89 if (DGifGetImageDesc(GifFileIn) == GIF_ERROR) {
90 QuitGifError(GifFileIn, GifFileOut);
91 }
92 /* Put image descriptor to out file: */
93 if (EGifPutImageDesc(
94 GifFileOut, GifFileIn->Image.Left,
95 GifFileIn->Image.Top, GifFileIn->Image.Width,
96 GifFileIn->Image.Height,
97 GifFileIn->Image.Interlace,
98 GifFileIn->Image.ColorMap) == GIF_ERROR) {
99 QuitGifError(GifFileIn, GifFileOut);
100 }
101
102 /* Now read image itself in decoded form as we dont
103 * really */
104 /* care what we have there, and this is much faster.
105 */
106 if (DGifGetCode(GifFileIn, &CodeSize, &CodeBlock) ==
107 GIF_ERROR ||
108 EGifPutCode(GifFileOut, CodeSize, CodeBlock) ==
109 GIF_ERROR) {
110 QuitGifError(GifFileIn, GifFileOut);
111 }
112 while (CodeBlock != NULL) {
113 if (DGifGetCodeNext(GifFileIn, &CodeBlock) ==
114 GIF_ERROR ||
115 EGifPutCodeNext(GifFileOut, CodeBlock) ==
116 GIF_ERROR) {
117 QuitGifError(GifFileIn, GifFileOut);
118 }
119 }
120 break;
121 case EXTENSION_RECORD_TYPE:
122 /* pass through extension records */
123 if (DGifGetExtension(GifFileIn, &ExtCode, &Extension) ==
124 GIF_ERROR ||
125 Extension == NULL) {
126 QuitGifError(GifFileIn, GifFileOut);
127 }
128 if (EGifPutExtensionLeader(GifFileOut, ExtCode) ==
129 GIF_ERROR) {
130 QuitGifError(GifFileIn, GifFileOut);
131 }
132 if (EGifPutExtensionBlock(GifFileOut, Extension[0],
133 Extension + 1) == GIF_ERROR) {
134 QuitGifError(GifFileIn, GifFileOut);
135 }
136 while (Extension != NULL) {
137 if (DGifGetExtensionNext(
138 GifFileIn, &Extension) == GIF_ERROR) {
139 QuitGifError(GifFileIn, GifFileOut);
140 }
141 if (Extension != NULL) {
142 if (EGifPutExtensionBlock(
143 GifFileOut, Extension[0],
144 Extension + 1) == GIF_ERROR) {
145 QuitGifError(GifFileIn,
146 GifFileOut);
147 }
148 }
149 }
150 if (EGifPutExtensionTrailer(GifFileOut) == GIF_ERROR) {
151 QuitGifError(GifFileIn, GifFileOut);
152 }
153 break;
154 case TERMINATE_RECORD_TYPE:
155 break;
156 default: /* Should be trapped by DGifGetRecordType */
157 break;
158 }
159 } while (RecordType != TERMINATE_RECORD_TYPE);
160
161 if (DGifCloseFile(GifFileIn, &ErrorCode) == GIF_ERROR) {
162 PrintGifError(ErrorCode);
163 exit(EXIT_FAILURE);
164 }
165 if (EGifCloseFile(GifFileOut, &ErrorCode) == GIF_ERROR) {
166 PrintGifError(ErrorCode);
167 exit(EXIT_FAILURE);
168 }
169
170 return 0;
171 }
172
173 /* end */
174