ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

wrgif.c
Go to the documentation of this file.
00001 /*
00002  * wrgif.c
00003  *
00004  * Copyright (C) 1991-1997, Thomas G. Lane.
00005  * This file is part of the Independent JPEG Group's software.
00006  * For conditions of distribution and use, see the accompanying README file.
00007  *
00008  * This file contains routines to write output images in GIF format.
00009  *
00010  **************************************************************************
00011  * NOTE: to avoid entanglements with Unisys' patent on LZW compression,   *
00012  * this code has been modified to output "uncompressed GIF" files.        *
00013  * There is no trace of the LZW algorithm in this file.                   *
00014  **************************************************************************
00015  *
00016  * These routines may need modification for non-Unix environments or
00017  * specialized applications.  As they stand, they assume output to
00018  * an ordinary stdio stream.
00019  */
00020 
00021 /*
00022  * This code is loosely based on ppmtogif from the PBMPLUS distribution
00023  * of Feb. 1991.  That file contains the following copyright notice:
00024  *    Based on GIFENCODE by David Rowley <mgardi@watdscu.waterloo.edu>.
00025  *    Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al.
00026  *    Copyright (C) 1989 by Jef Poskanzer.
00027  *    Permission to use, copy, modify, and distribute this software and its
00028  *    documentation for any purpose and without fee is hereby granted, provided
00029  *    that the above copyright notice appear in all copies and that both that
00030  *    copyright notice and this permission notice appear in supporting
00031  *    documentation.  This software is provided "as is" without express or
00032  *    implied warranty.
00033  *
00034  * We are also required to state that
00035  *    "The Graphics Interchange Format(c) is the Copyright property of
00036  *    CompuServe Incorporated. GIF(sm) is a Service Mark property of
00037  *    CompuServe Incorporated."
00038  */
00039 
00040 #include "cdjpeg.h"     /* Common decls for cjpeg/djpeg applications */
00041 
00042 #ifdef GIF_SUPPORTED
00043 
00044 
00045 /* Private version of data destination object */
00046 
00047 typedef struct {
00048   struct djpeg_dest_struct pub; /* public fields */
00049 
00050   j_decompress_ptr cinfo;   /* back link saves passing separate parm */
00051 
00052   /* State for packing variable-width codes into a bitstream */
00053   int n_bits;           /* current number of bits/code */
00054   int maxcode;          /* maximum code, given n_bits */
00055   INT32 cur_accum;      /* holds bits not yet output */
00056   int cur_bits;         /* # of bits in cur_accum */
00057 
00058   /* State for GIF code assignment */
00059   int ClearCode;        /* clear code (doesn't change) */
00060   int EOFCode;          /* EOF code (ditto) */
00061   int code_counter;     /* counts output symbols */
00062 
00063   /* GIF data packet construction buffer */
00064   int bytesinpkt;       /* # of bytes in current packet */
00065   char packetbuf[256];      /* workspace for accumulating packet */
00066 
00067 } gif_dest_struct;
00068 
00069 typedef gif_dest_struct * gif_dest_ptr;
00070 
00071 /* Largest value that will fit in N bits */
00072 #define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
00073 
00074 
00075 /*
00076  * Routines to package finished data bytes into GIF data blocks.
00077  * A data block consists of a count byte (1..255) and that many data bytes.
00078  */
00079 
00080 LOCAL(void)
00081 flush_packet (gif_dest_ptr dinfo)
00082 /* flush any accumulated data */
00083 {
00084   if (dinfo->bytesinpkt > 0) {  /* never write zero-length packet */
00085     dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++;
00086     if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt)
00087     != (size_t) dinfo->bytesinpkt)
00088       ERREXIT(dinfo->cinfo, JERR_FILE_WRITE);
00089     dinfo->bytesinpkt = 0;
00090   }
00091 }
00092 
00093 
00094 /* Add a character to current packet; flush to disk if necessary */
00095 #define CHAR_OUT(dinfo,c)  \
00096     { (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (c);  \
00097         if ((dinfo)->bytesinpkt >= 255)  \
00098           flush_packet(dinfo);  \
00099     }
00100 
00101 
00102 /* Routine to convert variable-width codes into a byte stream */
00103 
00104 LOCAL(void)
00105 output (gif_dest_ptr dinfo, int code)
00106 /* Emit a code of n_bits bits */
00107 /* Uses cur_accum and cur_bits to reblock into 8-bit bytes */
00108 {
00109   dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits;
00110   dinfo->cur_bits += dinfo->n_bits;
00111 
00112   while (dinfo->cur_bits >= 8) {
00113     CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
00114     dinfo->cur_accum >>= 8;
00115     dinfo->cur_bits -= 8;
00116   }
00117 }
00118 
00119 
00120 /* The pseudo-compression algorithm.
00121  *
00122  * In this module we simply output each pixel value as a separate symbol;
00123  * thus, no compression occurs.  In fact, there is expansion of one bit per
00124  * pixel, because we use a symbol width one bit wider than the pixel width.
00125  *
00126  * GIF ordinarily uses variable-width symbols, and the decoder will expect
00127  * to ratchet up the symbol width after a fixed number of symbols.
00128  * To simplify the logic and keep the expansion penalty down, we emit a
00129  * GIF Clear code to reset the decoder just before the width would ratchet up.
00130  * Thus, all the symbols in the output file will have the same bit width.
00131  * Note that emitting the Clear codes at the right times is a mere matter of
00132  * counting output symbols and is in no way dependent on the LZW patent.
00133  *
00134  * With a small basic pixel width (low color count), Clear codes will be
00135  * needed very frequently, causing the file to expand even more.  So this
00136  * simplistic approach wouldn't work too well on bilevel images, for example.
00137  * But for output of JPEG conversions the pixel width will usually be 8 bits
00138  * (129 to 256 colors), so the overhead added by Clear symbols is only about
00139  * one symbol in every 256.
00140  */
00141 
00142 LOCAL(void)
00143 compress_init (gif_dest_ptr dinfo, int i_bits)
00144 /* Initialize pseudo-compressor */
00145 {
00146   /* init all the state variables */
00147   dinfo->n_bits = i_bits;
00148   dinfo->maxcode = MAXCODE(dinfo->n_bits);
00149   dinfo->ClearCode = (1 << (i_bits - 1));
00150   dinfo->EOFCode = dinfo->ClearCode + 1;
00151   dinfo->code_counter = dinfo->ClearCode + 2;
00152   /* init output buffering vars */
00153   dinfo->bytesinpkt = 0;
00154   dinfo->cur_accum = 0;
00155   dinfo->cur_bits = 0;
00156   /* GIF specifies an initial Clear code */
00157   output(dinfo, dinfo->ClearCode);
00158 }
00159 
00160 
00161 LOCAL(void)
00162 compress_pixel (gif_dest_ptr dinfo, int c)
00163 /* Accept and "compress" one pixel value.
00164  * The given value must be less than n_bits wide.
00165  */
00166 {
00167   /* Output the given pixel value as a symbol. */
00168   output(dinfo, c);
00169   /* Issue Clear codes often enough to keep the reader from ratcheting up
00170    * its symbol size.
00171    */
00172   if (dinfo->code_counter < dinfo->maxcode) {
00173     dinfo->code_counter++;
00174   } else {
00175     output(dinfo, dinfo->ClearCode);
00176     dinfo->code_counter = dinfo->ClearCode + 2; /* reset the counter */
00177   }
00178 }
00179 
00180 
00181 LOCAL(void)
00182 compress_term (gif_dest_ptr dinfo)
00183 /* Clean up at end */
00184 {
00185   /* Send an EOF code */
00186   output(dinfo, dinfo->EOFCode);
00187   /* Flush the bit-packing buffer */
00188   if (dinfo->cur_bits > 0) {
00189     CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
00190   }
00191   /* Flush the packet buffer */
00192   flush_packet(dinfo);
00193 }
00194 
00195 
00196 /* GIF header construction */
00197 
00198 
00199 LOCAL(void)
00200 put_word (gif_dest_ptr dinfo, unsigned int w)
00201 /* Emit a 16-bit word, LSB first */
00202 {
00203   putc(w & 0xFF, dinfo->pub.output_file);
00204   putc((w >> 8) & 0xFF, dinfo->pub.output_file);
00205 }
00206 
00207 
00208 LOCAL(void)
00209 put_3bytes (gif_dest_ptr dinfo, int val)
00210 /* Emit 3 copies of same byte value --- handy subr for colormap construction */
00211 {
00212   putc(val, dinfo->pub.output_file);
00213   putc(val, dinfo->pub.output_file);
00214   putc(val, dinfo->pub.output_file);
00215 }
00216 
00217 
00218 LOCAL(void)
00219 emit_header (gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
00220 /* Output the GIF file header, including color map */
00221 /* If colormap==NULL, synthesize a gray-scale colormap */
00222 {
00223   int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte;
00224   int cshift = dinfo->cinfo->data_precision - 8;
00225   int i;
00226 
00227   if (num_colors > 256)
00228     ERREXIT1(dinfo->cinfo, JERR_TOO_MANY_COLORS, num_colors);
00229   /* Compute bits/pixel and related values */
00230   BitsPerPixel = 1;
00231   while (num_colors > (1 << BitsPerPixel))
00232     BitsPerPixel++;
00233   ColorMapSize = 1 << BitsPerPixel;
00234   if (BitsPerPixel <= 1)
00235     InitCodeSize = 2;
00236   else
00237     InitCodeSize = BitsPerPixel;
00238   /*
00239    * Write the GIF header.
00240    * Note that we generate a plain GIF87 header for maximum compatibility.
00241    */
00242   putc('G', dinfo->pub.output_file);
00243   putc('I', dinfo->pub.output_file);
00244   putc('F', dinfo->pub.output_file);
00245   putc('8', dinfo->pub.output_file);
00246   putc('7', dinfo->pub.output_file);
00247   putc('a', dinfo->pub.output_file);
00248   /* Write the Logical Screen Descriptor */
00249   put_word(dinfo, (unsigned int) dinfo->cinfo->output_width);
00250   put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
00251   FlagByte = 0x80;      /* Yes, there is a global color table */
00252   FlagByte |= (BitsPerPixel-1) << 4; /* color resolution */
00253   FlagByte |= (BitsPerPixel-1); /* size of global color table */
00254   putc(FlagByte, dinfo->pub.output_file);
00255   putc(0, dinfo->pub.output_file); /* Background color index */
00256   putc(0, dinfo->pub.output_file); /* Reserved (aspect ratio in GIF89) */
00257   /* Write the Global Color Map */
00258   /* If the color map is more than 8 bits precision, */
00259   /* we reduce it to 8 bits by shifting */
00260   for (i=0; i < ColorMapSize; i++) {
00261     if (i < num_colors) {
00262       if (colormap != NULL) {
00263     if (dinfo->cinfo->out_color_space == JCS_RGB) {
00264       /* Normal case: RGB color map */
00265       putc(GETJSAMPLE(colormap[0][i]) >> cshift, dinfo->pub.output_file);
00266       putc(GETJSAMPLE(colormap[1][i]) >> cshift, dinfo->pub.output_file);
00267       putc(GETJSAMPLE(colormap[2][i]) >> cshift, dinfo->pub.output_file);
00268     } else {
00269       /* Grayscale "color map": possible if quantizing grayscale image */
00270       put_3bytes(dinfo, GETJSAMPLE(colormap[0][i]) >> cshift);
00271     }
00272       } else {
00273     /* Create a gray-scale map of num_colors values, range 0..255 */
00274     put_3bytes(dinfo, (i * 255 + (num_colors-1)/2) / (num_colors-1));
00275       }
00276     } else {
00277       /* fill out the map to a power of 2 */
00278       put_3bytes(dinfo, 0);
00279     }
00280   }
00281   /* Write image separator and Image Descriptor */
00282   putc(',', dinfo->pub.output_file); /* separator */
00283   put_word(dinfo, 0);       /* left/top offset */
00284   put_word(dinfo, 0);
00285   put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); /* image size */
00286   put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
00287   /* flag byte: not interlaced, no local color map */
00288   putc(0x00, dinfo->pub.output_file);
00289   /* Write Initial Code Size byte */
00290   putc(InitCodeSize, dinfo->pub.output_file);
00291 
00292   /* Initialize for "compression" of image data */
00293   compress_init(dinfo, InitCodeSize+1);
00294 }
00295 
00296 
00297 /*
00298  * Startup: write the file header.
00299  */
00300 
00301 METHODDEF(void)
00302 start_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
00303 {
00304   gif_dest_ptr dest = (gif_dest_ptr) dinfo;
00305 
00306   if (cinfo->quantize_colors)
00307     emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap);
00308   else
00309     emit_header(dest, 256, (JSAMPARRAY) NULL);
00310 }
00311 
00312 
00313 /*
00314  * Write some pixel data.
00315  * In this module rows_supplied will always be 1.
00316  */
00317 
00318 METHODDEF(void)
00319 put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
00320         JDIMENSION rows_supplied)
00321 {
00322   gif_dest_ptr dest = (gif_dest_ptr) dinfo;
00323   register JSAMPROW ptr;
00324   register JDIMENSION col;
00325 
00326   ptr = dest->pub.buffer[0];
00327   for (col = cinfo->output_width; col > 0; col--) {
00328     compress_pixel(dest, GETJSAMPLE(*ptr++));
00329   }
00330 }
00331 
00332 
00333 /*
00334  * Finish up at the end of the file.
00335  */
00336 
00337 METHODDEF(void)
00338 finish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
00339 {
00340   gif_dest_ptr dest = (gif_dest_ptr) dinfo;
00341 
00342   /* Flush "compression" mechanism */
00343   compress_term(dest);
00344   /* Write a zero-length data block to end the series */
00345   putc(0, dest->pub.output_file);
00346   /* Write the GIF terminator mark */
00347   putc(';', dest->pub.output_file);
00348   /* Make sure we wrote the output file OK */
00349   fflush(dest->pub.output_file);
00350   if (ferror(dest->pub.output_file))
00351     ERREXIT(cinfo, JERR_FILE_WRITE);
00352 }
00353 
00354 
00355 /*
00356  * The module selection routine for GIF format output.
00357  */
00358 
00359 GLOBAL(djpeg_dest_ptr)
00360 jinit_write_gif (j_decompress_ptr cinfo)
00361 {
00362   gif_dest_ptr dest;
00363 
00364   /* Create module interface object, fill in method pointers */
00365   dest = (gif_dest_ptr)
00366       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
00367                   SIZEOF(gif_dest_struct));
00368   dest->cinfo = cinfo;      /* make back link for subroutines */
00369   dest->pub.start_output = start_output_gif;
00370   dest->pub.put_pixel_rows = put_pixel_rows;
00371   dest->pub.finish_output = finish_output_gif;
00372 
00373   if (cinfo->out_color_space != JCS_GRAYSCALE &&
00374       cinfo->out_color_space != JCS_RGB)
00375     ERREXIT(cinfo, JERR_GIF_COLORSPACE);
00376 
00377   /* Force quantization if color or if > 8 bits input */
00378   if (cinfo->out_color_space != JCS_GRAYSCALE || cinfo->data_precision > 8) {
00379     /* Force quantization to at most 256 colors */
00380     cinfo->quantize_colors = TRUE;
00381     if (cinfo->desired_number_of_colors > 256)
00382       cinfo->desired_number_of_colors = 256;
00383   }
00384 
00385   /* Calculate output image dimensions so we can allocate space */
00386   jpeg_calc_output_dimensions(cinfo);
00387 
00388   if (cinfo->output_components != 1) /* safety check: just one component? */
00389     ERREXIT(cinfo, JERR_GIF_BUG);
00390 
00391   /* Create decompressor output buffer. */
00392   dest->pub.buffer = (*cinfo->mem->alloc_sarray)
00393     ((j_common_ptr) cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) 1);
00394   dest->pub.buffer_height = 1;
00395 
00396   return (djpeg_dest_ptr) dest;
00397 }
00398 
00399 #endif /* GIF_SUPPORTED */

Generated on Sun May 27 2012 04:19:28 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.