386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Sat, 18 Apr 1992 19:17:40 +0000 (11:17 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Sat, 18 Apr 1992 19:17:40 +0000 (11:17 -0800)
Work on file usr/othersrc/public/ghostscript-2.4.1/gdevgif.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/othersrc/public/ghostscript-2.4.1/gdevgif.c [new file with mode: 0644]

diff --git a/usr/othersrc/public/ghostscript-2.4.1/gdevgif.c b/usr/othersrc/public/ghostscript-2.4.1/gdevgif.c
new file mode 100644 (file)
index 0000000..75489ea
--- /dev/null
@@ -0,0 +1,402 @@
+/* Copyright (C) 1992 Aladdin Enterprises.  All rights reserved.
+   Distributed by Free Software Foundation, Inc.
+
+This file is part of Ghostscript.
+
+Ghostscript is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
+to anyone for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.  Refer
+to the Ghostscript General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+Ghostscript, but only under the conditions described in the Ghostscript
+General Public License.  A copy of this license is supposed to have been
+given to you along with Ghostscript so you can know your rights and
+responsibilities.  It should be in a file named COPYING.  Among other
+things, the copyright notice and this notice must be preserved on all
+copies.  */
+
+/* gdevgif.c */
+/* GIF output device for Ghostscript. */
+#include "gdevprn.h"
+#include "gserrors.h"                  /* REALLY? */
+#include "gdevpccm.h"
+
+/* Thanks to Phil Conrad for donating the original version */
+/* of these drivers to Aladdin Enterprises. */
+
+/* ------ The device descriptors ------ */
+
+/*
+ * Standard U.S. page width and height.  A4 paper is 8.4" x 11.7".
+ */
+#define WIDTH_10THS 85
+#define HEIGHT_10THS 110
+
+/*
+ * Default X and Y resolution.
+ */
+#define X_DPI 72
+#define Y_DPI 72
+
+/* The same print_page routine currently serves for */
+/* both monochrome and color. */
+private dev_proc_print_page(gif_print_page);
+
+/* Monochrome. */
+
+gx_device_printer gs_gifmono_device =
+  prn_device(prn_std_procs, "gifmono",
+       WIDTH_10THS, HEIGHT_10THS,
+       X_DPI, Y_DPI,
+       0,0,0,0,                        /* margins */
+       1, gif_print_page);
+
+/* Chunky 8-bit (SuperVGA-style) color. */
+/* (Uses a fixed palette of 3,3,2 bits.) */
+
+private gx_device_procs gif8_procs =
+  prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+    pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
+gx_device_printer gs_gif8_device =
+  prn_device(gif8_procs, "gif8",
+       WIDTH_10THS, HEIGHT_10THS,
+       X_DPI, Y_DPI,
+       0,0,0,0,                        /* margins */
+       8, gif_print_page);
+
+/* ------ Private definitions ------ */
+
+typedef struct gif_header_s {
+       byte    signature[3];   /* magic number == 'GIF' */
+       byte    version[3];     /* version # '87a' or '89a' */
+       ushort  width;          /* screen width */
+       ushort  height;         /* screen height */
+
+/*     struct  {               /* bit structure of flags */
+/*     unsigned globalcolor:1; /* global color table flag - MSB*/
+#define globalcolor_shift 7
+/*     unsigned colorres:3;    /* bits/color */
+#define colorres_shift 4
+/*     unsigned sort:1;                /* color table sorted */
+#define sort_shift 3
+/*     unsigned colorsize:3;   /* 2^colorsize bytes in color table -LSB */
+#define colorsize_shift 0
+/*     } flags;                */
+
+       byte    flags;
+       byte    background;     /* background color index */
+       byte    aspect;         /* pixel aspect ratio */
+                               /* ratio = (aspect + 15) / 64 */
+} gif_header;
+
+typedef struct image_descriptor_s {
+/*     byte    separator;      /* image separator == 0x2c */
+       ushort  left_pos;       /* image left pos (pixels) */
+       ushort  top_pos;        /* image top  pos (pixels) */
+       ushort  width;          /* image width    (pixels) */
+       ushort  height;         /* image height   (pixels) */
+
+/*     struct  {               */
+/*     unsigned localcolor:1;  /* local color table flag */
+/*     unsigned interlace:1;   /* image interlaced  0=no */
+/*     unsigned sort:1;        /* color table sorted 0=no*/
+/*     unsigned resv:2;        */
+/*     unsigned localsize:3;   /* 2^localsize+1 = color table size */
+/*     } flags;                */
+
+       byte    flags;
+} image_descriptor;
+
+/* State for reading bits from image. */
+typedef struct pixel_reader_s {
+       byte *next;
+       int bits_left;
+       uint bit_buffer;        /* low-order bits_left bits are valid */
+} pixel_reader;
+
+/********************************************************/
+/* LZW routines are based on:                          */
+/* Dr. Dobbs Journal --- Oct. 1989.                    */
+/* Article on LZW Data Compression by Mark R. Nelson   */
+/********************************************************/
+
+#define MAX_BITS 12            /* this is max for GIF. */
+
+#define TABLE_SIZE 5021                /* this is max for 12-bit codes */
+
+/* State of LZW encoder */
+typedef struct code_entry_s {
+       int     code_value;
+       ushort  prefix_code;
+       byte    append_character;
+} code_entry;
+typedef struct lzw_encoder_s {
+       int     bits;
+       ushort  Max_Code;
+       ushort  Clear_code;
+       ushort  next_code;
+       FILE    *file;
+       code_entry      *table;
+       ushort  string_code;
+       /* State of output buffer */
+       byte    output_bit_buffer;
+       int     output_bit_count;       /* # of valid low-order bits */
+                                       /* (between 0 and 7) in buffer */
+       uint    byte_count;
+       byte    gif_buffer[260];
+} lzw_encoder;
+
+/* Initialize LZW encoder */
+private void lzw_set_bits(P2(register lzw_encoder _ss *, int));
+private void lzw_reset(P1(register lzw_encoder _ss *));
+private int
+lzw_init(register lzw_encoder _ss *pe, int bits, FILE *file)
+{      lzw_set_bits(pe, bits);
+       pe->Clear_code = (1 << bits);
+       pe->file = file;
+       pe->byte_count = 1;
+       pe->output_bit_count = 0;
+       pe->output_bit_buffer = 0;
+       pe->table = (code_entry *)gs_malloc(TABLE_SIZE, sizeof(code_entry), "GIF code table");
+
+       if ( pe->table == 0 )
+               return gs_error_VMerror;        /* can't allocate buffers */
+
+       lzw_reset(pe);
+       pe->string_code = 0;
+       return 0;
+}
+/* Establish the width of the code in bits */
+private void
+lzw_set_bits(register lzw_encoder _ss *pe, int bits)
+{      pe->bits = bits;
+       pe->Max_Code = (1 << (bits+1)) - 1;
+}
+/* Reset the encoding table */
+private void
+lzw_reset(register lzw_encoder _ss *pe)
+{      int index;
+       for ( index = 0; index < TABLE_SIZE; index++ )
+               pe->table[index].code_value = -1;
+       pe->next_code = pe->Clear_code + 2;
+}
+
+/* Put out (data) of length (bits) to GIF buffer */
+private void
+lzw_putc(register lzw_encoder _ss *pe, uint data)
+{      int bits = pe->bits + 1;        /* output width */
+       ulong buffer = pe->output_bit_buffer | ((ulong)data << pe->output_bit_count);
+       pe->output_bit_count += bits;
+       while ( pe->output_bit_count >= 8 )
+       {       /* putc(output_bit_buffer >> 24, file); */
+               pe->gif_buffer[pe->byte_count] = (byte)buffer;  /* low byte */
+               buffer >>= 8;
+               pe->output_bit_count -= 8;
+               pe->byte_count++;
+               if ( pe->byte_count == 256 )
+               {       pe->byte_count = 1;
+                       pe->gif_buffer[0] = 255;  /* byte count for block */
+                       fwrite(pe->gif_buffer, 1, 256, pe->file);
+               }
+       }
+       pe->output_bit_buffer = (byte)buffer;
+}
+
+/* Finish encoding, and flush the buffers. */
+private void
+lzw_finish(register lzw_encoder _ss *pe)
+{      lzw_putc(pe, pe->string_code);  /* output last code */
+       lzw_putc(pe, pe->Clear_code+1); /* output eof code */
+       lzw_putc(pe, 0);        /* force out last code */
+       if ( pe->byte_count != 1 )
+       {       pe->gif_buffer[0] = pe->byte_count;
+               fwrite(pe->gif_buffer, 1, pe->byte_count+1, pe->file);
+       }
+}
+
+/* Terminate LZW encoder. */
+private void
+lzw_exit(register lzw_encoder _ss *pe)
+{      gs_free((char *)pe->table, TABLE_SIZE, sizeof(code_entry), "GIF code table");
+}
+
+/* Get the next (depth) bits from the pixel buffer. */
+private uint
+lzw_getc(pixel_reader _ss *pr, uint depth)
+{      if ( pr->bits_left < depth )
+       {       pr->bit_buffer <<= 8; 
+               pr->bit_buffer |= *(pr->next++);
+               pr->bits_left += 8;
+       }
+       pr->bits_left -= depth;
+       return (pr->bit_buffer >> pr->bits_left) & ((1 << depth) - 1);
+}
+
+/* Output 1 row of data in GIF (LZW) format. */
+private void
+lzw(byte *from, byte *end, register lzw_encoder _ss *pe, byte depth)
+{      pixel_reader reader;
+       /* Set up the reader. */
+       reader.next = from;
+       reader.bits_left = 0;
+
+       if ( pe->next_code == (pe->Clear_code + 2))     /* first time through */
+       {       pe->string_code = lzw_getc(&reader, depth);
+       }
+
+       while ( reader.next < end || reader.bits_left >= depth )
+       {       uint    data = lzw_getc(&reader, depth);  /* actually only a byte */
+
+               /* Hash to find a match for the prefix+char */
+               /* string in the string table */
+
+               ushort  hash_prefix = pe->string_code;
+               int     index = (data << 4) ^ hash_prefix;
+               int     hash_offset;
+               register code_entry *pce;
+
+               if ( index == 0 )
+                       hash_offset = 1;
+               else
+                       hash_offset = TABLE_SIZE - index;
+
+               while ( 1 )
+               {       pce = &pe->table[index];
+                       if ( pce->code_value == -1 )
+                               break;
+                       if ( pce->prefix_code == hash_prefix && 
+                            pce->append_character == data )
+                               break;
+                       index -= hash_offset;
+                       if ( index < 0 )
+                               index += TABLE_SIZE;
+               }
+               if ( pce->code_value != -1 )
+                       pe->string_code = pce->code_value;
+               else
+               {       /* Make a new entry */
+                       pce->code_value = pe->next_code++;
+                       pce->prefix_code = pe->string_code;
+                       pce->append_character = data;
+
+                       lzw_putc(pe, pe->string_code);
+
+                       if ( pe->next_code > (pe->Max_Code + 1) )
+                       {       /* Increment the width of the code */
+                               if ( pe->bits+1 >= MAX_BITS )
+                               {       /* output clear code first*/
+                                       lzw_putc(pe, pe->Clear_code);
+                                       pe->bits = (depth == 1 ? 2 : depth);
+                                       lzw_reset(pe);
+                               }
+                               else
+                                       pe->bits++;
+                               lzw_set_bits(pe, pe->bits);
+                       }
+                       pe->string_code = data;
+               }
+       }
+}
+
+
+/* Write a page to a file in GIF format. */
+int
+gif_print_page(gx_device_printer *pdev, FILE *file)
+{      int raster = gdev_prn_bytes_per_scan_line(pdev);
+       int height = pdev->height;
+       int depth = pdev->color_info.depth;
+       byte *row = (byte *)gs_malloc(raster * 2, 1, "gif file buffer");
+       byte *end = row + raster;
+       gif_header header;
+       image_descriptor header_desc;
+       lzw_encoder encoder;
+       int y;
+       int code = 0;                   /* return code */
+
+       if ( row == 0 )                 /* can't allocate row buffer */
+               return gs_error_VMerror;
+       code = lzw_init(&encoder, (depth == 1 ? 2 : depth), file);
+       if ( code < 0 )
+               return code;
+
+       /* Set up the header. */
+
+       memcpy(header.signature, "GIF", 3);
+       memcpy(header.version, "87a", 3);
+       header.width = raster * (8/depth);      /*pdev->width;*/
+                                               /* for most decoders the */
+                                               /* width must be on byte */
+                                               /* boundry               */
+       header.height = height;
+/*     header.flags.globalcolor = TRUE;        */
+/*     header.flags.colorres = depth-1;        */
+/*     header.flags.sort = FALSE;              */
+/*     header.flags.colorsize = depth-1;       */
+       header.flags =
+               (1 << globalcolor_shift) +
+               ((depth - 1) << colorres_shift) +
+               (0 << sort_shift) +
+               ((depth - 1) << colorsize_shift);
+       header.background = 0;
+       header.aspect = 0;
+       
+       /* Write the header. */
+
+       if ( fwrite(&header, 1, 13, file) < 13 )
+          {    code = gs_error_ioerror;
+               goto gif_done;
+          }
+
+       /* Write the header global color palette. */
+
+       if ( pc_write_palette((gx_device *)pdev, 1 << depth, file) < 0 )
+          {    code = gs_error_ioerror;
+               goto gif_done;
+          }
+
+       header_desc.left_pos = 0;
+       header_desc.top_pos = 0;
+       header_desc.width = raster * (8/depth); /*pdev->width;*/
+       header_desc.height = height;
+/*     header_desc.flags.localcolor = FALSE;   */
+/*     header_desc.flags.interlace = FALSE;    */
+/*     header_desc.flags.sort = FALSE;         */
+/*     header_desc.flags.localsize = 0;        */
+
+       header_desc.flags = 0;
+
+       /* Write the header image descriptor. */
+
+       fputc(0x2c,file);               /* start with separator */
+       if ( fwrite(&header_desc, 1, 9, file) < 9 )
+          {    code = gs_error_ioerror;
+               goto gif_done;
+          }
+
+       fflush(file);
+
+       printf("The Graphics Interchange Format(c) is \n");
+       printf("the Copyright Property of CompuServe Incorporated.\n");
+       printf("GIF(sm) is a Service Mark property of CompuServe Incorporated\n");
+
+       fputc(encoder.bits, file);              /* start with code size */
+
+       lzw_putc(&encoder, encoder.Clear_code); /* output clear code first*/
+
+       /* Dump the contents of the image. */
+       for ( y = 0; y < height; y++ ) 
+          {    gdev_prn_copy_scan_lines(pdev, y, row, raster);
+               lzw(row, end, &encoder, depth);
+          }
+
+       lzw_finish(&encoder);
+        fputc(0, file);
+       fputc(0x3b, file);      /* EOF indicator */
+
+gif_done:
+       lzw_exit(&encoder);
+       gs_free((char *)row, raster * 2, 1, "gif file buffer");
+       return code;
+}