1 /* gif.c - Handles output to gif file */
2 
3 /*
4     libzint - the open source barcode library
5     Copyright (C) 2009-2017 Robin Stuart <rstuart114@gmail.com>
6 
7     Redistribution and use in source and binary forms, with or without
8     modification, are permitted provided that the following conditions
9     are met:
10 
11     1. Redistributions of source code must retain the above copyright
12        notice, this list of conditions and the following disclaimer.
13     2. Redistributions in binary form must reproduce the above copyright
14        notice, this list of conditions and the following disclaimer in the
15        documentation and/or other materials provided with the distribution.
16     3. Neither the name of the project nor the names of its contributors
17        may be used to endorse or promote products derived from this software
18        without specific prior written permission.
19 
20     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23     ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26     OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30     SUCH DAMAGE.
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include "common.h"
37 #include <math.h>
38 #ifdef _MSC_VER
39 #include <io.h>
40 #include <fcntl.h>
41 #include <malloc.h>
42 #endif
43 
44 #define SSET	"0123456789ABCDEF"
45 
46 /* Index of transparent color, -1 for no transparent color
47  * This might be set into a variable if transparency is activated as an option
48  */
49 #define TRANSPARENT_INDEX (-1)
50 
51 /* Used bit depth, may be changed for bigger pallet in future */
52 #define DESTINATION_IMAGE_BITS 1
53 #include <stdlib.h>
54 
55 typedef struct s_statestruct {
56     unsigned char * pOut;
57     unsigned char *pIn;
58     unsigned int InLen;
59     unsigned int OutLength;
60     unsigned int OutPosCur;
61     unsigned int OutByteCountPos;
62     unsigned short ClearCode;
63     unsigned short FreeCode;
64     char fByteCountByteSet;
65     unsigned char OutBitsFree;
66     unsigned short NodeAxon[4096];
67     unsigned short NodeNext[4096];
68     unsigned char NodePix[4096];
69 } statestruct;
70 
BufferNextByte(statestruct * pState)71 static char BufferNextByte(statestruct *pState) {
72     (pState->OutPosCur)++;
73     /* Check if this position is a byte count position
74      * fg_f_bytecountbyte_set indicates, if byte count position bytes should be
75      * inserted in general.
76      * If this is true, and the distance to the last byte count position is 256
77      * (e.g. 255 bytes in between), a byte count byte is inserted, and the value
78      * of the last one is set to 255.
79      * */
80     if (pState->fByteCountByteSet && (pState->OutByteCountPos + 256 == pState->OutPosCur)) {
81         (pState->pOut)[pState->OutByteCountPos] = 255;
82         pState->OutByteCountPos = pState->OutPosCur;
83         (pState->OutPosCur)++;
84     }
85     if (pState->OutPosCur >= pState->OutLength)
86         return 1;
87     (pState->pOut)[pState->OutPosCur] = 0x00;
88     return 0;
89 }
90 
AddCodeToBuffer(statestruct * pState,unsigned short CodeIn,unsigned char CodeBits)91 static char AddCodeToBuffer(statestruct *pState, unsigned short CodeIn, unsigned char CodeBits) {
92     /* Check, if we may fill up the current byte completely */
93     if (CodeBits >= pState->OutBitsFree) {
94         (pState->pOut)[pState->OutPosCur] |= (unsigned char)
95                 (CodeIn << (8 - pState->OutBitsFree));
96         if (BufferNextByte(pState))
97             return -1;
98         CodeIn = (unsigned short) (CodeIn >> pState->OutBitsFree);
99         CodeBits -= pState->OutBitsFree;
100         pState->OutBitsFree = 8;
101         /* Write a full byte if there are at least 8 code bits left */
102         if (CodeBits >= pState->OutBitsFree) {
103             (pState->pOut)[pState->OutPosCur] = (unsigned char) CodeIn;
104             if (BufferNextByte(pState))
105                 return -1;
106             CodeIn = (unsigned short) (CodeIn >> 8);
107             CodeBits -= 8;
108         }
109     }
110     /* The remaining bits of CodeIn fit in the current byte. */
111     if (CodeBits > 0) {
112         (pState->pOut)[pState->OutPosCur] |= (unsigned char)
113                 (CodeIn << (8 - pState->OutBitsFree));
114         pState->OutBitsFree -= CodeBits;
115     }
116     return 0;
117 }
118 
FlushStringTable(statestruct * pState)119 static void FlushStringTable(statestruct *pState) {
120     unsigned short Pos;
121     for (Pos = 0; Pos < pState->ClearCode; Pos++) {
122         (pState->NodeAxon)[Pos] = 0;
123     }
124 }
125 
FindPixelOutlet(statestruct * pState,unsigned short HeadNode,unsigned char Byte)126 unsigned short FindPixelOutlet(statestruct *pState, unsigned short HeadNode, unsigned char Byte) {
127     unsigned short Outlet;
128 
129     Outlet = (pState->NodeAxon)[HeadNode];
130     while (Outlet) {
131         if ((pState->NodePix)[Outlet] == Byte)
132             return Outlet;
133         Outlet = (pState->NodeNext)[Outlet];
134     }
135     return 0;
136 }
137 
NextCode(statestruct * pState,unsigned char * pPixelValueCur,unsigned char CodeBits)138 static char NextCode(statestruct *pState, unsigned char * pPixelValueCur, unsigned char CodeBits) {
139     unsigned short UpNode;
140     unsigned short DownNode;
141     /* start with the root node for last pixel chain */
142     UpNode = *pPixelValueCur;
143     if ((pState->InLen) == 0)
144         return AddCodeToBuffer(pState, UpNode, CodeBits);
145 
146     *pPixelValueCur = (*(pState->pIn)) - '0';
147     (pState->pIn)++;
148     (pState->InLen)--;
149     /* Follow the string table and the data stream to the end of the longest string that has a code */
150     while (0 != (DownNode = FindPixelOutlet(pState, UpNode, *pPixelValueCur))) {
151         UpNode = DownNode;
152         if ((pState->InLen) == 0)
153             return AddCodeToBuffer(pState, UpNode, CodeBits);
154 
155         *pPixelValueCur = (*(pState->pIn)) - '0';
156         (pState->pIn)++;
157         (pState->InLen)--;
158     }
159     /* Submit 'UpNode' which is the code of the longest string */
160     if (AddCodeToBuffer(pState, UpNode, CodeBits))
161         return -1;
162     /* ... and extend the string by appending 'PixelValueCur' */
163     /* Create a successor node for 'PixelValueCur' whose code is 'freecode' */
164     (pState->NodePix)[pState->FreeCode] = *pPixelValueCur;
165     (pState->NodeAxon)[pState->FreeCode] = (pState->NodeNext)[pState->FreeCode] = 0;
166     /* ...and link it to the end of the chain emanating from fg_axon[UpNode]. */
167     DownNode = (pState->NodeAxon)[UpNode];
168     if (!DownNode) {
169         (pState->NodeAxon)[UpNode] = pState->FreeCode;
170     } else {
171         while ((pState->NodeNext)[DownNode]) {
172             DownNode = (pState->NodeNext)[DownNode];
173         }
174         (pState->NodeNext)[DownNode] = pState->FreeCode;
175     }
176     return 1;
177 }
178 
gif_lzw(unsigned char * pOut,int OutLength,unsigned char * pIn,int InLen)179 int gif_lzw(unsigned char *pOut, int OutLength, unsigned char *pIn, int InLen) {
180     unsigned char PixelValueCur;
181     unsigned char CodeBits;
182     unsigned short Pos;
183     statestruct State;
184 
185     State.pIn = pIn;
186     State.InLen = InLen;
187     State.pOut = pOut;
188     State.OutLength = OutLength;
189     // > Get first data byte
190     if (State.InLen == 0)
191         return 0;
192 
193     PixelValueCur = (unsigned char) ((*(State.pIn)) - '0');
194     (State.pIn)++;
195     (State.InLen)--;
196     CodeBits = 3;
197     State.ClearCode = 4;
198     State.FreeCode = 6;
199     State.OutBitsFree = 8;
200     State.OutPosCur = -1;
201     State.fByteCountByteSet = 0;
202 
203     if (BufferNextByte(&State))
204         return 0;
205 
206     for (Pos = 0; Pos < State.ClearCode; Pos++)
207         State.NodePix[Pos] = (unsigned char) Pos;
208 
209     FlushStringTable(&State);
210 
211     /* Write what the GIF specification calls the "code size". */
212     (State.pOut)[State.OutPosCur] = 2;
213     /* Reserve first bytecount byte */
214     if (BufferNextByte(&State))
215         return 0;
216     State.OutByteCountPos = State.OutPosCur;
217     if (BufferNextByte(&State))
218         return 0;
219     State.fByteCountByteSet = 1;
220     /* Submit one 'ClearCode' as the first code */
221     if (AddCodeToBuffer(&State, State.ClearCode, CodeBits))
222         return 0;
223 
224     for (;;) {
225         char Res;
226         /* generate and save the next code, which may consist of multiple input pixels. */
227         Res = NextCode(&State, &PixelValueCur, CodeBits);
228         if (Res < 0)
229             return 0;
230         //* Check for end of data stream */
231         if (!Res) {
232             /* submit 'eoi' as the last item of the code stream */
233             if (AddCodeToBuffer(&State, (unsigned short) (State.ClearCode + 1), CodeBits))
234                 return 0;
235             State.fByteCountByteSet = 0;
236             if (State.OutBitsFree < 8) {
237                 if (BufferNextByte(&State))
238                     return 0;
239             }
240             // > Update last bytecount byte;
241             if (State.OutByteCountPos < State.OutPosCur) {
242                 (State.pOut)[State.OutByteCountPos] = (unsigned char) (State.OutPosCur - State.OutByteCountPos - 1);
243             }
244             State.OutPosCur++;
245             return State.OutPosCur;
246         }
247         /* Check for currently last code */
248         if (State.FreeCode == (1U << CodeBits))
249             CodeBits++;
250         State.FreeCode++;
251         /* Check for full stringtable */
252         if (State.FreeCode == 0xfff) {
253             FlushStringTable(&State);
254             if (AddCodeToBuffer(&State, State.ClearCode, CodeBits))
255                 return 0;
256 
257             CodeBits = (unsigned char) (1 + 2);
258             State.FreeCode = (unsigned short) (State.ClearCode + 2);
259         }
260     }
261 }
262 
gif_pixel_plot(struct zint_symbol * symbol,char * pixelbuf)263 int gif_pixel_plot(struct zint_symbol *symbol, char *pixelbuf) {
264     char outbuf[10];
265     FILE *gif_file;
266     unsigned short usTemp;
267     int byte_out;
268 #ifdef _MSC_VER
269     char * lzwoutbuf;
270 #endif
271 
272 #ifndef _MSC_VER
273     char lzwoutbuf[symbol->bitmap_height * symbol->bitmap_width];
274 #else
275     lzwoutbuf = (char *) _alloca((symbol->bitmap_height * symbol->bitmap_width) * sizeof (char));
276 #endif /* _MSC_VER */
277 
278     /* Open output file in binary mode */
279     if ((symbol->output_options & BARCODE_STDOUT) != 0) {
280 #ifdef _MSC_VER
281         if (-1 == _setmode(_fileno(stdout), _O_BINARY)) {
282             strcpy(symbol->errtxt, "610: Can't open output file");
283             return ZINT_ERROR_FILE_ACCESS;
284         }
285 #endif
286         gif_file = stdout;
287     } else {
288         if (!(gif_file = fopen(symbol->outfile, "wb"))) {
289             strcpy(symbol->errtxt, "611: Can't open output file");
290             return ZINT_ERROR_FILE_ACCESS;
291         }
292     }
293     /*ImageWidth = 2;
294     ImageHeight = 2;
295     rotated_bitmap[0] = 1;
296     rotated_bitmap[1] = 1;
297     rotated_bitmap[2] = 0;
298     rotated_bitmap[3] = 0;
299      */
300 
301     /* GIF signature (6) */
302     memcpy(outbuf, "GIF87a", 6);
303     if (TRANSPARENT_INDEX != -1)
304         outbuf[4] = '9';
305     fwrite(outbuf, 6, 1, gif_file);
306     /* Screen Descriptor (7) */
307     /* Screen Width */
308     usTemp = (unsigned short) symbol->bitmap_width;
309     outbuf[0] = (unsigned char) (0xff & usTemp);
310     outbuf[1] = (unsigned char) ((0xff00 & usTemp) / 0x100);
311     /* Screen Height */
312     usTemp = (unsigned short) symbol->bitmap_height;
313     outbuf[2] = (unsigned char) (0xff & usTemp);
314     outbuf[3] = (unsigned char) ((0xff00 & usTemp) / 0x100);
315     /* write ImageBits-1 to the three least significant bits of byte 5  of
316      * the Screen Descriptor
317      */
318     outbuf[4] = (unsigned char) (0xf0 | (0x7 & (DESTINATION_IMAGE_BITS - 1)));
319     /*  Background color = colortable index 0 */
320     outbuf[5] = 0x00;
321     /* Byte 7 must be 0x00  */
322     outbuf[6] = 0x00;
323     fwrite(outbuf, 7, 1, gif_file);
324     /* Global Color Table (6) */
325     /* RGB 0 color */
326     outbuf[0] = (unsigned char) (16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]);
327     outbuf[1] = (unsigned char) (16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]);
328     outbuf[2] = (unsigned char) (16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]);
329     /* RGB 1 color */
330     outbuf[3] = (unsigned char) (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]);
331     outbuf[4] = (unsigned char) (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]);
332     outbuf[5] = (unsigned char) (16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]);
333     fwrite(outbuf, 6, 1, gif_file);
334 
335     /* Graphic control extension (8) */
336     /* A graphic control extension block is used for overlay gifs.
337      * This is necessary to define a transparent color.
338      */
339     if (TRANSPARENT_INDEX != -1) {
340         /* Extension Introducer = '!' */
341         outbuf[0] = '\x21';
342         /* Graphic Control Label */
343         outbuf[1] = '\xf9';
344         /* Block Size */
345         outbuf[2] = 4;
346         /* Packet fields:
347          * 3 Reserved
348          * 3 Disposal Method: 0 No Action, 1 No Dispose, 2: Background, 3: Prev.
349          * 1 User Input Flag: 0: no user input, 1: user input
350          * 1 Transparent Color Flag: 0: No Transparency, 1: Transparency index
351          */
352         outbuf[3] = 1;
353         /* Delay Time */
354         outbuf[4] = 0;
355         outbuf[5] = 0;
356         /* Transparent Color Index */
357         outbuf[6] = (unsigned char) TRANSPARENT_INDEX;
358         /* Block Terminator */
359         outbuf[7] = 0;
360         fwrite(outbuf, 8, 1, gif_file);
361     }
362     /* Image Descriptor */
363     /* Image separator character = ',' */
364     outbuf[0] = 0x2c;
365     /* "Image Left" */
366     outbuf[1] = 0x00;
367     outbuf[2] = 0x00;
368     /* "Image Top" */
369     outbuf[3] = 0x00;
370     outbuf[4] = 0x00;
371     /* Image Width (low byte first) */
372     outbuf[5] = (unsigned char) (0xff & symbol->bitmap_width);
373     outbuf[6] = (unsigned char) ((0xff00 & symbol->bitmap_width) / 0x100);
374     /* Image Height */
375     outbuf[7] = (unsigned char) (0xff & symbol->bitmap_height);
376     outbuf[8] = (unsigned char) ((0xff00 & symbol->bitmap_height) / 0x100);
377 
378     /* Byte 10 contains the interlaced flag and
379      * information on the local color table.
380      * There is no local color table if its most significant bit is reset.
381      */
382     outbuf[9] = (unsigned char) (0 | (0x7 & (DESTINATION_IMAGE_BITS - 1)));
383     fwrite(outbuf, 10, 1, gif_file);
384 
385     /* call lzw encoding */
386     byte_out = gif_lzw(
387             (unsigned char *) lzwoutbuf,
388             symbol->bitmap_height * symbol->bitmap_width,
389             (unsigned char *) pixelbuf,
390             symbol->bitmap_height * symbol->bitmap_width);
391     if (byte_out <= 0) {
392         fclose(gif_file);
393         return ZINT_ERROR_MEMORY;
394     }
395     fwrite(lzwoutbuf, byte_out, 1, gif_file);
396 
397     /* GIF terminator */
398     fputc('\x3b', gif_file);
399     fclose(gif_file);
400 
401     return 0;
402 }