#include #ifdef __STDC__ #define ARGS(alist) alist #else #define ARGS(alist) () #endif #define HEADER_SIZE 512 #define MAXCOLORS 256 #define PICT_clipRgn 0x01 /* PICT opcodes */ #define PICT_picVersion 0x11 #define PICT_PackBitsRect 0x98 #define PICT_EndOfPicture 0xFF #define PICT_headerOp 0x0C00 #define put_byte(A) (*put_b)((byte)(A)); Nbyte++ typedef unsigned char byte; static long Nbyte; static void (*put_b) ARGS ((byte)); static void put_scline ARGS((byte *, int)); static void put_short ARGS((int)); static void put_long ARGS((long)); static void put_fixed ARGS((int, int)); static void put_rect ARGS((int, int, int, int)); static void put_fill ARGS((int)); /*********************************************************************** * * * Name: PICTencode Date: 20.11.92 * * Author: E.Chernyaev (IHEP/Protvino) Revised: * * * * Function: PICT (Macintosh) compression of the image * * * * Input: Width - image width (must be >= 8) * * Height - image height (must be >= 8) * * 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 PICT * * * ***********************************************************************/ long PICTencode(Width, Height, Ncol, R, G, B, ScLine, get_scline, pb) int Width, Height, Ncol; byte R[], G[], B[], ScLine[]; void (*get_scline) ARGS((int, int, byte *)), (*pb) ARGS((byte)); { int i; /* C H E C K P A R A M E T E R S */ if (Width < 8 || Height < 8) { fprintf(stderr,"\nPICTencode: very small image, must be >= 8x8\n"); return 0; } if (Width > 4096 || Height > 4096) { fprintf(stderr,"\nPICTencode: too big image: %d x %d\n", Width, Height); return 0; } if (Ncol <= 0 || Ncol > 256) { fprintf(stderr,"\nPICTencode: wrong number of colors: %d\n", Ncol); return 0; } /* I N I T I A L I S A T I O N */ put_b = pb; Nbyte = 0; /* W R I T E O U T T H E H E A D E R */ put_fill(HEADER_SIZE); /* write the header */ put_short(0xffff); /* write picSize(?) and picFrame */ put_rect(0, 0, Height, Width); put_short(PICT_picVersion); /* write version op and version */ put_short(0x02FF); put_short(PICT_headerOp); put_long(-1L); put_fixed(0, 0); put_fixed(0, 0); put_fixed(Width, 0); put_fixed(Height, 0); put_fill(4); put_short(PICT_clipRgn); /* needed by many PICT2 programs */ put_short(10); put_rect(0, 0, Height, Width); put_short(PICT_PackBitsRect); /* write picture */ put_short(Width | 0x8000); put_rect(0, 0, Height, Width); put_short(0); /* pmVersion */ put_short(0); /* packType */ put_long(0L); /* packSize */ put_fixed(72, 0); /* hRes */ put_fixed(72, 0); /* vRes */ put_short(0); /* pixelType */ put_short(8); /* pixelSize */ put_short(1); /* cmpCount */ put_short(8); /* cmpSize */ put_long(0L); /* planeBytes */ put_long(0L); /* pmTable */ put_long(0L); /* pmReserved */ put_long(0L); /* ctSeed */ put_short(0); /* ctFlags */ put_short(Ncol-1); /* ctSize */ /* W R I T E O U T T H E C O L O R M A P */ for (i = 0; i < Ncol; i++) { put_short(i); put_short((int)(R[i]*65535L/255L)); put_short((int)(G[i]*65535L/255L)); put_short((int)(B[i]*65535L/255L)); } put_rect(0, 0, Height, Width); /* srcRect */ put_rect(0, 0, Height, Width); /* dstRect */ put_short(0); /* mode */ /* W R I T E O U T T H E I M A G E */ for (i = 0; i < Height; i++) { (*get_scline)(i, Width, ScLine); put_scline(ScLine, Width); } if (Nbyte & 1) { put_byte(0); } /* if we wrote odd # of bytes */ put_short(PICT_EndOfPicture); return (Nbyte); } #define RUN_THRESH 3 #define MAX_RUN 128 /* 0xff = 2, 0xfe = 3, etc */ #define MAX_COUNT 128 /* 0x00 = 1, 0x01 = 2, etc */ #define RunToChar(c) (257-(c)) #define CountToChar(c) ((c)-1) static void put_scline(buf, size) byte *buf; int size; { byte *ptr, *end; int current, previous, run, count, rep; /* F I N D N U M B E R O F B Y T E S TO BE WRITTEN */ ptr = buf; end = ptr + size; previous = *ptr++; run = 1; count = 0; rep = 0; while (ptr < end) { current = *ptr++; if (current == previous && run < MAX_RUN) { run++; continue; } if (run < RUN_THRESH) { count += run; previous = current; run = 1; continue; } rep += count + (count+MAX_COUNT-1)/MAX_COUNT + 2; previous = current; run = 1; count = 0; } if (run < RUN_THRESH) { /* scan line finished */ count += run; run = 0; } rep += count + (count+MAX_COUNT-1)/MAX_COUNT; if (run > 0) rep += 2; /* W R I T E B Y T E C O U N T E R */ if (size > 250) put_short(rep); else { put_byte(rep); } /* R U N L E N G T H E N C O D I N G */ ptr = buf; previous = *ptr++; run = 1; count = 0; while (ptr < end) { current = *ptr++; if (current == previous && run < MAX_RUN) { run++; continue; } if (run < RUN_THRESH) { count += run; previous = current; run = 1; continue; } ptr -= run + count; while (count > 0) { rep = count > MAX_COUNT ? MAX_COUNT : count; put_byte(CountToChar(rep)); count -= rep; while (rep > 0) { put_byte(*ptr++); rep--; } } ptr += run; put_byte(RunToChar(run)); put_byte(previous); previous = current; run = 1; } if (run < RUN_THRESH) { /* scan line finished */ count += run; run = 0; } ptr -= run + count; while (count > 0) { rep = count > MAX_COUNT ? MAX_COUNT : count; put_byte(CountToChar(rep)); count -= rep; while (rep > 0) { put_byte(*ptr++); rep--; } } if (run > 0) { put_byte(RunToChar(run)); put_byte(previous); } } static void put_short(k) int k; { put_byte((k >> 8) & 0xFF); put_byte(k & 0xFF); } static void put_long(k) long k; { put_byte((k >> 24) & 0xFF); put_byte((k >> 16) & 0xFF); put_byte((k >> 8) & 0xFF); put_byte(k & 0xFF); } static void put_fixed(in, frac) int in, frac; { put_short(in); put_short(frac); } static void put_rect(x1, x2, y1, y2) int x1, x2, y1, y2; { put_short(x1); put_short(x2); put_short(y1); put_short(y2); } static void put_fill(n) int n; { int i; for (i=0; i