/* sff2jpeg - convert sff group 3 fax files to jpeg. Copyright (C) 2002,2003 Matthias Kramm This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "tables.h" #include "sff.h" typedef unsigned char byte; typedef unsigned short int word; typedef unsigned long int dword; struct hufflookup { int len; int runlen; int type; // 0 = makeup }; static int tables_ok = 0; static struct hufflookup white[8192]; static struct hufflookup black[8192]; static unsigned char line[2048]; static int lines = 0; static int currentline = 0; static char gfxline[4096]; static int pixlen = 1728; static int currentpage = 0; static char debug; int xmax=-1,ymax=-1; static struct FaxPage destfaxpage; static void decodeline(int len) { int bitpos = 0; char color = 1; //white struct hufflookup*table = white; int runlen = 0; int x = 0; line[len] = line[len+1]=line[len+2] = 0; while(bitpos>>3 < len) { int bytepos = bitpos>>3; dword data = ((line[bytepos]+(line[bytepos+1]<<8)+(line[bytepos+2]<<16)) >> (bitpos&7))&8191; if(table[data].len < 0) { printf("decoding error 1 in line %d, x%d %08x(%d) of %d [%08x]\n", lines, x, bitpos, bytepos, len, data); return; } if(table[data].type==2) { printf("eol in line %d, x%d %08x(%d) of %d\n", lines, x, bitpos, bytepos, len); return; } //printf("%08x col:%d run:%d\n", data, color, table[data].runlen); bitpos += table[data].len; runlen += table[data].runlen; if(!table[data].type) // makeup code continue; if(runlen) do { if(x>=pixlen) { printf("decoding error 2 in line %d, x%d %08x(%d) of %d\n", lines, x, bitpos, bytepos, len); return; } gfxline[x] = color; x++; } while(--runlen); color = 1 - color; if(color) table = white; else table = black; if(x>=pixlen) break; } } static void handleline() { if(currentpage && destfaxpage.pagenr == currentpage-1) { memcpy(&destfaxpage.data[destfaxpage.scanline*lines], gfxline, pixlen); } } static void readline(FILE*fi, int bytes) { if(bytes > 2047) { printf("line to long:%d\n", lines); exit(1); } fread(line,bytes,1,fi); decodeline(bytes); handleline(); //printf("decoded line %d\n", lines); lines++; } static void skipline() { memset(gfxline, 1, pixlen); handleline(); lines++; } static void processtable(struct huffcode*src, struct hufflookup*dest, int type) { int t=0; while(src[t].code) { int s=0,d=0,k=1,l=strlen(src[t].code); if(l != src[t].len || l>13 || l<=0) { printf("Error in tables\n"); exit(1); } for(s=0;s=0) { printf("Duplicate entry\n"); exit(1); } dest[pos].len = src[t].len; dest[pos].runlen = src[t].run; dest[pos].type = type; } t++; } } static int readfax(char * filename) { FILE*fi; char a[4]; byte version; byte reserved; word user_info; word num_pages; word first_page; dword last_page; dword file_size; int t; currentpage = 0; if(!tables_ok) { for(t=0;t<8192;t++) { white[t].len = -1; white[t].runlen = -1; black[t].len = -1; black[t].runlen = -1; } processtable(makeupwhite, white,0); processtable(termwhite, white,1); processtable(makeupblack, black,0); processtable(termblack, black,1); processtable(extmakeup, white,0); processtable(extmakeup, black,0); processtable(term, white,2); processtable(term, black,2); tables_ok = 1; } fi = fopen(filename, "rb"); fread(a,4,1,fi); if(strncmp(a,"Sfff",4)) fprintf(stderr, "Not a fax file!\n"); fread(&version,1,1,fi); fread(&reserved,1,1,fi); fread(&user_info,2,1,fi); fread(&num_pages,2,1,fi); fread(&first_page,2,1,fi); fread(&last_page,4,1,fi); fread(&file_size,4,1,fi); if(debug) { printf("Version:%d\n",version); printf("Reserved:%02x\n",reserved); printf("User Info:%04x\n",user_info); printf("%d pages, %d/%d, %d bytes\n", num_pages, first_page, last_page, file_size); } fseek(fi,first_page, SEEK_SET); /* currentpage header */ do { lines = 0; while(1) { byte b; fread(&b,1,1,fi); if(!b) { dword len; fread(&len,4,1,fi); if(len<=216 || len>=32768) { printf("reserved(1)\n"); exit(1); } readline(fi,len); } else if(b>=1 && b<=216) { readline(fi,b); } else if(b>=217 && b<=253) { int t; for(t=0;t0) printf("End of fax page\n"); break; } else if(b==255) { char c; fread(&c,1,1,fi); if(!c) { printf("255-0 line!\n"); exit(1); } else { int t; char a; for(t=0;t0) { if(debug) printf("fax page %d has %d lines.\n", currentpage, lines); } if(lines > ymax) { ymax = lines; } { byte vert_res; byte horiz_res; byte coding; byte specials; word linelen; word pagelen; dword prev_page; dword next_page; byte len; int pos; fread(&len,1,1,fi); pos = ftell(fi); if(len == 0) break; // last currentpage if(debug) printf(" === page %d === \n", currentpage+1); fread(&vert_res,1,1,fi); fread(&horiz_res,1,1,fi); fread(&coding,1,1,fi); fread(&specials,1,1,fi); fread(&linelen,2,1,fi); fread(&pagelen,2,1,fi); fread(&prev_page,4,1,fi); fread(&next_page,4,1,fi); if(linelen>xmax) xmax = linelen; if(debug) { printf("Vertical resolution: [code %d] %s\n", vert_res, vert_res==0?"98":(vert_res==1?"196":"unknown")); printf("Horizontal resolution: [code %d] %s\n", horiz_res, horiz_res==0?"98":"unknown"); printf("coding:%d (%s), specials:%d (%s), linelen:%d (%s)\n", coding, coding?"unknown":"MH", specials, specials?"unknown":"none", linelen, (linelen==1728)?"Standard":((linelen==2048)?"B4":((linelen==2432)?"A3":"unknown"))); } pixlen = linelen; // set global variable if(debug) { printf("pagelen:%d (%s), prevpage:%04x (%s), nextpage:%04x (%s)\n", pagelen, pagelen?"":"not given", prev_page, !prev_page?"not given":((prev_page==1)?"not existing":""), next_page, next_page?"":"not given"); printf("seeking to %04x - reading page %d\n", pos+len, currentpage+1); } fseek(fi, pos+len, SEEK_SET); } } while(++currentpage); fclose(fi); return currentpage; } int sff_countpages(char* filename) { destfaxpage.pagenr = -1; debug = 0; return readfax(filename); } void sff_printinfo(char* filename) { destfaxpage.pagenr = -1; debug = 1; printf("============= SFF INFO ================\n"); readfax(filename); printf("=======================================\n"); } struct FaxPage sff_getpage(char* filename, int page) { if(xmax<0 || ymax<0) { readfax(filename); if(xmax<0 || ymax<0) { printf("Error in fax\n"); exit(1); } } destfaxpage.pagenr = page; destfaxpage.lenx = xmax; destfaxpage.scanline = xmax; destfaxpage.leny = ymax; destfaxpage.data = malloc(xmax*ymax); debug = 0; readfax(filename); destfaxpage.pagenr = -1; return destfaxpage; }