#include <stdio.h>
#include <stdlib.h>
#include "savegif.h"
#define FLUSH_WITHLEN -2
#define FLUSH_NOLEN -1
typedef struct { //Fⁿr Data Sub-Blocks
BYTE len, str[255]; //Data Sub-Blocks brauchen die LΣnge am Anfang
}PASCALSTR;
static PASCALSTR passtr;
static FILE *fid;
static int writechar(int c) {
if (c>=0) passtr.str[passtr.len++]=(unsigned char)c; //AnhΣngen
if (passtr.len==255) c=-2; //FLUSH erzwingen
if (c<0) { //FLUSH
//c==-2 --> mit lΣngenangabe
//c==-1 --> ohne LΣngenangabe
if (fwrite((char*)&passtr+2+c, passtr.len-1-c, 1, fid)<1) return -1;
passtr.len=0;
}
return 0;
}
static int writestr(char *str, int anz) {
while (anz--) if (writechar(*(BYTE*)str++)) return -1;
return 0;
}
//anz>0 bits schreiben
//anz==0 bits bis jetzt schreiben (flush)
//anz<0 zurⁿcksetzen
static int writebits(int x, int anz){
static BYTE c=0;
static int stelle=0; //merke stelle in c
BYTE hc;
if (!anz) { //FLUSH
if (!stelle) return 0;
hc=0;
while (stelle--) { //hc fⁿllen mit den interessanten Stellen
hc<<=1;
hc|=1;
}
c&=hc; //uninteressante Stellen in c l÷schen
if (writechar(c)) return -1;
c=0;
stelle=0;
}else if (anz<0) { //RESET
stelle=0;
c=0;
}else{ //WRITE
while (anz--) {
c|=(x&1)<<stelle; //Bit aus x holen und in c schreiben
x>>=1; //x immer runterschieben
stelle++;
if (stelle==8) {
if (writechar(c)) return -1;
stelle=0;
c=0;
}
}
}
return 0;
}
#include <stdlib.h>
/*========================================================================*
= =
= Routines to maintain an LZW-string table =
= =
*========================================================================*/
#define HASHSIZE 9973
#define HASHSTEP 2039
#define HASH(index, lastbyte) (((lastbyte << 8) ^ index) % HASHSIZE)
static BYTE *StrChr;
static unsigned short *StrNxt, *StrHsh, NumStrings;
/*========================================================================*
= =
= Routines to maintain an LZW-string table =
= =
*========================================================================*/
/*-------------------------------------------------------------------------
* NAME: FreeStrtab()
* DESCRIPTION: Free arrays used in string table routines
* PARAMETERS: None
* RETURNS: Nothing
*/
static void FreeStrtab(void){
if (StrHsh) {free(StrHsh); StrHsh = NULL;}
if (StrNxt) {free(StrNxt); StrNxt = NULL;}
if (StrChr) {free(StrChr); StrChr = NULL;}
}
/*-------------------------------------------------------------------------
* NAME: AllocStrtab()
* DESCRIPTION: Allocate arrays used in string table routines
* PARAMETERS: None
* RETURNS: GIF_OK - OK
* GIF_OUTMEM - Out of memory
*/
static int AllocStrtab(void){
StrChr=/*(unsigned char *)*/malloc(4096);
StrNxt=/*(unsigned short *)*/malloc(4096*sizeof(unsigned short));
StrHsh=/*(unsigned short *)*/malloc(HASHSIZE*sizeof(unsigned short));
if (!StrChr) return 0;
if (!StrNxt) return 0;
if (!StrHsh) return 0;
return 1;
}
/*-------------------------------------------------------------------------
* NAME: AddCharString()
* DESCRIPTION: Add a string consisting of the string of index plus
* the byte b.
* If a string of length 1 is wanted, the index should
* be 0xFFFF.
* PARAMETERS: index - Index to first part of string, or 0xFFFF is
* only 1 byte is wanted
* b - Last byte in new string
* RETURNS: Index to new string, or 0xFFFF if no more room
*/
static unsigned short AddCharString(unsigned short index, BYTE b){
unsigned short hshidx;
/* Check if there is more room */
if (NumStrings >= 4096) return 0xFFFF;
/* Search the string table until a free position is found */
hshidx = HASH(index, b);
while (StrHsh[hshidx] != 0xFFFF)
hshidx = (hshidx + HASHSTEP) % HASHSIZE;
/* Insert new string */
StrHsh[hshidx] = NumStrings;
StrChr[NumStrings] = b;
StrNxt[NumStrings] = index;
return NumStrings++;
}
/*-------------------------------------------------------------------------
*
* NAME: FindCharString()
* DESCRIPTION: Find index of string consisting of the string of index
* plus the byte b.
* If a string of length 1 is wanted, the index should
* be 0xFFFF.
* PARAMETERS: index - Index to first part of string, or 0xFFFF is
* only 1 byte is wanted
* b - Last byte in string
* RETURNS: Index to string, or 0xFFFF if not found
*/
static unsigned short FindCharString(unsigned short index, BYTE b){
unsigned short hshidx, nxtidx;
/* Check if index is 0xFFFF. In that case we need only
* return b, since all one-character strings has their
* bytevalue as their index */
if (index == 0xFFFF) return (unsigned short) b;
/* Search the string table until the string is found, or
* we find 0xFFFF. In that case the string does not exist. */
hshidx = HASH(index, b);
while ((nxtidx = StrHsh[hshidx]) != 0xFFFF) {
if ((StrNxt[nxtidx] == index) && (StrChr[nxtidx] == b)) return nxtidx;
hshidx = (hshidx + HASHSTEP) % HASHSIZE;
}
/* No match is found */
return 0xFFFF;
}
/*-------------------------------------------------------------------------
* NAME: ClearStrtab()
* DESCRIPTION: Mark the entire table as free, enter the 2**codesize
* one-byte strings, and reserve the 2 reserved
* codes.
* PARAMETERS: codesize - Number of bits to encode one pixel
* RETURNS: Nothing
*/
static void ClearStrtab(BYTE codesize){
unsigned short i;
unsigned short *wp;
NumStrings = 0;/* Stringtabelle ist nun leer */
wp = StrHsh;
for (i=0; i<HASHSIZE; i++)/* HASHtabelle leeren */
*wp++ = 0xFFFF;
for (i=0; i< ((1 << codesize) + 2); i++)
AddCharString(0xFFFF, i);/* "Terminale" Strings und reservierte Codes seten */
}
/*========================================================================*
= =
= LZW compression routine =
= =
*========================================================================*/
/*-------------------------------------------------------------------------
* NAME: LZW_Compress()
* DESCRIPTION: Perform LZW compression as specified in the
* GIF-standard.
* PARAMETERS: codesize - Number of bits needed to represent
* one pixelvalue.
* buf - Pixel-Puffer (jedes Byte ein Pixel!)
* RETURNS: GIF_OK - OK
* GIF_OUTMEM - Out of memory
*/
static int LZWCompress(const unsigned char *buf, int len, BYTE codesize){
BYTE c, numbits;
unsigned short index;
unsigned short clearcode, endofinfo, limit;
unsigned short prefix = 0xFFFF;
int i;
StrChr=NULL; StrNxt=NULL; StrHsh=NULL;
if (codesize<2) codesize=2; /* Mu▀ mindestens 2 sein, auch bei s/w */
clearcode = 1 << codesize; /* Fixwerte berechnen */
endofinfo = clearcode + 1;
numbits = codesize + 1; /* bei 16 Farben gehts mit 5 Bits los! */
limit = (1 << numbits) - 1; /* dann wΣre das Limit=1F */
if (!AllocStrtab()) return 0;
ClearStrtab(codesize); /* Tabellen initialisieren */
writechar(codesize); /* Kennung z.B. mit "4" */
writechar(FLUSH_NOLEN);
writebits(clearcode, numbits); /* zuerst ein Clear-Code schicken */
for (i=0; i<len; i++){ /* Packe los! */
c=*buf++;
index=FindCharString(prefix, c);
// Check if the prefix + the new character is a string that exists in the table
if (index!=0xFFFF){
// The string exists in the table. Make this string the new prefix.
prefix = index;
}else{
// The string does not exist in the table. First write code of the old prefix to
// the file.
writebits(prefix, numbits);
// Add the new string (the prefix + the new character) to the stringtable.
if (AddCharString(prefix, c) > limit){
if (++numbits>12){ /* Drohender ▄berlauf? */
writebits(clearcode, 12); /* 12 bit breiten Clearcode schicken */
ClearStrtab(codesize);
numbits = codesize + 1;
}
limit = (1 << numbits) - 1;/* Neues Limit (ggf. wieder 1F) */
}
//Set prefix to a string containing only the character read. Since all possible
//one-character strings exists int the table, there's no need to check if it is
//found.
prefix = c;
} /* else */
} /* for i */
// End of info is reached. Write last prefix.
if (prefix != 0xFFFF) writebits(prefix, numbits);
writebits(endofinfo, numbits);/* End-Of-Info schreiben */
writebits(0,0);
writechar(FLUSH_WITHLEN);
FreeStrtab(); /* aufrΣumen */
writechar(FLUSH_WITHLEN); //Terminator rausschreiben
return 0;
}
int savegif(FILE *f, const BYTE *b, int w, int h, const RGBCOLOR *c, int bitcount,
int transcolor) {
int nc;
passtr.len=0;
nc=1<<bitcount;
fid=f;
if (!fid) return -1;
writestr("GIF89a", 6); //GIF-Header
//Logical Screen Descriptor
writebits(0, -1);
writebits(w, 16); //Breite
writebits(h, 16); //H÷he
writebits(bitcount-1, 3); //Size of Global Color Table 0 --> 2 Farben
writebits(0, 1); //Nicht sortiert (sowieso sinnlos)
writebits(bitcount-1, 3); //Color Resolution 0 --> 2 Farben
writebits(1, 1); //Global Color Table Flag
writestr("\0", 2); //Background Color Index, Pixel Aspect Ratio
// (sinnlos)
writechar(FLUSH_NOLEN);
//Global Color Table
// writestr((char *)colors, nc*sizeof(RGBCOLOR));
if (fwrite(c, nc*sizeof(RGBCOLOR), 1, fid)<1) return -1;
if (transcolor>=0) { //Graphic Control Extension (Transparente Farbe)
writestr("\x21\xF9\x04\x01\x00",6);
//Introducer, Control Label, Block Size,
//Packed Fields, Delay Time
writebits(transcolor, 8); //Transparent Color Index
writestr("", 1); //Block Terminator
}
//Image Descriptor
writestr("\x2c\0\0\0", 5); //Trick 17c ...
writebits(w, 16); //Breite
writebits(h, 16); //H÷he
writebits(bitcount-1, 8); //Size of Global Color Table, Rest ist 0
//Image Data
writechar(FLUSH_NOLEN);
LZWCompress(b, w*h, bitcount);
writechar(0x3B);
writechar(FLUSH_NOLEN);
return 0;
}
Detected encoding: OEM (CP437) | 1
|
|