xref: /plan9/sys/src/cmd/gs/jpeg/wrgif.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * wrgif.c
37dd7cddfSDavid du Colombier  *
4*593dc095SDavid du Colombier  * Copyright (C) 1991-1997, Thomas G. Lane.
57dd7cddfSDavid du Colombier  * This file is part of the Independent JPEG Group's software.
67dd7cddfSDavid du Colombier  * For conditions of distribution and use, see the accompanying README file.
77dd7cddfSDavid du Colombier  *
87dd7cddfSDavid du Colombier  * This file contains routines to write output images in GIF format.
97dd7cddfSDavid du Colombier  *
10*593dc095SDavid du Colombier  **************************************************************************
11*593dc095SDavid du Colombier  * NOTE: to avoid entanglements with Unisys' patent on LZW compression,   *
12*593dc095SDavid du Colombier  * this code has been modified to output "uncompressed GIF" files.        *
13*593dc095SDavid du Colombier  * There is no trace of the LZW algorithm in this file.                   *
14*593dc095SDavid du Colombier  **************************************************************************
15*593dc095SDavid du Colombier  *
167dd7cddfSDavid du Colombier  * These routines may need modification for non-Unix environments or
177dd7cddfSDavid du Colombier  * specialized applications.  As they stand, they assume output to
187dd7cddfSDavid du Colombier  * an ordinary stdio stream.
197dd7cddfSDavid du Colombier  */
207dd7cddfSDavid du Colombier 
217dd7cddfSDavid du Colombier /*
227dd7cddfSDavid du Colombier  * This code is loosely based on ppmtogif from the PBMPLUS distribution
237dd7cddfSDavid du Colombier  * of Feb. 1991.  That file contains the following copyright notice:
247dd7cddfSDavid du Colombier  *    Based on GIFENCODE by David Rowley <mgardi@watdscu.waterloo.edu>.
257dd7cddfSDavid du Colombier  *    Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al.
267dd7cddfSDavid du Colombier  *    Copyright (C) 1989 by Jef Poskanzer.
277dd7cddfSDavid du Colombier  *    Permission to use, copy, modify, and distribute this software and its
287dd7cddfSDavid du Colombier  *    documentation for any purpose and without fee is hereby granted, provided
297dd7cddfSDavid du Colombier  *    that the above copyright notice appear in all copies and that both that
307dd7cddfSDavid du Colombier  *    copyright notice and this permission notice appear in supporting
317dd7cddfSDavid du Colombier  *    documentation.  This software is provided "as is" without express or
327dd7cddfSDavid du Colombier  *    implied warranty.
337dd7cddfSDavid du Colombier  *
347dd7cddfSDavid du Colombier  * We are also required to state that
357dd7cddfSDavid du Colombier  *    "The Graphics Interchange Format(c) is the Copyright property of
367dd7cddfSDavid du Colombier  *    CompuServe Incorporated. GIF(sm) is a Service Mark property of
377dd7cddfSDavid du Colombier  *    CompuServe Incorporated."
387dd7cddfSDavid du Colombier  */
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier #include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier #ifdef GIF_SUPPORTED
437dd7cddfSDavid du Colombier 
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier /* Private version of data destination object */
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier typedef struct {
487dd7cddfSDavid du Colombier   struct djpeg_dest_struct pub;	/* public fields */
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier   j_decompress_ptr cinfo;	/* back link saves passing separate parm */
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier   /* State for packing variable-width codes into a bitstream */
537dd7cddfSDavid du Colombier   int n_bits;			/* current number of bits/code */
54*593dc095SDavid du Colombier   int maxcode;			/* maximum code, given n_bits */
557dd7cddfSDavid du Colombier   INT32 cur_accum;		/* holds bits not yet output */
567dd7cddfSDavid du Colombier   int cur_bits;			/* # of bits in cur_accum */
577dd7cddfSDavid du Colombier 
58*593dc095SDavid du Colombier   /* State for GIF code assignment */
59*593dc095SDavid du Colombier   int ClearCode;		/* clear code (doesn't change) */
60*593dc095SDavid du Colombier   int EOFCode;			/* EOF code (ditto) */
61*593dc095SDavid du Colombier   int code_counter;		/* counts output symbols */
627dd7cddfSDavid du Colombier 
637dd7cddfSDavid du Colombier   /* GIF data packet construction buffer */
647dd7cddfSDavid du Colombier   int bytesinpkt;		/* # of bytes in current packet */
657dd7cddfSDavid du Colombier   char packetbuf[256];		/* workspace for accumulating packet */
667dd7cddfSDavid du Colombier 
677dd7cddfSDavid du Colombier } gif_dest_struct;
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier typedef gif_dest_struct * gif_dest_ptr;
707dd7cddfSDavid du Colombier 
71*593dc095SDavid du Colombier /* Largest value that will fit in N bits */
72*593dc095SDavid du Colombier #define MAXCODE(n_bits)	((1 << (n_bits)) - 1)
73*593dc095SDavid du Colombier 
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier /*
76*593dc095SDavid du Colombier  * Routines to package finished data bytes into GIF data blocks.
777dd7cddfSDavid du Colombier  * A data block consists of a count byte (1..255) and that many data bytes.
787dd7cddfSDavid du Colombier  */
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier LOCAL(void)
flush_packet(gif_dest_ptr dinfo)817dd7cddfSDavid du Colombier flush_packet (gif_dest_ptr dinfo)
827dd7cddfSDavid du Colombier /* flush any accumulated data */
837dd7cddfSDavid du Colombier {
847dd7cddfSDavid du Colombier   if (dinfo->bytesinpkt > 0) {	/* never write zero-length packet */
857dd7cddfSDavid du Colombier     dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++;
867dd7cddfSDavid du Colombier     if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt)
877dd7cddfSDavid du Colombier 	!= (size_t) dinfo->bytesinpkt)
887dd7cddfSDavid du Colombier       ERREXIT(dinfo->cinfo, JERR_FILE_WRITE);
897dd7cddfSDavid du Colombier     dinfo->bytesinpkt = 0;
907dd7cddfSDavid du Colombier   }
917dd7cddfSDavid du Colombier }
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier /* Add a character to current packet; flush to disk if necessary */
957dd7cddfSDavid du Colombier #define CHAR_OUT(dinfo,c)  \
967dd7cddfSDavid du Colombier 	{ (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (c);  \
977dd7cddfSDavid du Colombier 	    if ((dinfo)->bytesinpkt >= 255)  \
987dd7cddfSDavid du Colombier 	      flush_packet(dinfo);  \
997dd7cddfSDavid du Colombier 	}
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier 
1027dd7cddfSDavid du Colombier /* Routine to convert variable-width codes into a byte stream */
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier LOCAL(void)
output(gif_dest_ptr dinfo,int code)105*593dc095SDavid du Colombier output (gif_dest_ptr dinfo, int code)
1067dd7cddfSDavid du Colombier /* Emit a code of n_bits bits */
1077dd7cddfSDavid du Colombier /* Uses cur_accum and cur_bits to reblock into 8-bit bytes */
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier   dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits;
1107dd7cddfSDavid du Colombier   dinfo->cur_bits += dinfo->n_bits;
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier   while (dinfo->cur_bits >= 8) {
1137dd7cddfSDavid du Colombier     CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
1147dd7cddfSDavid du Colombier     dinfo->cur_accum >>= 8;
1157dd7cddfSDavid du Colombier     dinfo->cur_bits -= 8;
1167dd7cddfSDavid du Colombier   }
117*593dc095SDavid du Colombier }
1187dd7cddfSDavid du Colombier 
119*593dc095SDavid du Colombier 
120*593dc095SDavid du Colombier /* The pseudo-compression algorithm.
121*593dc095SDavid du Colombier  *
122*593dc095SDavid du Colombier  * In this module we simply output each pixel value as a separate symbol;
123*593dc095SDavid du Colombier  * thus, no compression occurs.  In fact, there is expansion of one bit per
124*593dc095SDavid du Colombier  * pixel, because we use a symbol width one bit wider than the pixel width.
125*593dc095SDavid du Colombier  *
126*593dc095SDavid du Colombier  * GIF ordinarily uses variable-width symbols, and the decoder will expect
127*593dc095SDavid du Colombier  * to ratchet up the symbol width after a fixed number of symbols.
128*593dc095SDavid du Colombier  * To simplify the logic and keep the expansion penalty down, we emit a
129*593dc095SDavid du Colombier  * GIF Clear code to reset the decoder just before the width would ratchet up.
130*593dc095SDavid du Colombier  * Thus, all the symbols in the output file will have the same bit width.
131*593dc095SDavid du Colombier  * Note that emitting the Clear codes at the right times is a mere matter of
132*593dc095SDavid du Colombier  * counting output symbols and is in no way dependent on the LZW patent.
133*593dc095SDavid du Colombier  *
134*593dc095SDavid du Colombier  * With a small basic pixel width (low color count), Clear codes will be
135*593dc095SDavid du Colombier  * needed very frequently, causing the file to expand even more.  So this
136*593dc095SDavid du Colombier  * simplistic approach wouldn't work too well on bilevel images, for example.
137*593dc095SDavid du Colombier  * But for output of JPEG conversions the pixel width will usually be 8 bits
138*593dc095SDavid du Colombier  * (129 to 256 colors), so the overhead added by Clear symbols is only about
139*593dc095SDavid du Colombier  * one symbol in every 256.
1407dd7cddfSDavid du Colombier  */
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier LOCAL(void)
compress_init(gif_dest_ptr dinfo,int i_bits)1437dd7cddfSDavid du Colombier compress_init (gif_dest_ptr dinfo, int i_bits)
144*593dc095SDavid du Colombier /* Initialize pseudo-compressor */
1457dd7cddfSDavid du Colombier {
1467dd7cddfSDavid du Colombier   /* init all the state variables */
147*593dc095SDavid du Colombier   dinfo->n_bits = i_bits;
1487dd7cddfSDavid du Colombier   dinfo->maxcode = MAXCODE(dinfo->n_bits);
149*593dc095SDavid du Colombier   dinfo->ClearCode = (1 << (i_bits - 1));
1507dd7cddfSDavid du Colombier   dinfo->EOFCode = dinfo->ClearCode + 1;
151*593dc095SDavid du Colombier   dinfo->code_counter = dinfo->ClearCode + 2;
1527dd7cddfSDavid du Colombier   /* init output buffering vars */
1537dd7cddfSDavid du Colombier   dinfo->bytesinpkt = 0;
1547dd7cddfSDavid du Colombier   dinfo->cur_accum = 0;
1557dd7cddfSDavid du Colombier   dinfo->cur_bits = 0;
1567dd7cddfSDavid du Colombier   /* GIF specifies an initial Clear code */
1577dd7cddfSDavid du Colombier   output(dinfo, dinfo->ClearCode);
1587dd7cddfSDavid du Colombier }
1597dd7cddfSDavid du Colombier 
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier LOCAL(void)
compress_pixel(gif_dest_ptr dinfo,int c)162*593dc095SDavid du Colombier compress_pixel (gif_dest_ptr dinfo, int c)
163*593dc095SDavid du Colombier /* Accept and "compress" one pixel value.
164*593dc095SDavid du Colombier  * The given value must be less than n_bits wide.
1657dd7cddfSDavid du Colombier  */
166*593dc095SDavid du Colombier {
167*593dc095SDavid du Colombier   /* Output the given pixel value as a symbol. */
168*593dc095SDavid du Colombier   output(dinfo, c);
169*593dc095SDavid du Colombier   /* Issue Clear codes often enough to keep the reader from ratcheting up
170*593dc095SDavid du Colombier    * its symbol size.
171*593dc095SDavid du Colombier    */
172*593dc095SDavid du Colombier   if (dinfo->code_counter < dinfo->maxcode) {
173*593dc095SDavid du Colombier     dinfo->code_counter++;
174*593dc095SDavid du Colombier   } else {
175*593dc095SDavid du Colombier     output(dinfo, dinfo->ClearCode);
176*593dc095SDavid du Colombier     dinfo->code_counter = dinfo->ClearCode + 2;	/* reset the counter */
1777dd7cddfSDavid du Colombier   }
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier LOCAL(void)
compress_term(gif_dest_ptr dinfo)1827dd7cddfSDavid du Colombier compress_term (gif_dest_ptr dinfo)
1837dd7cddfSDavid du Colombier /* Clean up at end */
1847dd7cddfSDavid du Colombier {
1857dd7cddfSDavid du Colombier   /* Send an EOF code */
1867dd7cddfSDavid du Colombier   output(dinfo, dinfo->EOFCode);
1877dd7cddfSDavid du Colombier   /* Flush the bit-packing buffer */
1887dd7cddfSDavid du Colombier   if (dinfo->cur_bits > 0) {
1897dd7cddfSDavid du Colombier     CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
1907dd7cddfSDavid du Colombier   }
1917dd7cddfSDavid du Colombier   /* Flush the packet buffer */
1927dd7cddfSDavid du Colombier   flush_packet(dinfo);
1937dd7cddfSDavid du Colombier }
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier /* GIF header construction */
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier 
1997dd7cddfSDavid du Colombier LOCAL(void)
put_word(gif_dest_ptr dinfo,unsigned int w)2007dd7cddfSDavid du Colombier put_word (gif_dest_ptr dinfo, unsigned int w)
2017dd7cddfSDavid du Colombier /* Emit a 16-bit word, LSB first */
2027dd7cddfSDavid du Colombier {
2037dd7cddfSDavid du Colombier   putc(w & 0xFF, dinfo->pub.output_file);
2047dd7cddfSDavid du Colombier   putc((w >> 8) & 0xFF, dinfo->pub.output_file);
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier LOCAL(void)
put_3bytes(gif_dest_ptr dinfo,int val)2097dd7cddfSDavid du Colombier put_3bytes (gif_dest_ptr dinfo, int val)
2107dd7cddfSDavid du Colombier /* Emit 3 copies of same byte value --- handy subr for colormap construction */
2117dd7cddfSDavid du Colombier {
2127dd7cddfSDavid du Colombier   putc(val, dinfo->pub.output_file);
2137dd7cddfSDavid du Colombier   putc(val, dinfo->pub.output_file);
2147dd7cddfSDavid du Colombier   putc(val, dinfo->pub.output_file);
2157dd7cddfSDavid du Colombier }
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier LOCAL(void)
emit_header(gif_dest_ptr dinfo,int num_colors,JSAMPARRAY colormap)2197dd7cddfSDavid du Colombier emit_header (gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
2207dd7cddfSDavid du Colombier /* Output the GIF file header, including color map */
2217dd7cddfSDavid du Colombier /* If colormap==NULL, synthesize a gray-scale colormap */
2227dd7cddfSDavid du Colombier {
2237dd7cddfSDavid du Colombier   int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte;
2247dd7cddfSDavid du Colombier   int cshift = dinfo->cinfo->data_precision - 8;
2257dd7cddfSDavid du Colombier   int i;
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier   if (num_colors > 256)
2287dd7cddfSDavid du Colombier     ERREXIT1(dinfo->cinfo, JERR_TOO_MANY_COLORS, num_colors);
2297dd7cddfSDavid du Colombier   /* Compute bits/pixel and related values */
2307dd7cddfSDavid du Colombier   BitsPerPixel = 1;
2317dd7cddfSDavid du Colombier   while (num_colors > (1 << BitsPerPixel))
2327dd7cddfSDavid du Colombier     BitsPerPixel++;
2337dd7cddfSDavid du Colombier   ColorMapSize = 1 << BitsPerPixel;
2347dd7cddfSDavid du Colombier   if (BitsPerPixel <= 1)
2357dd7cddfSDavid du Colombier     InitCodeSize = 2;
2367dd7cddfSDavid du Colombier   else
2377dd7cddfSDavid du Colombier     InitCodeSize = BitsPerPixel;
2387dd7cddfSDavid du Colombier   /*
2397dd7cddfSDavid du Colombier    * Write the GIF header.
2407dd7cddfSDavid du Colombier    * Note that we generate a plain GIF87 header for maximum compatibility.
2417dd7cddfSDavid du Colombier    */
2427dd7cddfSDavid du Colombier   putc('G', dinfo->pub.output_file);
2437dd7cddfSDavid du Colombier   putc('I', dinfo->pub.output_file);
2447dd7cddfSDavid du Colombier   putc('F', dinfo->pub.output_file);
2457dd7cddfSDavid du Colombier   putc('8', dinfo->pub.output_file);
2467dd7cddfSDavid du Colombier   putc('7', dinfo->pub.output_file);
2477dd7cddfSDavid du Colombier   putc('a', dinfo->pub.output_file);
2487dd7cddfSDavid du Colombier   /* Write the Logical Screen Descriptor */
2497dd7cddfSDavid du Colombier   put_word(dinfo, (unsigned int) dinfo->cinfo->output_width);
2507dd7cddfSDavid du Colombier   put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
2517dd7cddfSDavid du Colombier   FlagByte = 0x80;		/* Yes, there is a global color table */
2527dd7cddfSDavid du Colombier   FlagByte |= (BitsPerPixel-1) << 4; /* color resolution */
2537dd7cddfSDavid du Colombier   FlagByte |= (BitsPerPixel-1);	/* size of global color table */
2547dd7cddfSDavid du Colombier   putc(FlagByte, dinfo->pub.output_file);
2557dd7cddfSDavid du Colombier   putc(0, dinfo->pub.output_file); /* Background color index */
2567dd7cddfSDavid du Colombier   putc(0, dinfo->pub.output_file); /* Reserved (aspect ratio in GIF89) */
2577dd7cddfSDavid du Colombier   /* Write the Global Color Map */
2587dd7cddfSDavid du Colombier   /* If the color map is more than 8 bits precision, */
2597dd7cddfSDavid du Colombier   /* we reduce it to 8 bits by shifting */
2607dd7cddfSDavid du Colombier   for (i=0; i < ColorMapSize; i++) {
2617dd7cddfSDavid du Colombier     if (i < num_colors) {
2627dd7cddfSDavid du Colombier       if (colormap != NULL) {
2637dd7cddfSDavid du Colombier 	if (dinfo->cinfo->out_color_space == JCS_RGB) {
2647dd7cddfSDavid du Colombier 	  /* Normal case: RGB color map */
2657dd7cddfSDavid du Colombier 	  putc(GETJSAMPLE(colormap[0][i]) >> cshift, dinfo->pub.output_file);
2667dd7cddfSDavid du Colombier 	  putc(GETJSAMPLE(colormap[1][i]) >> cshift, dinfo->pub.output_file);
2677dd7cddfSDavid du Colombier 	  putc(GETJSAMPLE(colormap[2][i]) >> cshift, dinfo->pub.output_file);
2687dd7cddfSDavid du Colombier 	} else {
2697dd7cddfSDavid du Colombier 	  /* Grayscale "color map": possible if quantizing grayscale image */
2707dd7cddfSDavid du Colombier 	  put_3bytes(dinfo, GETJSAMPLE(colormap[0][i]) >> cshift);
2717dd7cddfSDavid du Colombier 	}
2727dd7cddfSDavid du Colombier       } else {
2737dd7cddfSDavid du Colombier 	/* Create a gray-scale map of num_colors values, range 0..255 */
2747dd7cddfSDavid du Colombier 	put_3bytes(dinfo, (i * 255 + (num_colors-1)/2) / (num_colors-1));
2757dd7cddfSDavid du Colombier       }
2767dd7cddfSDavid du Colombier     } else {
2777dd7cddfSDavid du Colombier       /* fill out the map to a power of 2 */
2787dd7cddfSDavid du Colombier       put_3bytes(dinfo, 0);
2797dd7cddfSDavid du Colombier     }
2807dd7cddfSDavid du Colombier   }
2817dd7cddfSDavid du Colombier   /* Write image separator and Image Descriptor */
2827dd7cddfSDavid du Colombier   putc(',', dinfo->pub.output_file); /* separator */
2837dd7cddfSDavid du Colombier   put_word(dinfo, 0);		/* left/top offset */
2847dd7cddfSDavid du Colombier   put_word(dinfo, 0);
2857dd7cddfSDavid du Colombier   put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); /* image size */
2867dd7cddfSDavid du Colombier   put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
2877dd7cddfSDavid du Colombier   /* flag byte: not interlaced, no local color map */
2887dd7cddfSDavid du Colombier   putc(0x00, dinfo->pub.output_file);
2897dd7cddfSDavid du Colombier   /* Write Initial Code Size byte */
2907dd7cddfSDavid du Colombier   putc(InitCodeSize, dinfo->pub.output_file);
2917dd7cddfSDavid du Colombier 
292*593dc095SDavid du Colombier   /* Initialize for "compression" of image data */
2937dd7cddfSDavid du Colombier   compress_init(dinfo, InitCodeSize+1);
2947dd7cddfSDavid du Colombier }
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier /*
2987dd7cddfSDavid du Colombier  * Startup: write the file header.
2997dd7cddfSDavid du Colombier  */
3007dd7cddfSDavid du Colombier 
3017dd7cddfSDavid du Colombier METHODDEF(void)
start_output_gif(j_decompress_ptr cinfo,djpeg_dest_ptr dinfo)3027dd7cddfSDavid du Colombier start_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
3037dd7cddfSDavid du Colombier {
3047dd7cddfSDavid du Colombier   gif_dest_ptr dest = (gif_dest_ptr) dinfo;
3057dd7cddfSDavid du Colombier 
3067dd7cddfSDavid du Colombier   if (cinfo->quantize_colors)
3077dd7cddfSDavid du Colombier     emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap);
3087dd7cddfSDavid du Colombier   else
3097dd7cddfSDavid du Colombier     emit_header(dest, 256, (JSAMPARRAY) NULL);
3107dd7cddfSDavid du Colombier }
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier 
3137dd7cddfSDavid du Colombier /*
3147dd7cddfSDavid du Colombier  * Write some pixel data.
3157dd7cddfSDavid du Colombier  * In this module rows_supplied will always be 1.
3167dd7cddfSDavid du Colombier  */
3177dd7cddfSDavid du Colombier 
3187dd7cddfSDavid du Colombier METHODDEF(void)
put_pixel_rows(j_decompress_ptr cinfo,djpeg_dest_ptr dinfo,JDIMENSION rows_supplied)3197dd7cddfSDavid du Colombier put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
3207dd7cddfSDavid du Colombier 		JDIMENSION rows_supplied)
3217dd7cddfSDavid du Colombier {
3227dd7cddfSDavid du Colombier   gif_dest_ptr dest = (gif_dest_ptr) dinfo;
3237dd7cddfSDavid du Colombier   register JSAMPROW ptr;
3247dd7cddfSDavid du Colombier   register JDIMENSION col;
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier   ptr = dest->pub.buffer[0];
3277dd7cddfSDavid du Colombier   for (col = cinfo->output_width; col > 0; col--) {
328*593dc095SDavid du Colombier     compress_pixel(dest, GETJSAMPLE(*ptr++));
3297dd7cddfSDavid du Colombier   }
3307dd7cddfSDavid du Colombier }
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier 
3337dd7cddfSDavid du Colombier /*
3347dd7cddfSDavid du Colombier  * Finish up at the end of the file.
3357dd7cddfSDavid du Colombier  */
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier METHODDEF(void)
finish_output_gif(j_decompress_ptr cinfo,djpeg_dest_ptr dinfo)3387dd7cddfSDavid du Colombier finish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
3397dd7cddfSDavid du Colombier {
3407dd7cddfSDavid du Colombier   gif_dest_ptr dest = (gif_dest_ptr) dinfo;
3417dd7cddfSDavid du Colombier 
342*593dc095SDavid du Colombier   /* Flush "compression" mechanism */
3437dd7cddfSDavid du Colombier   compress_term(dest);
3447dd7cddfSDavid du Colombier   /* Write a zero-length data block to end the series */
3457dd7cddfSDavid du Colombier   putc(0, dest->pub.output_file);
3467dd7cddfSDavid du Colombier   /* Write the GIF terminator mark */
3477dd7cddfSDavid du Colombier   putc(';', dest->pub.output_file);
3487dd7cddfSDavid du Colombier   /* Make sure we wrote the output file OK */
3497dd7cddfSDavid du Colombier   fflush(dest->pub.output_file);
3507dd7cddfSDavid du Colombier   if (ferror(dest->pub.output_file))
3517dd7cddfSDavid du Colombier     ERREXIT(cinfo, JERR_FILE_WRITE);
3527dd7cddfSDavid du Colombier }
3537dd7cddfSDavid du Colombier 
3547dd7cddfSDavid du Colombier 
3557dd7cddfSDavid du Colombier /*
3567dd7cddfSDavid du Colombier  * The module selection routine for GIF format output.
3577dd7cddfSDavid du Colombier  */
3587dd7cddfSDavid du Colombier 
3597dd7cddfSDavid du Colombier GLOBAL(djpeg_dest_ptr)
jinit_write_gif(j_decompress_ptr cinfo)3607dd7cddfSDavid du Colombier jinit_write_gif (j_decompress_ptr cinfo)
3617dd7cddfSDavid du Colombier {
3627dd7cddfSDavid du Colombier   gif_dest_ptr dest;
3637dd7cddfSDavid du Colombier 
3647dd7cddfSDavid du Colombier   /* Create module interface object, fill in method pointers */
3657dd7cddfSDavid du Colombier   dest = (gif_dest_ptr)
3667dd7cddfSDavid du Colombier       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
3677dd7cddfSDavid du Colombier 				  SIZEOF(gif_dest_struct));
3687dd7cddfSDavid du Colombier   dest->cinfo = cinfo;		/* make back link for subroutines */
3697dd7cddfSDavid du Colombier   dest->pub.start_output = start_output_gif;
3707dd7cddfSDavid du Colombier   dest->pub.put_pixel_rows = put_pixel_rows;
3717dd7cddfSDavid du Colombier   dest->pub.finish_output = finish_output_gif;
3727dd7cddfSDavid du Colombier 
3737dd7cddfSDavid du Colombier   if (cinfo->out_color_space != JCS_GRAYSCALE &&
3747dd7cddfSDavid du Colombier       cinfo->out_color_space != JCS_RGB)
3757dd7cddfSDavid du Colombier     ERREXIT(cinfo, JERR_GIF_COLORSPACE);
3767dd7cddfSDavid du Colombier 
3777dd7cddfSDavid du Colombier   /* Force quantization if color or if > 8 bits input */
3787dd7cddfSDavid du Colombier   if (cinfo->out_color_space != JCS_GRAYSCALE || cinfo->data_precision > 8) {
3797dd7cddfSDavid du Colombier     /* Force quantization to at most 256 colors */
3807dd7cddfSDavid du Colombier     cinfo->quantize_colors = TRUE;
3817dd7cddfSDavid du Colombier     if (cinfo->desired_number_of_colors > 256)
3827dd7cddfSDavid du Colombier       cinfo->desired_number_of_colors = 256;
3837dd7cddfSDavid du Colombier   }
3847dd7cddfSDavid du Colombier 
3857dd7cddfSDavid du Colombier   /* Calculate output image dimensions so we can allocate space */
3867dd7cddfSDavid du Colombier   jpeg_calc_output_dimensions(cinfo);
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier   if (cinfo->output_components != 1) /* safety check: just one component? */
3897dd7cddfSDavid du Colombier     ERREXIT(cinfo, JERR_GIF_BUG);
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier   /* Create decompressor output buffer. */
3927dd7cddfSDavid du Colombier   dest->pub.buffer = (*cinfo->mem->alloc_sarray)
3937dd7cddfSDavid du Colombier     ((j_common_ptr) cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) 1);
3947dd7cddfSDavid du Colombier   dest->pub.buffer_height = 1;
3957dd7cddfSDavid du Colombier 
3967dd7cddfSDavid du Colombier   return (djpeg_dest_ptr) dest;
3977dd7cddfSDavid du Colombier }
3987dd7cddfSDavid du Colombier 
3997dd7cddfSDavid du Colombier #endif /* GIF_SUPPORTED */
400