This is compress.c in view mode; [Download] [Up]
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% CCCC OOO M M PPPP RRRR EEEEE SSSSS SSSSS %
% C O O MM MM P P R R E SS SS %
% C O O M M M PPPP RRRR EEE SSS SSS %
% C O O M M P R R E SS SS %
% CCCC OOO M M P R R EEEEE SSSSS SSSSS %
% %
% %
% Image Compression/Decompression Coders %
% %
% %
% %
% Software Design %
% John Cristy %
% May 1993 %
% %
% %
% Copyright 1997 E. I. du Pont de Nemours and Company %
% %
% Permission to use, copy, modify, distribute, and sell this software and %
% its documentation for any purpose is hereby granted without fee, %
% provided that the above Copyright notice appear in all copies and that %
% both that Copyright notice and this permission notice appear in %
% supporting documentation, and that the name of E. I. du Pont de Nemours %
% and Company not be used in advertising or publicity pertaining to %
% distribution of the software without specific, written prior %
% permission. E. I. du Pont de Nemours and Company makes no representations %
% about the suitability of this software for any purpose. It is provided %
% "as is" without express or implied warranty. %
% %
% E. I. du Pont de Nemours and Company disclaims all warranties with regard %
% to this software, including all implied warranties of merchantability %
% and fitness, in no event shall E. I. du Pont de Nemours and Company be %
% liable for any special, indirect or consequential damages or any %
% damages whatsoever resulting from loss of use, data or profits, whether %
% in an action of contract, negligence or other tortious action, arising %
% out of or in connection with the use or performance of this software. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
%
*/
/*
Include declarations.
*/
#include "magick.h"
/*
Define declarations.
*/
#define LoadImageText " Loading image... "
#define SaveImageText " Saving image... "
/*
Typedef declarations.
*/
typedef struct HuffmanTable
{
int
id,
code,
length,
count;
} HuffmanTable;
typedef struct _ScanlinePacket
{
unsigned char
pixel;
int
state;
} ScanlinePacket;
/*
Huffman coding declarations.
*/
#define TWId 23
#define MWId 24
#define TBId 25
#define MBId 26
#define EXId 27
static HuffmanTable
MBTable[]=
{
{ MBId, 0x0f, 10, 64 }, { MBId, 0xc8, 12, 128 },
{ MBId, 0xc9, 12, 192 }, { MBId, 0x5b, 12, 256 },
{ MBId, 0x33, 12, 320 }, { MBId, 0x34, 12, 384 },
{ MBId, 0x35, 12, 448 }, { MBId, 0x6c, 13, 512 },
{ MBId, 0x6d, 13, 576 }, { MBId, 0x4a, 13, 640 },
{ MBId, 0x4b, 13, 704 }, { MBId, 0x4c, 13, 768 },
{ MBId, 0x4d, 13, 832 }, { MBId, 0x72, 13, 896 },
{ MBId, 0x73, 13, 960 }, { MBId, 0x74, 13, 1024 },
{ MBId, 0x75, 13, 1088 }, { MBId, 0x76, 13, 1152 },
{ MBId, 0x77, 13, 1216 }, { MBId, 0x52, 13, 1280 },
{ MBId, 0x53, 13, 1344 }, { MBId, 0x54, 13, 1408 },
{ MBId, 0x55, 13, 1472 }, { MBId, 0x5a, 13, 1536 },
{ MBId, 0x5b, 13, 1600 }, { MBId, 0x64, 13, 1664 },
{ MBId, 0x65, 13, 1728 }, { MBId, 0x00, 0, 0 }
};
static HuffmanTable
EXTable[]=
{
{ EXId, 0x08, 11, 1792 }, { EXId, 0x0c, 11, 1856 },
{ EXId, 0x0d, 11, 1920 }, { EXId, 0x12, 12, 1984 },
{ EXId, 0x13, 12, 2048 }, { EXId, 0x14, 12, 2112 },
{ EXId, 0x15, 12, 2176 }, { EXId, 0x16, 12, 2240 },
{ EXId, 0x17, 12, 2304 }, { EXId, 0x1c, 12, 2368 },
{ EXId, 0x1d, 12, 2432 }, { EXId, 0x1e, 12, 2496 },
{ EXId, 0x1f, 12, 2560 }, { EXId, 0x00, 0, 0 }
};
static HuffmanTable
MWTable[]=
{
{ MWId, 0x1b, 5, 64 }, { MWId, 0x12, 5, 128 },
{ MWId, 0x17, 6, 192 }, { MWId, 0x37, 7, 256 },
{ MWId, 0x36, 8, 320 }, { MWId, 0x37, 8, 384 },
{ MWId, 0x64, 8, 448 }, { MWId, 0x65, 8, 512 },
{ MWId, 0x68, 8, 576 }, { MWId, 0x67, 8, 640 },
{ MWId, 0xcc, 9, 704 }, { MWId, 0xcd, 9, 768 },
{ MWId, 0xd2, 9, 832 }, { MWId, 0xd3, 9, 896 },
{ MWId, 0xd4, 9, 960 }, { MWId, 0xd5, 9, 1024 },
{ MWId, 0xd6, 9, 1088 }, { MWId, 0xd7, 9, 1152 },
{ MWId, 0xd8, 9, 1216 }, { MWId, 0xd9, 9, 1280 },
{ MWId, 0xda, 9, 1344 }, { MWId, 0xdb, 9, 1408 },
{ MWId, 0x98, 9, 1472 }, { MWId, 0x99, 9, 1536 },
{ MWId, 0x9a, 9, 1600 }, { MWId, 0x18, 6, 1664 },
{ MWId, 0x9b, 9, 1728 }, { MWId, 0x00, 0, 0 }
};
static HuffmanTable
TBTable[]=
{
{ TBId, 0x37, 10, 0 }, { TBId, 0x02, 3, 1 }, { TBId, 0x03, 2, 2 },
{ TBId, 0x02, 2, 3 }, { TBId, 0x03, 3, 4 }, { TBId, 0x03, 4, 5 },
{ TBId, 0x02, 4, 6 }, { TBId, 0x03, 5, 7 }, { TBId, 0x05, 6, 8 },
{ TBId, 0x04, 6, 9 }, { TBId, 0x04, 7, 10 }, { TBId, 0x05, 7, 11 },
{ TBId, 0x07, 7, 12 }, { TBId, 0x04, 8, 13 }, { TBId, 0x07, 8, 14 },
{ TBId, 0x18, 9, 15 }, { TBId, 0x17, 10, 16 }, { TBId, 0x18, 10, 17 },
{ TBId, 0x08, 10, 18 }, { TBId, 0x67, 11, 19 }, { TBId, 0x68, 11, 20 },
{ TBId, 0x6c, 11, 21 }, { TBId, 0x37, 11, 22 }, { TBId, 0x28, 11, 23 },
{ TBId, 0x17, 11, 24 }, { TBId, 0x18, 11, 25 }, { TBId, 0xca, 12, 26 },
{ TBId, 0xcb, 12, 27 }, { TBId, 0xcc, 12, 28 }, { TBId, 0xcd, 12, 29 },
{ TBId, 0x68, 12, 30 }, { TBId, 0x69, 12, 31 }, { TBId, 0x6a, 12, 32 },
{ TBId, 0x6b, 12, 33 }, { TBId, 0xd2, 12, 34 }, { TBId, 0xd3, 12, 35 },
{ TBId, 0xd4, 12, 36 }, { TBId, 0xd5, 12, 37 }, { TBId, 0xd6, 12, 38 },
{ TBId, 0xd7, 12, 39 }, { TBId, 0x6c, 12, 40 }, { TBId, 0x6d, 12, 41 },
{ TBId, 0xda, 12, 42 }, { TBId, 0xdb, 12, 43 }, { TBId, 0x54, 12, 44 },
{ TBId, 0x55, 12, 45 }, { TBId, 0x56, 12, 46 }, { TBId, 0x57, 12, 47 },
{ TBId, 0x64, 12, 48 }, { TBId, 0x65, 12, 49 }, { TBId, 0x52, 12, 50 },
{ TBId, 0x53, 12, 51 }, { TBId, 0x24, 12, 52 }, { TBId, 0x37, 12, 53 },
{ TBId, 0x38, 12, 54 }, { TBId, 0x27, 12, 55 }, { TBId, 0x28, 12, 56 },
{ TBId, 0x58, 12, 57 }, { TBId, 0x59, 12, 58 }, { TBId, 0x2b, 12, 59 },
{ TBId, 0x2c, 12, 60 }, { TBId, 0x5a, 12, 61 }, { TBId, 0x66, 12, 62 },
{ TBId, 0x67, 12, 63 }, { TBId, 0x00, 0, 0 }
};
static HuffmanTable
TWTable[]=
{
{ TWId, 0x35, 8, 0 }, { TWId, 0x07, 6, 1 }, { TWId, 0x07, 4, 2 },
{ TWId, 0x08, 4, 3 }, { TWId, 0x0b, 4, 4 }, { TWId, 0x0c, 4, 5 },
{ TWId, 0x0e, 4, 6 }, { TWId, 0x0f, 4, 7 }, { TWId, 0x13, 5, 8 },
{ TWId, 0x14, 5, 9 }, { TWId, 0x07, 5, 10 }, { TWId, 0x08, 5, 11 },
{ TWId, 0x08, 6, 12 }, { TWId, 0x03, 6, 13 }, { TWId, 0x34, 6, 14 },
{ TWId, 0x35, 6, 15 }, { TWId, 0x2a, 6, 16 }, { TWId, 0x2b, 6, 17 },
{ TWId, 0x27, 7, 18 }, { TWId, 0x0c, 7, 19 }, { TWId, 0x08, 7, 20 },
{ TWId, 0x17, 7, 21 }, { TWId, 0x03, 7, 22 }, { TWId, 0x04, 7, 23 },
{ TWId, 0x28, 7, 24 }, { TWId, 0x2b, 7, 25 }, { TWId, 0x13, 7, 26 },
{ TWId, 0x24, 7, 27 }, { TWId, 0x18, 7, 28 }, { TWId, 0x02, 8, 29 },
{ TWId, 0x03, 8, 30 }, { TWId, 0x1a, 8, 31 }, { TWId, 0x1b, 8, 32 },
{ TWId, 0x12, 8, 33 }, { TWId, 0x13, 8, 34 }, { TWId, 0x14, 8, 35 },
{ TWId, 0x15, 8, 36 }, { TWId, 0x16, 8, 37 }, { TWId, 0x17, 8, 38 },
{ TWId, 0x28, 8, 39 }, { TWId, 0x29, 8, 40 }, { TWId, 0x2a, 8, 41 },
{ TWId, 0x2b, 8, 42 }, { TWId, 0x2c, 8, 43 }, { TWId, 0x2d, 8, 44 },
{ TWId, 0x04, 8, 45 }, { TWId, 0x05, 8, 46 }, { TWId, 0x0a, 8, 47 },
{ TWId, 0x0b, 8, 48 }, { TWId, 0x52, 8, 49 }, { TWId, 0x53, 8, 50 },
{ TWId, 0x54, 8, 51 }, { TWId, 0x55, 8, 52 }, { TWId, 0x24, 8, 53 },
{ TWId, 0x25, 8, 54 }, { TWId, 0x58, 8, 55 }, { TWId, 0x59, 8, 56 },
{ TWId, 0x5a, 8, 57 }, { TWId, 0x5b, 8, 58 }, { TWId, 0x4a, 8, 59 },
{ TWId, 0x4b, 8, 60 }, { TWId, 0x32, 8, 61 }, { TWId, 0x33, 8, 62 },
{ TWId, 0x34, 8, 63 }, { TWId, 0x00, 0, 0 }
};
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% A S C I I 8 5 E n c o d e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function ASCII85Encode encodes data in ASCII base-85 format. ASCII base-85
% encoding produces five ASCII printing characters from every four bytes of
% binary data.
%
% The format of the ASCII85Encode routine is:
%
% ASCII85Encode(code,file)
%
% A description of each parameter follows:
%
% o code: a binary unsigned char to encode to ASCII 85.
%
% o file: write the encoded ASCII character to this file.
%
%
*/
#define MaxLineExtent 36
static int
count,
line_break;
static unsigned char
ascii85_buffer[10];
static char *Ascii85Tuple(unsigned char *data)
{
static char
tuple[6];
register unsigned int
word,
x;
register unsigned short
y;
word=(((data[0] << 8) | data[1]) << 16) | (data[2] << 8) | data[3];
if (word == 0L)
{
tuple[0]='z';
tuple[1]='\0';
return(tuple);
}
x=(unsigned int) (word/(85L*85*85*85));
tuple[0]=x+'!';
word-=x*(85L*85*85*85);
x=(unsigned int) (word/(85L*85*85));
tuple[1]=x+'!';
word-=x*(85L*85*85);
x=(unsigned int) (word/(85*85));
tuple[2]=x+'!';
y=(unsigned short) (word-x*(85L*85));
tuple[3]=(y/85)+'!';
tuple[4]=(y % 85)+'!';
tuple[5]='\0';
return(tuple);
}
void Ascii85Initialize(void)
{
line_break=MaxLineExtent << 1;
count=0;
}
void Ascii85Flush(FILE *file)
{
register char
*tuple;
assert(file != (FILE *) NULL);
if (count > 0)
{
ascii85_buffer[count]=0;
ascii85_buffer[count+1]=0;
ascii85_buffer[count+2]=0;
tuple=Ascii85Tuple(ascii85_buffer);
(void) fwrite(*tuple == 'z' ? "!!!!" : tuple,count+1,1,file);
}
(void) fputc('~',file);
(void) fputc('>',file);
}
void Ascii85Encode(const unsigned int code,FILE *file)
{
int
n;
register char
*q;
register unsigned char
*p;
assert(file != (FILE *) NULL);
ascii85_buffer[count]=code;
count++;
if (count < 4)
return;
p=ascii85_buffer;
for (n=count; n >= 4; n-=4)
{
for (q=Ascii85Tuple(p); *q; q++)
{
(void) fputc(*q,file);
line_break--;
if (line_break == 0)
{
(void) fputc('\n',file);
line_break=2*MaxLineExtent;
}
}
p+=8;
}
count=n;
p-=4;
for (n=0; n < 4; n++)
ascii85_buffer[n]=(*p++);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% B M P D e c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function BMPDecodeImage unpacks the packed image pixels into
% runlength-encoded pixel packets.
%
% The format of the BMPDecodeImage routine is:
%
% status=BMPDecodeImage(compressed_pixels,pixels,compression,
% number_columns,number_rows)
%
% A description of each parameter follows:
%
% o status: Function BMPDecodeImage returns True if all the pixels are
% uncompressed without error, otherwise False.
%
% o compressed_pixels: The address of a byte (8 bits) array of compressed
% pixel data.
%
% o pixels: The address of a byte (8 bits) array of pixel data created by
% the decoding process.
%
% o compression: A value of 1 means the compressed pixels are runlength
% encoded for a 256-color bitmap. A value of 2 means a 16-color bitmap.
%
% o number_columns: An integer value that is the number of columns or
% width in pixels of your source image.
%
% o number_rows: An integer value that is the number of rows or
% heigth in pixels of your source image.
%
%
*/
unsigned int BMPDecodeImage(unsigned char *compressed_pixels,
unsigned char *pixels,const unsigned int compression,
const unsigned int number_columns,const unsigned int number_rows)
{
register int
i,
x,
y;
register unsigned char
*p,
*q;
unsigned char
byte,
count;
assert(compressed_pixels != (unsigned char *) NULL);
assert(pixels != (unsigned char *) NULL);
byte=0;
x=0;
p=compressed_pixels;
q=pixels;
for (y=0; y < number_rows; )
{
count=(*p++);
if (count != 0)
{
/*
Encoded mode.
*/
byte=(*p++);
for (i=0; i < (int) count; i++)
{
if (compression == 1)
*q++=byte;
else
*q++=(i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f);
x++;
}
}
else
{
/*
Escape mode.
*/
count=(*p++);
if (count == 0x01)
return(True);
switch (count)
{
case 0x00:
{
/*
End of line.
*/
x=0;
y++;
q=pixels+y*number_columns;
break;
}
case 0x02:
{
/*
Delta mode.
*/
x+=(*p++);
y+=(*p++);
q=pixels+y*number_columns+x;
break;
}
default:
{
/*
Absolute mode.
*/
for (i=0; i < (int) count; i++)
{
if (compression == 1)
*q++=(*p++);
else
{
if ((i & 0x01) == 0)
byte=(*p++);
*q++=(i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f);
}
x++;
}
/*
Read pad byte.
*/
if (compression == 1)
{
if (count & 0x01)
p++;
}
else
if (((count & 0x03) == 1) || ((count & 0x03) == 2))
p++;
break;
}
}
}
ProgressMonitor(LoadImageText,y,number_rows);
}
return(False);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% B M P E n c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function BMPEncodeImage compresses pixels using a runlength encoded format.
%
% The format of the BMPEncodeImage routine is:
%
% status=BMPEncodeImage(pixels,compressed_pixels,number_columns,
% number_rows)
%
% A description of each parameter follows:
%
% o status: Function BMPEncodeImage returns the number of bytes in the
% runlength encoded compress_pixels array.
%
% o pixels: The address of a byte (8 bits) array of pixel data created by
% the compression process.
%
% o compressed_pixels: The address of a byte (8 bits) array of compressed
% pixel data.
%
% o number_columns: An integer value that is the number of columns or
% width in pixels of your source image.
%
% o number_rows: An integer value that is the number of rows or
% heigth in pixels of your source image.
%
%
*/
unsigned int BMPEncodeImage(unsigned char *pixels,
unsigned char *compressed_pixels,const unsigned int number_columns,
const unsigned int number_rows)
{
register int
i,
x,
y;
register unsigned char
*p,
*q;
/*
Runlength encode pixels.
*/
assert(pixels != (unsigned char *) NULL);
assert(compressed_pixels != (unsigned char *) NULL);
p=pixels;
q=compressed_pixels;
i=0;
for (y=0; y < number_rows; y++)
{
for (x=0; x < number_columns; x+=i)
{
/*
Determine runlength.
*/
for (i=1; ((x+i) < number_columns); i++)
if ((*(p+i) != *p) || (i == 255))
break;
*q++=i;
*q++=(*p);
p+=i;
}
/*
End of line.
*/
*q++=0;
*q++=0x00;
ProgressMonitor(SaveImageText,y,number_rows);
}
/*
End of bitmap.
*/
*q++=0;
*q++=0x01;
return((unsigned int) (q-compressed_pixels));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G I F D e c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function GIFDecodeImage uncompresses an image via GIF-coding.
%
% The format of the GIFDecodeImage routine is:
%
% status=GIFDecodeImage(image)
%
% A description of each parameter follows:
%
% o status: Function GIFDecodeImage returns True if all the pixels are
% uncompressed without error, otherwise False.
%
% o image: The address of a structure of type Image.
%
%
*/
unsigned int GIFDecodeImage(Image *image)
{
#define MaxStackSize 4096
#define NullCode (-1)
int
available,
clear,
code_mask,
code_size,
end_of_information,
in_code,
old_code,
status;
register int
bits,
code,
count,
i;
register RunlengthPacket
*p;
register unsigned char
*c;
register unsigned int
datum;
short
*prefix;
unsigned char
data_size,
first,
*packet,
*pixel_stack,
*suffix,
*top_stack;
/*
Allocate decoder tables.
*/
assert(image != (Image *) NULL);
packet=(unsigned char *) malloc(256*sizeof(unsigned char));
prefix=(short *) malloc(MaxStackSize*sizeof(short));
suffix=(unsigned char *) malloc(MaxStackSize*sizeof(unsigned char));
pixel_stack=(unsigned char *) malloc((MaxStackSize+1)*sizeof(unsigned char));
if ((packet == (unsigned char *) NULL) ||
(prefix == (short *) NULL) ||
(suffix == (unsigned char *) NULL) ||
(pixel_stack == (unsigned char *) NULL))
return(False);
/*
Initialize GIF data stream decoder.
*/
data_size=fgetc(image->file);
clear=1 << data_size;
end_of_information=clear+1;
available=clear+2;
old_code=NullCode;
code_size=data_size+1;
code_mask=(1 << code_size)-1;
for (code=0; code < clear; code++)
{
prefix[code]=0;
suffix[code]=code;
}
/*
Decode GIF pixel stream.
*/
datum=0;
bits=0;
c=0;
count=0;
first=0;
top_stack=pixel_stack;
p=image->pixels;
for (i=0; i < image->packets; )
{
if (top_stack == pixel_stack)
{
if (bits < code_size)
{
/*
Load bytes until there is enough bits for a code.
*/
if (count == 0)
{
/*
Read a new data block.
*/
count=ReadDataBlock((char *) packet,image->file);
if (count <= 0)
break;
c=packet;
}
datum+=(*c) << bits;
bits+=8;
c++;
count--;
continue;
}
/*
Get the next code.
*/
code=datum & code_mask;
datum>>=code_size;
bits-=code_size;
/*
Interpret the code
*/
if ((code > available) || (code == end_of_information))
break;
if (code == clear)
{
/*
Reset decoder.
*/
code_size=data_size+1;
code_mask=(1 << code_size)-1;
available=clear+2;
old_code=NullCode;
continue;
}
if (old_code == NullCode)
{
*top_stack++=suffix[code];
old_code=code;
first=code;
continue;
}
in_code=code;
if (code == available)
{
*top_stack++=first;
code=old_code;
}
while (code > clear)
{
*top_stack++=suffix[code];
code=prefix[code];
}
first=suffix[code];
/*
Add a new string to the string table,
*/
if (available >= MaxStackSize)
break;
*top_stack++=first;
prefix[available]=old_code;
suffix[available]=first;
available++;
if (((available & code_mask) == 0) && (available < MaxStackSize))
{
code_size++;
code_mask+=available;
}
old_code=in_code;
}
/*
Pop a pixel off the pixel stack.
*/
top_stack--;
p->index=(unsigned short) *top_stack;
p->length=0;
p++;
i++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(LoadImageText,i,image->packets);
}
/*
Initialize any remaining color packets to a known color.
*/
status=i == image->packets;
for ( ; i < image->packets; i++)
{
p->index=0;
p->length=0;
p++;
}
SyncImage(image);
/*
Free decoder memory.
*/
free((char *) pixel_stack);
free((char *) suffix);
free((char *) prefix);
free((char *) packet);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G I F E n c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function GIFEncodeImage compresses an image via GIF-coding.
%
% The format of the GIFEncodeImage routine is:
%
% status=GIFEncodeImage(image,data_size)
%
% A description of each parameter follows:
%
% o status: Function GIFEncodeImage returns True if all the pixels are
% compressed without error, otherwise False.
%
% o image: The address of a structure of type Image.
%
%
*/
unsigned int GIFEncodeImage(Image *image,const unsigned int data_size)
{
#define MaxCode(number_bits) ((1 << (number_bits))-1)
#define MaxHashTable 5003
#define MaxGIFBits 12
#define MaxGIFTable (1 << MaxGIFBits)
#define GIFOutputCode(code) \
{ \
/* \
Emit a code. \
*/ \
if (bits > 0) \
datum|=((long) code << bits); \
else \
datum=(long) code; \
bits+=number_bits; \
while (bits >= 8) \
{ \
/* \
Add a character to current packet. \
*/ \
packet[byte_count++]=(unsigned char) (datum & 0xff); \
if (byte_count >= 254) \
{ \
(void) fputc(byte_count,image->file); \
(void) fwrite((char *) packet,1,byte_count,image->file); \
byte_count=0; \
} \
datum>>=8; \
bits-=8; \
} \
if (free_code > max_code) \
{ \
number_bits++; \
if (number_bits == MaxGIFBits) \
max_code=MaxGIFTable; \
else \
max_code=MaxCode(number_bits); \
} \
}
int
bits,
byte_count,
i,
number_bits;
long
datum;
register int
j,
k;
register RunlengthPacket
*p;
short
clear_code,
end_of_information_code,
free_code,
*hash_code,
*hash_prefix,
index,
max_code,
waiting_code;
unsigned char
*packet,
*hash_suffix;
/*
Allocate encoder tables.
*/
assert(image != (Image *) NULL);
packet=(unsigned char *) malloc(256*sizeof(unsigned char));
hash_code=(short *) malloc(MaxHashTable*sizeof(short));
hash_prefix=(short *) malloc(MaxHashTable*sizeof(short));
hash_suffix=(unsigned char *) malloc(MaxHashTable*sizeof(unsigned char));
if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) ||
(hash_prefix == (short *) NULL) ||
(hash_suffix == (unsigned char *) NULL))
return(False);
/*
Initialize GIF encoder.
*/
number_bits=data_size;
max_code=MaxCode(number_bits);
clear_code=((short) 1 << (data_size-1));
end_of_information_code=clear_code+1;
free_code=clear_code+2;
byte_count=0;
datum=0;
bits=0;
for (i=0; i < MaxHashTable; i++)
hash_code[i]=0;
GIFOutputCode(clear_code);
/*
Encode pixels.
*/
p=image->pixels;
waiting_code=p->index;
for (i=0; i < image->packets; i++)
{
for (j=(i == 0) ? 1 : 0; j <= ((int) p->length); j++)
{
/*
Probe hash table.
*/
index=p->index & 0xff;
k=(int) ((int) index << (MaxGIFBits-8))+waiting_code;
if (k >= MaxHashTable)
k-=MaxHashTable;
GIFOutputCode(waiting_code);
if (free_code < MaxGIFTable)
{
hash_code[k]=free_code++;
hash_prefix[k]=waiting_code;
hash_suffix[k]=index;
}
else
{
/*
Fill the hash table with empty entries.
*/
for (k=0; k < MaxHashTable; k++)
hash_code[k]=0;
/*
Reset compressor and issue a clear code.
*/
free_code=clear_code+2;
GIFOutputCode(clear_code);
number_bits=data_size;
max_code=MaxCode(number_bits);
}
waiting_code=index;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
p++;
}
/*
Flush out the buffered code.
*/
GIFOutputCode(waiting_code);
GIFOutputCode(end_of_information_code);
if (bits > 0)
{
/*
Add a character to current packet.
*/
packet[byte_count++]=(unsigned char) (datum & 0xff);
if (byte_count >= 254)
{
(void) fputc(byte_count,image->file);
(void) fwrite((char *) packet,1,byte_count,image->file);
byte_count=0;
}
}
/*
Flush accumulated data.
*/
if (byte_count > 0)
{
(void) fputc(byte_count,image->file);
(void) fwrite((char *) packet,1,byte_count,image->file);
}
/*
Free encoder memory.
*/
free((char *) hash_suffix);
free((char *) hash_prefix);
free((char *) hash_code);
free((char *) packet);
if (i < image->packets)
return(False);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% H u f f m a n D e c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function HuffmanDecodeImage uncompresses an image via Huffman-coding.
%
% The format of the HuffmanDecodeImage routine is:
%
% status=HuffmanDecodeImage(image)
%
% A description of each parameter follows:
%
% o status: Function HuffmanDecodeImage returns True if all the pixels are
% compressed without error, otherwise False.
%
% o image: The address of a structure of type Image.
%
%
*/
unsigned int HuffmanDecodeImage(Image *image)
{
#define HashSize 1021
#define MBHashA 293
#define MBHashB 2695
#define MWHashA 3510
#define MWHashB 1178
#define InitializeHashTable(hash,table,a,b) \
{ \
entry=table; \
while (entry->code != 0) \
{ \
hash[((entry->length+a)*(entry->code+b)) % HashSize]=entry; \
entry++; \
} \
}
#define InputBit(bit) \
{ \
if ((mask & 0xff) == 0) \
{ \
byte=getc(image->file); \
mask=0x80; \
} \
runlength++; \
bit=byte & mask ? 1 : 0; \
mask>>=1; \
if (bit) \
runlength=0; \
if (feof(image->file)) \
break; \
}
HuffmanTable
*entry,
**mb_hash,
**mw_hash;
int
bail,
code,
color,
count,
length,
null_lines,
runlength,
x,
y;
register int
i;
register RunlengthPacket
*q;
register unsigned char
*p;
unsigned char
bit,
byte,
mask,
*scanline;
unsigned int
packets;
unsigned short
index;
/*
Allocate buffers.
*/
assert(image != (Image *) NULL);
mb_hash=(HuffmanTable **) malloc(HashSize*sizeof(HuffmanTable *));
mw_hash=(HuffmanTable **) malloc(HashSize*sizeof(HuffmanTable *));
scanline=(unsigned char *) malloc(image->columns*sizeof(unsigned char));
if ((mb_hash == (HuffmanTable **) NULL) ||
(mw_hash == (HuffmanTable **) NULL) ||
(scanline == (unsigned char *) NULL))
{
Warning("Unable to allocate memory",(char *) NULL);
return(False);
}
/*
Initialize Huffman tables.
*/
for (i=0; i < HashSize; i++)
{
mb_hash[i]=(HuffmanTable *) NULL;
mw_hash[i]=(HuffmanTable *) NULL;
}
InitializeHashTable(mw_hash,TWTable,MWHashA,MWHashB);
InitializeHashTable(mw_hash,MWTable,MWHashA,MWHashB);
InitializeHashTable(mw_hash,EXTable,MWHashA,MWHashB);
InitializeHashTable(mb_hash,TBTable,MBHashA,MBHashB);
InitializeHashTable(mb_hash,MBTable,MBHashA,MBHashB);
InitializeHashTable(mb_hash,EXTable,MBHashA,MBHashB);
/*
Uncompress 1D Huffman to runlength encoded pixels.
*/
byte=0;
mask=0;
null_lines=0;
runlength=0;
while (runlength < 11)
InputBit(bit);
do { InputBit(bit); } while (bit == 0);
packets=image->packets;
image->packets=0;
q=image->pixels;
q->length=MaxRunlength;
for (y=0; ((y < image->rows) && (null_lines < 3)); )
{
/*
Initialize scanline to white.
*/
p=scanline;
for (x=0; x < image->columns; x++)
*p++=0;
/*
Decode Huffman encoded scanline.
*/
color=True;
code=0;
count=0;
length=0;
runlength=0;
x=0;
for ( ; ; )
{
if (x >= image->columns)
{
while (runlength < 11)
InputBit(bit);
do { InputBit(bit); } while (bit == 0);
break;
}
bail=False;
do
{
if (runlength < 11)
InputBit(bit)
else
{
InputBit(bit);
if (bit)
{
null_lines++;
if (x != 0)
null_lines=0;
bail=True;
break;
}
}
code=(code << 1)+bit;
length++;
} while (code <= 0);
if (bail)
break;
if (length > 13)
{
while (runlength < 11)
InputBit(bit);
do { InputBit(bit); } while (bit == 0);
break;
}
if (color)
{
if (length < 4)
continue;
entry=mw_hash[((length+MWHashA)*(code+MWHashB)) % HashSize];
}
else
{
if (length < 2)
continue;
entry=mb_hash[((length+MBHashA)*(code+MBHashB)) % HashSize];
}
if (!entry)
continue;
if ((entry->length != length) || (entry->code != code))
continue;
switch (entry->id)
{
case TWId:
case TBId:
{
count+=entry->count;
if ((x+count) > image->columns)
count=image->columns-x;
if (count > 0)
if (color)
{
x+=count;
count=0;
}
else
for ( ; count > 0; count--)
scanline[x++]=1;
color=!color;
break;
}
case MWId:
case MBId:
case EXId:
{
count+=entry->count;
break;
}
default:
break;
}
code=0;
length=0;
}
/*
Transfer scanline to image pixels.
*/
p=scanline;
for (x=0; x < image->columns; x++)
{
index=(unsigned short) (*p++);
if ((index == q->index) && ((int) q->length < MaxRunlength))
q->length++;
else
{
if (image->packets != 0)
q++;
image->packets++;
if (image->packets == packets)
{
packets<<=1;
image->pixels=(RunlengthPacket *)
realloc((char *) image->pixels,packets*sizeof(RunlengthPacket));
if (image->pixels == (RunlengthPacket *) NULL)
{
Warning("Unable to allocate memory",(char *) NULL);
return(False);
}
q=image->pixels+image->packets-1;
}
q->index=index;
q->length=0;
}
}
ProgressMonitor(LoadImageText,y++,image->rows);
}
image->rows=y;
SyncImage(image);
image->pixels=(RunlengthPacket *)
realloc((char *) image->pixels,image->packets*sizeof(RunlengthPacket));
/*
Free decoder memory.
*/
free((char *) mw_hash);
free((char *) mb_hash);
free((char *) scanline);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% H u f f m a n E n c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function HuffmanEncodeImage compresses an image via Huffman-coding.
%
% The format of the HuffmanEncodeImage routine is:
%
% status=HuffmanEncodeImage(image_info,image)
%
% A description of each parameter follows:
%
% o status: Function HuffmanEncodeImage returns True if all the pixels are
% compressed without error, otherwise False.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: The address of a structure of type Image.
%
*/
unsigned int HuffmanEncodeImage(const ImageInfo *image_info,Image *image)
{
#define HuffmanOutputCode(entry) \
{ \
mask=1 << (entry->length-1); \
while (mask != 0) \
{ \
OutputBit((entry->code & mask ? 1 : 0)); \
mask>>=1; \
} \
}
#define OutputBit(count) \
{ \
if(count > 0) \
byte=byte | bit; \
bit>>=1; \
if ((bit & 0xff) == 0) \
{ \
if (strcmp(image_info->magick,"FAX") == 0) \
(void) fputc((char) byte,image->file); \
else \
Ascii85Encode((unsigned int) byte,image->file); \
byte=0; \
bit=0x80; \
} \
}
HuffmanTable
*entry;
int
i,
k,
runlength;
register int
j,
n,
x;
register RunlengthPacket
*p;
register unsigned char
*q;
register unsigned short
polarity;
unsigned char
bit,
byte,
*scanline;
unsigned int
mask,
width;
/*
Allocate scanline buffer.
*/
assert(image != (Image *) NULL);
width=image->columns;
if (strcmp(image_info->magick,"FAX") == 0)
width=Max(image->columns,1728);
scanline=(unsigned char *) malloc((width+1)*sizeof(unsigned char));
if (scanline == (unsigned char *) NULL)
{
Warning("Unable to allocate memory",(char *) NULL);
return(False);
}
if (strcmp(image_info->magick,"FAX") != 0)
Ascii85Initialize();
else
{
/*
End of line.
*/
for (k=0; k < 11; k++)
OutputBit(0);
OutputBit(1);
}
/*
Compress runlength encoded to 1D Huffman pixels.
*/
polarity=0;
if (image->colors == 2)
polarity=(Intensity(image->colormap[0]) >
Intensity(image->colormap[1]) ? 0 : 1);
q=scanline;
for (i=0; i < width; i++)
*q++=polarity;
byte=0;
bit=0x80;
p=image->pixels;
q=scanline;
x=0;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
*q++=(unsigned char)
(p->index == polarity ? (int) polarity : (int) !polarity);
x++;
if (x < image->columns)
continue;
/*
Huffman encode scanline.
*/
q=scanline;
for (n=width; n > 0; )
{
/*
Output white run.
*/
for (runlength=0; ((*q == polarity) && (n > 0)); n--)
{
q++;
runlength++;
}
if (runlength >= 64)
{
entry=MWTable+((runlength/64)-1);
if (runlength >= 1792)
entry=EXTable+(Min(runlength,2560)-1792)/64;
runlength-=entry->count;
HuffmanOutputCode(entry);
}
entry=TWTable+Min(runlength,63);
HuffmanOutputCode(entry);
if (n != 0)
{
/*
Output black run.
*/
for (runlength=0; ((*q != polarity) && (n > 0)); n--)
{
q++;
runlength++;
}
if (runlength >= 64)
{
entry=MBTable+((runlength/64)-1);
if (runlength >= 1792)
entry=EXTable+(Min(runlength,2560)-1792)/64;
runlength-=entry->count;
HuffmanOutputCode(entry);
}
entry=TBTable+Min(runlength,63);
HuffmanOutputCode(entry);
}
}
/*
End of line.
*/
for (k=0; k < 11; k++)
OutputBit(0);
OutputBit(1);
x=0;
q=scanline;
}
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
/*
End of page.
*/
for (i=0; i < 6; i++)
{
for (k=0; k < 11; k++)
OutputBit(0);
OutputBit(1);
}
/*
Flush bits.
*/
if (bit != 0x80)
if (strcmp(image_info->magick,"FAX") == 0)
(void) fputc((char) byte,image->file);
else
Ascii85Encode((unsigned int) byte,image->file);
if (strcmp(image_info->magick,"FAX") != 0)
Ascii85Flush(image->file);
free((char *) scanline);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% P a c k b i t s E n c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function PackbitsEncodeImage compresses an image via Macintosh Packbits
% encoding specific to Postscript Level II or Portable Document Format. To
% ensure portability, the binary Packbits bytes are encoded as ASCII Base-85.
%
% The format of the PackbitsEncodeImage routine is:
%
% status=PackbitsEncodeImage(file,pixels,number_pixels)
%
% A description of each parameter follows:
%
% o status: Function PackbitsEncodeImage returns True if all the pixels are
% compressed without error, otherwise False.
%
% o file: The address of a structure of type FILE. LZW encoded pixels
% are written to this file.
%
% o pixels: The address of an unsigned array of characters containing the
% pixels to compress.
%
% o number_pixels: An unsigned interger that specifies the number of
% pixels to compress.
%
%
*/
unsigned int PackbitsEncodeImage(FILE *file,unsigned char *pixels,
unsigned int number_pixels)
{
register int
count,
i;
unsigned char
*packbits;
/*
Compress pixels with Packbits encoding.
*/
assert(file != (FILE *) NULL);
assert(pixels != (unsigned char *) NULL);
packbits=(unsigned char *) malloc(128*sizeof(unsigned char));
if (packbits == (unsigned char *) NULL)
{
Warning("Memory allocation error",(char *) NULL);
return(False);
}
Ascii85Initialize();
while (number_pixels != 0)
{
switch (number_pixels)
{
case 1:
{
number_pixels--;
Ascii85Encode(0,file);
Ascii85Encode(*pixels,file);
break;
}
case 2:
{
number_pixels-=2;
Ascii85Encode(1,file);
Ascii85Encode(*pixels,file);
Ascii85Encode(pixels[1],file);
break;
}
case 3:
{
number_pixels-=3;
if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
{
Ascii85Encode((256-3)+1,file);
Ascii85Encode(*pixels,file);
break;
}
Ascii85Encode(2,file);
Ascii85Encode(*pixels,file);
Ascii85Encode(pixels[1],file);
Ascii85Encode(pixels[2],file);
break;
}
default:
{
if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
{
/*
Packed run.
*/
count=3;
while ((count < number_pixels) && (*pixels == *(pixels+count)))
{
count++;
if (count >= 127)
break;
}
number_pixels-=count;
Ascii85Encode((256-count)+1,file);
Ascii85Encode(*pixels,file);
pixels+=count;
break;
}
/*
Literal run.
*/
count=0;
while ((*(pixels+count) != *(pixels+count+1)) ||
(*(pixels+count+1) != *(pixels+count+2)))
{
packbits[count+1]=pixels[count];
count++;
if ((count >= (number_pixels-3)) || (count >= 127))
break;
}
number_pixels-=count;
*packbits=count-1;
for (i=0; i <= count; i++)
Ascii85Encode(packbits[i],file);
pixels+=count;
break;
}
}
}
Ascii85Encode(128,file); /* EOD marker */
Ascii85Flush(file);
free((char *) packbits);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% P C D D e c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function PCDDecodeImage recovers the Huffman encoded luminance and
% chrominance deltas.
%
% The format of the PCDDecodeImage routine is:
%
% status=PCDDecodeImage(image,luma,chroma1,chroma2)
%
% A description of each parameter follows:
%
% o status: Function PCDDecodeImage returns True if all the deltas are
% recovered without error, otherwise False.
%
% o image: The address of a structure of type Image.
%
% o luma: The address of a character buffer that contains the
% luminance information.
%
% o chroma1: The address of a character buffer that contains the
% chrominance information.
%
% o chroma2: The address of a character buffer that contains the
% chrominance information.
%
%
%
*/
unsigned int PCDDecodeImage(Image *image,unsigned char *luma,
unsigned char *chroma1,unsigned char *chroma2)
{
#define IsSync ((accumulator & 0xffffff00) == 0xfffffe00)
#define PCDDecodeImageText " PCD decode image... "
#define PCDGetBits(n) \
{ \
accumulator=(accumulator << n) & 0xffffffff; \
bits-=n; \
while (bits <= 24) \
{ \
if (p >= (buffer+0x800)) \
{ \
(void) ReadData((char *) buffer,1,0x800,image->file); \
p=buffer; \
} \
accumulator|=((unsigned int) (*p) << (24-bits)); \
bits+=8; \
p++; \
} \
if (feof(image->file)) \
break; \
}
typedef struct PCDTable
{
unsigned int
length;
unsigned long
sequence;
unsigned char
key;
unsigned long
mask;
} PCDTable;
int
count;
PCDTable
*pcd_table[3];
register int
i,
j;
register PCDTable
*r;
register Quantum
*range_limit;
register unsigned char
*p,
*q;
unsigned char
*buffer;
unsigned int
accumulator,
bits,
length,
pcd_length[3],
plane,
row;
/*
Initialize Huffman tables.
*/
assert(image != (Image *) NULL);
assert(luma != (unsigned char *) NULL);
assert(chroma1 != (unsigned char *) NULL);
assert(chroma2 != (unsigned char *) NULL);
buffer=(unsigned char *) malloc(0x800*sizeof(unsigned char));
if (buffer == (unsigned char *) NULL)
{
Warning("Memory allocation error",(char *) NULL);
return(False);
}
(void) ReadData((char *) buffer,1,0x800,image->file);
p=buffer;
for (i=0; i < (image->columns > 1536 ? 3 : 1); i++)
{
length=(*p++)+1;
pcd_table[i]=(PCDTable *) malloc(length*sizeof(PCDTable));
if (pcd_table[i] == (PCDTable *) NULL)
{
Warning("Memory allocation error",(char *) NULL);
free((char *) buffer);
return(False);
}
r=pcd_table[i];
for (j=0; j < length; j++)
{
r->length=(*p++)+1;
r->sequence=(((unsigned int) *p++) << 24);
r->sequence|=(((unsigned int) *p++) << 16);
r->key=(*p++);
r->mask=(~((((unsigned int) 1) << (32-r->length))-1));
r++;
}
pcd_length[i]=length;
}
/*
Initialize range limits.
*/
range_limit=(Quantum *) malloc(3*(MaxRGB+1)*sizeof(Quantum));
if (range_limit == (Quantum *) NULL)
{
Warning("Memory allocation error",(char *) NULL);
free((char *) buffer);
return(False);
}
for (i=0; i <= MaxRGB; i++)
{
range_limit[i]=0;
range_limit[i+(MaxRGB+1)]=(Quantum) i;
range_limit[i+(MaxRGB+1)*2]=MaxRGB;
}
range_limit+=(MaxRGB+1);
/*
Search for Sync byte.
*/
accumulator=0;
bits=32;
do { PCDGetBits(16) } while (0);
do { PCDGetBits(16) } while (0);
while ((accumulator & 0x00fff000) != 0x00fff000)
PCDGetBits(8);
while (!IsSync)
PCDGetBits(1);
/*
Recover the Huffman encoded luminance and chrominance deltas.
*/
count=0;
length=0;
plane=0;
q=luma;
for ( ; ; )
{
if (IsSync)
{
/*
Determine plane and row number.
*/
PCDGetBits(24);
row=(accumulator >> 17) & 0x1fff;
plane=accumulator >> 30;
PCDGetBits(16);
ProgressMonitor(PCDDecodeImageText,row,image->rows);
if (row >= image->rows)
break;
switch (plane)
{
case 0:
{
q=luma+row*image->columns;
count=image->columns;
break;
}
case 2:
{
q=chroma1+(row >> 1)*image->columns;
count=image->columns >> 1;
plane--;
break;
}
case 3:
{
q=chroma2+(row >> 1)*image->columns;
count=image->columns >> 1;
plane--;
break;
}
default:
{
Warning("Corrupt PCD image",image->filename);
return(False);
}
}
length=pcd_length[plane];
continue;
}
/*
Decode luminance or chrominance deltas.
*/
r=pcd_table[plane];
for (i=0; ((i < length) && ((accumulator & r->mask) != r->sequence)); i++)
r++;
if (r == (PCDTable *) NULL)
{
Warning("Corrupt PCD image, skipping to sync byte",image->filename);
while ((accumulator & 0x00fff000) != 0x00fff000)
PCDGetBits(8);
while (!IsSync)
PCDGetBits(1);
continue;
}
if (count >= 0)
if (r->key < 128)
*q++=range_limit[(int) *q+(int) r->key];
else
*q++=range_limit[(int) *q+(int) r->key-256];
PCDGetBits(r->length);
count--;
}
/*
Free memory.
*/
for (i=0; i < (image->columns > 1536 ? 3 : 1); i++)
free((char *) pcd_table[i]);
range_limit-=(MaxRGB+1);
free((char *) range_limit);
free((char *) buffer);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% P I C T E n c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function PICTEncodeImage compresses an image via Macintosh pack bits
% encoding for Macintosh PICT images.
%
% The format of the PICTEncodeImage routine is:
%
% status=PICTEncodeImage(image,scanline,packbits)
%
% A description of each parameter follows:
%
% o status: Function PICTEncodeImage returns True if all the pixels are
% compressed without error, otherwise False.
%
% o image: The address of a structure of type Image.
%
% o scanline: A pointer to an array of characters to pack.
%
% o packbits: A pointer to an array of characters where the packed
% characters are stored.
%
%
*/
unsigned int PICTEncodeImage(Image *image,unsigned char *scanline,unsigned char *packbits)
{
#define MaxCount 128
#define MaxPackbitsRunlength 128
int
count,
number_packets,
repeat_count,
runlength;
register int
i;
register unsigned char
*p,
*q;
unsigned char
index;
unsigned int
bytes_per_line;
/*
Pack scanline.
*/
assert(image != (Image *) NULL);
assert(scanline != (unsigned char *) NULL);
assert(packbits != (unsigned char *) NULL);
bytes_per_line=image->columns;
if (image->class == DirectClass)
bytes_per_line*=3;
count=0;
runlength=0;
p=scanline+(bytes_per_line-1);
q=packbits;
index=(*p);
for (i=bytes_per_line-1; i >= 0; i--)
{
if (index == *p)
runlength++;
else
{
if (runlength < 3)
while (runlength > 0)
{
*q++=index;
runlength--;
count++;
if (count == MaxCount)
{
*q++=MaxCount-1;
count-=MaxCount;
}
}
else
{
if (count > 0)
*q++=count-1;
count=0;
while (runlength > 0)
{
repeat_count=runlength;
if (repeat_count > MaxPackbitsRunlength)
repeat_count=MaxPackbitsRunlength;
*q++=index;
*q++=257-repeat_count;
runlength-=repeat_count;
}
}
runlength=1;
}
index=(*p);
p--;
}
if (runlength < 3)
while (runlength > 0)
{
*q++=index;
runlength--;
count++;
if (count == MaxCount)
{
*q++=MaxCount-1;
count-=MaxCount;
}
}
else
{
if (count > 0)
*q++=count-1;
count=0;
while (runlength > 0)
{
repeat_count=runlength;
if (repeat_count > MaxPackbitsRunlength)
repeat_count=MaxPackbitsRunlength;
*q++=index;
*q++=257-repeat_count;
runlength-=repeat_count;
}
}
if (count > 0)
*q++=count-1;
/*
Write the number of and the packed packets.
*/
number_packets=(int) (q-packbits);
if ((bytes_per_line-1) > 250)
{
MSBFirstWriteShort((unsigned short) number_packets,image->file);
number_packets+=2;
}
else
{
index=number_packets;
(void) fputc((char) index,image->file);
number_packets++;
}
while (q != packbits)
{
q--;
(void) fputc((char) *q,image->file);
}
return(number_packets);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R u n l e n g t h D e c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function RunlengthDecodeImage unpacks the packed image pixels into
% runlength-encoded pixel packets. The packed image pixel memory is then
% freed.
%
% The format of the RunlengthDecodeImage routine is:
%
% status=RunlengthDecodeImage(image)
%
% A description of each parameter follows:
%
% o status: Function RunlengthDecodeImage return True if the image is
% decoded. False is returned if there is an error occurs.
%
% o image: The address of a structure of type Image.
%
%
*/
unsigned int RunlengthDecodeImage(Image *image)
{
register int
i;
register RunlengthPacket
*q;
register unsigned char
*p;
unsigned long
count;
unsigned short
value;
assert(image != (Image *) NULL);
if (image->packed_pixels == (unsigned char *) NULL)
return(True);
/*
Allocate pixels.
*/
if (image->pixels == (RunlengthPacket *) NULL)
image->pixels=(RunlengthPacket *)
malloc((unsigned int) image->packets*sizeof(RunlengthPacket));
else
image->pixels=(RunlengthPacket *) realloc((char *) image->pixels,
image->packets*sizeof(RunlengthPacket));
if (image->pixels == (RunlengthPacket *) NULL)
{
Warning("Unable to unpack pixels","Memory allocation failed");
return(False);
}
/*
Unpack the packed image pixels into runlength-encoded pixel packets.
*/
p=image->packed_pixels;
q=image->pixels;
count=0;
if (image->class == DirectClass)
{
if (image->compression == RunlengthEncodedCompression)
for (i=0; i < image->packets; i++)
{
ReadQuantum(q->red,p);
ReadQuantum(q->green,p);
ReadQuantum(q->blue,p);
q->index=0;
if (image->matte)
ReadQuantum(q->index,p);
q->length=(*p++);
count+=(q->length+1);
q++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(LoadImageText,i,image->packets);
}
else
for (i=0; i < image->packets; i++)
{
ReadQuantum(q->red,p);
ReadQuantum(q->green,p);
ReadQuantum(q->blue,p);
q->index=0;
if (image->matte)
ReadQuantum(q->index,p);
q->length=0;
count++;
q++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(LoadImageText,i,image->packets);
}
}
else
{
register unsigned short
index;
if (image->compression == RunlengthEncodedCompression)
{
if (image->colors <= 256)
for (i=0; i < image->packets; i++)
{
q->index=(unsigned short) (*p++);
q->length=(*p++);
count+=(q->length+1);
q++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(LoadImageText,i,image->packets);
}
else
for (i=0; i < image->packets; i++)
{
index=(*p++) << 8;
index|=(*p++);
q->index=index;
q->length=(*p++);
count+=(q->length+1);
q++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(LoadImageText,i,image->packets);
}
}
else
if (image->colors <= 256)
for (i=0; i < image->packets; i++)
{
q->index=(unsigned short) (*p++);
q->length=0;
count++;
q++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(LoadImageText,i,image->packets);
}
else
for (i=0; i < image->packets; i++)
{
index=(*p++) << 8;
index|=(*p++);
q->index=index;
q->length=0;
count++;
q++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(LoadImageText,i,image->packets);
}
SyncImage(image);
}
/*
Free packed pixels memory.
*/
free((char *) image->packed_pixels);
image->packed_pixels=(unsigned char *) NULL;
/*
Guarentee the correct number of pixel packets.
*/
if (count > (image->columns*image->rows))
{
Warning("insufficient image data in file",image->filename);
return(False);
}
else
if (count < (image->columns*image->rows))
{
Warning("too much image data in file",image->filename);
return(False);
}
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R u n l e n g t h E n c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function RunlengthEncodeImage packs the runlength-encoded pixel packets
% into the minimum number of bytes.
%
% The format of the RunlengthEncodeImage routine is:
%
% count=RunlengthEncodeImage(image)
%
% A description of each parameter follows:
%
% o status: Function RunlengthEncodeImage return the number of bytes the
% image consumes. Zero is returned if an error occurs.
%
% o image: The address of a structure of type Image.
%
%
*/
unsigned int RunlengthEncodeImage(Image *image)
{
#define SpecialRunlength 255
register int
i,
j;
register RunlengthPacket
*p;
register unsigned char
*q;
unsigned long
count,
packets;
unsigned short
value;
assert(image != (Image *) NULL);
if (image->pixels == (RunlengthPacket *) NULL)
{
Warning("Unable to pack pixels","no image pixels");
return(0);
}
if (image->compression == RunlengthEncodedCompression)
{
register RunlengthPacket
*q;
/*
Compress image.
*/
p=image->pixels;
for (i=0; i < image->packets; i++)
{
if (p->length > SpecialRunlength)
{
/*
Uncompress image to allow in-place compression.
*/
if (!UncompressImage(image))
return(0);
break;
}
p++;
}
p=image->pixels;
image->runlength=p->length+1;
image->packets=0;
q=image->pixels;
q->length=SpecialRunlength;
if (image->matte)
for (i=0; i < (image->columns*image->rows); i++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
if ((p->red == q->red) && (p->green == q->green) &&
(p->blue == q->blue) && (p->index == q->index) &&
(q->length < SpecialRunlength))
q->length++;
else
{
if (image->packets != 0)
q++;
image->packets++;
*q=(*p);
q->length=0;
}
}
else
for (i=0; i < (image->columns*image->rows); i++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
if ((p->red == q->red) && (p->green == q->green) &&
(p->blue == q->blue) && (q->length < SpecialRunlength))
q->length++;
else
{
if (image->packets != 0)
q++;
image->packets++;
*q=(*p);
q->length=0;
}
}
image->pixels=(RunlengthPacket *) realloc((char *) image->pixels,
image->packets*sizeof(RunlengthPacket));
/*
Runlength-encode only if it consumes less memory than no compression.
*/
if (image->class == DirectClass)
{
if (image->packets >= ((image->columns*image->rows*3) >> 2))
image->compression=NoCompression;
}
else
if (image->packets >= ((image->columns*image->rows) >> 1))
image->compression=NoCompression;
}
/*
Determine packed packet size.
*/
if (image->class == PseudoClass)
{
image->packet_size=1;
if (image->colors > 256)
image->packet_size++;
}
else
{
image->packet_size=3*(image->depth >> 3);
if (image->matte)
image->packet_size+=image->depth >> 3;
}
if (image->compression == RunlengthEncodedCompression)
image->packet_size++;
/*
Allocate packed pixel memory.
*/
packets=image->packets;
if (image->compression != RunlengthEncodedCompression)
packets=image->columns*image->rows;
if (image->packed_pixels == (unsigned char *) NULL)
image->packed_pixels=(unsigned char *)
malloc((unsigned int) packets*image->packet_size*sizeof(unsigned char));
else
image->packed_pixels=(unsigned char *) realloc((char *)
image->packed_pixels,packets*image->packet_size*sizeof(unsigned char));
if (image->packed_pixels == (unsigned char *) NULL)
{
Warning("Unable to pack pixels","Memory allocation failed");
return(0);
}
/*
Packs the runlength-encoded pixel packets into the minimum number of bytes.
*/
p=image->pixels;
q=image->packed_pixels;
count=0;
if (image->class == DirectClass)
{
if (image->compression == RunlengthEncodedCompression)
for (i=0; i < image->packets; i++)
{
WriteQuantum(p->red,q);
WriteQuantum(p->green,q);
WriteQuantum(p->blue,q);
if (image->matte)
WriteQuantum(p->index,q);
*q++=p->length;
count+=(p->length+1);
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
else
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
WriteQuantum(p->red,q);
WriteQuantum(p->green,q);
WriteQuantum(p->blue,q);
if (image->matte)
WriteQuantum(p->index,q);
}
count+=(p->length+1);
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
}
else
if (image->compression == RunlengthEncodedCompression)
{
if (image->colors <= 256)
for (i=0; i < image->packets; i++)
{
*q++=(unsigned char) p->index;
*q++=p->length;
count+=(p->length+1);
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
else
for (i=0; i < image->packets; i++)
{
*q++=p->index >> 8;
*q++=(unsigned char) p->index;
*q++=p->length;
count+=(p->length+1);
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
}
else
if (image->colors <= 256)
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
*q++=p->index;
count+=(p->length+1);
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
else
{
register unsigned char
xff00,
xff;
for (i=0; i < image->packets; i++)
{
xff00=p->index >> 8;
xff=p->index;
for (j=0; j <= ((int) p->length); j++)
{
*q++=xff00;
*q++=xff;
}
count+=(p->length+1);
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
}
/*
Guarentee the correct number of pixel packets.
*/
if (count < (image->columns*image->rows))
{
Warning("insufficient image data in",image->filename);
return(0);
}
else
if (count > (image->columns*image->rows))
{
Warning("too much image data in",image->filename);
return(0);
}
return((unsigned int) packets);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% S U N D e c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function SUNDecodeImage unpacks the packed image pixels into
% runlength-encoded pixel packets.
%
% The format of the SUNDecodeImage routine is:
%
% status=SUNDecodeImage(compressed_pixels,pixels,number_columns,
% number_rows)
%
% A description of each parameter follows:
%
% o status: Function SUNDecodeImage returns True if all the pixels are
% uncompressed without error, otherwise False.
%
% o compressed_pixels: The address of a byte (8 bits) array of compressed
% pixel data.
%
% o pixels: The address of a byte (8 bits) array of pixel data created by
% the uncompression process. The number of bytes in this array
% must be at least equal to the number columns times the number of rows
% of the source pixels.
%
% o number_columns: An integer value that is the number of columns or
% width in pixels of your source image.
%
% o number_rows: An integer value that is the number of rows or
% heigth in pixels of your source image.
%
%
*/
unsigned int SUNDecodeImage(unsigned char *compressed_pixels,
unsigned char *pixels,const unsigned int number_columns,
const unsigned int number_rows)
{
register int
count;
register unsigned char
*p,
*q;
unsigned char
byte;
assert(compressed_pixels != (unsigned char *) NULL);
assert(pixels != (unsigned char *) NULL);
p=compressed_pixels;
q=pixels;
while ((q-pixels) <= (number_columns*number_rows))
{
byte=(*p++);
if (byte != 128)
*q++=byte;
else
{
/*
Runlength-encoded packet: <count><byte>
*/
count=(*p++);
if (count > 0)
byte=(*p++);
while (count >= 0)
{
*q++=byte;
count--;
}
}
}
return(True);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.