summaryrefslogtreecommitdiffstats
path: root/src/gifenc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gifenc.cpp')
-rw-r--r--src/gifenc.cpp287
1 files changed, 287 insertions, 0 deletions
diff --git a/src/gifenc.cpp b/src/gifenc.cpp
new file mode 100644
index 0000000..501e433
--- /dev/null
+++ b/src/gifenc.cpp
@@ -0,0 +1,287 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ *
+ * Copyright (C) 1997-2009 by Dimitri van Heesch.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * All output generated with Doxygen is not covered by this license.
+ *
+ * The GIF compression code below is based on the file ppmtogif.c of the
+ * netpbm package. The original copyright message follows:
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * Copyright (C) 1989 by Jef Poskanzer.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. This software is provided "as is" without express or
+ * implied warranty.
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * The Graphics Interchange Format(c) is the Copyright property of
+ * CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ * CompuServe Incorporated.
+ */
+
+#include "gifenc.h"
+
+static const unsigned int masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
+ 0x001F, 0x003F, 0x007F, 0x00FF,
+ 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
+ 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
+
+GifEncoder::GifEncoder(Byte *rawBytes,Color *p,int w,int h, Byte d,
+ int t)
+ : colorResolution(8),globalPaletteFlag(0x80),bits(12),
+ maxMaxCode(1<<bits)
+{
+ width = w;
+ height = h;
+ depth = d;
+ transIndex = t;
+ palette = p;
+ data = rawBytes;
+ dataPtr = data;
+}
+
+GifEncoder::~GifEncoder()
+{
+}
+
+void GifEncoder::writeGIF(QFile &fp)
+{
+ // Write the Magic header
+ fp.writeBlock( transIndex < 0 ? "GIF87a" : "GIF89a", 6 );
+
+ // Write the logical screen descriptor
+ putWord( width, fp );
+ putWord( height, fp );
+ Byte pack = globalPaletteFlag | ((colorResolution-1)<<4) | (depth-1);
+ putByte( pack, fp );
+ putByte( 0, fp ); // the background color
+ putByte( 0, fp ); // no aspect ration defined
+
+ // Write global color table
+ int i; for ( i=0 ; i< (1<<depth) ; i++)
+ {
+ putByte(palette[i].red, fp);
+ putByte(palette[i].green,fp);
+ putByte(palette[i].blue, fp);
+ }
+
+ if ( transIndex >= 0)
+ {
+ // Write graphic control extension (needed for GIF transparancy)
+ putByte( 0x21, fp); // extension introducer
+ putByte( 0xf9, fp); // graphic control label
+ putByte( 4, fp); // block size
+ putByte( 1, fp); // announce transparacy value
+ putWord( 0, fp); // zero delay time
+ putByte( transIndex, fp); // write transparant index
+ putByte( 0, fp); // end block
+ }
+
+ // Write the image descriptor
+ putByte( 0x2c, fp); // image separator
+ putWord( 0, fp); // image left position
+ putWord( 0, fp); // image top position
+ putWord( width, fp); // image width
+ putWord( height, fp); // image height
+ putByte( 0, fp); // no local color table, no interlacing
+
+ // Write table based image data
+ Byte initCodeSize = depth<=1 ? 2 : depth;
+ putByte( initCodeSize, fp); // LZW Minimum Code Size
+ compress( initCodeSize+1, fp);
+ putByte( 0, fp); // end of blocks
+
+ // Write GIF Trailer
+ putByte( 0x3b, fp);
+}
+
+void GifEncoder::compress( int ibits, QFile &outfile )
+{
+ int i;
+ int entry;
+
+ initBits = ibits;
+ numPixels = width*height;
+ dataPtr = data;
+ clearFlag = FALSE;
+ nBits = initBits;
+ maxCode = (1<<nBits) -1;
+ ClearCode = (1 << (initBits - 1));
+ EOFCode = ClearCode + 1;
+ freeEntry = ClearCode + 2;
+ aCount = 0;
+ curAccum = 0;
+ curBits = 0;
+
+ entry = nextPixel();
+
+ int hshift = 0;
+ int fcode;
+ for ( fcode = hashTableSize; fcode < 65536L; fcode *= 2L ) ++hshift;
+ hshift = 8 - hshift; /* set hash code range bound */
+
+ clearHashTable(); /* clear hash table */
+
+ writeCode( ClearCode,outfile );
+
+ int c;
+ while ( (c = nextPixel()) != EOF )
+ {
+ fcode = (c << bits) + entry;
+ i = (c << hshift) ^ entry; /* xor hashing */
+
+ bool found=FALSE;
+ if (htab[i]==fcode)
+ {
+ entry = codetab[i];
+ found=TRUE;
+ }
+ else if (htab[i]>=0)
+ {
+ int disp = hashTableSize - i;
+ if (i==0) disp=1;
+ do
+ {
+ if ((i-=disp)<0) i+=hashTableSize;
+ if (htab[i]==fcode)
+ {
+ entry=codetab[i];
+ found=TRUE;
+ }
+ } while (htab[i]>0 && !found);
+ }
+ if (!found)
+ {
+ writeCode( entry, outfile );
+ entry = c;
+ if ( freeEntry < maxMaxCode )
+ {
+ codetab[i] = freeEntry++; /* code -> hashtable */
+ htab[i] = fcode;
+ }
+ else
+ {
+ clearHashTable();
+ freeEntry = ClearCode + 2;
+ clearFlag = TRUE;
+ writeCode( ClearCode, outfile );
+ }
+ }
+ }
+ writeCode( entry, outfile );
+ writeCode( EOFCode, outfile );
+}
+
+void GifEncoder::putWord( Word w, QFile &fp )
+{
+ fp.putch( w & 0xff );
+ fp.putch( (w>>8) & 0xff );
+}
+
+void GifEncoder::putByte( Byte b, QFile &fp )
+{
+ fp.putch( b );
+}
+
+void GifEncoder::writeCode( int code, QFile &outfile )
+{
+ curAccum &= masks[ curBits ];
+
+ if ( curBits > 0 )
+ {
+ curAccum |= (code << curBits);
+ }
+ else
+ {
+ curAccum = code;
+ }
+
+ curBits += nBits;
+
+ while( curBits >= 8 )
+ {
+ writeChar( (Byte)(curAccum & 0xff),outfile );
+ curAccum >>= 8;
+ curBits -= 8;
+ }
+
+ /*
+ * If the next entry is going to be too big for the code size,
+ * then increase it, if possible.
+ */
+ if ( freeEntry > maxCode || clearFlag )
+ {
+ if( clearFlag )
+ {
+ nBits = initBits;
+ maxCode = (1<<nBits)-1;
+ clearFlag = FALSE;
+ }
+ else
+ {
+ ++nBits;
+ if ( nBits == bits )
+ maxCode = maxMaxCode;
+ else
+ maxCode = (1<<nBits)-1;
+ }
+ }
+
+ if ( code == EOFCode )
+ {
+ /* At EOF, write the rest of the buffer. */
+ while( curBits > 0 )
+ {
+ writeChar( (Byte)(curAccum & 0xff), outfile );
+ curAccum >>= 8;
+ curBits -= 8;
+ }
+
+ writePacket(outfile);
+ }
+}
+
+/*
+ * Add a character to the end of the current packet, and if it is 254
+ * characters, flush the packet to disk.
+ */
+void GifEncoder::writeChar( Byte c, QFile &fp )
+{
+ accum[ aCount++ ] = c;
+ if( aCount >= 254 ) writePacket(fp);
+}
+
+/*
+ * Flush the packet to disk, and reset the accumulator
+ */
+void GifEncoder::writePacket(QFile &fp)
+{
+ if ( aCount > 0 )
+ {
+ fp.putch( aCount );
+ fp.writeBlock( (const char *)accum, aCount );
+ aCount = 0;
+ }
+}
+
+void GifEncoder::clearHashTable() /* reset code table */
+{
+ int *htab_p = htab;
+ int i; for (i=0;i<hashTableSize;i++) *htab_p++ = -1;
+}
+