diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c78d94e --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +PROJECT=faxcoder +PROGG4=g4coder +PROGLZW=lzwcoder +PROGS=$(PROGG4) $(PROGLZW) +SRCSPBM=src/pbm.c +SRCSG4=src/g4code.c src/g4coder.c +SRCSLZW=src/lzwcode.c src/lzwcoder.c + +CFLAGS=-O3 -funroll-all-loops -finline-functions -Wall + +OBJSPBM=$(SRCSPBM:.c=.o) +OBJSG4=$(SRCSG4:.c=.o) +OBJSLZW=$(SRCSLZW:.c=.o) + +all: $(PROGS) + +clean: + rm -f $(PROGS) $(OBJSPBM) $(OBJSG4) $(OBJSLZW) + +$(PROGG4): $(OBJSPBM) $(OBJSG4) + $(CC) $(CFLAGS) -o $@ $^ + +$(PROGLZW): $(OBJSPBM) $(OBJSLZW) + $(CC) $(CFLAGS) -o $@ $^ diff --git a/NOTES b/NOTES new file mode 100644 index 0000000..1717cc0 --- /dev/null +++ b/NOTES @@ -0,0 +1,23 @@ +PDF: (default) + want EOL EOL, resp. EOL(1?)x6 + do NOT need EOL after each line!!! +optionally allow 0 bits to align with byte boundary at line start. (check this) + might allow resync to EOL for K>=0 (then: requires EOL after each line) + +FOR US: check how to deal with reads 1 byte more + + +libtiff: + does not write RTC (6xEOL(1?)) in G3. (no EOL at end of file) + +FOR US: to implement this we need to allow (*read) to return some kind of EOF + + +TIFF 6.0 Spec: + never write EOL in G3 1d, (i.e. also no RTC) + Strips are independent images + +want? + - pbm reader/writer (P1,P4) +... may want: + - simple tiff reader/writer diff --git a/README.md b/README.md new file mode 100644 index 0000000..9d50801 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# faxcoder + +A C tools to access streams in PDF-files at the object level. + +License: GNU Lesser GPL + +This project includes two tools: + * g4coder - a G3/G4 Fax En-/Decoder + * lzwcoder - a (TIFF) LZW En-/Decoder + +## Build + +Type +```shell +make +``` diff --git a/src/g4code.c b/src/g4code.c new file mode 100644 index 0000000..fceb26c --- /dev/null +++ b/src/g4code.c @@ -0,0 +1,744 @@ +#include +#include +#include +#include "g4code.h" +#include "tables.h" + +// init functions +G4STATE *init_g4(int kval,int width,READFUNC rf,WRITEFUNC wf,void *user_read,void *user_write) +{ + G4STATE *ret; + + if (width<=0) // use default + { + width=1728; + } + + ret=malloc(sizeof(G4STATE)); + if (!ret) + { + return NULL; + } + ret->read=rf; + ret->write=wf; + ret->user_read=user_read; + ret->user_write=user_write; + ret->width=width; + ret->kval=kval; + ret->lastline=malloc(sizeof(int)*(width+2)); + if (!ret->lastline) + { + free(ret); + return NULL; + } + ret->curline=malloc(sizeof(int)*(width+2)); + if (!ret->curline) + { + free(ret->lastline); + free(ret); + return NULL; + } + restart_g4(ret); + return ret; +} + +G4STATE *init_g4_read(int kval,int width,READFUNC rf,void *user_read) +{ + assert(rf); + if (!rf) + { + return 0; + } + return init_g4(kval,width,rf,NULL,user_read,NULL); +} + +G4STATE *init_g4_write(int kval,int width,WRITEFUNC wf,void *user_write) +{ + assert(wf); + if (!wf) + { + return 0; + } + return init_g4(kval,width,NULL,wf,NULL,user_write); +} + +void restart_g4(G4STATE *state) +{ + assert(state); + if (state) + { + memset(state->lastline,0,sizeof(int)*(state->width+2)); + state->lastline[0]=state->width; + state->lines_done=0; + state->bitpos=0; + state->bitbuf=0; + } +} + +void free_g4(G4STATE *state) +{ + if (state) + { + free(state->lastline); + free(state->curline); + free(state); + } +} + +// helper functions +int writecode(G4STATE *state,ENCHUFF *table,int code) +{ + unsigned char buf[4]; + int iA=0; + + // TODO? make tables LSB-aligned(or ints) + state->bitbuf|=(unsigned)(table[code].bits<<16)>>state->bitpos; + state->bitpos+=table[code].len; + while (state->bitpos>=8) + { + buf[iA++]=state->bitbuf>>24; + state->bitbuf<<=8; + state->bitpos-=8; + } + if (!iA) + { + return 0; + } + return (*state->write)(state->user_write,buf,iA); +} + +int writeflush(G4STATE *state) +{ + unsigned char buf[4]; + int iA=0; + + while (state->bitpos>0) + { + buf[iA++]=state->bitbuf>>24; + state->bitbuf<<=8; + state->bitpos-=8; + } + state->bitpos=0; + if (!iA) + { + return 0; + } + return (*state->write)(state->user_write,buf,iA); +} + +int writehuff(G4STATE *state,int black,int num) +{ + ENCHUFF *colorhuff[]= {whitehuff,blackhuff}; + int ret=0; + + while (num>=2560) + { + ret=writecode(state,colorhuff[black],63+2560/64); + if (ret) + { + return ret; + } + num-=2560; + } + if (num>=64) + { + ret=writecode(state,colorhuff[black],63+num/64); + if (ret) + { + return ret; + } + num%=64; + } + return writecode(state,colorhuff[black],num); +} + +int next_bits(G4STATE *state,int bits) +{ + int ret,iA; + unsigned char buf[4]; + + if (state->bitposbitpos+7)>>3; + ret=(*state->read)(state->user_read,buf,num); + if (ret) + { + return -MAX_OP; + } + for (iA=0; iAbitbuf|=buf[iA]<<(24-state->bitpos); + state->bitpos+=8; + } + } + return state->bitbuf>>(32-bits); +} + +void eat_bits(G4STATE *state,int bits) +{ + state->bitpos-=bits; + state->bitbuf<<=bits; +} + +int readcode(G4STATE *state,unsigned short *table,int bits) +{ + int ip=0,data,len=0; + + data=next_bits(state,bits); + if (data<0) + { + return data; + } + while (((ip=table[ip+data])&0xf000)==0) + { + eat_bits(state,bits); + len+=bits; + data=next_bits(state,bits); + if (data<0) // read error (-MAX_OP) + { + return data; + } + } + eat_bits(state,(ip>>12)-len); + if ((ip&0xfff)>2560) // OPCODE + { + return ip|0xfffff000; + } + else + { + return ip&0xfff; + } +} + +int readhuff(G4STATE *state,int black) +{ + unsigned short *colortable[]= {whitehufftable,blackhufftable}; + int ret,val=0; + + while (1) + { + ret=readcode(state,colortable[black],DECODE_COLORHUFF_BITS); + if (ret<0) // maybe: -1,-2,-3; read error: -MAX_OP + { + return ret; + } + else if (ret<64) + { + return ret+val; + } + else if ( (ret<103)&&(val%2560) ) // error with bigmakeup: expected no 2560 any more + { + return -1-MAX_OP; // wrong_code error + } + val+=ret; + } + return val; +} + +void rle_encode(int *line,const unsigned char *inbuf,int width) +{ + unsigned int ip; + int pos; + + if (*inbuf&0x80) + { + *line++=0; + ip=rlecode[*inbuf^0xff]; + } + else + { + ip=rlecode[*inbuf]; + } + pos=ip&0xf; + while (pos>=4; + if (ip==0) + { + if (*inbuf&1) + { + ++inbuf; + if ((*inbuf&0x80)==0) + { + *line++=pos; + ip=rlecode[*inbuf]; + } + else + { + ip=rlecode[*inbuf^0xff]; + } + } + else + { + ++inbuf; + if (*inbuf&0x80) + { + *line++=pos; + ip=rlecode[*inbuf^0xff]; + } + else + { + ip=rlecode[*inbuf]; + } + } + } + else + { + *line++=pos; + } + pos+=ip&0xf; + } + *line++=width; +} + +void rle_decode(const int *line,unsigned char *outbuf,int width) +{ + static const unsigned char rletab[8]= {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe}; + int pos=0,black=0; + + memset(outbuf,0,(width+7)/8); + for (; *line<=width; line++) + { + while (*line>pos) + { + const int bitpos=pos&7; + if (*line-pos>=8-bitpos) + { + if (black) + { + *outbuf|=0xff>>bitpos; + } + outbuf++; + pos+=8-bitpos; + } + else + { + if (black) + { + *outbuf|=rletab[*line-pos]>>bitpos; + } + pos=*line; + } + } + black^=1; + } +} + +int encode_line_2d(G4STATE *state) +{ + int black=0,a0,*curpos,*lastpos,ret; + + a0=0; + curpos=state->curline; // a1 + lastpos=state->lastline; // b1 + while (*curpos<=state->width) + { + int iA=*lastpos-*curpos; + if ( (*lastposwidth)&&(lastpos[1]<*curpos) ) // b2=-3)&&(iA<=3) ) + { + if ((ret=writecode(state,opcode,iA-OP_V))) + { + return ret; + } + a0=*curpos; + if (a0>=state->width) + { + break; + } + curpos++; + black^=1; + if ( (lastpos>state->lastline)&&(lastpos[-1]>a0) ) // maybe previous is still interesting! + { + lastpos--; + } + else if (*lastposwidth) + { + lastpos++; + } + } + else + { + if ((ret=writecode(state,opcode,-OP_H))) + { + return ret; + } + if ((ret=writehuff(state,black,*curpos-a0))) + { + return ret; + } + a0=*curpos; + if (a0width) // otherwise "generate a 0" + { + curpos++; + } + if ((ret=writehuff(state,black^1,*curpos-a0))) + { + return ret; + } + a0=*curpos; + if (a0>=state->width) + { + break; + } + curpos++; + } + while ( (*lastposwidth)&&(*lastpos<=a0) ) // update lastpos + { + lastpos++; + if (*lastposwidth) + { + lastpos++; + } + } + } + return 0; +} + +int encode_line_1d(G4STATE *state) +{ + int black=0,a0,*curpos,ret; + + a0=0; + curpos=state->curline; // a1 + do + { + if ((ret=writehuff(state,black,*curpos-a0))) + { + return ret; + } + black^=1; + a0=*curpos; + curpos++; + } + while (a0width); + return 0; +} + +int decode_line_2d(G4STATE *state) +{ + int black=0,a0,*curpos,*lastpos,ret; + + a0=0; + curpos=state->curline; // a1 + lastpos=state->lastline; // b1 + do + { + ret=readcode(state,opcodetable,DECODE_OPCODE_BITS); + if (ret==-1) + { + return -ERR_UNKNOWN_CODE; + } + else if (ret==-MAX_OP) + { + return -ERR_READ; + } + else if (ret==OP_P) + { + a0=lastpos[1]; + } + else if (ret==OP_H) + { + // read more + ret=readhuff(state,black); + if (ret==-1) + { + return -ERR_UNKNOWN_CODE; + } + else if (ret==-MAX_OP) + { + return -ERR_READ; + } + else if (ret<0) // FILL,EOL,wrong_bigmakeup + { + return -ERR_WRONG_CODE; +// TODO: check ret==0 + } + a0+=ret; + *curpos++=a0; + ret=readhuff(state,black^1); + if (ret==-1) + { + return -ERR_UNKNOWN_CODE; + } + else if (ret==-MAX_OP) + { + return -ERR_READ; + } + else if (ret<0) // FILL,EOL,wrong_bigmakeup + { + return -ERR_WRONG_CODE; +// TODO: check ret==0 + } + a0+=ret; + *curpos++=a0; + } + else if ( (ret>=OP_VL3)&&(ret<=OP_VR3) ) // OP_V.. + { + a0=*lastpos+(ret-OP_V); + assert(a0<=state->width); + *curpos++=a0; + black^=1; + if ( (lastpos>state->lastline)&&(lastpos[-1]>a0) ) // maybe previous is still interesting! + { + lastpos--; + } + else if (*lastposwidth) + { + lastpos++; + } + } + else if (ret==EOL) + { + if (state->kval==-1) // G4 + { + if (next_bits(state,12)!=0x001) + { + return -ERR_WRONG_CODE; + } + eat_bits(state,12); + return 1; // done + } + else // G3 2d, TODO? hmm eol in 2d code... + { + assert(0); + return -ERR_WRONG_CODE; + } + } + else // OP_EXT + { + assert(0); + return -ERR_UNKNOWN_CODE; + } + while ( (*lastposwidth)&&(*lastpos<=a0) ) // update lastpos + { + lastpos++; + if (*lastposwidth) + { + lastpos++; + } + } + } + while (a0width); +// printf("%d\n",a0); + assert(a0==state->width); + *curpos++=state->width+1; + return 0; +} + +int decode_line_1d(G4STATE *state) +{ + int black=0,a0,*curpos,ret; + + a0=0; + curpos=state->curline; // a1 + do + { + ret=readhuff(state,black); +// printf("%da%x\n",black,ret); + if (ret==-1) + { + return -ERR_UNKNOWN_CODE; + } + else if (ret==EOL) + { + if (curpos==state->curline) // EOL EOL ... + { + int iA; + for (iA=1; iA<0; iA++) // TODO: how many EOLs are checked (? last line's EOL counted?) + { + if (next_bits(state,12)!=0x001) + { + return -ERR_WRONG_CODE; + } + eat_bits(state,12); + } + return 1; + } + // a0width! TODO? not enough, maybe graceful! +// *curpos++=state->width; + assert(0); + return -ERR_WRONG_CODE; + } + else if (ret==FILL) + { + // TODO? handle FILL + return -ERR_UNKNOWN_CODE; + } + else if (ret==-MAX_OP) + { + return -ERR_READ; + } + else if (ret<0) // namely: BIGMAKEUP-sequence wrong + { + return -ERR_WRONG_CODE; + } + else if ( (ret==0)&&(curpos!=state->curline) ) // namely: futile rle encoding. might overflow buffers + { + return -ERR_WRONG_CODE; + } + a0+=ret; + *curpos++=a0; + black^=1; + } + while (a0width); + assert(a0==state->width); + *curpos++=state->width+1; + return 0; +} + +void swap_lines(G4STATE *state) +{ + // swap lastline, curline + int *tmp=state->curline; + state->curline=state->lastline; + state->lastline=tmp; + + state->lines_done++; +} + +// main procedures +int encode_g4(G4STATE *state,const unsigned char *inbuf) +{ + int ret=0,iA; + + assert(state); + if ( (!state)||(!state->write) ) + { + return -ERR_INVALID_ARGUMENT; + } + if (!inbuf) // flush + { + if (state->kval==-1) // G4: EOL EOL + { + if ((ret=writecode(state,opcode,-EOL))) + { + return -ERR_WRITE; + } + if ((ret=writecode(state,opcode,-EOL))) + { + return -ERR_WRITE; + } + } + else if (state->kval==0) // G3 1d + { + for (iA=0; iA<7; iA++) // TODO? customize how many EOL's are to be written + { + if ((ret=writecode(state,opcode,-EOL))) + { + return -ERR_WRITE; + } + } + } + else // G3 2d + { + for (iA=0; iA<7; iA++) + { + if ((ret=writecode(state,opcode,-EOL1))) + { + return -ERR_WRITE; + } + } + } + // "pad to byte boundary" and flush + writeflush(state); + return 0; + } + rle_encode(state->curline,inbuf,state->width); + + if (state->kval==-1) // G4 + { + ret=encode_line_2d(state); + } + else if (state->kval==0) // G3 1d + { + if ((ret=writecode(state,opcode,-EOL))) + { + return -ERR_WRITE; + } + ret=encode_line_1d(state); + } + else + { + if (state->lines_done%state->kval!=0) + { + if ((ret=writecode(state,opcode,-EOL0))) + { + return -ERR_WRITE; + } + ret=encode_line_2d(state); + } + else + { + if ((ret=writecode(state,opcode,-EOL1))) + { + return -ERR_WRITE; + } + ret=encode_line_1d(state); + } + } + + swap_lines(state); + return ret; +} + +int decode_g4(G4STATE *state,unsigned char *outbuf) +{ + int ret=0; + + assert(state); + assert(outbuf); + if ( (!state)||(!state->read)||(!outbuf) ) + { + return -ERR_INVALID_ARGUMENT; + } + if (state->kval>=0) + { + // read EOL on G3 + if (next_bits(state,12)!=0x001) + { + return -ERR_WRONG_CODE; + } + eat_bits(state,12); + } + if (state->kval==-1) // G4 + { + ret=decode_line_2d(state); + } + else if (state->kval==0) // G3 1d + { + ret=decode_line_1d(state); + } + else + { + if (next_bits(state,1)) + { + eat_bits(state,1); + ret=decode_line_1d(state); + } + else + { + eat_bits(state,1); + ret=decode_line_2d(state); + } + } + if (ret<0) // error + { + return ret; + } + else if (ret==1) // File done + { + return 1; + } + rle_decode(state->curline,outbuf,state->width); + + swap_lines(state); + return 0; +} diff --git a/src/g4code.h b/src/g4code.h new file mode 100644 index 0000000..7601f51 --- /dev/null +++ b/src/g4code.h @@ -0,0 +1,53 @@ +#ifndef _G4CODE_H +#define _G4CODE_H + +#ifdef __cplusplus +extern "C" { +#endif + +// have to return 0 on success, !=0 on error +typedef int (*WRITEFUNC)(void *user,unsigned char *buf,int len); +typedef int (*READFUNC)(void *user,unsigned char *buf,int len); + +typedef struct G4STATE +{ + READFUNC read; + WRITEFUNC write; + int width; + int kval; + void *user_read,*user_write; + int *lastline,*curline; + int lines_done,bitpos; + unsigned int bitbuf; +} G4STATE; + +// kval==-1 means G4-code, kval=0 means G3 1dim, kval>0 G3 2dim with K=>kval +// width<=0 means default (1728) +G4STATE *init_g4_read(int kval,int width,READFUNC rf,void *user_read); +G4STATE *init_g4_write(int kval,int width,WRITEFUNC wf,void *user_write); +void restart_g4(G4STATE *state); +void free_g4(G4STATE *state); + +// The following functions encode/decode one line of +// return 0 on success +// 1 on End-Of-File +// <0 on Error +// >inbuf resp. >outbuf have to be ceil(width/8) bytes big +// +// When the image is done, call encode_g4 once more with >inbuf==NULL to +// finish up the stream +int encode_g4(G4STATE *state,const unsigned char *inbuf); +// maybe we read 1 byte too much! +int decode_g4(G4STATE *state,unsigned char *outbuf); + +#define ERR_INVALID_ARGUMENT 1 +#define ERR_READ 2 +#define ERR_WRITE 3 +#define ERR_UNKNOWN_CODE 4 +#define ERR_WRONG_CODE 5 + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/src/g4coder.c b/src/g4coder.c new file mode 100644 index 0000000..a7cc7a2 --- /dev/null +++ b/src/g4coder.c @@ -0,0 +1,335 @@ +/** + * G3,G4 Encoder and Decoder + * (c) 2006,2007 by Tobias Hoffmann + */ +#include +#include +#include +#include +#include "pbm.h" +#include "g4code.h" + +void usage(const char *name) +{ + printf("G3 and G4 En-/Decoder\n" + "(c) 2006,2007 by Tobias Hoffmann\n\n" + + "Usage: %s [-g3|-g3K|-g4] [-decodeW] [-h -p -b] [infile] [outfile]\n\n" + + " -g3: G3 1-dimensional code (default)\n" + " -g3K: G3 2-dimensional code, parameter K, e.g. -g32 for K=2\n" + " -g4: G4 (2-dim) code\n\n" + + "-decodeW: Decode to pbm-file, using image width W,\n" + " e.g. -decode1728 (default, if not given)\n" + " else : Encode from pbm-file\n\n" + + " -h: Show this help\n" + " -p: Write plain pbm\n" + " -b: Read/Write bitstrings\n\n" + + "Only K=2 (low resolution) and K=4 (high resolution) are standardized.\n" + "If outfile or both infile and outfile are not given\n" + "standard output and maybe standard input are used.\n\n" + ,name); + // TODO: maybe accept -g3 -2d +} + +int wrfunc(void *user,unsigned char *buf,int len) +{ + FILE *f=(FILE *)user; + + return (fwrite(buf,1,len,f)==len)?0:1; +} + +int rdfunc(void *user,unsigned char *buf,int len) +{ + FILE *f=(FILE *)user; + + return (fread(buf,1,len,f)==len)?0:1; +} + +int wrfunc_bits(void *user,unsigned char *buf,int len) +{ + FILE *f=(FILE *)user; + int iA; + unsigned char iB; + + for (iA=0; iA0; iB>>=1) + { + if (buf[iA]&iB) + { + putc('1',f); + } + else + { + putc('0',f); + } + } + } + return 0; +} + +int rdfunc_bits(void *user,unsigned char *buf,int len) +{ + FILE *f=(FILE *)user; + int iA,c; + unsigned char iB; + + for (iA=0; iA0; iB>>=1) + { + do + { + c=getc(f); + } + while ( (c=='\r')||(c=='\n') ); + if (c=='1') + { + buf[iA]|=iB; + } + else if (c==-1) // EOF: pad zero + { + break; + } + else if (c!='0') + { + return 1; + } + } + } + return 0; +} + +int main(int argc,char **argv) +{ + G4STATE *gst; + int ret=0,k=0,decode=-1,width,height,plain=0,bits=0; + char *files[2]= {NULL,NULL}; + unsigned char *buf=NULL,*tmp; + int iA,iB; + FILE *f; + + // parse commandline + iB=0; + for (iA=1; iA=0) // decode + { + const int bwidth=(decode+7)/8; + width=decode; + iA=100; // initial alloc + buf=malloc(iA*bwidth); + if (!buf) + { + fprintf(stderr,"Malloc failed: %m\n"); + return 2; + } + if (files[0]) + { + if ((f=fopen(files[0],"r"))==NULL) + { + fprintf(stderr,"Error opening \"%s\" for reading: %m\n",files[0]); + free(buf); + return 3; + } + } + else + { + f=stdin; + } + gst=init_g4_read(k,decode,(bits)?rdfunc_bits:rdfunc,f); + if (!gst) + { + fprintf(stderr,"Alloc error: %m\n"); + if (files[0]) + { + fclose(f); + } + free(buf); + return 2; + } + height=0; + while (1) + { + if (height>=iA) + { + iA+=iA; + tmp=realloc(buf,iA*bwidth); + if (!tmp) + { + fprintf(stderr,"Realloc error: %m\n"); + ret=-1; + } + else + { + buf=tmp; + } + } + if (!ret) + { + ret=decode_g4(gst,buf+height*bwidth); + if (ret==1) // done + { + break; + } + else if (ret<0) + { + fprintf(stderr,"Decoder error: %d\n",ret); + } + } + if (ret) // error + { + // Try to write partial result + free_g4(gst); + if (files[0]) + { + fclose(f); + } + ret=write_pbm(files[1],buf,width,height,plain); + if (ret) + { + fprintf(stderr,"PBM writer error: %d\n",ret); + } + free(buf); + return 2; + } + height++; + } + free_g4(gst); + if (files[0]) + { + fclose(f); + } + ret=write_pbm(files[1],buf,width,height,plain); + free(buf); + if (ret) + { + fprintf(stderr,"PBM writer error: %d\n",ret); + return 2; + } + } + else // encode + { + ret=read_pbm(files[0],&buf,&width,&height); + if (ret) + { + fprintf(stderr,"PBM reader error: %d\n",ret); + return 2; + } + if (files[1]) + { + if ((f=fopen(files[1],"w"))==NULL) + { + fprintf(stderr,"Error opening \"%s\" for writing: %m\n",files[1]); + free(buf); + return 3; + } + } + else + { + f=stdout; + } + gst=init_g4_write(k,width,(bits)?wrfunc_bits:wrfunc,f); + if (!gst) + { + fprintf(stderr,"Alloc error: %m\n"); + free(buf); + if (files[1]) + { + fclose(f); + } + return 2; + } + // encode + { + const int bwidth=(width+7)/8; + for (iA=0; iA +#include +#include +#include "lzwcode.h" + +// warnings +#include + +#define LZW_CLEAR 256 +#define LZW_END 257 +#define LZW_START 258 +#define LZW_MINBITS 9 +#define LZW_MAXBITS 12 // max 12 because of table=32 bit +#define LZW_HASHSIZE 9001 // at least 1<>8)&0xfff) +#define CODE(a) ((a>>20)&0xfff) // encode only +#define MAKETABLE(code,prefixcode,nextbyte) ( (code<<20)|(prefixcode<<8)|(nextbyte) ) // for decode: code=0 +// hash func; +#define HASH(prefixcode,nextbyte) ( (((prefixcode<<8)|nextbyte)<<11)%LZW_HASHSIZE ) + +LZWSTATE *init_lzw(int earlychange,READFUNC rf,WRITEFUNC wf,void *user_read,void *user_write,int tablesize,unsigned char *stack) +{ + LZWSTATE *ret; + + if (earlychange<0) + { + earlychange=1; // default + } + + ret=malloc(sizeof(LZWSTATE)); + if (!ret) + { + return 0; + } + + ret->read=rf; + ret->write=wf; + ret->user_read=user_read; + ret->user_write=user_write; + + ret->earlychange=earlychange; + + ret->table=malloc(tablesize*sizeof(unsigned int)); + if (!ret->table) + { + free(ret); + return NULL; + } + ret->stackend=ret->stackptr=stack+(1<numcodes=LZW_START; + state->codebits=LZW_MINBITS; + state->prefix=-1; // no prefix / clear table + state->stackptr=state->stackend; + + state->bitbuf=0; + state->bitpos=0; + } +} + +void free_lzw(LZWSTATE *state) +{ + if (state) + { + free(state->stackend-(1<table); + free(state); + } +} + +// helper +static int readbits(LZWSTATE *state) +{ + int ret,iA; + unsigned char buf[4]; + + if (state->bitposcodebits) // ensure enough bits + { + int num=(state->codebits-state->bitpos+7)/8; + ret=(*state->read)(state->user_read,buf,num); + if (ret) + { + return -1; + } + for (iA=0; iAbitbuf|=buf[iA]<<(24-state->bitpos); + state->bitpos+=8; + } + } + state->bitpos-=state->codebits; + ret=state->bitbuf>>(32-state->codebits); + state->bitbuf<<=state->codebits; + return ret; +} + +static int writecode(LZWSTATE *state,unsigned int code) +{ + unsigned char buf[4]; + int iA=0; + + state->bitbuf|=code<<(32-state->bitpos-state->codebits); + state->bitpos+=state->codebits; + while (state->bitpos>=8) + { + buf[iA++]=state->bitbuf>>24; + state->bitbuf<<=8; + state->bitpos-=8; + } + if (!iA) + { + return 0; + } + return (*state->write)(state->user_write,buf,iA); +} + +static int writeflush(LZWSTATE *state) +{ + unsigned char c; + + assert(state->bitpos<8); + if (!state->bitpos) + { + return 0; + } + c=state->bitbuf>>24; + state->bitbuf=0; + state->bitpos=0; + return (*state->write)(state->user_write,&c,1); +} + +// -> encode +// tries to append >nextbyte to >prefixcode. +// if a matching code is found: this is the new ("longer") prefixcode (>returned) +// otherwise a new code is created (state->numcodes resp. state->numcodes-1) +static inline int find_add_hash(LZWSTATE *state,int prefixcode,unsigned char nextbyte) +{ + unsigned int hash=HASH(prefixcode,nextbyte); + + while (1) + { + unsigned int ret=state->table[hash]; + if (!ret) // empty entry + { + break; + } + if ( (PREFIXCODE(ret)==prefixcode)&&(NEXTBYTE(ret)==nextbyte) ) // found + { + return CODE(ret); + } + hash=(hash+1)%LZW_HASHSIZE; + } + // not found: add entry + state->table[hash]=MAKETABLE(state->numcodes,prefixcode,nextbyte); + state->numcodes++; + return -1; +} + +// TODO: check errors from writecode +int encode_lzw(LZWSTATE *state,unsigned char *buf,int len) +{ + assert(state); + assert(len>=0); + if (!buf) // finish up the stream + { + if (state->prefix>=0) // the current prefixcode won't become any longer + { + writecode(state,state->prefix); + } + // TODO? empty stream: LZW_CLEAR LZW_END + writecode(state,LZW_END); + writeflush(state); + return 0; + } + while (len>0) + { + if (state->prefix==-1) // begin / clear table + { + writecode(state,LZW_CLEAR); + memset(state->table,0,LZW_HASHSIZE*sizeof(unsigned int)); + state->numcodes=LZW_START; + state->codebits=LZW_MINBITS; + state->prefix=*buf; + len--; + buf++; + } + // here we go: find prefixcode + for (; len>0; len--,buf++) + { + int code=find_add_hash(state,state->prefix,*buf); + if (code==-1) // no longer prefix found; new code assigned + { + writecode(state,state->prefix); + state->prefix=*buf; // set new prefix to current char + + if ( ((state->numcodes-1)==(1<codebits)-state->earlychange-1)&& + (state->codebits==LZW_MAXBITS) ) + { + state->prefix=-1; // clear table (one early, so we don't "have to" increase >codebits) + break; + } + else if ((state->numcodes-1)==(1<codebits)-state->earlychange) + { + state->codebits++; + } + } + else + { + state->prefix=code; + } + } + } + return 0; +} + +int decode_lzw(LZWSTATE *state,unsigned char *buf,int len) +{ + int outlen=0; + assert(state); + assert(len>=0); + + while (len>0) + { + // first empty the stack + const int stacklen=state->stackend-state->stackptr; + if (stacklen>0) + { + if (lenstackptr,len*sizeof(char)); + state->stackptr+=len; + return 0; + } + else + { + memcpy(buf,state->stackptr,stacklen*sizeof(char)); + outlen+=stacklen; + len-=stacklen; + buf+=stacklen; + state->stackptr=state->stackend; + continue; // check for len==0; + } + } + // decode next code + int code=readbits(state); + if (code<0) + { + return -1; // read error + } + else if (code==LZW_CLEAR) + { + state->numcodes=LZW_START; + state->codebits=LZW_MINBITS; + state->prefix=-1; + } + else if (code==LZW_END) + { + return 1+outlen; // done + } + else if (code<256) // not in table + { + *buf=code; + buf++; + len--; + outlen++; + if (state->prefix>=0) + { + state->table[state->numcodes++]=MAKETABLE(0,state->prefix,code); + } + state->prefix=code; + } + else if (codenumcodes) + { + int scode=code; + assert(state->prefix>=0); + // push on stack to reverse + while (code>=256) + { + *--state->stackptr=NEXTBYTE(state->table[code]); + code=PREFIXCODE(state->table[code]); + } + *--state->stackptr=code; + // add to table + state->table[state->numcodes++]=MAKETABLE(0,state->prefix,code); + state->prefix=scode; + } + else if (code==state->numcodes) + { + if (state->prefix<0) + { + return -2; // invalid code, a <256 code is required first + } + code=state->prefix; + assert(state->stackptr==state->stackend); // the stack is empty! + --state->stackptr; // will be filled later: first char==last char + while (code>=256) + { + *--state->stackptr=NEXTBYTE(state->table[code]); + code=PREFIXCODE(state->table[code]); + } + *--state->stackptr=code; + state->stackend[-1]=code; + state->table[state->numcodes]=MAKETABLE(0,state->prefix,code); + state->prefix=state->numcodes++; + } + else + { + return -2; // invalid code + } + if (state->numcodes==(1<codebits)-state->earlychange) + { + if (state->codebits==LZW_MAXBITS) + { + // leave table unchanged, keep codebits (see also GIF 89a) +#if 1 // TODO? encode: as long as no high code used (->verbatim coding) there is no need for reset (Adobe PDFLib 5.0 does it!) + state->numcodes--; +#else + code=readbits(state); + if (code<0) + { + return -1; // read error + } + else if (code==LZW_CLEAR) + { + fprintf(stderr,"Warning: overfull table\n"); + state->numcodes=LZW_START; + state->codebits=LZW_MINBITS; + state->prefix=-1; + } + else if (code==LZW_END) + { + fprintf(stderr,"Warning: overfull table\n"); + return 1+outlen; // done + } + else + { + fprintf(stderr,"Warning: over2full table: %d\n",code); +// return -3; // table full + } +#endif + } + else + { + state->codebits++; + } + } + } + return 0; +} diff --git a/src/lzwcode.h b/src/lzwcode.h new file mode 100644 index 0000000..cd022d4 --- /dev/null +++ b/src/lzwcode.h @@ -0,0 +1,47 @@ +#ifndef _LZWCODE_H +#define _LZWCODE_H + +#ifdef __cplusplus +extern "C" { +#endif + +// have to return 0 on success, !=0 on error +typedef int (*WRITEFUNC)(void *user,unsigned char *buf,int len); +typedef int (*READFUNC)(void *user,unsigned char *buf,int len); + +typedef struct LZWSTATE +{ + READFUNC read; + WRITEFUNC write; + void *user_read,*user_write; + + int earlychange; + + int numcodes; // currently used codes + int codebits; // currently used bits + int prefix; // current prefix (encoding) / last code (decoding) + unsigned int *table; // encoding: hash-table (code[12bit],prefixcode[12bit],nextbyte)[hash(prefixcode,nextbyte)] + // decoding: symbol-table (prefixcode,nextbyte)[code] + unsigned char *stackend,*stackptr; // for decoding. + + int bitpos; + unsigned int bitbuf; +} LZWSTATE; + +LZWSTATE *init_lzw_read(int earlychange,READFUNC rf,void *user_read); +LZWSTATE *init_lzw_write(int earlychange,WRITEFUNC wf,void *user_write); +void restart_lzw(LZWSTATE *state); +void free_lzw(LZWSTATE *state); + +// return 0 on success, <0 on error +// to finish the stream: call once with >buf==NULL +int encode_lzw(LZWSTATE *state,unsigned char *buf,int len); +// returns 1+len(really decoded) on EOD +int decode_lzw(LZWSTATE *state,unsigned char *buf,int len); +// TODO: error: "Warning: EOD missing, EOF came first\n" + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/src/lzwcoder.c b/src/lzwcoder.c new file mode 100644 index 0000000..1e2a6cc --- /dev/null +++ b/src/lzwcoder.c @@ -0,0 +1,420 @@ +/** + * LZW Encoder and Decoder + * (c) 2007 by Tobias Hoffmann + */ +#include +#include +#include +#include +#include "pbm.h" +#include "lzwcode.h" + +void usage(const char *name) +{ + printf("LZW En-/Decoder\n" + "(c) 2007 by Tobias Hoffmann\n\n" + + "Usage: %s [-d] [-pbmW] [-h] [-earlyE] [infile] [outfile]\n\n" + + " -d: Decode\n" + " else : Encode\n\n" + + " -earlyE: Enlarge the code length E entries early (default: 1)\n\n" + + " -pbmW: Read/Write pbm-file; using image width W (for decoding)\n\n" + + " -h: Show this help\n\n" +// " -x: Read/Write hexstrings\n\n" + + "If outfile or both infile and outfile are not given\n" + "standard output and maybe standard input are used.\n\n" + ,name); +} + +int wrfunc(void *user,unsigned char *buf,int len) +{ + FILE *f=(FILE *)user; + + return (fwrite(buf,1,len,f)==len)?0:1; +} + +int rdfunc(void *user,unsigned char *buf,int len) +{ + FILE *f=(FILE *)user; + + return (fread(buf,1,len,f)==len)?0:1; +} + +int wrfunc_mem(void *user,unsigned char *buf,int len) +{ + char **tmp=(char **)user; + memcpy(*tmp,buf,len); + *tmp+=len; + return 0; +} + +int rdfunc_mem(void *user,unsigned char *buf,int len) +{ + char **tmp=(char **)user; + memcpy(buf,*tmp,len); + *tmp+=len; + return 0; +} + +int wrfunc_bits(void *user,unsigned char *buf,int len) +{ + FILE *f=(FILE *)user; + int iA; + unsigned char iB; + + for (iA=0; iA0; iB>>=1) + { + if (buf[iA]&iB) + { + putc('1',f); + } + else + { + putc('0',f); + } + } + } + printf("\n"); + for (iA=0; iA=iA) + { + iA+=iA; + tmp=realloc(buf,iA*width); + if (!tmp) + { + fprintf(stderr,"Realloc error: %m\n"); + ret=-1; + break; + } + else + { + buf=tmp; + } + } + ret=decode_lzw(lzw,buf+height*width,width); + if (ret>0) // done + { + if (ret!=1) + { + fprintf(stderr,"Incomplete last line\n"); + } + break; + } + else if (ret<0) + { + fprintf(stderr,"Decoder error: %d\n",ret); + break; + } + height++; + } + } + else + { + while (1) + { + ret=decode_lzw(lzw,buf,BUFSIZE); + if (ret>0) // done + { + int len=ret-1; + ret=fwrite(buf,1,len,g); + if (ret!=len) + { + fprintf(stderr,"Write error: %m\n"); + } + break; + } + else if (ret<0) + { + fprintf(stderr,"Decoder error: %d\n",ret); + break; + } + ret=fwrite(buf,1,BUFSIZE,g); + if (ret!=BUFSIZE) + { + fprintf(stderr,"Write error: %m\n"); + break; + } + } + } + free_lzw(lzw); + if (files[0]) + { + fclose(f); + } + if (pbm) + { + ret=write_pbm(files[1],buf,pbm,height,0); + if (ret) + { + fprintf(stderr,"PBM writer error: %d\n",ret); + free(buf); + return 2; + } + } + else if (files[1]) + { + fclose(g); + } + free(buf); + } + else // encode + { + if (pbm!=0) + { + ret=read_pbm(files[0],&buf,&width,&height); + if (ret) + { + fprintf(stderr,"PBM reader error: %d\n",ret); + return 2; + } + } + else + { + buf=malloc(BUFSIZE); + if (!buf) + { + fprintf(stderr,"Malloc failed: %m\n"); + return 2; + } + if (files[0]) + { + if ((f=fopen(files[0],"r"))==NULL) + { + fprintf(stderr,"Error opening \"%s\" for reading: %m\n",files[0]); + free(buf); + return 2; + } + } + else + { + f=stdin; + } + } + if (files[1]) + { + if ((g=fopen(files[1],"w"))==NULL) + { + fprintf(stderr,"Error opening \"%s\" for writing: %m\n",files[1]); + free(buf); + if ( (!pbm)&&(files[0]) ) + { + fclose(f); + } + return 3; + } + } + else + { + g=stdout; + } +// lzw=init_lzw_write(1,wrfunc_mem,&tmp); + lzw=init_lzw_write(early,wrfunc,g); + if (!lzw) + { + fprintf(stderr,"Alloc error: %m\n"); + free(buf); + if ( (!pbm)&&(files[0]) ) + { + fclose(f); + } + if (files[1]) + { + fclose(g); + } + return 2; + } + // encode + if (pbm) + { + ret=encode_lzw(lzw,buf,(width+7)/8*height); + } + else + { + int len; + while ((len=fread(buf,1,BUFSIZE,f))>0) + { + ret=encode_lzw(lzw,buf,len); + if (ret) + { + break; + } + } + } + free(buf); + if (!ret) + { + ret=encode_lzw(lzw,NULL,0); + } + free_lzw(lzw); + if ( (!pbm)&&(files[0]) ) + { + fclose(f); + } + if (files[1]) + { + fclose(g); + } + if (ret) + { + fprintf(stderr,"Encoder error: %d\n",ret); + return 2; + } + } + + return 0; +} diff --git a/src/pbm.c b/src/pbm.c new file mode 100644 index 0000000..5087e4f --- /dev/null +++ b/src/pbm.c @@ -0,0 +1,222 @@ +#include +#include +#include +#include "pbm.h" + +int read_pbm(const char *filename,unsigned char **buf,int *width,int *height) +{ + FILE *f=stdin; + int iA,iB,plain; + char tmp[256],c; + unsigned char iC,*out; + + assert( (buf)&&(width)&&(height) ); + if (filename) + { + if ((f=fopen(filename,"r"))==NULL) + { + return -1; + } + } + + fread(tmp,2,1,f); + if (tmp[0]!='P') + { + return -2; + } + if (tmp[1]=='1') // P1 + { + plain=1; + } + else if (tmp[1]=='4') // P4 + { + plain=0; + } + else + { + return -2; + } + + // read header + // skip to number + do + { + c=getc(f); + if (c=='#') + { + while (c!='\n') + { + c=getc(f); + } + } + } + while ( (c==' ')||(c=='\r')||(c=='\n')||(c=='\t') ); + // read width + iA=0; + while ( (c>='0')&&(c<='9') ) + { + iA=(iA*10)+(c-'0'); + c=getc(f); + } + if (!iA) + { + return -2; + } + // skip ws + while ( (c==' ')||(c=='\r')||(c=='\n')||(c=='\t') ) + { + c=getc(f); + } + // read height + iB=0; + while ( (c>='0')&&(c<='9') ) + { + iB=(iB*10)+(c-'0'); + c=getc(f); + } + if (!iB) + { + return -2; + } + if ( (c!=' ')&&(c!='\r')&&(c!='\n')&&(c!='\t') ) + { + return -2; + } + + // allocate buffer, if necessary + if (*buf) + { + if (iA*iB>(*width)*(*height)) + { + free(*buf); + *buf=malloc((iA+7)/8*iB); + } + } + else + { + *buf=malloc((iA+7)/8*iB); + } + if (!*buf) // malloc failed + { + return -3; + } + *width=iA; + *height=iB; + + if (plain) + { + out=*buf; + for (; iB>0; iB--) + { + for (iA=*width; iA>0;) + { + *out=0; + for (iC=0x80; (iC>0)&&(iA>0); iC>>=1,iA--) + { + do + { + c=fgetc(f); + } + while ( (c==' ')||(c=='\r')||(c=='\n')||(c=='\t') ); + if (c=='1') + { + *out|=iC; + } + else if (c!='0') + { + return -2; + } + } + out++; + } + } + } + else + { + const int bwidth=(*width+7)/8; + fread(*buf,bwidth,*height,f); + } + + if (filename) + { + fclose(f); + } + return 0; // TODO: check returncodes +} + +void writebits(FILE *f,unsigned char c,unsigned char endbit) +{ + unsigned char iA; + for (iA=0x80; iA>endbit; iA>>=1) + { + if (c&iA) + { + putc('1',f); + } + else + { + putc('0',f); + } + } +} + +int write_pbm(const char *filename,unsigned char *buf,int width,int height,int plain) +{ + FILE *f=stdout; + int iA,iB; + const int bwidth=(width+7)/8,bmod=((width-1)&7)+1; + + if (filename) + { + if ((f=fopen(filename,"w"))==NULL) + { + return -1; + } + } + if (plain) // P1 + { + fprintf(f,"P1 %d %d\n",width,height); + for (iA=0; iA>bmod); + putc('\n',f); + } + } + else // P4 + { + fprintf(f,"P4 %d %d\n",width,height); + fwrite(buf,bwidth,height,f); + } + if (filename) + { + fclose(f); + } + return 0; // TODO: check returncodes +} + +/* + * TIFF HINTS: +Header: + short byte_order_indication; 0x4949 or 0x4d4d; (01001001 or 01001101); Little-endian or Big-endian + short version=42; + ulong ptr_to_ifd; // SEEK_POS, must !=0 + +IFD: have to start on word boundaries! (=^= page / image). Baseline needs only to read first + short no_of_tags_in_ifd; // must >=1 + TAGDATA tag_data[no_of_tags_in_ifd]; + ulong (@2+no_of_tags_in_ifd*12) ptr_to_ifd; // or 0 + +TAGDATA: 12 byte + short tag_id; + short datatype; // 1=ubyte, 2=7bit ASCII,NUL-terminated (may multiple, using num_of_values(bytes)), 3=ushort, 4=ulong, 5=ulong + ulong, a/b + // maybe: 6=sbyte, 7=undef char, 8=sshort, 9=slong, 10=slong+slong, 11=float, 12=double + ulong num_of_values; + ulong ptr_to_values_data; // or special case - datatype*num_of_values <=4 byte - the valuedata itself + +need much support! e.g. strips, maybe tiles, ColorInterpretation, maybe uncompressed mode,... + */ diff --git a/src/pbm.h b/src/pbm.h new file mode 100644 index 0000000..a9a8e1f --- /dev/null +++ b/src/pbm.h @@ -0,0 +1,10 @@ +#ifndef _PBM_H +#define _PBM_H + +// return 0 on success +// if >filename==NULL stdin resp. stdout is used +// read will allocate memory if *buf==NULL or free and allocate if (*width+7)/8*(*height) too small +int read_pbm(const char *filename,unsigned char **buf,int *width,int *height); +int write_pbm(const char *filename,unsigned char *buf,int width,int height,int plain); + +#endif diff --git a/src/tables.h b/src/tables.h new file mode 100644 index 0000000..350076a --- /dev/null +++ b/src/tables.h @@ -0,0 +1,271 @@ +#ifndef _TABLES_H +#define _TABLES_H + +// also fix opcode-encoding table! +#define EOL -2 +#define FILL -3 +#define EOL0 0 // not for decoding +#define EOL1 -1 + +#define OP_P -5 +#define OP_H -6 +#define OP_VR3 -7 +#define OP_VR2 -8 +#define OP_VR1 -9 +#define OP_V -10 +#define OP_VL1 -11 +#define OP_VL2 -12 +#define OP_VL3 -13 +#define OP_EXT -14 + +#define MAX_OP 15 + +// 6bit decoding Table for white huffmann codes +#define DECODE_COLORHUFF_BITS 6 +unsigned short whitehufftable[1280]= +{ + 320, 1152, 896,0x600d, 128, 832, 192,0x6001,0x600c, 448, 1024, 256, 704, 64,0x500a,0x500a, + 0x500b,0x500b, 576, 384, 960, 1088, 512,0x60c0,0x6680, 640, 1216, 768,0x4002,0x4002,0x4002,0x4002, + 0x4003,0x4003,0x4003,0x4003,0x5080,0x5080,0x5008,0x5008,0x5009,0x5009,0x6010,0x6011,0x4004,0x4004,0x4004,0x4004, + 0x4005,0x4005,0x4005,0x4005,0x600e,0x600f,0x5040,0x5040,0x4006,0x4006,0x4006,0x4006,0x4007,0x4007,0x4007,0x4007, + 0x803f,0x803f,0x803f,0x803f,0x803f,0x803f,0x803f,0x803f,0x803f,0x803f,0x803f,0x803f,0x803f,0x803f,0x803f,0x803f, + 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, + 0x8140,0x8140,0x8140,0x8140,0x8140,0x8140,0x8140,0x8140,0x8140,0x8140,0x8140,0x8140,0x8140,0x8140,0x8140,0x8140, + 0x8180,0x8180,0x8180,0x8180,0x8180,0x8180,0x8180,0x8180,0x8180,0x8180,0x8180,0x8180,0x8180,0x8180,0x8180,0x8180, + 0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014, + 0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014,0x7014, + 0x8021,0x8021,0x8021,0x8021,0x8021,0x8021,0x8021,0x8021,0x8021,0x8021,0x8021,0x8021,0x8021,0x8021,0x8021,0x8021, + 0x8022,0x8022,0x8022,0x8022,0x8022,0x8022,0x8022,0x8022,0x8022,0x8022,0x8022,0x8022,0x8022,0x8022,0x8022,0x8022, + 0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013, + 0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013,0x7013, + 0x801f,0x801f,0x801f,0x801f,0x801f,0x801f,0x801f,0x801f,0x801f,0x801f,0x801f,0x801f,0x801f,0x801f,0x801f,0x801f, + 0x8020,0x8020,0x8020,0x8020,0x8020,0x8020,0x8020,0x8020,0x8020,0x8020,0x8020,0x8020,0x8020,0x8020,0x8020,0x8020, + 0x802b,0x802b,0x802b,0x802b,0x802b,0x802b,0x802b,0x802b,0x802b,0x802b,0x802b,0x802b,0x802b,0x802b,0x802b,0x802b, + 0x802c,0x802c,0x802c,0x802c,0x802c,0x802c,0x802c,0x802c,0x802c,0x802c,0x802c,0x802c,0x802c,0x802c,0x802c,0x802c, + 0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015, + 0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015,0x7015, + 0xcffd,0xcffe, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // FILL, EOL + 0xb700,0xb700,0xc7c0,0xc800,0xc840,0xc880,0xc8c0,0xc900,0xb740,0xb740,0xb780,0xb780,0xc940,0xc980,0xc9c0,0xca00, + 0x801d,0x801d,0x801d,0x801d,0x801d,0x801d,0x801d,0x801d,0x801d,0x801d,0x801d,0x801d,0x801d,0x801d,0x801d,0x801d, + 0x801e,0x801e,0x801e,0x801e,0x801e,0x801e,0x801e,0x801e,0x801e,0x801e,0x801e,0x801e,0x801e,0x801e,0x801e,0x801e, + 0x95c0,0x95c0,0x95c0,0x95c0,0x95c0,0x95c0,0x95c0,0x95c0,0x9600,0x9600,0x9600,0x9600,0x9600,0x9600,0x9600,0x9600, + 0x9640,0x9640,0x9640,0x9640,0x9640,0x9640,0x9640,0x9640,0x96c0,0x96c0,0x96c0,0x96c0,0x96c0,0x96c0,0x96c0,0x96c0, + 0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012, + 0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012,0x7012, + 0x8035,0x8035,0x8035,0x8035,0x8035,0x8035,0x8035,0x8035,0x8035,0x8035,0x8035,0x8035,0x8035,0x8035,0x8035,0x8035, + 0x8036,0x8036,0x8036,0x8036,0x8036,0x8036,0x8036,0x8036,0x8036,0x8036,0x8036,0x8036,0x8036,0x8036,0x8036,0x8036, + 0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a, + 0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a,0x701a, + 0x8037,0x8037,0x8037,0x8037,0x8037,0x8037,0x8037,0x8037,0x8037,0x8037,0x8037,0x8037,0x8037,0x8037,0x8037,0x8037, + 0x8038,0x8038,0x8038,0x8038,0x8038,0x8038,0x8038,0x8038,0x8038,0x8038,0x8038,0x8038,0x8038,0x8038,0x8038,0x8038, + 0x8039,0x8039,0x8039,0x8039,0x8039,0x8039,0x8039,0x8039,0x8039,0x8039,0x8039,0x8039,0x8039,0x8039,0x8039,0x8039, + 0x803a,0x803a,0x803a,0x803a,0x803a,0x803a,0x803a,0x803a,0x803a,0x803a,0x803a,0x803a,0x803a,0x803a,0x803a,0x803a, + 0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b, + 0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b,0x701b, + 0x803b,0x803b,0x803b,0x803b,0x803b,0x803b,0x803b,0x803b,0x803b,0x803b,0x803b,0x803b,0x803b,0x803b,0x803b,0x803b, + 0x803c,0x803c,0x803c,0x803c,0x803c,0x803c,0x803c,0x803c,0x803c,0x803c,0x803c,0x803c,0x803c,0x803c,0x803c,0x803c, + 0x81c0,0x81c0,0x81c0,0x81c0,0x81c0,0x81c0,0x81c0,0x81c0,0x81c0,0x81c0,0x81c0,0x81c0,0x81c0,0x81c0,0x81c0,0x81c0, + 0x8200,0x8200,0x8200,0x8200,0x8200,0x8200,0x8200,0x8200,0x8200,0x8200,0x8200,0x8200,0x8200,0x8200,0x8200,0x8200, + 0x92c0,0x92c0,0x92c0,0x92c0,0x92c0,0x92c0,0x92c0,0x92c0,0x9300,0x9300,0x9300,0x9300,0x9300,0x9300,0x9300,0x9300, + 0x8280,0x8280,0x8280,0x8280,0x8280,0x8280,0x8280,0x8280,0x8280,0x8280,0x8280,0x8280,0x8280,0x8280,0x8280,0x8280, + 0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c, + 0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c,0x701c, + 0x803d,0x803d,0x803d,0x803d,0x803d,0x803d,0x803d,0x803d,0x803d,0x803d,0x803d,0x803d,0x803d,0x803d,0x803d,0x803d, + 0x803e,0x803e,0x803e,0x803e,0x803e,0x803e,0x803e,0x803e,0x803e,0x803e,0x803e,0x803e,0x803e,0x803e,0x803e,0x803e, + 0x94c0,0x94c0,0x94c0,0x94c0,0x94c0,0x94c0,0x94c0,0x94c0,0x9500,0x9500,0x9500,0x9500,0x9500,0x9500,0x9500,0x9500, + 0x9540,0x9540,0x9540,0x9540,0x9540,0x9540,0x9540,0x9540,0x9580,0x9580,0x9580,0x9580,0x9580,0x9580,0x9580,0x9580, + 0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100, + 0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100,0x7100, + 0x8023,0x8023,0x8023,0x8023,0x8023,0x8023,0x8023,0x8023,0x8023,0x8023,0x8023,0x8023,0x8023,0x8023,0x8023,0x8023, + 0x8024,0x8024,0x8024,0x8024,0x8024,0x8024,0x8024,0x8024,0x8024,0x8024,0x8024,0x8024,0x8024,0x8024,0x8024,0x8024, + 0x8025,0x8025,0x8025,0x8025,0x8025,0x8025,0x8025,0x8025,0x8025,0x8025,0x8025,0x8025,0x8025,0x8025,0x8025,0x8025, + 0x8026,0x8026,0x8026,0x8026,0x8026,0x8026,0x8026,0x8026,0x8026,0x8026,0x8026,0x8026,0x8026,0x8026,0x8026,0x8026, + 0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017, + 0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017,0x7017, + 0x802f,0x802f,0x802f,0x802f,0x802f,0x802f,0x802f,0x802f,0x802f,0x802f,0x802f,0x802f,0x802f,0x802f,0x802f,0x802f, + 0x8030,0x8030,0x8030,0x8030,0x8030,0x8030,0x8030,0x8030,0x8030,0x8030,0x8030,0x8030,0x8030,0x8030,0x8030,0x8030, + 0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018, + 0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018,0x7018, + 0x8031,0x8031,0x8031,0x8031,0x8031,0x8031,0x8031,0x8031,0x8031,0x8031,0x8031,0x8031,0x8031,0x8031,0x8031,0x8031, + 0x8032,0x8032,0x8032,0x8032,0x8032,0x8032,0x8032,0x8032,0x8032,0x8032,0x8032,0x8032,0x8032,0x8032,0x8032,0x8032, + 0x8027,0x8027,0x8027,0x8027,0x8027,0x8027,0x8027,0x8027,0x8027,0x8027,0x8027,0x8027,0x8027,0x8027,0x8027,0x8027, + 0x8028,0x8028,0x8028,0x8028,0x8028,0x8028,0x8028,0x8028,0x8028,0x8028,0x8028,0x8028,0x8028,0x8028,0x8028,0x8028, + 0x8029,0x8029,0x8029,0x8029,0x8029,0x8029,0x8029,0x8029,0x8029,0x8029,0x8029,0x8029,0x8029,0x8029,0x8029,0x8029, + 0x802a,0x802a,0x802a,0x802a,0x802a,0x802a,0x802a,0x802a,0x802a,0x802a,0x802a,0x802a,0x802a,0x802a,0x802a,0x802a, + 0x8033,0x8033,0x8033,0x8033,0x8033,0x8033,0x8033,0x8033,0x8033,0x8033,0x8033,0x8033,0x8033,0x8033,0x8033,0x8033, + 0x8034,0x8034,0x8034,0x8034,0x8034,0x8034,0x8034,0x8034,0x8034,0x8034,0x8034,0x8034,0x8034,0x8034,0x8034,0x8034, + 0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019, + 0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019,0x7019, + 0x802d,0x802d,0x802d,0x802d,0x802d,0x802d,0x802d,0x802d,0x802d,0x802d,0x802d,0x802d,0x802d,0x802d,0x802d,0x802d, + 0x802e,0x802e,0x802e,0x802e,0x802e,0x802e,0x802e,0x802e,0x802e,0x802e,0x802e,0x802e,0x802e,0x802e,0x802e,0x802e, + 0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016, + 0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016,0x7016, + 0x8240,0x8240,0x8240,0x8240,0x8240,0x8240,0x8240,0x8240,0x8240,0x8240,0x8240,0x8240,0x8240,0x8240,0x8240,0x8240, + 0x9340,0x9340,0x9340,0x9340,0x9340,0x9340,0x9340,0x9340,0x9380,0x9380,0x9380,0x9380,0x9380,0x9380,0x9380,0x9380, + 0x93c0,0x93c0,0x93c0,0x93c0,0x93c0,0x93c0,0x93c0,0x93c0,0x9400,0x9400,0x9400,0x9400,0x9400,0x9400,0x9400,0x9400, + 0x9440,0x9440,0x9440,0x9440,0x9440,0x9440,0x9440,0x9440,0x9480,0x9480,0x9480,0x9480,0x9480,0x9480,0x9480,0x9480 +}; + +// 6bit decoding Table for black huffmann codes +unsigned short blackhufftable[960]= +{ + 64, 128, 512, 192,0x6009,0x6008,0x5007,0x5007,0x4006,0x4006,0x4006,0x4006,0x4005,0x4005,0x4005,0x4005, + 0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3004,0x3004,0x3004,0x3004,0x3004,0x3004,0x3004,0x3004, + 0x2003,0x2003,0x2003,0x2003,0x2003,0x2003,0x2003,0x2003,0x2003,0x2003,0x2003,0x2003,0x2003,0x2003,0x2003,0x2003, + 0x2002,0x2002,0x2002,0x2002,0x2002,0x2002,0x2002,0x2002,0x2002,0x2002,0x2002,0x2002,0x2002,0x2002,0x2002,0x2002, + 0xcffd,0xcffe, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // FILL, EOL + 0xb700,0xb700,0xc7c0,0xc800,0xc840,0xc880,0xc8c0,0xc900,0xb740,0xb740,0xb780,0xb780,0xc940,0xc980,0xc9c0,0xca00, + 0xa012,0xa012,0xa012,0xa012,0xc034, 768, 640,0xc037,0xc038, 384, 448,0xc03b,0xc03c, 576,0xb018,0xb018, + 0xb019,0xb019, 256,0xc140,0xc180,0xc1c0, 320,0xc035,0xc036, 832, 704, 896,0xa040,0xa040,0xa040,0xa040, + 0x800d,0x800d,0x800d,0x800d,0x800d,0x800d,0x800d,0x800d,0x800d,0x800d,0x800d,0x800d,0x800d,0x800d,0x800d,0x800d, + 0xb017,0xb017,0xc032,0xc033,0xc02c,0xc02d,0xc02e,0xc02f,0xc039,0xc03a,0xc03d,0xc100,0xa010,0xa010,0xa010,0xa010, + 0xa011,0xa011,0xa011,0xa011,0xc030,0xc031,0xc03e,0xc03f,0xc01e,0xc01f,0xc020,0xc021,0xc028,0xc029,0xb016,0xb016, + 0x800e,0x800e,0x800e,0x800e,0x800e,0x800e,0x800e,0x800e,0x800e,0x800e,0x800e,0x800e,0x800e,0x800e,0x800e,0x800e, + 0x900f,0x900f,0x900f,0x900f,0x900f,0x900f,0x900f,0x900f,0xc080,0xc0c0,0xc01a,0xc01b,0xc01c,0xc01d,0xb013,0xb013, + 0xb014,0xb014,0xc022,0xc023,0xc024,0xc025,0xc026,0xc027,0xb015,0xb015,0xc02a,0xc02b,0xa000,0xa000,0xa000,0xa000, + 0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c, + 0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c,0x700c, + 0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680, + 0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680,0xd680, + 0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0, + 0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0,0xd6c0, + 0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200, + 0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200,0xd200, + 0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240, + 0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240,0xd240, + 0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500, + 0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500,0xd500, + 0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540, + 0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540,0xd540, + 0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580, + 0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580,0xd580, + 0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0, + 0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0,0xd5c0, + 0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a, + 0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a,0x700a, + 0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b, + 0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b,0x700b, + 0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600, + 0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600,0xd600, + 0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640, + 0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640,0xd640, + 0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300, + 0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300,0xd300, + 0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340, + 0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340,0xd340, + 0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400, + 0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400,0xd400, + 0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440, + 0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440,0xd440, + 0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280, + 0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280,0xd280, + 0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0, + 0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0,0xd2c0, + 0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380, + 0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380,0xd380, + 0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0, + 0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0,0xd3c0, + 0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480, + 0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480,0xd480, + 0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0, + 0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0,0xd4c0 +}; + +// 4bit decoding Table for Opcodes +#define DECODE_OPCODE_BITS 4 +unsigned short opcodetable[48]= // OP: 0x(width)+1+OP_C +{ + 16,0x4ffb,0x3ffa,0x3ffa,0x3ff5,0x3ff5,0x3ff7,0x3ff7, // OP_P, OP_H, OP_H, OP_VL1, OP_VL1, OP_VR1, OP_VR1 + 0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6, // OP_V + 32, -1,0x7ff2,0x7ff2,0x7ff3,0x7ff3,0x7ff9,0x7ff9, // OP_EXT, OP_EXT, OP_VL3, OP_VL3, OP_VL3, OP_VR3 + 0x6ff4,0x6ff4,0x6ff4,0x6ff4,0x6ff8,0x6ff8,0x6ff8,0x6ff8, // OP_VL2, OP_VR2 + -1,0xcffe,0xbffc, -1, -1, -1, -1, -1, // EOL, SEOL + -1, -1, -1, -1, -1, -1, -1, -1 +}; + +// Encoding +typedef struct +{ + char len; + unsigned short bits; +} ENCHUFF; + +// whitehuff: 0..63,64,128,192,...,2560 +ENCHUFF whitehuff[104]= +{ + { 8,0x3500},{ 6,0x1c00},{ 4,0x7000},{ 4,0x8000},{ 4,0xb000},{ 4,0xc000},{ 4,0xe000},{ 4,0xf000}, + { 5,0x9800},{ 5,0xa000},{ 5,0x3800},{ 5,0x4000},{ 6,0x2000},{ 6,0x0c00},{ 6,0xd000},{ 6,0xd400}, + { 6,0xa800},{ 6,0xac00},{ 7,0x4e00},{ 7,0x1800},{ 7,0x1000},{ 7,0x2e00},{ 7,0x0600},{ 7,0x0800}, + { 7,0x5000},{ 7,0x5600},{ 7,0x2600},{ 7,0x4800},{ 7,0x3000},{ 8,0x0200},{ 8,0x0300},{ 8,0x1a00}, + { 8,0x1b00},{ 8,0x1200},{ 8,0x1300},{ 8,0x1400},{ 8,0x1500},{ 8,0x1600},{ 8,0x1700},{ 8,0x2800}, + { 8,0x2900},{ 8,0x2a00},{ 8,0x2b00},{ 8,0x2c00},{ 8,0x2d00},{ 8,0x0400},{ 8,0x0500},{ 8,0x0a00}, + { 8,0x0b00},{ 8,0x5200},{ 8,0x5300},{ 8,0x5400},{ 8,0x5500},{ 8,0x2400},{ 8,0x2500},{ 8,0x5800}, + { 8,0x5900},{ 8,0x5a00},{ 8,0x5b00},{ 8,0x4a00},{ 8,0x4b00},{ 8,0x3200},{ 8,0x3300},{ 8,0x3400}, + + { 5,0xd800},{ 5,0x9000},{ 6,0x5c00},{ 7,0x6e00},{ 8,0x3600},{ 8,0x3700},{ 8,0x6400},{ 8,0x6500}, + { 8,0x6800},{ 8,0x6700},{ 9,0x6600},{ 9,0x6680},{ 9,0x6900},{ 9,0x6980},{ 9,0x6a00},{ 9,0x6a80}, + { 9,0x6b00},{ 9,0x6b80},{ 9,0x6c00},{ 9,0x6c80},{ 9,0x6d00},{ 9,0x6d80},{ 9,0x4c00},{ 9,0x4c80}, + { 9,0x4d00},{ 6,0x6000},{ 9,0x4d80},{11,0x0100},{11,0x0180},{11,0x01a0},{12,0x0120},{12,0x0130}, + {12,0x0140},{12,0x0150},{12,0x0160},{12,0x0170},{12,0x01c0},{12,0x01d0},{12,0x01e0},{12,0x01f0} +}; + +// blackhuff: 0..63,64,128,192,...,2560 +ENCHUFF blackhuff[104]= +{ + {10,0x0dc0},{ 3,0x4000},{ 2,0xc000},{ 2,0x8000},{ 3,0x6000},{ 4,0x3000},{ 4,0x2000},{ 5,0x1800}, + { 6,0x1400},{ 6,0x1000},{ 7,0x0800},{ 7,0x0a00},{ 7,0x0e00},{ 8,0x0400},{ 8,0x0700},{ 9,0x0c00}, + {10,0x05c0},{10,0x0600},{10,0x0200},{11,0x0ce0},{11,0x0d00},{11,0x0d80},{11,0x06e0},{11,0x0500}, + {11,0x02e0},{11,0x0300},{12,0x0ca0},{12,0x0cb0},{12,0x0cc0},{12,0x0cd0},{12,0x0680},{12,0x0690}, + {12,0x06a0},{12,0x06b0},{12,0x0d20},{12,0x0d30},{12,0x0d40},{12,0x0d50},{12,0x0d60},{12,0x0d70}, + {12,0x06c0},{12,0x06d0},{12,0x0da0},{12,0x0db0},{12,0x0540},{12,0x0550},{12,0x0560},{12,0x0570}, + {12,0x0640},{12,0x0650},{12,0x0520},{12,0x0530},{12,0x0240},{12,0x0370},{12,0x0380},{12,0x0270}, + {12,0x0280},{12,0x0580},{12,0x0590},{12,0x02b0},{12,0x02c0},{12,0x05a0},{12,0x0660},{12,0x0670}, + + {10,0x03c0},{12,0x0c80},{12,0x0c90},{12,0x05b0},{12,0x0330},{12,0x0340},{12,0x0350},{13,0x0360}, + {13,0x0368},{13,0x0250},{13,0x0258},{13,0x0260},{13,0x0268},{13,0x0390},{13,0x0398},{13,0x03a0}, + {13,0x03a8},{13,0x03b0},{13,0x03b8},{13,0x0290},{13,0x0298},{13,0x02a0},{13,0x02a8},{13,0x02d0}, + {13,0x02d8},{13,0x0320},{13,0x0328},{11,0x0100},{11,0x0180},{11,0x01a0},{12,0x0120},{12,0x0130}, + {12,0x0140},{12,0x0150},{12,0x0160},{12,0x0170},{12,0x01c0},{12,0x01d0},{12,0x01e0},{12,0x01f0} +}; + +// Opcodes with code OP_? at position -OP_? ! +ENCHUFF opcode[MAX_OP]= +{ + {13,0x0010}, // EOL0, encode only + {13,0x0018}, // EOL1, encode only + {12,0x0010}, // EOL + {12,0x0000}, // "FILL" just for completeness... + {-1,-1}, + { 4,0x1000}, // OP_P + { 3,0x2000}, // OP_H + { 7,0x0600}, // OP_VR3 + { 6,0x0c00}, // OP_VR2 + { 3,0x6000}, // OP_VR1 + { 1,0x8000}, // OP_V + { 3,0x4000}, // OP_VL1 + { 6,0x0800}, // OP_VL2 + { 7,0x0400}, // OP_VL3 + { 7,0x0200} // OP_EXT +}; + +// Table for RLE-encoding +int rlecode[128]= +{ + 0x00000008,0x00000017,0x00000116,0x00000026,0x00000215,0x00001115,0x00000125,0x00000035, + 0x00000314,0x00001214,0x00011114,0x00002114,0x00000224,0x00001124,0x00000134,0x00000044, + 0x00000413,0x00001313,0x00011213,0x00002213,0x00021113,0x00111113,0x00012113,0x00003113, + 0x00000323,0x00001223,0x00011123,0x00002123,0x00000233,0x00001133,0x00000143,0x00000053, + 0x00000512,0x00001412,0x00011312,0x00002312,0x00021212,0x00111212,0x00012212,0x00003212, + 0x00031112,0x00121112,0x01111112,0x00211112,0x00022112,0x00112112,0x00013112,0x00004112, + 0x00000422,0x00001322,0x00011222,0x00002222,0x00021122,0x00111122,0x00012122,0x00003122, + 0x00000332,0x00001232,0x00011132,0x00002132,0x00000242,0x00001142,0x00000152,0x00000062, + 0x00000611,0x00001511,0x00011411,0x00002411,0x00021311,0x00111311,0x00012311,0x00003311, + 0x00031211,0x00121211,0x01111211,0x00211211,0x00022211,0x00112211,0x00013211,0x00004211, + 0x00041111,0x00131111,0x01121111,0x00221111,0x02111111,0x11111111,0x01211111,0x00311111, + 0x00032111,0x00122111,0x01112111,0x00212111,0x00023111,0x00113111,0x00014111,0x00005111, + 0x00000521,0x00001421,0x00011321,0x00002321,0x00021221,0x00111221,0x00012221,0x00003221, + 0x00031121,0x00121121,0x01111121,0x00211121,0x00022121,0x00112121,0x00013121,0x00004121, + 0x00000431,0x00001331,0x00011231,0x00002231,0x00021131,0x00111131,0x00012131,0x00003131, + 0x00000341,0x00001241,0x00011141,0x00002141,0x00000251,0x00001151,0x00000161,0x00000071 +}; +#endif