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