/*********************************************************************** * * * PS_LZWencode.c - output an image in PostScript format * * (Lelpel-Ziv Welch encoding) * * * * Author: Evgeni Chernyaev (chernaev@mx.ihep.su) * * * * Copyright (C) 1993, 1994 by Evgeni Chernyaev. * * * * Permission to use, copy, modify, and distribute this software and * * its documentation for non-commercial purpose is hereby granted * * without fee, provided that the above copyright notice appear in all * * copies and that both the copyright notice and this permission * * notice appear in supporting documentation. * * * * This software is provided "as is" without express or implied * * warranty. * * * ***********************************************************************/ #include #include #include #include #ifdef __STDC__ #define ARGS(alist) alist #else #define ARGS(alist) () #endif typedef unsigned char byte; static int Nbyte; static char s[80]; static void (*put_b) ARGS((byte)); #define put_string nc=strlen(s); for(i=0;i=0; n--) { s[n] = Value % 85 + 33; Value /= 85; } if (k-j < 4) s[k-j+1] = '\0'; put_string; } sprintf(s,"\n"); put_string; } #define BITS 12 /* largest code size */ #define HSIZE 5003 /* hash table size */ #define SHIFT 4 /* shift for hashing */ #define CLEARCODE 256 /* Clear Code */ #define EOD 257 /* End Of Data code */ #define PIXS 170000 /* largest # of pixels */ /*********************************************************************** * * * Name: PutCode Date: 05.11.93 * * Author: E.Chernyaev (IHEP/Protvino) Revised: * * * * Function: Put out code (LZW encoding) * * * * Input: Code - code * * CodeSize - codesize * * * ***********************************************************************/ static void PutCode(Code, CodeSize) int Code, CodeSize; { static int k, PartA, PartB, SizeA, SizeB; static int mask[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF }; static byte Accum[56]; if (Code == -1) { k = 0; PartA = 0; SizeA = 0; return; } PartB = Code; SizeB = CodeSize; while (SizeB >= 8) { SizeB = SizeA + SizeB - 8; Accum[k++] = PartA | (PartB >> SizeB); if (k == 56) { ASCII85encode(k,Accum); k = 0; } PartB &= mask[SizeB]; SizeA = 0; PartA = 0; } SizeA = SizeB; PartA = PartB << (8-SizeB); if (Code == EOD) { if (SizeA != 0) Accum[k++] = PartA; ASCII85encode(k, Accum); } } /*********************************************************************** * * * Name: EncodeData Date: 05.11.93 * * Author: E.Chernyaev (IHEP/Protvino) Revised: 21.06.94 * * 04.06.94 * * Function: Lelpel-Ziv Welch encoding of an image * * * * Input: Width - image width * * Height - image height * * Ncol - number of colors * * R[] - red components * * G[] - green components * * B[] - blue components * * ScLine[] - array for scan line (byte per pixel) * * get_scline - user routine to read scan line: * * get_scline(y, Width, ScLine) * * * * Return: size of PS * * * ***********************************************************************/ static void EncodeData(Width, Height, Ncol, R, G, B, ScLine, get_scline) int Width, Height, Ncol; byte R[], G[], B[], ScLine[]; void (*get_scline) ARGS((int, int, byte *)); { int i, k, nc, x, y, disp, Code, K; long CodeK, Npix; char **q; int FreeCode, CurCodeSize, CurMaxCode; long HashTab [HSIZE]; /* hash table */ int CodeTab [HSIZE]; /* code table */ /* O U T P U T P A L E T T E */ for (k=0; k 0) /* try again */ goto PROBE; NOMATCH: /* full code not found */ PutCode(Code, CurCodeSize); Code = K; if (FreeCode == CurMaxCode) { CurCodeSize++; CurMaxCode = CurMaxCode*2 + 1; } if (CurCodeSize <= BITS && Npix <= PIXS) { CodeTab[k] = FreeCode++; /* code -> hashtable */ HashTab[k] = CodeK; }else{ if (CurCodeSize > BITS) CurCodeSize = BITS; PutCode(CLEARCODE, CurCodeSize); memset((char *) HashTab, -1, sizeof(HashTab)); FreeCode = CLEARCODE + 2; CurCodeSize = 9; CurMaxCode = 511; Npix = 0; } } } /* O U T P U T T H E R E S T */ PutCode(Code, CurCodeSize); if (FreeCode == CurMaxCode && CurCodeSize != BITS) CurCodeSize++; PutCode(EOD, CurCodeSize); sprintf(s,"~>\n"); put_string; } /*********************************************************************** * * * Name: PS_LZWencode Date: 02.02.93 * * Author: E.Chernyaev (IHEP/Protvino) Revised: 02.11.93 * * * * Function: Output image in PostScript format * * (Lelpel-Ziv Welch encoding) * * * * Input: iwhat - 0 - PostScript (PS) * * 1 - encapsulated PostScript (EPS) * * 2 - encapsulated PostScript with preview (EPSI) * * 10 - PostScript (Gray) (PS) * * 11 - encapsulated PostScript (Gray) (EPS) * * 12 - encapsulated PostScript with preview (EPSI) * * Width - image width * * Height - image height * * Ncol - number of colors * * R[] - red components * * G[] - green components * * B[] - blue components * * ScLine[] - array for scan line (byte per pixel) * * get_scline - user routine to read scan line: * * get_scline(y, Width, ScLine) * * pb - user routine for "put_byte": pb(b) * * * * Return: size of PS * * * ***********************************************************************/ long PS_LZWencode(iwhat, Width, Height, Ncol, R, G, B, ScLine, get_scline, pb) int iwhat, Width, Height, Ncol; byte R[], G[], B[], ScLine[]; void (*get_scline) ARGS((int, int, byte *)), (*pb) ARGS((byte)); { extern char ProgName[]; extern char ProgVers[]; extern char FileName[]; int ifeps, ifgray, i, nc; char **q; time_t clock; static char *HeaderPS[] = { "%***********************************************************************", "%* *", "%* Function: Display a Lempel-Ziv Welch (LZW) encoded color image. *", "%* This file is suitable for any kind of PostScript printer: *", "%* Level I/II, color/grayscale, format A4/A3/... *", "%* By default the image will be centered, rotated and scaled *", "%* to fill the maximum space on a page. *", "%* If you want to use this file as an Encapsulated PostScript*", "%* file (for example inside a LaTeX document), then just *", "%* uncomment line '/EPSneeded true def'. *", "%* To optimize output on GrayScale printers you may uncomment*", "%* line '/GRAYneeded true def'. *", "%* *", "%* Author: Evgeni CHERNYAEV (chernaev@mx.ihep.su) *", "%* *", "%***********************************************************************", "gsave", "userdict begin", "%/EPSneeded true def", NULL, }; static char *HeaderEPS[] = { "%***********************************************************************", "%* *", "%* Function: Display a Lempel-Ziv Welch (LZW) encoded color image. *", "%* This is an Encapsulated PostScript file suitable for any *", "% kind of PostScript printer: Level I/II, color/grayscale...*", "%* To optimize output on GrayScale printers you may uncomment*", "%* line '/GRAYneeded true def'. *", "%* *", "%* Author: Evgeni CHERNYAEV (chernaev@vxcern.cern.ch) *", "%* *", "%***********************************************************************", "gsave", "userdict begin", "/EPSneeded true def", NULL, }; static char *HeaderCol[] = { "%/GRAYneeded true def", "end", "%***********************************************************************", "%* Image Description *", "%***********************************************************************", NULL, }; static char *HeaderGray[] = { "/GRAYneeded true def", "end", "%***********************************************************************", "%* Image Description *", "%***********************************************************************", NULL, }; static char *CommonPart[] = { "/mm {2.835 mul} def", "userdict /EPSneeded known {", " /EPSneeded userdict /EPSneeded get def", "}{", " /EPSneeded false def", "} ifelse", "userdict /GRAYneeded known {", " /GRAYneeded userdict /GRAYneeded get def", "}{", " /GRAYneeded false def", "} ifelse", "EPSneeded {", " /IfRotate false def", " /MarginX 0 def /MarginY 0 def", " /Ymax rows def /Xmax colomns def /Ymin 0 def /Xmin 0 def", "}{", " /IfRotate colomns rows gt {true} {false} ifelse def", " /MarginX 8 mm def /MarginY 18 mm def", " 0 0 moveto clippath pathbbox", " /Ymax exch def /Xmax exch def /Ymin exch def /Xmin exch def", "} ifelse", "/IfColor systemdict /colorimage known {true} {false} ifelse def", "GRAYneeded {/IfColor false def} if", "/IfLevel2 systemdict /filter known systemdict /setcolorspace known and", " {true} {false} ifelse def", "%***********************************************************************", "% Procedures *", "%***********************************************************************", "/Table 4096 array def", "/StrArray 10 array def", "/InLine 70 string def", "/BinCodes 112 string def", "/CurBit 0 def /FreeCode 258 def /CurCodeSize 9 def /CurMask 511 def", "/incr IfColor {3} {1} ifelse def", "IfLevel2 not {/setcolorspace null def /filter null def} if", "%***********************************************************************", "/ReadLine { % Read Next Data Line (ASCII85 decode) *", "%***********************************************************************", " BinCodes 0 BinCodes 56 56 getinterval putinterval", " currentfile InLine readline pop pop", " 1 1 14 {", " /i exch 1 sub def", " /k i 5 mul def", " /c1 InLine k get 33 sub 255 and def", " /rest c1 1868977 mul", " InLine k 1 add get 33 sub 255 and 614125 mul add", " InLine k 2 add get 33 sub 255 and 7225 mul add", " InLine k 3 add get 33 sub 255 and 85 mul add", " InLine k 4 add get 33 sub 255 and add def", " /k i 4 mul 56 add def", " BinCodes k c1 3 mul rest 16777216 idiv add 255 and put", " /rest rest 16777216 mod def", " BinCodes k 1 add rest 65536 idiv put", " BinCodes k 2 add rest 256 idiv 255 and put", " BinCodes k 3 add rest 255 and put", " } for", "} bind def", "%***********************************************************************", "/ReadCode { % Read next code *", "%***********************************************************************", " /CurByte CurBit 8 idiv def", " /CurCode", " BinCodes CurByte get 8 bitshift", " BinCodes CurByte 1 add get add 8 bitshift", " BinCodes CurByte 2 add get add", " CurCodeSize CurBit 7 and add 24 sub bitshift CurMask and def", " /CurBit CurBit CurCodeSize add dup 448 ge {ReadLine 448 sub} if def", "} bind def", "%***********************************************************************", "/DecodeCode { % Decode CurCode *", "%***********************************************************************", " ReadCode CurCode 256 eq {", " /FreeCode 258 def /CurCodeSize 9 def /CurMask 511 def", " /StrInd -1 def /Lrest 0 def ReadCode", " }{", " L Lrest gt {", " /StrInd StrInd 1 add def /Lrest 65535 def", " StrArray StrInd get null eq {StrArray StrInd 65535 string put} if", " /CurStr StrArray StrInd get def", " } if", " Table FreeCode CurStr 65535 Lrest sub L getinterval", " dup 0 Table OldCode get putinterval", " dup L incr sub Table", " CurCode FreeCode lt {CurCode} {OldCode} ifelse get", " 0 incr getinterval putinterval put", " /Lrest Lrest L sub def /FreeCode FreeCode 1 add def", " FreeCode CurMask ge CurCodeSize 12 lt and {", " /CurCodeSize CurCodeSize 1 add def", " /CurMask CurMask 1 bitshift 1 add def", " } if", " } ifelse", " /OldCode CurCode def", " Table CurCode get dup length incr add /L exch def", "} bind def", "%***********************************************************************", "/DisplayImage { % Display a LZW-encoded color image *", "%***********************************************************************", " /DelX Xmax Xmin sub MarginX 2 mul sub def", " /DelY Ymax Ymin sub MarginY 2 mul sub def", " /SizeX IfRotate {rows} {colomns} ifelse def", " /SizeY IfRotate {colomns} {rows} ifelse def", " /FactorX DelX SizeX div def /FactorY DelY SizeY div def", " /Factor FactorX FactorY le {FactorX} {FactorY} ifelse def", " /ScaleX SizeX Factor mul def /ScaleY SizeY Factor mul def", " Xmin DelX ScaleX sub 2 div MarginX add add", " Ymin DelY ScaleY sub 2 div MarginY add add translate", " IfRotate {ScaleY ScaleX} {ScaleX ScaleY} ifelse scale", " /Palette currentfile 768 string readhexstring pop def", " currentfile InLine readline pop pop", " IfColor not {", " 0 1 255 {", " Palette exch dup /i exch 3 mul def", " Palette i 0 add get 0.299 mul", " Palette i 1 add get 0.587 mul add", " Palette i 2 add get 0.114 mul add cvi put", " } for", " /Palette Palette 0 256 getinterval def", " } if", " /Matr IfRotate", " {[0 colomns rows 0 0 0]} {[colomns 0 0 rows neg 0 rows]} ifelse def", " IfLevel2 {", " [/Indexed IfColor {/DeviceRGB} {/DeviceGray} ifelse 255 Palette]", " setcolorspace", " /infile currentfile /ASCII85Decode filter /LZWDecode filter def", " 8 dict", " dup /ImageType 1 put", " dup /Width colomns put", " dup /Height rows put", " dup /BitsPerComponent 8 put", " dup /ImageMatrix Matr put", " dup /Interpolate false put", " dup /Decode [0 255] put", " dup /DataSource infile put image", " }{", " 0 1 255 {", " Table exch dup incr mul Palette exch incr getinterval put", " } for", " ReadLine ReadLine", " colomns rows 8 Matr {DecodeCode}", " IfColor {false 3 colorimage} {image} ifelse", " } ifelse", "} bind def", "%***********************************************************************", "%* Image decoding *", "%***********************************************************************", "DisplayImage", NULL, }; /* C H E C K P A R A M E T E R S */ if (Width <= 0 || Width > MAXWIDTH || Height <= 0 || Height > MAXWIDTH) { fprintf(stderr, "\n%s: incorrect image size: %d x %d\n", ProgName, Width, Height); return 0; } if (Ncol <= 0 || Ncol > 256) { fprintf(stderr,"\n%s: wrong number of colors: %d\n", ProgName, Ncol); return 0; } /* I N I T I A L I S A T I O N */ if (iwhat < 10) ifeps = iwhat; else ifeps = iwhat - 10; put_b = pb; Nbyte = 0; /* O U T P U T H E A D E R */ sprintf(s,"%%!PS-Adobe-2.0 EPSF-2.0\n"); put_string; sprintf(s,"%%%%Title: %s\n", FileName); put_string; sprintf(s,"%%%%Creator: %s %s\n", ProgName, ProgVers); put_string; sprintf(s,"%%%%CreationDate: %s",(time(&clock),ctime(&clock))); put_string; sprintf(s,"%%%%BoundingBox: 0 0 %d %d\n", Width, Height); put_string; sprintf(s,"%%%%EndComments\n"); put_string; /* O U T P U T P R E V I E W */ if (ifeps == 2) PutPreview(Width, Height, R, G, B, ScLine, get_scline); /* O U T P U T P O S T S C R I P T P R O G R A M M */ if (ifeps == 0) q = HeaderPS; else q = HeaderEPS; for ( ; *q; q++) { sprintf(s,"%s\n",*q); put_string; } if (iwhat < 10) q = HeaderCol; else q = HeaderGray; for ( ; *q; q++) { sprintf(s,"%s\n",*q); put_string; } sprintf(s,"/colomns %d def\n",Width); put_string; sprintf(s,"/rows %d def\n",Height); put_string; for (q=CommonPart; *q; q++) { sprintf(s,"%s\n",*q); put_string; } /* O U T P U T E N C O D E D D A T A */ EncodeData(Width, Height, Ncol, R, G, B, ScLine, get_scline); sprintf(s,"showpage grestore\n"); put_string; sprintf(s,"%%%%Trailer\n"); put_string; return (Nbyte); }