summaryrefslogtreecommitdiff
path: root/graphics/sam2p/out_gif.cpp
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/sam2p/out_gif.cpp
Initial commit
Diffstat (limited to 'graphics/sam2p/out_gif.cpp')
-rw-r--r--graphics/sam2p/out_gif.cpp341
1 files changed, 341 insertions, 0 deletions
diff --git a/graphics/sam2p/out_gif.cpp b/graphics/sam2p/out_gif.cpp
new file mode 100644
index 0000000000..522242174f
--- /dev/null
+++ b/graphics/sam2p/out_gif.cpp
@@ -0,0 +1,341 @@
+/* out_gif.cpp
+ * by pts@fazekas.hu at Sat Mar 23 11:02:36 CET 2002
+ */
+
+#include "image.hpp"
+
+#if USE_OUT_GIF
+#include <string.h>
+#include <stdio.h>
+
+/**** pts ****/
+#ifdef __cplusplus
+# define AALLOC(var,len,itemtype) var=new itemtype[len]
+# define AFREE(expr) delete [] (expr)
+#else
+# include <stdlib.h> /* malloc(), free() */
+# define AALLOC(var,len,itemtype) var=(itemtype*)malloc(len*sizeof(itemtype));
+# define AFREE(expr) free((expr))
+#endif
+#define HasLZW HAVE_LZW /* Imp: or USE_BUILTIN_LZW? */
+#define True true
+#define False false
+
+/* The code of GIFEncodeImage is based on an early version of ImageMagick. */
+static unsigned int GIFEncodeImage(GenBuffer::Writable& out, char const*ppbeg, register char const*ppend, const unsigned int data_size)
+{
+#define MaxCode(number_bits) ((1 << (number_bits))-1)
+#define MaxHashTable 5003
+#define MaxGIFBits 12
+#if defined(HasLZW)
+#define MaxGIFTable (1 << MaxGIFBits)
+#else
+#define MaxGIFTable max_code
+#endif
+#define GIFOutputCode(code) \
+{ \
+ /* \
+ Emit a code. \
+ */ \
+ if (bits > 0) \
+ datum|=((long) code << bits); \
+ else \
+ datum=(long) code; \
+ bits+=number_bits; \
+ while (bits >= 8) \
+ { \
+ /* \
+ Add a character to current packet. \
+ */ \
+ packet[byte_count++]=(unsigned char) (datum & 0xff); \
+ if (byte_count >= 254) \
+ { \
+ packet[-1]=byte_count; \
+ out.vi_write((char*)packet-1, byte_count+1); \
+ byte_count=0; \
+ } \
+ datum>>=8; \
+ bits-=8; \
+ } \
+ if (free_code > max_code) \
+ { \
+ number_bits++; \
+ if (number_bits == MaxGIFBits) \
+ max_code=MaxGIFTable; \
+ else \
+ max_code=MaxCode(number_bits); \
+ } \
+}
+
+ int
+ bits,
+ byte_count,
+ i,
+ next_pixel,
+ number_bits;
+
+ long
+ datum;
+
+ register int
+ displacement,
+ k;
+
+ register char const*pp;
+
+ short
+ clear_code,
+ end_of_information_code,
+ free_code,
+ *hash_code,
+ *hash_prefix,
+ index,
+ max_code,
+ waiting_code;
+
+ unsigned char
+ *packet,
+ *hash_suffix;
+
+ /*
+ Allocate encoder tables.
+ */
+ AALLOC(packet,257,unsigned char);
+ AALLOC(hash_code,MaxHashTable,short);
+ AALLOC(hash_prefix,MaxHashTable,short);
+ AALLOC(hash_suffix,MaxHashTable,unsigned char);
+ if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) ||
+ (hash_prefix == (short *) NULL) ||
+ (hash_suffix == (unsigned char *) NULL))
+ return(False);
+ packet++;
+ /* Now: packet-1 == place for byte_count */
+ /*
+ Initialize GIF encoder.
+ */
+ number_bits=data_size;
+ max_code=MaxCode(number_bits);
+ clear_code=((short) 1 << (data_size-1));
+ end_of_information_code=clear_code+1;
+ free_code=clear_code+2;
+ byte_count=0;
+ datum=0;
+ bits=0;
+ for (i=0; i < MaxHashTable; i++)
+ hash_code[i]=0;
+ GIFOutputCode(clear_code);
+ /*
+ Encode pixels.
+ */
+ /**** pts ****/
+ pp=ppbeg;
+ waiting_code=*(unsigned char const*)pp++; /* unsigned char BUGFIX at Sun Dec 8 13:17:00 CET 2002 */
+
+ while (pp!=ppend) {
+ /*
+ Probe hash table.
+ */
+ index=*(unsigned char const*)pp++;
+ k=(int) ((int) index << (MaxGIFBits-8))+waiting_code;
+ if (k >= MaxHashTable)
+ k-=MaxHashTable;
+#if defined(HasLZW)
+ if (hash_code[k] > 0)
+ {
+ if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == index))
+ {
+ waiting_code=hash_code[k];
+ continue;
+ }
+ if (k == 0)
+ displacement=1;
+ else
+ displacement=MaxHashTable-k;
+ next_pixel=False;
+ for ( ; ; )
+ {
+ k-=displacement;
+ if (k < 0)
+ k+=MaxHashTable;
+ if (hash_code[k] == 0)
+ break;
+ if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == index))
+ {
+ waiting_code=hash_code[k];
+ next_pixel=True;
+ break;
+ }
+ }
+ if (next_pixel != False) /* pacify VC6.0 */
+ continue;
+ }
+#endif
+ GIFOutputCode(waiting_code);
+ // printf("wc=%u\n", waiting_code);
+ if (free_code < MaxGIFTable)
+ {
+ hash_code[k]=free_code++;
+ hash_prefix[k]=waiting_code;
+ hash_suffix[k]=index;
+ }
+ else
+ {
+ /*
+ Fill the hash table with empty entries.
+ */
+ for (k=0; k < MaxHashTable; k++)
+ hash_code[k]=0;
+ /*
+ Reset compressor and issue a clear code.
+ */
+ free_code=clear_code+2;
+ GIFOutputCode(clear_code);
+ number_bits=data_size;
+ max_code=MaxCode(number_bits);
+ }
+ waiting_code=index;
+#if 0 /**** pts ****/
+ if (QuantumTick(i,image) && (image->previous == (Image2 *) NULL))
+ ProgressMonitor(SaveImageText,i,image->packets);
+#endif
+ }
+ /*
+ Flush out the buffered code.
+ */
+ GIFOutputCode(waiting_code);
+ GIFOutputCode(end_of_information_code);
+ if (bits > 0)
+ {
+ /*
+ Add a character to current packet.
+ */
+ packet[byte_count++]=(unsigned char) (datum & 0xff);
+ if (byte_count >= 254)
+ {
+ packet[-1]=byte_count;
+ out.vi_write((char*)packet-1, byte_count+1);
+ byte_count=0;
+ }
+ }
+ /*
+ Flush accumulated data.
+ */
+ if (byte_count > 0)
+ {
+ packet[-1]=byte_count;
+ out.vi_write((char*)packet-1, byte_count+1);
+ }
+ /*
+ Free encoder memory.
+ */
+ AFREE(hash_suffix);
+ AFREE(hash_prefix);
+ AFREE(hash_code);
+ AFREE(packet-1);
+ return pp==ppend;
+}
+
+/** This isn't a complete GIF writer. For example, it doesn't support
+ * animation or multiple sub-images. But it supports transparency and
+ * compression. Only works when . The user should call
+ * packPal() first to ensure img->getBpc()==8, and to get a minimal palette.
+ */
+void out_gif_write(GenBuffer::Writable& out, Image::Indexed *img) {
+ /* Tested and proven to work at Sat Mar 23 13:11:41 CET 2002 */
+ unsigned i, c, bits_per_pixel;
+ signed transp;
+ char hd[19];
+
+ assert(img->getBpc()==8); /* 1 palette entry == 8 bits */
+
+ transp=img->getTransp();
+ memcpy(hd, transp!=-1 ? "GIF89a" : "GIF87a", 6);
+ i=img->getWd(); hd[6]=i; hd[7]=i>>8;
+ i=img->getHt(); hd[8]=i; hd[9]=i>>8;
+
+ // transp=-1; /* With this, transparency will be ignored */
+ c=img->getNcols();
+ bits_per_pixel=1; while (((c-1)>>bits_per_pixel)!=0) bits_per_pixel++;
+ /* ^^^ (c-1) BUGFIX at Mon Oct 20 15:18:24 CEST 2003 */
+ /* 63 -> 6, 64 -> 6, 65 -> 7 */
+ // if (bits_per_pixel>1) bits_per_pixel--; /* BUGFIX at Wed Apr 30 15:55:27 CEST 2003 */ /* BUGFIX at Mon Oct 20 15:18:14 CEST 2003 */
+ // fprintf(stderr, "GIF89 write transp=%d ncols=%d bpp=%d\n", transp, c, bits_per_pixel);
+ assert(1<=bits_per_pixel && bits_per_pixel<=8);
+ c=3*((1<<bits_per_pixel)-c);
+ /* Now: c is the number of padding bytes */
+
+ hd[10]= 0x80 /* have global colormap */
+ | ((8-1) << 4) /* color resolution: bpc==8 */
+ | (bits_per_pixel-1); /* size of global colormap */
+ hd[11]=0; /* background color: currently unused */
+ hd[12]=0; /* reversed */
+ out.vi_write(hd, 13);
+
+ // out.vi_write("\xFF\x00\x00" "\x00\xFF\x00" "\x00\x00\xFF", 9);
+
+ out.vi_write(img->getHeadp(), img->getRowbeg()-img->getHeadp()); /* write colormap */
+ if (c!=0) {
+ char *padding=new char[(unsigned char)c]; /* BUGFIX at Fri Oct 17 18:05:09 CEST 2003 */
+ memset(padding, '\0', (unsigned char)c); /* Not automatic! */
+ out.vi_write(padding, (unsigned char)c);
+ delete [] padding;
+ }
+
+ if (transp!=-1) {
+ /* Write Graphics Control extension. Only GIF89a */
+ hd[0]=0x21; hd[1]=(char)0xf9; hd[2]=0x04;
+ hd[3]=transp!=-1; /* dispose==0 */
+ hd[4]=hd[5]=0; /* delay==0 */
+ hd[6]=transp; /* transparent color index -- or 255 */
+ hd[7]=0;
+ out.vi_write(hd, 8);
+ }
+
+ /* Write image header */
+ hd[8]=',';
+ hd[ 9]=hd[10]=0; /* left */
+ hd[11]=hd[12]=0; /* top */
+ i=img->getWd(); hd[13]=i; hd[14]=i>>8;
+ i=img->getHt(); hd[15]=i; hd[16]=i>>8;
+ hd[17]=0; /* no interlace, no local colormap, no bits in local colormap */
+
+ if ((c=bits_per_pixel)<2) c=4;
+ hd[18]=c; /* compression bits_per_pixel */
+ out.vi_write(hd+8, 11);
+
+#if 0
+ printf("GIFEncodeImage out r r+%u %u; off=%u\n", img->getRlen()*img->getHt(), c+1, img->getRowbeg()-img->getHeadp());
+ FILE *f=fopen("tjo.dat","wb");
+ fprintf(f, "P6 %u %u 255\n", img->getWd(), img->getHt());
+ // fwrite(img->getRowbeg(), 1, img->getRlen()*img->getHt(), f);
+ for (unsigned u=0; u<img->getRlen()*img->getHt(); u++) {
+ char *p=img->getHeadp()+3* *(unsigned char*)(img->getRowbeg()+u);
+ putc(p[0],f);
+ putc(p[1],f);
+ putc(p[2],f);
+ }
+#endif
+
+ i=GIFEncodeImage(out, img->getRowbeg(), img->getRowbeg()+img->getRlen()*img->getHt(), c+1);
+#if 0
+ { char buf[500000];
+ FILE *f=fopen("tjo.dat","rb");
+ int got=fread(buf, 1, sizeof(buf), f);
+ assert(got==486109);
+ assert(got==img->getRlen()*img->getHt());
+ i=GIFEncodeImage(out, buf, buf+img->getRlen()*img->getHt(), c+1);
+ }
+#endif
+ assert(i!=0);
+
+ /* Write trailer */
+ hd[0]=0; hd[1]=';';
+ out.vi_write(hd, 2);
+}
+#else
+#include <stdlib.h>
+void out_gif_write(GenBuffer::Writable&, Image::Indexed *) {
+ assert(0);
+ abort();
+}
+#endif