1/*
2 * wrgif.c
3 *
4 * This file was part of the Independent JPEG Group's software:
5 * Copyright (C) 1991-1997, Thomas G. Lane.
6 * It was modified by The libjpeg-turbo Project to include only code relevant
7 * to libjpeg-turbo.
8 * For conditions of distribution and use, see the accompanying README file.
9 *
10 * This file contains routines to write output images in GIF format.
11 *
12 **************************************************************************
13 * NOTE: to avoid entanglements with Unisys' patent on LZW compression,   *
14 * this code has been modified to output "uncompressed GIF" files.        *
15 * There is no trace of the LZW algorithm in this file.                   *
16 **************************************************************************
17 *
18 * These routines may need modification for non-Unix environments or
19 * specialized applications.  As they stand, they assume output to
20 * an ordinary stdio stream.
21 */
22
23/*
24 * This code is loosely based on ppmtogif from the PBMPLUS distribution
25 * of Feb. 1991.  That file contains the following copyright notice:
26 *    Based on GIFENCODE by David Rowley <mgardi@watdscu.waterloo.edu>.
27 *    Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al.
28 *    Copyright (C) 1989 by Jef Poskanzer.
29 *    Permission to use, copy, modify, and distribute this software and its
30 *    documentation for any purpose and without fee is hereby granted, provided
31 *    that the above copyright notice appear in all copies and that both that
32 *    copyright notice and this permission notice appear in supporting
33 *    documentation.  This software is provided "as is" without express or
34 *    implied warranty.
35 *
36 * We are also required to state that
37 *    "The Graphics Interchange Format(c) is the Copyright property of
38 *    CompuServe Incorporated. GIF(sm) is a Service Mark property of
39 *    CompuServe Incorporated."
40 */
41
42#include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
43
44#ifdef GIF_SUPPORTED
45
46
47/* Private version of data destination object */
48
49typedef struct {
50  struct djpeg_dest_struct pub; /* public fields */
51
52  j_decompress_ptr cinfo;       /* back link saves passing separate parm */
53
54  /* State for packing variable-width codes into a bitstream */
55  int n_bits;                   /* current number of bits/code */
56  int maxcode;                  /* maximum code, given n_bits */
57  INT32 cur_accum;              /* holds bits not yet output */
58  int cur_bits;                 /* # of bits in cur_accum */
59
60  /* State for GIF code assignment */
61  int ClearCode;                /* clear code (doesn't change) */
62  int EOFCode;                  /* EOF code (ditto) */
63  int code_counter;             /* counts output symbols */
64
65  /* GIF data packet construction buffer */
66  int bytesinpkt;               /* # of bytes in current packet */
67  char packetbuf[256];          /* workspace for accumulating packet */
68
69} gif_dest_struct;
70
71typedef gif_dest_struct * gif_dest_ptr;
72
73/* Largest value that will fit in N bits */
74#define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
75
76
77/*
78 * Routines to package finished data bytes into GIF data blocks.
79 * A data block consists of a count byte (1..255) and that many data bytes.
80 */
81
82LOCAL(void)
83flush_packet (gif_dest_ptr dinfo)
84/* flush any accumulated data */
85{
86  if (dinfo->bytesinpkt > 0) {  /* never write zero-length packet */
87    dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++;
88    if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt)
89        != (size_t) dinfo->bytesinpkt)
90      ERREXIT(dinfo->cinfo, JERR_FILE_WRITE);
91    dinfo->bytesinpkt = 0;
92  }
93}
94
95
96/* Add a character to current packet; flush to disk if necessary */
97#define CHAR_OUT(dinfo,c)  \
98        { (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (c);  \
99            if ((dinfo)->bytesinpkt >= 255)  \
100              flush_packet(dinfo);  \
101        }
102
103
104/* Routine to convert variable-width codes into a byte stream */
105
106LOCAL(void)
107output (gif_dest_ptr dinfo, int code)
108/* Emit a code of n_bits bits */
109/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */
110{
111  dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits;
112  dinfo->cur_bits += dinfo->n_bits;
113
114  while (dinfo->cur_bits >= 8) {
115    CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
116    dinfo->cur_accum >>= 8;
117    dinfo->cur_bits -= 8;
118  }
119}
120
121
122/* The pseudo-compression algorithm.
123 *
124 * In this module we simply output each pixel value as a separate symbol;
125 * thus, no compression occurs.  In fact, there is expansion of one bit per
126 * pixel, because we use a symbol width one bit wider than the pixel width.
127 *
128 * GIF ordinarily uses variable-width symbols, and the decoder will expect
129 * to ratchet up the symbol width after a fixed number of symbols.
130 * To simplify the logic and keep the expansion penalty down, we emit a
131 * GIF Clear code to reset the decoder just before the width would ratchet up.
132 * Thus, all the symbols in the output file will have the same bit width.
133 * Note that emitting the Clear codes at the right times is a mere matter of
134 * counting output symbols and is in no way dependent on the LZW patent.
135 *
136 * With a small basic pixel width (low color count), Clear codes will be
137 * needed very frequently, causing the file to expand even more.  So this
138 * simplistic approach wouldn't work too well on bilevel images, for example.
139 * But for output of JPEG conversions the pixel width will usually be 8 bits
140 * (129 to 256 colors), so the overhead added by Clear symbols is only about
141 * one symbol in every 256.
142 */
143
144LOCAL(void)
145compress_init (gif_dest_ptr dinfo, int i_bits)
146/* Initialize pseudo-compressor */
147{
148  /* init all the state variables */
149  dinfo->n_bits = i_bits;
150  dinfo->maxcode = MAXCODE(dinfo->n_bits);
151  dinfo->ClearCode = (1 << (i_bits - 1));
152  dinfo->EOFCode = dinfo->ClearCode + 1;
153  dinfo->code_counter = dinfo->ClearCode + 2;
154  /* init output buffering vars */
155  dinfo->bytesinpkt = 0;
156  dinfo->cur_accum = 0;
157  dinfo->cur_bits = 0;
158  /* GIF specifies an initial Clear code */
159  output(dinfo, dinfo->ClearCode);
160}
161
162
163LOCAL(void)
164compress_pixel (gif_dest_ptr dinfo, int c)
165/* Accept and "compress" one pixel value.
166 * The given value must be less than n_bits wide.
167 */
168{
169  /* Output the given pixel value as a symbol. */
170  output(dinfo, c);
171  /* Issue Clear codes often enough to keep the reader from ratcheting up
172   * its symbol size.
173   */
174  if (dinfo->code_counter < dinfo->maxcode) {
175    dinfo->code_counter++;
176  } else {
177    output(dinfo, dinfo->ClearCode);
178    dinfo->code_counter = dinfo->ClearCode + 2; /* reset the counter */
179  }
180}
181
182
183LOCAL(void)
184compress_term (gif_dest_ptr dinfo)
185/* Clean up at end */
186{
187  /* Send an EOF code */
188  output(dinfo, dinfo->EOFCode);
189  /* Flush the bit-packing buffer */
190  if (dinfo->cur_bits > 0) {
191    CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
192  }
193  /* Flush the packet buffer */
194  flush_packet(dinfo);
195}
196
197
198/* GIF header construction */
199
200
201LOCAL(void)
202put_word (gif_dest_ptr dinfo, unsigned int w)
203/* Emit a 16-bit word, LSB first */
204{
205  putc(w & 0xFF, dinfo->pub.output_file);
206  putc((w >> 8) & 0xFF, dinfo->pub.output_file);
207}
208
209
210LOCAL(void)
211put_3bytes (gif_dest_ptr dinfo, int val)
212/* Emit 3 copies of same byte value --- handy subr for colormap construction */
213{
214  putc(val, dinfo->pub.output_file);
215  putc(val, dinfo->pub.output_file);
216  putc(val, dinfo->pub.output_file);
217}
218
219
220LOCAL(void)
221emit_header (gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
222/* Output the GIF file header, including color map */
223/* If colormap==NULL, synthesize a grayscale colormap */
224{
225  int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte;
226  int cshift = dinfo->cinfo->data_precision - 8;
227  int i;
228
229  if (num_colors > 256)
230    ERREXIT1(dinfo->cinfo, JERR_TOO_MANY_COLORS, num_colors);
231  /* Compute bits/pixel and related values */
232  BitsPerPixel = 1;
233  while (num_colors > (1 << BitsPerPixel))
234    BitsPerPixel++;
235  ColorMapSize = 1 << BitsPerPixel;
236  if (BitsPerPixel <= 1)
237    InitCodeSize = 2;
238  else
239    InitCodeSize = BitsPerPixel;
240  /*
241   * Write the GIF header.
242   * Note that we generate a plain GIF87 header for maximum compatibility.
243   */
244  putc('G', dinfo->pub.output_file);
245  putc('I', dinfo->pub.output_file);
246  putc('F', dinfo->pub.output_file);
247  putc('8', dinfo->pub.output_file);
248  putc('7', dinfo->pub.output_file);
249  putc('a', dinfo->pub.output_file);
250  /* Write the Logical Screen Descriptor */
251  put_word(dinfo, (unsigned int) dinfo->cinfo->output_width);
252  put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
253  FlagByte = 0x80;              /* Yes, there is a global color table */
254  FlagByte |= (BitsPerPixel-1) << 4; /* color resolution */
255  FlagByte |= (BitsPerPixel-1); /* size of global color table */
256  putc(FlagByte, dinfo->pub.output_file);
257  putc(0, dinfo->pub.output_file); /* Background color index */
258  putc(0, dinfo->pub.output_file); /* Reserved (aspect ratio in GIF89) */
259  /* Write the Global Color Map */
260  /* If the color map is more than 8 bits precision, */
261  /* we reduce it to 8 bits by shifting */
262  for (i=0; i < ColorMapSize; i++) {
263    if (i < num_colors) {
264      if (colormap != NULL) {
265        if (dinfo->cinfo->out_color_space == JCS_RGB) {
266          /* Normal case: RGB color map */
267          putc(GETJSAMPLE(colormap[0][i]) >> cshift, dinfo->pub.output_file);
268          putc(GETJSAMPLE(colormap[1][i]) >> cshift, dinfo->pub.output_file);
269          putc(GETJSAMPLE(colormap[2][i]) >> cshift, dinfo->pub.output_file);
270        } else {
271          /* Grayscale "color map": possible if quantizing grayscale image */
272          put_3bytes(dinfo, GETJSAMPLE(colormap[0][i]) >> cshift);
273        }
274      } else {
275        /* Create a grayscale map of num_colors values, range 0..255 */
276        put_3bytes(dinfo, (i * 255 + (num_colors-1)/2) / (num_colors-1));
277      }
278    } else {
279      /* fill out the map to a power of 2 */
280      put_3bytes(dinfo, 0);
281    }
282  }
283  /* Write image separator and Image Descriptor */
284  putc(',', dinfo->pub.output_file); /* separator */
285  put_word(dinfo, 0);           /* left/top offset */
286  put_word(dinfo, 0);
287  put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); /* image size */
288  put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
289  /* flag byte: not interlaced, no local color map */
290  putc(0x00, dinfo->pub.output_file);
291  /* Write Initial Code Size byte */
292  putc(InitCodeSize, dinfo->pub.output_file);
293
294  /* Initialize for "compression" of image data */
295  compress_init(dinfo, InitCodeSize+1);
296}
297
298
299/*
300 * Startup: write the file header.
301 */
302
303METHODDEF(void)
304start_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
305{
306  gif_dest_ptr dest = (gif_dest_ptr) dinfo;
307
308  if (cinfo->quantize_colors)
309    emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap);
310  else
311    emit_header(dest, 256, (JSAMPARRAY) NULL);
312}
313
314
315/*
316 * Write some pixel data.
317 * In this module rows_supplied will always be 1.
318 */
319
320METHODDEF(void)
321put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
322                JDIMENSION rows_supplied)
323{
324  gif_dest_ptr dest = (gif_dest_ptr) dinfo;
325  register JSAMPROW ptr;
326  register JDIMENSION col;
327
328  ptr = dest->pub.buffer[0];
329  for (col = cinfo->output_width; col > 0; col--) {
330    compress_pixel(dest, GETJSAMPLE(*ptr++));
331  }
332}
333
334
335/*
336 * Finish up at the end of the file.
337 */
338
339METHODDEF(void)
340finish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
341{
342  gif_dest_ptr dest = (gif_dest_ptr) dinfo;
343
344  /* Flush "compression" mechanism */
345  compress_term(dest);
346  /* Write a zero-length data block to end the series */
347  putc(0, dest->pub.output_file);
348  /* Write the GIF terminator mark */
349  putc(';', dest->pub.output_file);
350  /* Make sure we wrote the output file OK */
351  fflush(dest->pub.output_file);
352  if (ferror(dest->pub.output_file))
353    ERREXIT(cinfo, JERR_FILE_WRITE);
354}
355
356
357/*
358 * The module selection routine for GIF format output.
359 */
360
361GLOBAL(djpeg_dest_ptr)
362jinit_write_gif (j_decompress_ptr cinfo)
363{
364  gif_dest_ptr dest;
365
366  /* Create module interface object, fill in method pointers */
367  dest = (gif_dest_ptr)
368      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
369                                  sizeof(gif_dest_struct));
370  dest->cinfo = cinfo;          /* make back link for subroutines */
371  dest->pub.start_output = start_output_gif;
372  dest->pub.put_pixel_rows = put_pixel_rows;
373  dest->pub.finish_output = finish_output_gif;
374
375  if (cinfo->out_color_space != JCS_GRAYSCALE &&
376      cinfo->out_color_space != JCS_RGB)
377    ERREXIT(cinfo, JERR_GIF_COLORSPACE);
378
379  /* Force quantization if color or if > 8 bits input */
380  if (cinfo->out_color_space != JCS_GRAYSCALE || cinfo->data_precision > 8) {
381    /* Force quantization to at most 256 colors */
382    cinfo->quantize_colors = TRUE;
383    if (cinfo->desired_number_of_colors > 256)
384      cinfo->desired_number_of_colors = 256;
385  }
386
387  /* Calculate output image dimensions so we can allocate space */
388  jpeg_calc_output_dimensions(cinfo);
389
390  if (cinfo->output_components != 1) /* safety check: just one component? */
391    ERREXIT(cinfo, JERR_GIF_BUG);
392
393  /* Create decompressor output buffer. */
394  dest->pub.buffer = (*cinfo->mem->alloc_sarray)
395    ((j_common_ptr) cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) 1);
396  dest->pub.buffer_height = 1;
397
398  return (djpeg_dest_ptr) dest;
399}
400
401#endif /* GIF_SUPPORTED */
402