/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% EEEEE N N CCCC OOO DDDD EEEEE %
% E NN N C O O D D E %
% EEE N N N C O O D D EEE %
% E N NN C O O D D E %
% EEEEE N N CCCC OOO DDDD EEEEE %
% %
% %
% Utility Routines to Write Image Formats %
% %
% %
% %
% Software Design %
% John Cristy %
% January 1992 %
% %
% %
% 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. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Functions in this library convert to and from `alien' image formats to the
% MIFF image format.
%
%
*/
/*
Include declarations.
*/
#include "magick.h"
#include "version.h"
#include "Colorlist.h"
#include "XWDFile.h"
#include "plug-ins.h"
/*
Define declarations.
*/
#define SaveImageText " Saving image... "
#define PrematureExit(message,image) \
{ \
Warning(message,image->filename); \
return(False); \
}
/*
Function prototypes.
*/
static unsigned int
WriteMIFFImage(const ImageInfo *,Image *),
WritePNMImage(const ImageInfo *,Image *),
WriteYUVImage(const ImageInfo *,Image *);
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e A V S I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteAVSImage writes an image to a file in AVS X image format.
%
% The format of the WriteAVSImage routine is:
%
% status=WriteAVSImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteAVSImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteAVSImage(const ImageInfo *image_info,Image *image)
{
register int
i,
j;
register RunlengthPacket
*p;
unsigned int
scene;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
scene=0;
do
{
/*
Initialize raster file header.
*/
MSBFirstWriteLong(image->columns,image->file);
MSBFirstWriteLong(image->rows,image->file);
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
(void) fputc(image->matte ? DownScale(p->index) : Opaque,image->file);
(void) fputc(DownScale(p->red),image->file);
(void) fputc(DownScale(p->green),image->file);
(void) fputc(DownScale(p->blue),image->file);
}
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
if (image->next == (Image *) NULL)
break;
image->next->file=image->file;
image=image->next;
ProgressMonitor(SaveImageText,scene++,image->number_scenes);
} while (image_info->adjoin);
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e B M P I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteBMPImage writes an image in Microsoft Windows bitmap encoded
% image format.
%
% The format of the WriteBMPImage routine is:
%
% status=WriteBMPImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteBMPImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteBMPImage(const ImageInfo *image_info,Image *image)
{
typedef struct _BMPHeader
{
unsigned long
file_size;
unsigned short
reserved[2];
unsigned long
offset_bits,
size,
width,
height;
unsigned short
planes,
bit_count;
unsigned long
compression,
image_size,
x_pixels,
y_pixels,
number_colors,
colors_important;
} BMPHeader;
BMPHeader
bmp_header;
register int
i,
j,
x,
y;
register RunlengthPacket
*p;
register unsigned char
*q;
unsigned char
*bmp_data,
*bmp_pixels;
unsigned int
bytes_per_line,
scene;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
scene=0;
do
{
/*
Initialize BMP raster file header.
*/
bmp_header.file_size=14+40;
bmp_header.offset_bits=14+40;
if (!IsPseudoClass(image) && !IsGrayImage(image))
{
/*
Full color BMP raster.
*/
bmp_header.number_colors=0;
bmp_header.bit_count=24;
bytes_per_line=((image->columns*bmp_header.bit_count+31)/32)*4;
}
else
{
/*
Colormapped BMP raster.
*/
bmp_header.bit_count=8;
bytes_per_line=((image->columns*bmp_header.bit_count+31)/32)*4;
image->compression=image_info->compression;
if (image->compression == RunlengthEncodedCompression)
bytes_per_line=image->columns;
if (IsMonochromeImage(image))
{
bmp_header.bit_count=1;
bytes_per_line=((image->columns*bmp_header.bit_count+31)/32)*4;
}
bmp_header.file_size+=4*(1 << bmp_header.bit_count);
bmp_header.offset_bits+=4*(1 << bmp_header.bit_count);
bmp_header.number_colors=1 << bmp_header.bit_count;
}
bmp_header.reserved[0]=0;
bmp_header.reserved[1]=0;
bmp_header.size=40;
bmp_header.width=image->columns;
bmp_header.height=image->rows;
bmp_header.planes=1;
bmp_header.compression=0;
bmp_header.image_size=bytes_per_line*image->rows;
bmp_header.file_size+=bmp_header.image_size;
bmp_header.x_pixels=75*39;
bmp_header.y_pixels=75*39;
if (image->units == PixelsPerInchResolution)
{
bmp_header.x_pixels=(unsigned long) (100.0*image->x_resolution/2.54);
bmp_header.y_pixels=(unsigned long) (100.0*image->y_resolution/2.54);
}
if (image->units == PixelsPerCentimeterResolution)
{
bmp_header.x_pixels=(unsigned long) (100.0*image->x_resolution);
bmp_header.y_pixels=(unsigned long) (100.0*image->y_resolution);
}
bmp_header.colors_important=bmp_header.number_colors;
/*
Convert MIFF to BMP raster pixels.
*/
bmp_pixels=(unsigned char *)
malloc(bmp_header.image_size*sizeof(unsigned char));
if (bmp_pixels == (unsigned char *) NULL)
PrematureExit("Unable to allocate memory",image);
x=0;
y=image->rows-1;
switch (bmp_header.bit_count)
{
case 1:
{
register unsigned char
bit,
byte,
polarity;
/*
Convert PseudoClass image to a BMP monochrome image.
*/
p=image->pixels;
polarity=0;
if (image->colors == 2)
polarity=
Intensity(image->colormap[1]) > Intensity(image->colormap[0]);
bit=0;
byte=0;
q=bmp_pixels+y*bytes_per_line;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
byte<<=1;
if (p->index == polarity)
byte|=0x01;
bit++;
if (bit == 8)
{
*q++=byte;
bit=0;
byte=0;
}
x++;
if (x == image->columns)
{
/*
Advance to the next scanline.
*/
if (bit != 0)
*q++=byte << (8-bit);
bit=0;
byte=0;
x=0;
y--;
q=bmp_pixels+y*bytes_per_line;
}
}
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
break;
}
case 8:
{
/*
Convert PseudoClass packet to BMP pixel.
*/
p=image->pixels;
q=bmp_pixels+y*bytes_per_line;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
*q++=p->index;
x++;
if (x == image->columns)
{
x=0;
y--;
q=bmp_pixels+y*bytes_per_line;
}
}
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
break;
}
case 24:
{
/*
Convert DirectClass packet to BMP RGB pixel.
*/
p=image->pixels;
q=bmp_pixels+y*bytes_per_line-1;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
*q++=DownScale(p->blue);
*q++=DownScale(p->green);
*q++=DownScale(p->red);
x++;
if (x == image->columns)
{
x=0;
y--;
q=bmp_pixels+y*bytes_per_line;
}
}
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
break;
}
}
if (bmp_header.bit_count == 8)
if (image->compression == RunlengthEncodedCompression)
{
unsigned int
packets;
/*
Convert run-length encoded raster pixels.
*/
packets=(unsigned int)
((bytes_per_line*(bmp_header.height+2)+1) << 1);
bmp_data=(unsigned char *) malloc(packets*sizeof(unsigned char));
if (bmp_pixels == (unsigned char *) NULL)
{
Warning("Memory allocation error",(char *) NULL);
free((char *) bmp_pixels);
return(False);
}
bmp_header.image_size=
BMPEncodeImage(bmp_pixels,bmp_data,image->columns,image->rows);
free((char *) bmp_pixels);
bmp_pixels=bmp_data;
bmp_header.compression=1;
}
/*
Write BMP header.
*/
(void) fwrite("BM",1,2,image->file);
LSBFirstWriteLong(bmp_header.file_size,image->file);
LSBFirstWriteShort(bmp_header.reserved[0],image->file);
LSBFirstWriteShort(bmp_header.reserved[1],image->file);
LSBFirstWriteLong(bmp_header.offset_bits,image->file);
LSBFirstWriteLong(bmp_header.size,image->file);
LSBFirstWriteLong(bmp_header.width,image->file);
LSBFirstWriteLong(bmp_header.height,image->file);
LSBFirstWriteShort(bmp_header.planes,image->file);
LSBFirstWriteShort(bmp_header.bit_count,image->file);
LSBFirstWriteLong(bmp_header.compression,image->file);
LSBFirstWriteLong(bmp_header.image_size,image->file);
LSBFirstWriteLong(bmp_header.x_pixels,image->file);
LSBFirstWriteLong(bmp_header.y_pixels,image->file);
LSBFirstWriteLong(bmp_header.number_colors,image->file);
LSBFirstWriteLong(bmp_header.colors_important,image->file);
if (image->class == PseudoClass)
{
unsigned char
*bmp_colormap;
/*
Dump colormap to file.
*/
bmp_colormap=(unsigned char *)
malloc(4*(1 << bmp_header.bit_count)*sizeof(unsigned char));
if (bmp_colormap == (unsigned char *) NULL)
PrematureExit("Unable to allocate memory",image);
q=bmp_colormap;
for (i=0; i < image->colors; i++)
{
*q++=DownScale(image->colormap[i].blue);
*q++=DownScale(image->colormap[i].green);
*q++=DownScale(image->colormap[i].red);
q++;
}
for ( ; i < (int) (1 << bmp_header.bit_count); i++)
{
*q++=0;
*q++=0;
*q++=0;
q++;
}
(void) fwrite((char *) bmp_colormap,4,1 << bmp_header.bit_count,
image->file);
free((char *) bmp_colormap);
}
(void) fwrite((char *) bmp_pixels,1,(int) bmp_header.image_size,
image->file);
free((char *) bmp_pixels);
if (image->next == (Image *) NULL)
break;
image->next->file=image->file;
image=image->next;
ProgressMonitor(SaveImageText,scene++,image->number_scenes);
} while (image_info->adjoin);
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e C G M I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteCGMImage writes an image in the CGM encoded image format.
%
% The format of the WriteCGMImage routine is:
%
% status=WriteCGMImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteCGMImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteCGMImage(const ImageInfo *image_info,
Image *image)
{
unsigned int
status;
Warning("Cannot write CGM images",image->filename);
status=WriteMIFFImage(image_info,image);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e C M Y K I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteCMYKImage writes an image to a file in cyan, magenta,
% yellow, and black rasterfile format.
%
% The format of the WriteCMYKImage routine is:
%
% status=WriteCMYKImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteCMYKImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteCMYKImage(const ImageInfo *image_info,Image *image)
{
float
black_generation,
undercolor;
int
black,
cyan,
magenta,
yellow;
register int
i,
j;
register RunlengthPacket
*p;
unsigned int
scene;
image->depth=QuantumDepth;
if (image_info->interlace != PartitionInterlace)
{
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
}
/*
Convert MIFF to CMYK raster pixels.
*/
undercolor=1.0;
black_generation=1.0;
if (image_info->undercolor != (char *) NULL)
{
(void) sscanf(image_info->undercolor,"%fx%f",&undercolor,
&black_generation);
if (black_generation == 1.0)
black_generation=undercolor;
}
scene=0;
do
{
switch (image_info->interlace)
{
case NoneInterlace:
default:
{
/*
No interlacing: CMYKCMYKCMYKCMYKCMYKCMYK...
*/
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
cyan=MaxRGB-p->red;
magenta=MaxRGB-p->green;
yellow=MaxRGB-p->blue;
black=cyan;
if (magenta < black)
black=magenta;
if (yellow < black)
black=yellow;
WriteQuantumFile((unsigned int) (cyan-undercolor*black));
WriteQuantumFile((unsigned int) (magenta-undercolor*black));
WriteQuantumFile((unsigned int) (yellow-undercolor*black));
WriteQuantumFile((unsigned int) (black_generation*black));
}
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
break;
}
case LineInterlace:
{
register int
x,
y;
/*
Line interlacing: CCC...MMM...YYY...CCC...MMM...YYY...
*/
if (!UncompressImage(image))
return(False);
for (y=0; y < image->rows; y++)
{
p=image->pixels+(y*image->columns);
for (x=0; x < image->columns; x++)
{
cyan=MaxRGB-p->red;
magenta=MaxRGB-p->green;
yellow=MaxRGB-p->blue;
black=cyan;
if (magenta < black)
black=magenta;
if (yellow < black)
black=yellow;
WriteQuantumFile((unsigned int) (cyan-undercolor*black));
p++;
}
p=image->pixels+(y*image->columns);
for (x=0; x < image->columns; x++)
{
cyan=MaxRGB-p->red;
magenta=MaxRGB-p->green;
yellow=MaxRGB-p->blue;
black=cyan;
if (magenta < black)
black=magenta;
if (yellow < black)
black=yellow;
WriteQuantumFile((unsigned int) (magenta-undercolor*black));
p++;
}
p=image->pixels+(y*image->columns);
for (x=0; x < image->columns; x++)
{
cyan=MaxRGB-p->red;
magenta=MaxRGB-p->green;
yellow=MaxRGB-p->blue;
black=cyan;
if (magenta < black)
black=magenta;
if (yellow < black)
black=yellow;
WriteQuantumFile((unsigned int) (yellow-undercolor*black));
p++;
}
p=image->pixels+(y*image->columns);
for (x=0; x < image->columns; x++)
{
cyan=MaxRGB-p->red;
magenta=MaxRGB-p->green;
yellow=MaxRGB-p->blue;
black=cyan;
if (magenta < black)
black=magenta;
if (yellow < black)
black=yellow;
WriteQuantumFile((unsigned int) (black_generation*black));
p++;
}
ProgressMonitor(SaveImageText,y,image->rows);
}
break;
}
case PlaneInterlace:
case PartitionInterlace:
{
/*
Plane interlacing: CCCCCC...MMMMMM...YYYYYY...KKKKKK...
*/
if (image_info->interlace == PartitionInterlace)
{
AppendImageFormat("C",image->filename);
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
}
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
cyan=MaxRGB-p->red;
magenta=MaxRGB-p->green;
yellow=MaxRGB-p->blue;
black=cyan;
if (magenta < black)
black=magenta;
if (yellow < black)
black=yellow;
WriteQuantumFile((unsigned int) (cyan-undercolor*black));
}
p++;
}
if (image_info->interlace == PartitionInterlace)
{
CloseImage(image);
AppendImageFormat("M",image->filename);
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
}
ProgressMonitor(SaveImageText,100,400);
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
cyan=MaxRGB-p->red;
magenta=MaxRGB-p->green;
yellow=MaxRGB-p->blue;
black=cyan;
if (magenta < black)
black=magenta;
if (yellow < black)
black=yellow;
WriteQuantumFile((unsigned int) (magenta-undercolor*black));
}
p++;
}
if (image_info->interlace == PartitionInterlace)
{
CloseImage(image);
AppendImageFormat("Y",image->filename);
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
}
ProgressMonitor(SaveImageText,200,400);
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
cyan=MaxRGB-p->red;
magenta=MaxRGB-p->green;
yellow=MaxRGB-p->blue;
black=cyan;
if (magenta < black)
black=magenta;
if (yellow < black)
black=yellow;
WriteQuantumFile((unsigned int) (yellow-undercolor*black));
}
p++;
}
if (image_info->interlace == PartitionInterlace)
{
CloseImage(image);
AppendImageFormat("K",image->filename);
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
}
ProgressMonitor(SaveImageText,300,400);
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
cyan=MaxRGB-p->red;
magenta=MaxRGB-p->green;
yellow=MaxRGB-p->blue;
black=cyan;
if (magenta < black)
black=magenta;
if (yellow < black)
black=yellow;
WriteQuantumFile((unsigned int) (black_generation*black));
}
p++;
}
if (image_info->interlace == PartitionInterlace)
(void) strcpy(image->filename,image_info->filename);
ProgressMonitor(SaveImageText,400,400);
break;
}
}
if (image->next == (Image *) NULL)
break;
image->next->file=image->file;
image=image->next;
ProgressMonitor(SaveImageText,scene++,image->number_scenes);
} while (image_info->adjoin);
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e F A X I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Procedure WriteFAXImage writes an image to a file in 1 dimensional Huffman
% encoded format.
%
% The format of the WriteFAXImage routine is:
%
% status=WriteFAXImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteFAXImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteFAXImage(const ImageInfo *image_info,Image *image)
{
unsigned int
scene,
status;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
scene=0;
do
{
/*
Convert MIFF to monochrome.
*/
if (!IsMonochromeImage(image))
{
QuantizeInfo
quantize_info;
GetQuantizeInfo(&quantize_info);
quantize_info.number_colors=2;
quantize_info.dither=image_info->dither;
quantize_info.colorspace=GRAYColorspace;
QuantizeImage(&quantize_info,image);
SyncImage(image);
}
status=HuffmanEncodeImage(image_info,image);
if (image->next == (Image *) NULL)
break;
image->next->file=image->file;
image=image->next;
ProgressMonitor(SaveImageText,scene++,image->number_scenes);
} while (image_info->adjoin);
CloseImage(image);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e F I T S I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteFITSImage writes a Flexible Image Transport System image to a
% file as gray scale intensities [0..255].
%
% The format of the WriteFITSImage routine is:
%
% status=WriteFITSImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteFITSImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteFITSImage(const ImageInfo *image_info,Image *image)
{
char
buffer[81],
*fits_header;
register int
i,
j;
register RunlengthPacket
*p;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
/*
Allocate image header.
*/
fits_header=(char *) malloc(2880*sizeof(unsigned char));
if (fits_header == (char *) NULL)
PrematureExit("Unable to allocate memory",image);
/*
Initialize image header.
*/
for (i=0; i < 2880; i++)
fits_header[i]=' ';
(void) strcpy(buffer,"SIMPLE = T");
(void) strncpy(fits_header+0,buffer,Extent(buffer));
(void) strcpy(buffer,"BITPIX = 8");
(void) strncpy(fits_header+80,buffer,Extent(buffer));
(void) strcpy(buffer,"NAXIS = 2");
(void) strncpy(fits_header+160,buffer,Extent(buffer));
(void) sprintf(buffer,"NAXIS1 = %10u",image->columns);
(void) strncpy(fits_header+240,buffer,Extent(buffer));
(void) sprintf(buffer,"NAXIS2 = %10u",image->rows);
(void) strncpy(fits_header+320,buffer,Extent(buffer));
(void) strcpy(buffer,"HISTORY Created by ImageMagick.");
(void) strncpy(fits_header+400,buffer,Extent(buffer));
(void) strcpy(buffer,"END");
(void) strncpy(fits_header+480,buffer,Extent(buffer));
(void) fwrite((char *) fits_header,1,2880,image->file);
free((char *) fits_header);
/*
Convert image to fits scale PseudoColor class.
*/
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
(void) fputc(DownScale(Intensity(*p)),image->file);
p++;
if (QuantumTick(i,image))
ProgressMonitor(SaveImageText,i,image->packets);
}
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e G I F I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteGIFImage writes an image to a file in the Compuserve Graphics
% image format.
%
% The format of the WriteGIFImage routine is:
%
% status=WriteGIFImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteGIFImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteGIFImage(const ImageInfo *image_info,Image *image)
{
ColorPacket
transparent_pixel;
Image
*next_image;
RectangleInfo
page_info;
register int
i,
x;
register RunlengthPacket
*p;
register unsigned char
*q;
unsigned char
bits_per_pixel,
c,
*colormap;
unsigned int
colors,
global_colormap,
height,
interlace,
scene,
status,
width;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
/*
Allocate colormap.
*/
colormap=(unsigned char *) malloc(3*256*sizeof(unsigned char));
if (colormap == (unsigned char *) NULL)
PrematureExit("Unable to allocate memory",image);
/*
Write GIF header.
*/
if ((image->comments == (char *) NULL) && !image_info->adjoin &&
!image->matte)
(void) fwrite("GIF87a",1,6,image->file);
else
if (strcmp(image_info->magick,"GIF87") == 0)
(void) fwrite("GIF87a",1,6,image->file);
else
(void) fwrite("GIF89a",1,6,image->file);
/*
Determine image bounding box and global colormap status.
*/
page_info.x=0;
page_info.y=0;
page_info.width=image->columns;
page_info.height=image->rows;
global_colormap=image->class == PseudoClass;
next_image=image;
for ( ; next_image != (Image *) NULL; next_image=next_image->next)
{
width=next_image->columns;
height=next_image->rows;
if (next_image->page != (char *) NULL)
(void) XParseGeometry(next_image->page,&page_info.x,&page_info.y,&width,
&height);
if ((width+page_info.x) > page_info.width);
page_info.width=width+page_info.y;
if ((height+page_info.y) > page_info.height);
page_info.height=height+page_info.y;
if (!global_colormap)
continue;
if ((next_image->class == DirectClass) ||
(next_image->colors != image->colors))
{
global_colormap=False;
continue;
}
for (i=0; i < image->colors; i++)
if (!ColorMatch(next_image->colormap[i],image->colormap[i],0))
{
global_colormap=False;
break;
}
}
if (image_info->page != (char *) NULL)
(void) XParseGeometry(image_info->page,&page_info.x,&page_info.y,
&page_info.width,&page_info.height);
LSBFirstWriteShort(page_info.width,image->file);
LSBFirstWriteShort(page_info.height,image->file);
/*
Write images to file.
*/
interlace=image_info->interlace;
if (image_info->adjoin && (image->next != (Image *) NULL))
interlace=NoneInterlace;
scene=0;
do
{
transparent_pixel.flags=False;
if (IsPseudoClass(image))
colors=image->colors;
else
{
QuantizeInfo
quantize_info;
unsigned char
*matte_image;
matte_image=(unsigned char *) NULL;
if (image->matte)
{
/*
Track all the transparent pixels.
*/
if (!UncompressImage(image))
return(False);
matte_image=(unsigned char *)
malloc(image->packets*sizeof(unsigned char));
if (matte_image == (unsigned char *) NULL)
{
Warning("Memory allocation error",image->filename);
return(False);
}
p=image->pixels;
for (i=0; i < image->packets; i++)
{
matte_image[i]=p->index == Transparent;
if (p->index == Transparent)
{
transparent_pixel.red=p->red;
transparent_pixel.green=p->green;
transparent_pixel.blue=p->blue;
transparent_pixel.flags=True;
}
p++;
}
}
colors=transparent_pixel.flags ? 255 : 256;
GetQuantizeInfo(&quantize_info);
quantize_info.number_colors=colors;
quantize_info.dither=image_info->dither;
QuantizeImage(&quantize_info,image);
SyncImage(image);
CompressColormap(image);
colors=image->colors;
if (transparent_pixel.flags)
{
/*
Set the transparent pixel index.
*/
image->class=DirectClass;
if (!UncompressImage(image))
return(False);
p=image->pixels;
for (i=0; i < image->packets; i++)
{
if (matte_image[i])
p->index=image->colors;
p++;
}
colors++;
}
if (matte_image != (unsigned char *) NULL)
free((char *) matte_image);
}
for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++)
if ((1 << bits_per_pixel) >= colors)
break;
q=colormap;
for (i=0; i < image->colors; i++)
{
*q++=DownScale(image->colormap[i].red);
*q++=DownScale(image->colormap[i].green);
*q++=DownScale(image->colormap[i].blue);
}
if (transparent_pixel.flags)
{
*q++=DownScale(transparent_pixel.red);
*q++=DownScale(transparent_pixel.green);
*q++=DownScale(transparent_pixel.blue);
i++;
}
for ( ; i < (int) (1 << bits_per_pixel); i++)
{
*q++=0x0;
*q++=0x0;
*q++=0x0;
}
if (!image_info->adjoin || (image->previous == (Image *) NULL))
{
register int
j;
/*
Write global colormap.
*/
c=0x80;
c|=(8-1) << 4; /* color resolution */
c|=(bits_per_pixel-1); /* size of global colormap */
(void) fputc((char) c,image->file);
for (j=0; j < image->colors; j++)
if (ColorMatch(image->background_color,image->colormap[j],0))
break;
(void) fputc(j,image->file); /* background color */
(void) fputc(0x0,image->file); /* reserved */
(void) fwrite(colormap,1,3*(1 << bits_per_pixel),image->file);
}
if (strcmp(image_info->magick,"GIF87") != 0)
{
/*
Write Graphics Control extension.
*/
(void) fputc(0x21,image->file);
(void) fputc(0xf9,image->file);
(void) fputc(0x04,image->file);
c=image->dispose << 2;
if (transparent_pixel.flags)
c|=0x01;
(void) fputc(c,image->file);
LSBFirstWriteShort(image->delay,image->file);
(void) fputc((char) image->colors,image->file);
(void) fputc(0x00,image->file);
if (image->comments != (char *) NULL)
{
register char
*p;
register unsigned int
count;
/*
Write Comment extension.
*/
(void) fputc(0x21,image->file);
(void) fputc(0xfe,image->file);
p=image->comments;
while (Extent(p) > 0)
{
count=Min(Extent(p),255);
(void) fputc(count,image->file);
for (i=0; i < count; i++)
(void) fputc(*p++,image->file);
}
(void) fputc(0x0,image->file);
}
if ((image->previous == (Image *) NULL) &&
(image->next != (Image *) NULL) && (image->iterations != 1))
{
/*
Write Netscape Loop extension.
*/
(void) fputc(0x21,image->file);
(void) fputc(0xff,image->file);
(void) fputc(0x0b,image->file);
(void) fwrite("NETSCAPE2.0",1,11,image->file);
(void) fputc(0x03,image->file);
(void) fputc(0x01,image->file);
LSBFirstWriteShort(image->iterations,image->file);
(void) fputc(0x00,image->file);
}
}
(void) fputc(',',image->file); /* image separator */
/*
Write the image header.
*/
if (image->page != (char *) NULL)
(void) XParseGeometry(image->page,&page_info.x,&page_info.y,
&page_info.width,&page_info.height);
LSBFirstWriteShort(page_info.x,image->file);
LSBFirstWriteShort(page_info.y,image->file);
LSBFirstWriteShort(image->columns,image->file);
LSBFirstWriteShort(image->rows,image->file);
c=0x00;
if (interlace != NoneInterlace)
c|=0x40; /* pixel data is interlaced */
if (global_colormap)
(void) fputc((char) c,image->file);
else
{
c|=0x80;
c|=(bits_per_pixel-1); /* size of local colormap */
(void) fputc((char) c,image->file);
(void) fwrite(colormap,1,3*(1 << bits_per_pixel),image->file);
}
/*
Write the image data.
*/
c=Max(bits_per_pixel,2);
(void) fputc((char) c,image->file);
if (interlace == NoneInterlace)
status=GIFEncodeImage(image,Max(bits_per_pixel,2)+1);
else
{
Image
*interlaced_image;
int
pass,
y;
register RunlengthPacket
*q;
static int
interlace_rate[4] = { 8, 8, 4, 2 },
interlace_start[4] = { 0, 4, 2, 1 };
/*
Interlace image.
*/
if (!UncompressImage(image))
return(False);
image->orphan=True;
interlaced_image=CloneImage(image,image->columns,image->rows,False);
image->orphan=False;
if (interlaced_image == (Image *) NULL)
PrematureExit("Unable to allocate memory",image);
p=image->pixels;
q=interlaced_image->pixels;
for (pass=0; pass < 4; pass++)
{
y=interlace_start[pass];
while (y < image->rows)
{
p=image->pixels+(y*image->columns);
for (x=0; x < image->columns; x++)
{
*q=(*p);
p++;
q++;
}
y+=interlace_rate[pass];
}
}
interlaced_image->file=image->file;
status=GIFEncodeImage(interlaced_image,Max(bits_per_pixel,2)+1);
interlaced_image->file=(FILE *) NULL;
DestroyImage(interlaced_image);
}
if (status == False)
PrematureExit("Unable to allocate memory",image);
(void) fputc(0x0,image->file);
if (image->next == (Image *) NULL)
break;
image->next->file=image->file;
image=image->next;
ProgressMonitor(SaveImageText,scene++,image->number_scenes);
} while (image_info->adjoin);
(void) fputc(';',image->file); /* terminator */
free((char *) colormap);
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e G R A D A T I O N I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteGRADATIONImage writes an image in the gradation image format.
%
% The format of the WriteGRADATIONImage routine is:
%
% status=WriteGRADATIONImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteGRADATIONImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteGRADATIONImage(const ImageInfo *image_info,
Image *image)
{
unsigned int
status;
Warning("Cannot write GRADATION images",image->filename);
status=WriteMIFFImage(image_info,image);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e G R A Y I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteGRAYImage writes an image to a file as gray scale intensity
% values.
%
% The format of the WriteGRAYImage routine is:
%
% status=WriteGRAYImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteGRAYImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteGRAYImage(const ImageInfo *image_info,Image *image)
{
register int
i,
j;
register RunlengthPacket
*p;
unsigned int
scene;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
/*
Convert image to gray scale PseudoColor class.
*/
image->depth=QuantumDepth;
scene=0;
do
{
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
WriteQuantumFile(Intensity(*p));
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
if (image->next == (Image *) NULL)
break;
image->next->file=image->file;
image=image->next;
ProgressMonitor(SaveImageText,scene++,image->number_scenes);
} while (image_info->adjoin);
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e H D F I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteHDFImage writes an image in the Hierarchial Data Format image
% format.
%
% The format of the WriteHDFImage routine is:
%
% status=WriteHDFImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteHDFImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
#ifdef HasHDF
static unsigned int WriteHDFImage(const ImageInfo *image_info,Image *image)
{
#include "hdf.h"
#undef BSD
#undef LOCAL
int
status;
register int
i,
j;
register RunlengthPacket
*p;
register unsigned char
*q;
uint16
reference;
unsigned char
*hdf_pixels;
unsigned int
compression,
packet_size,
scene;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
CloseImage(image);
scene=0;
do
{
/*
Initialize raster file header.
*/
packet_size=1;
if (image->class == DirectClass)
packet_size=3;
hdf_pixels=(unsigned char *)
malloc(packet_size*image->columns*image->rows*sizeof(unsigned char));
if (hdf_pixels == (unsigned char *) NULL)
PrematureExit("Unable to allocate memory",image);
p=image->pixels;
if (!IsPseudoClass(image) && !IsGrayImage(image))
{
/*
Convert DirectClass packet to HDF pixels.
*/
q=hdf_pixels;
switch (image_info->interlace)
{
case NoneInterlace:
default:
{
/*
No interlacing: RGBRGBRGBRGBRGBRGB...
*/
DF24setil(DFIL_PIXEL);
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
*q++=DownScale(p->red);
*q++=DownScale(p->green);
*q++=DownScale(p->blue);
}
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
break;
}
case LineInterlace:
{
register int
x,
y;
/*
Line interlacing: RRR...GGG...BBB...RRR...GGG...BBB...
*/
if (!UncompressImage(image))
return(False);
DF24setil(DFIL_LINE);
for (y=0; y < image->rows; y++)
{
p=image->pixels+(y*image->columns);
for (x=0; x < image->columns; x++)
{
*q++=DownScale(p->red);
p++;
}
p=image->pixels+(y*image->columns);
for (x=0; x < image->columns; x++)
{
*q++=DownScale(p->green);
p++;
}
p=image->pixels+(y*image->columns);
for (x=0; x < image->columns; x++)
{
*q++=DownScale(p->blue);
p++;
}
ProgressMonitor(SaveImageText,y,image->rows);
}
break;
}
case PlaneInterlace:
case PartitionInterlace:
{
/*
Plane interlacing: RRRRRR...GGGGGG...BBBBBB...
*/
DF24setil(DFIL_PLANE);
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
*q++=DownScale(p->red);
p++;
}
ProgressMonitor(SaveImageText,100,400);
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
*q++=DownScale(p->green);
p++;
}
ProgressMonitor(SaveImageText,250,400);
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
*q++=DownScale(p->blue);
p++;
}
ProgressMonitor(SaveImageText,400,400);
break;
}
}
if (scene == 0)
status=DF24putimage(image->filename,(void *) hdf_pixels,
image->columns,image->rows);
else
status=DF24addimage(image->filename,(void *) hdf_pixels,
image->columns,image->rows);
reference=DF24lastref();
}
else
{
/*
Convert PseudoClass packet to HDF pixels.
*/
q=hdf_pixels;
if (IsGrayImage(image))
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
*q++=DownScale(p->red);
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
else
{
unsigned char
*hdf_palette;
hdf_palette=(unsigned char *) malloc(768*sizeof(unsigned char));
if (hdf_palette == (unsigned char *) NULL)
PrematureExit("Unable to allocate memory",image);
q=hdf_palette;
for (i=0; i < image->colors; i++)
{
*q++=DownScale(image->colormap[i].red);
*q++=DownScale(image->colormap[i].green);
*q++=DownScale(image->colormap[i].blue);
}
(void) DFR8setpalette(hdf_palette);
free(hdf_palette);
q=hdf_pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
*q++=p->index;
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
}
compression=image_info->compression == NoCompression ? 0 : DFTAG_RLE;
if (scene == 0)
status=DFR8putimage(image->filename,(void *) hdf_pixels,
image->columns,image->rows,compression);
else
status=DFR8addimage(image->filename,(void *) hdf_pixels,
image->columns,image->rows,compression);
reference=DFR8lastref();
}
if (image->label != (char *) NULL)
(void) DFANputlabel(image->filename,DFTAG_RIG,reference,image->label);
if (image->comments != (char *) NULL)
(void) DFANputdesc(image->filename,DFTAG_RIG,reference,image->comments,
Extent(image->comments)+1);
free(hdf_pixels);
if (image->next == (Image *) NULL)
break;
image->next->file=image->file;
image=image->next;
ProgressMonitor(SaveImageText,scene++,image->number_scenes);
} while (image_info->adjoin);
return(status != -1);
}
#else
static unsigned int WriteHDFImage(const ImageInfo *image_info,Image *image)
{
unsigned int
status;
Warning("HDF library is not available",image->filename);
status=WriteMIFFImage(image_info,image);
return(status);
}
#endif
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e H I S T O G R A M I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteHISTOGRAMImage writes an image to a file in HISTOGRAM format.
% The image shows a histogram of the color (or gray) values in the image. The
% image consists of three overlaid histograms: a red one for the red channel,
% a green one for the green channel, and a blue one for the blue channel. The
% image comment contains a list of unique pixel values and the number of times
% each occurs in the image.
%
% This routine is strongly based on a similiar one written by
% muquit@warm.semcor.com which in turn is based on ppmhistmap of netpbm.
%
% The format of the WriteHISTOGRAMImage routine is:
%
% status=WriteHISTOGRAMImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteHISTOGRAMImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteHISTOGRAMImage(const ImageInfo *image_info,
Image *image)
{
#define HistogramDensity "256x200"
char
filename[MaxTextExtent];
double
scale;
FILE
*file;
Image
*histogram_image;
int
*blue,
*green,
maximum,
*red,
sans_offset;
register RunlengthPacket
*p,
*q;
register int
i,
j;
unsigned int
height,
status,
width;
/*
Allocate histogram image.
*/
(void) XParseGeometry(HistogramDensity,&sans_offset,&sans_offset,
&width,&height);
if (image_info->density != (char *) NULL)
(void) XParseGeometry(image_info->density,&sans_offset,&sans_offset,
&width,&height);
image->orphan=True;
histogram_image=CloneImage(image,width,height,False);
image->orphan=False;
if (histogram_image == (Image *) NULL)
PrematureExit("Unable to allocate memory",image);
histogram_image->class=DirectClass;
/*
Allocate histogram count arrays.
*/
red=(int *) malloc (histogram_image->columns*sizeof(int));
green=(int *) malloc (histogram_image->columns*sizeof(int));
blue=(int *) malloc (histogram_image->columns*sizeof(int));
if ((red == (int *) NULL) || (green == (int *) NULL) ||
(blue == (int *) NULL))
{
DestroyImage(histogram_image);
PrematureExit("Unable to allocate memory",image);
}
/*
Initialize histogram count arrays.
*/
for (i=0; i < histogram_image->columns; i++)
{
red[i]=0;
green[i]=0;
blue[i]=0;
}
p=image->pixels;
for (i=0; i < image->packets; i++)
{
red[DownScale(p->red)]+=(p->length+1);
green[DownScale(p->green)]+=(p->length+1);
blue[DownScale(p->blue)]+=(p->length+1);
p++;
}
maximum=0;
for (i=0; i < histogram_image->columns; i++)
{
if (maximum < red[i])
maximum=red[i];
if (maximum < green[i])
maximum=green[i];
if (maximum < blue[i])
maximum=blue[i];
}
for (i=0; i < histogram_image->columns; i++)
{
if (red[i] > maximum)
red[i]=maximum;
if (green[i] > maximum)
green[i]=maximum;
if (blue[i] > maximum)
blue[i]=maximum;
}
/*
Initialize histogram image.
*/
q=histogram_image->pixels;
for (i=0; i < histogram_image->packets; i++)
{
q->red=0;
q->green=0;
q->blue=0;
q->index=0;
q->length=0;
q++;
}
scale=(double) histogram_image->rows/maximum;
q=histogram_image->pixels;
for (i=0; i < histogram_image->columns; i++)
{
j=histogram_image->rows-(int) (scale*red[i]);
while (j < histogram_image->rows)
{
q=histogram_image->pixels+(j*histogram_image->columns+i);
q->red=MaxRGB;
j++;
}
j=histogram_image->rows-(int) (scale*green[i]);
while (j < histogram_image->rows)
{
q=histogram_image->pixels+(j*histogram_image->columns+i);
q->green=MaxRGB;
j++;
}
j=histogram_image->rows-(int) (scale*blue[i]);
while (j < histogram_image->rows)
{
q=histogram_image->pixels+(j*histogram_image->columns+i);
q->blue=MaxRGB;
j++;
}
ProgressMonitor(SaveImageText,i,histogram_image->columns);
}
free ((char *) blue);
free ((char *) green);
free ((char *) red);
TemporaryFilename(filename);
file=fopen(filename,WriteBinaryType);
if (file != (FILE *) NULL)
{
char
command[MaxTextExtent];
/*
Add a histogram as an image comment.
*/
(void) fprintf(file,"%s\n",image->comments);
NumberColors(image,file);
(void) fclose(file);
(void) sprintf(command,"@%s",filename);
CommentImage(histogram_image,command);
(void) remove(filename);
}
/*
Write HISTOGRAM image as MIFF.
*/
status=WriteMIFFImage(image_info,histogram_image);
DestroyImage(histogram_image);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e H T M L I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteHTMLImage writes an image in the HTML encoded image format.
%
% The format of the WriteHTMLImage routine is:
%
% status=WriteHTMLImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteHTMLImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteHTMLImage(const ImageInfo *image_info,Image *image)
{
char
filename[MaxTextExtent],
mapname[MaxTextExtent],
url[MaxTextExtent];
int
x,
y;
register char
*p;
unsigned int
height,
status,
width;
*url='\0';
if ((strcmp(image_info->magick,"FTP") == 0) ||
(strcmp(image_info->magick,"HTTP") == 0))
{
/*
Extract URL base from filename.
*/
p=strrchr(image->filename,'/');
if (p)
{
p++;
(void) strcpy(url,image_info->magick);
(void) strcat(url,":");
url[Extent(url)+p-image->filename]='\0';
(void) strncat(url,image->filename,p-image->filename);
(void) strcpy(image->filename,p);
}
}
/*
Refer to image map file.
*/
(void) strcpy(filename,image->filename);
AppendImageFormat("map",filename);
p=filename+Extent(filename)-1;
while ((p > filename) && (*(p-1) != *BasenameSeparator))
p--;
(void) strcpy(mapname,p);
for (p=mapname+Extent(mapname)-1; p > mapname; p--)
if (*p == '.')
{
*p='\0';
break;
}
(void) strcpy(filename,image->filename);
status=True;
if (strcmp(image_info->magick,"SHTML") != 0)
{
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
/*
Write the HTML image file.
*/
if (*image->magick_filename != '\0')
(void) strcpy(image->filename,image->magick_filename);
(void) fprintf(image->file,"\n");
(void) fprintf(image->file,"
\n");
(void) fprintf(image->file,"%s\n",image->filename);
(void) fprintf(image->file,"\n");
(void) fprintf(image->file,"\n");
(void) fprintf(image->file,"\n");
(void) fprintf(image->file,"%s
\n",image->filename);
(void) fprintf(image->file,"
\n");
(void) strcpy(filename,image->filename);
AppendImageFormat("gif",filename);
(void) fprintf(image->file,"
\n",
mapname,filename);
/*
Determine the size and location of each image tile.
*/
x=0;
y=0;
width=image->columns;
height=image->rows;
if (image->montage != (char *) NULL)
(void) XParseGeometry(image->montage,&x,&y,&width,&height);
/*
Write an image map.
*/
(void) fprintf(image->file,"\n");
if (image->montage != (char *) NULL)
{
char
color[MaxTextExtent];
/*
Back montage background transparent.
*/
(void) sprintf(color,"#%02x%02x%02x",
(unsigned int) image->pixels[0].red,
(unsigned int) image->pixels[0].green,
(unsigned int) image->pixels[0].blue);
TransparentImage(image,color);
}
(void) strcpy(filename,image->filename);
(void) fprintf(image->file,"\n");
(void) fprintf(image->file,"\n");
status=fprintf(image->file,"\n");
CloseImage(image);
if (strcmp(image_info->magick,"GIF") != 0)
{
/*
Write the image as transparent GIF.
*/
(void) strcpy(image->filename,filename);
AppendImageFormat("gif",image->filename);
status|=WriteGIFImage(image_info,image);
}
/*
Determine image map filename.
*/
(void) strcpy(image->filename,filename);
for (p=filename+Extent(filename)-1; p > filename; p--)
if (*p == '.')
{
(void) strncpy(image->filename,filename,p-filename);
image->filename[p-filename]='\0';
break;
}
(void) strcat(image->filename,"_map.shtml");
}
/*
Open image map.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
/*
Determine the size and location of each image tile.
*/
x=0;
y=0;
width=image->columns;
height=image->rows;
if (image->montage != (char *) NULL)
(void) XParseGeometry(image->montage,&x,&y,&width,&height);
/*
Write an image map.
*/
(void) fprintf(image->file,"\n");
CloseImage(image);
(void) strcpy(image->filename,filename);
return(status);
}
#ifdef HasJBIG
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e J B I G I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteJBIGImage writes an image in the JBIG encoded image format.
%
% The format of the WriteJBIGImage routine is:
%
% status=WriteJBIGImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteJBIGImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static void JBIGEncode(unsigned char *start,size_t length,void *file)
{
(void) fwrite(start,length,1,(FILE *) file);
return;
}
static unsigned int WriteJBIGImage(const ImageInfo *image_info,Image *image)
{
int
sans_offset;
register int
i,
j;
register RunlengthPacket
*p;
register unsigned char
bit,
*q;
struct jbg_enc_state
jbig_info;
unsigned char
*pixels,
polarity;
unsigned int
byte,
number_packets,
scene,
x,
x_resolution,
y_resolution;
/*
Open image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
scene=0;
do
{
/*
Allocate pixel data.
*/
number_packets=((image->columns+7) >> 3)*image->rows;
pixels=(unsigned char *) malloc(number_packets*sizeof(unsigned char));
if (pixels == (unsigned char *) NULL)
PrematureExit("Unable to allocate memory",image);
/*
Convert Runlength encoded pixels to a bitmap.
*/
if (!IsMonochromeImage(image))
{
QuantizeInfo
quantize_info;
GetQuantizeInfo(&quantize_info);
quantize_info.number_colors=2;
quantize_info.dither=image_info->dither;
quantize_info.colorspace=GRAYColorspace;
QuantizeImage(&quantize_info,image);
SyncImage(image);
}
polarity=0;
if (image->colors == 2)
polarity=Intensity(image->colormap[0]) > Intensity(image->colormap[1]);
bit=0;
byte=0;
x=0;
p=image->pixels;
q=pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
byte<<=1;
if (p->index == polarity)
byte|=0x01;
bit++;
if (bit == 8)
{
*q++=byte;
bit=0;
byte=0;
}
x++;
if (x == image->columns)
{
/*
Advance to the next scanline.
*/
if (bit != 0)
*q++=byte << (8-bit);
bit=0;
byte=0;
x=0;
}
}
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
/*
Initialize JBIG info structure.
*/
jbg_enc_init(&jbig_info,image->columns,image->rows,1,&pixels,
(void (*)(unsigned char *,size_t,void *)) JBIGEncode,image->file);
x_resolution=640;
y_resolution=480;
(void) XParseGeometry(image_info->density,&sans_offset,&sans_offset,
&x_resolution,&y_resolution);
if (image_info->subimage != 0)
jbg_enc_layers(&jbig_info,image_info->subimage);
else
jbg_enc_lrlmax(&jbig_info,x_resolution,y_resolution);
jbg_enc_lrange(&jbig_info,-1,-1);
jbg_enc_options(&jbig_info,JBG_ILEAVE | JBG_SMID,JBG_TPDON | JBG_TPBON |
JBG_DPON,-1,-1,-1);
/*
Write JBIG image.
*/
jbg_enc_out(&jbig_info);
jbg_enc_free(&jbig_info);
free((char *) pixels);
if (image->next == (Image *) NULL)
break;
image->next->file=image->file;
image=image->next;
ProgressMonitor(SaveImageText,scene++,image->number_scenes);
} while (image_info->adjoin);
CloseImage(image);
return(True);
}
#else
static unsigned int WriteJBIGImage(const ImageInfo *image_info,Image *image)
{
unsigned int
status;
Warning("JBIG library is not available",image->filename);
status=WriteMIFFImage(image_info,image);
return(status);
}
#endif
#ifdef HasJPEG
static Image
*image;
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e J P E G I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteJPEGImage writes a JPEG image file and returns it. It
% allocates the memory necessary for the new Image structure and returns a
% pointer to the new image.
%
% The format of the WriteJPEGImage routine is:
%
% status=WriteJPEGImage(image_info,image)
%
% A description of each parameter follows:
%
% o status: Function WriteJPEGImage return True if the image is written.
% False is returned is there is of a memory shortage or if the image
% file cannot be opened for writing.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o jpeg_image: A pointer to a Image structure.
%
%
*/
static void EmitMessage(j_common_ptr jpeg_info,int level)
{
char
message[JMSG_LENGTH_MAX];
struct jpeg_error_mgr
*jpeg_error;
jpeg_error=jpeg_info->err;
(jpeg_error->format_message) (jpeg_info,message);
if (level < 0)
{
if (jpeg_error->num_warnings == 0 || jpeg_error->trace_level >= 3)
Warning((char *) message,image->filename);
jpeg_error->num_warnings++;
}
else
if (jpeg_error->trace_level >= level)
Warning((char *) message,image->filename);
}
static unsigned int WriteJPEGImage(const ImageInfo *image_info,Image *image)
{
JSAMPLE
*jpeg_pixels;
JSAMPROW
scanline[1];
register int
i,
j,
x;
register JSAMPLE
*q;
register RunlengthPacket
*p;
struct jpeg_compress_struct
jpeg_info;
struct jpeg_error_mgr
jpeg_error;
unsigned int
packets;
/*
Open image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
/*
Initialize JPEG parameters.
*/
jpeg_info.err=jpeg_std_error(&jpeg_error);
jpeg_info.err->emit_message=EmitMessage;
jpeg_create_compress(&jpeg_info);
jpeg_stdio_dest(&jpeg_info,image->file);
jpeg_info.image_width=image->columns;
jpeg_info.image_height=image->rows;
jpeg_info.input_components=3;
jpeg_info.in_color_space=JCS_RGB;
if (IsGrayImage(image))
{
jpeg_info.input_components=1;
jpeg_info.in_color_space=JCS_GRAYSCALE;
}
jpeg_set_defaults(&jpeg_info);
jpeg_info.density_unit=0;
jpeg_info.X_density=(short) image->x_resolution;
jpeg_info.Y_density=(short) image->y_resolution;
if (image->units == PixelsPerInchResolution)
jpeg_info.density_unit=1;
if (image->units == PixelsPerCentimeterResolution)
jpeg_info.density_unit=2;
for (i=0; i < MAX_COMPONENTS; i++)
{
jpeg_info.comp_info[i].h_samp_factor=1;
jpeg_info.comp_info[i].v_samp_factor=1;
}
jpeg_set_quality(&jpeg_info,image_info->quality,True);
jpeg_info.optimize_coding=True;
#if (JPEG_LIB_VERSION >= 61)
jpeg_info.dct_method=JDCT_FLOAT;
if (image_info->interlace != NoneInterlace)
jpeg_simple_progression(&jpeg_info);
#endif
jpeg_start_compress(&jpeg_info,True);
if (image->comments != (char *) NULL)
for (i=0; i < Extent(image->comments); i+=65533)
jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) image->comments+i,
(unsigned int) Min(Extent(image->comments+i),65533));
/*
Convert MIFF to JPEG raster pixels.
*/
packets=jpeg_info.input_components*image->columns;
jpeg_pixels=(JSAMPLE *) malloc(packets*sizeof(JSAMPLE));
if (jpeg_pixels == (JSAMPLE *) NULL)
PrematureExit("Unable to allocate memory",image);
p=image->pixels;
q=jpeg_pixels;
x=0;
scanline[0]=(JSAMPROW) jpeg_pixels;
if ((jpeg_info.data_precision > 8) && (QuantumDepth > 8))
{
if (jpeg_info.in_color_space == JCS_GRAYSCALE)
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
*q++=(JSAMPLE) (Intensity(*p) >> 4);
x++;
if (x == image->columns)
{
(void) jpeg_write_scanlines(&jpeg_info,scanline,1);
q=jpeg_pixels;
x=0;
}
}
p++;
if (QuantumTick(i,image))
ProgressMonitor(SaveImageText,i,image->packets);
}
else
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
*q++=(JSAMPLE) (p->red >> 4);
*q++=(JSAMPLE) (p->green >> 4);
*q++=(JSAMPLE) (p->blue >> 4);
x++;
if (x == image->columns)
{
(void) jpeg_write_scanlines(&jpeg_info,scanline,1);
q=jpeg_pixels;
x=0;
}
}
p++;
if (QuantumTick(i,image))
ProgressMonitor(SaveImageText,i,image->packets);
}
}
else
if (jpeg_info.in_color_space == JCS_GRAYSCALE)
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
*q++=(JSAMPLE) DownScale(Intensity(*p));
x++;
if (x == image->columns)
{
(void) jpeg_write_scanlines(&jpeg_info,scanline,1);
q=jpeg_pixels;
x=0;
}
}
p++;
if (QuantumTick(i,image))
ProgressMonitor(SaveImageText,i,image->packets);
}
else
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
*q++=(JSAMPLE) DownScale(p->red);
*q++=(JSAMPLE) DownScale(p->green);
*q++=(JSAMPLE) DownScale(p->blue);
x++;
if (x == image->columns)
{
(void) jpeg_write_scanlines(&jpeg_info,scanline,1);
q=jpeg_pixels;
x=0;
}
}
p++;
if (QuantumTick(i,image))
ProgressMonitor(SaveImageText,i,image->packets);
}
jpeg_finish_compress(&jpeg_info);
/*
Free memory.
*/
jpeg_destroy_compress(&jpeg_info);
free((char *) jpeg_pixels);
CloseImage(image);
return(True);
}
#else
static unsigned int WriteJPEGImage(const ImageInfo *image_info,Image *image)
{
unsigned int
status;
Warning("JPEG library is not available",image->filename);
status=WriteMIFFImage(image_info,image);
return(status);
}
#endif
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e L O G O I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteLOGOImage writes an image in the LOGO encoded image format.
% We use GIF because it is the only format that is compressed without
% requiring addition optional plug-ins (TIFF, ZIP, etc).
%
% The format of the WriteLOGOImage routine is:
%
% status=WriteLOGOImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteLOGOImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteLOGOImage(const ImageInfo *image_info,Image *image)
{
char
filename[MaxTextExtent];
FILE
*file;
int
c;
register int
i;
unsigned int
status;
unsigned long
filesize;
/*
Write logo as PseudoColor MIFF image to a temporary file.
*/
(void) strcpy(filename,image->filename);
TemporaryFilename(image->filename);
status=WriteGIFImage(image_info,image);
if (status == False)
return(status);
OpenImage(image_info,image,ReadBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
(void) remove(image->filename);
filesize=image->filesize;
file=image->file;
/*
Write logo image.
*/
(void) strcpy(image->filename,filename);
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
(void) fprintf(image->file,"/*\n");
(void) fprintf(image->file," Logo image declaration.\n");
(void) fprintf(image->file,"*/\n");
(void) fprintf(image->file,"#define LogoImageExtent %lu\n\n",filesize);
(void) fprintf(image->file,"static unsigned char\n");
(void) fprintf(image->file," LogoImage[]=\n");
(void) fprintf(image->file," {\n");
(void) fprintf(image->file," ");
for (i=0; ; i++)
{
c=fgetc(file);
if (c < 0)
break;
(void) fprintf(image->file,"0x%02x, ",c);
if (((i+1) % 12) == 0)
(void) fprintf(image->file,"\n ");
}
(void) fprintf(image->file,"\n };\n");
(void) fclose(file);
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e M A P I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteMAPImage writes an image to a file as red, green, and blue
% colormap bytes followed by the colormap indexes.
%
% The format of the WriteMAPImage routine is:
%
% status=WriteMAPImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteMAPImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteMAPImage(const ImageInfo *image_info,Image *image)
{
register int
i;
register unsigned char
*q;
unsigned char
*colormap;
unsigned int
packets,
packet_size;
unsigned short
value;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
/*
Allocate colormap.
*/
if (image->class == DirectClass)
{
QuantizeInfo
quantize_info;
/*
Demote DirectClass to PseudoClass.
*/
GetQuantizeInfo(&quantize_info);
quantize_info.number_colors=MaxColormapSize;
quantize_info.dither=image_info->dither;
QuantizeImage(&quantize_info,image);
SyncImage(image);
}
packet_size=3*(image->depth >> 3);
colormap=(unsigned char *)
malloc(packet_size*image->colors*sizeof(unsigned char));
if (colormap == (unsigned char *) NULL)
PrematureExit("Unable to allocate memory",image);
/*
Write colormap to file.
*/
q=colormap;
for (i=0; i < image->colors; i++)
{
WriteQuantum(image->colormap[i].red,q);
WriteQuantum(image->colormap[i].green,q);
WriteQuantum(image->colormap[i].blue,q);
}
(void) fwrite((char *) colormap,1,(int) image->colors*packet_size,
image->file);
free((char *) colormap);
/*
Write image pixels to file.
*/
image->compression=NoCompression;
packets=RunlengthEncodeImage(image);
(void) fwrite((char *) image->packed_pixels,(int) image->packet_size,
(int) packets,image->file);
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e M A T T E I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteMATTEImage writes an image of matte bytes to a file. It
% consists of data from the matte component of the image [0..255].
%
% The format of the WriteMATTEImage routine is:
%
% status=WriteMATTEImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteMATTEImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteMATTEImage(const ImageInfo *image_info,Image *image)
{
Image
*matte_image;
register int
i;
unsigned int
status;
if (!image->matte)
PrematureExit("Image does not have a matte channel",image);
image->orphan=True;
matte_image=CloneImage(image,image->columns,image->rows,True);
image->orphan=False;
if (matte_image == (Image *) NULL)
PrematureExit("Unable to allocate memory",image);
matte_image->class=PseudoClass;
matte_image->colors=(Opaque-Transparent)+1;
matte_image->colormap=(ColorPacket *)
malloc(matte_image->colors*sizeof(ColorPacket));
if (matte_image->colormap == (ColorPacket *) NULL)
PrematureExit("Unable to allocate memory",image);
for (i=Transparent; i <= Opaque; i++)
{
matte_image->colormap[i].red=i;
matte_image->colormap[i].green=i;
matte_image->colormap[i].blue=i;
}
SyncImage(matte_image);
status=WriteMIFFImage(image_info,matte_image);
DestroyImage(matte_image);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e M I F F I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteMIFFImage writes an image to a file.
%
% The format of the WriteMIFFImage routine is:
%
% status=WriteMIFFImage(image_info,image)
%
% A description of each parameter follows:
%
% o status: Function WriteMIFFImage return True if the image is written.
% False is returned if there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteMIFFImage(const ImageInfo *image_info,Image *image)
{
register int
i;
unsigned int
scene;
unsigned long
packets;
if ((image->class != DirectClass) && (image->class != PseudoClass))
PrematureExit("Unknown image class",image);
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
(void) strcpy((char *) image_info->magick,"MIFF");
scene=0;
do
{
/*
Pack image pixels.
*/
image->compression=image_info->compression;
packets=RunlengthEncodeImage(image);
if (image_info->compression == ZipCompression)
{
int
status;
unsigned char
*compressed_pixels;
unsigned long
compressed_packets;
/*
Compress image pixels with Zip encoding.
*/
compressed_packets=((packets*image->packet_size*110)/100)+8;
compressed_pixels=(unsigned char *)
malloc(compressed_packets*sizeof(unsigned char));
if (compressed_pixels == (unsigned char *) NULL)
PrematureExit("Unable to allocate memory",image);
status=True;
#ifdef HasPNG
status=compress(compressed_pixels,&compressed_packets,
image->packed_pixels,packets*image->packet_size);
#endif
if (status)
{
Warning("Unable to Zip compress image",image->filename);
free((char *) compressed_pixels);
}
else
{
free((char *) image->packed_pixels);
image->packed_pixels=compressed_pixels;
image->packet_size=1;
packets=compressed_packets;
}
}
/*
Write header to file.
*/
(void) fprintf(image->file,"id=ImageMagick\n");
if (image->class == PseudoClass)
(void) fprintf(image->file,"class=PseudoClass colors=%u\n",
image->colors);
else
if (image->matte)
(void) fprintf(image->file,"class=DirectClass matte=True\n");
else
(void) fprintf(image->file,"class=DirectClass\n");
if (image->compression == RunlengthEncodedCompression)
(void) fprintf(image->file,"compression=RunlengthEncoded packets=%lu\n",
packets);
else
if (image->compression == ZipCompression)
(void) fprintf(image->file,"compression=Zip packets=%lu\n",packets);
(void) fprintf(image->file,"columns=%u rows=%u depth=%u\n",image->columns,
image->rows,image->depth);
SignatureImage(image);
if (image->signature != (char *) NULL)
(void) fprintf(image->file,"signature=%s\n",image->signature);
if (image->scene != 0)
(void) fprintf(image->file,"scene=%u\n",image->scene);
if (image->gamma != 0.0)
(void) fprintf(image->file,"gamma=%f\n",image->gamma);
if (image->delay != 0)
(void) fprintf(image->file,"delay=%u\n",image->delay);
if (image->montage != (char *) NULL)
(void) fprintf(image->file,"montage=%s\n",image->montage);
if (image->label != (char *) NULL)
(void) fprintf(image->file,"label=\"%s\"\n",image->label);
if (image->comments != (char *) NULL)
(void) fprintf(image->file,"{\n%s\n}\n",image->comments);
(void) fprintf(image->file,"\f\n:\n");
if (image->montage != (char *) NULL)
{
/*
Write montage tile directory.
*/
if (image->directory != (char *) NULL)
(void) fprintf(image->file,"%s",image->directory);
(void) fputc('\0',image->file);
}
if (image->class == PseudoClass)
{
register unsigned char
*q;
unsigned char
*colormap;
unsigned int
packet_size;
unsigned short
value;
/*
Allocate colormap.
*/
packet_size=3*(image->depth >> 3);
colormap=(unsigned char *)
malloc(packet_size*image->colors*sizeof(unsigned char));
if (colormap == (unsigned char *) NULL)
PrematureExit("Unable to allocate memory",image);
q=colormap;
for (i=0; i < image->colors; i++)
{
WriteQuantum(image->colormap[i].red,q);
WriteQuantum(image->colormap[i].green,q);
WriteQuantum(image->colormap[i].blue,q);
}
/*
Write colormap to file.
*/
(void) fwrite((char *) colormap,1,(int) image->colors*packet_size,
image->file);
free((char *) colormap);
}
/*
Write image pixels to file.
*/
(void) fwrite((char *) image->packed_pixels,(int) image->packet_size,
(int) packets,image->file);
if (image->next == (Image *) NULL)
break;
image->next->file=image->file;
image=image->next;
ProgressMonitor(SaveImageText,scene++,image->number_scenes);
} while (image_info->adjoin);
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e M O N O I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteMONOImage writes an image of raw bits in LSB order to a file.
%
% The format of the WriteMONOImage routine is:
%
% status=WriteMONOImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteMATTEImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteMONOImage(const ImageInfo *image_info,Image *image)
{
int
x;
register unsigned char
bit,
byte,
polarity;
register int
i,
j;
register RunlengthPacket
*p;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
/*
Convert image to a bi-level image.
*/
if (!IsMonochromeImage(image))
{
QuantizeInfo
quantize_info;
GetQuantizeInfo(&quantize_info);
quantize_info.number_colors=2;
quantize_info.dither=image_info->dither;
quantize_info.colorspace=GRAYColorspace;
QuantizeImage(&quantize_info,image);
SyncImage(image);
}
polarity=0;
if (image->colors == 2)
polarity=Intensity(image->colormap[0]) > Intensity(image->colormap[1]);
bit=0;
byte=0;
x=0;
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
byte>>=1;
if (p->index == polarity)
byte|=0x80;
bit++;
if (bit == 8)
{
(void) fputc(byte,image->file);
bit=0;
byte=0;
}
x++;
if (x == image->columns)
{
/*
Advance to the next scanline.
*/
if (bit != 0)
(void) fputc(byte >> (8-bit),image->file);
bit=0;
byte=0;
x=0;
}
}
p++;
if (QuantumTick(i,image))
ProgressMonitor(SaveImageText,i,image->packets);
}
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e M P E G I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteMPEGImage writes an image in the MPEG encoded image format.
%
% The format of the WriteMPEGImage routine is:
%
% status=WriteMPEGImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteMPEGImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteMPEGImage(const ImageInfo *image_info,Image *image)
{
char
basename[MaxTextExtent],
command[MaxTextExtent],
filename[MaxTextExtent];
Image
component_image;
ImageInfo
local_info;
MonitorHandler
handler;
register int
i;
unsigned int
scene,
status;
if (image->next == (Image *) NULL)
PrematureExit("MPEG requires multi-frame image",image);
/*
Write component images.
*/
scene=image->scene;
TemporaryFilename(basename);
(void) strcpy(filename,basename);
(void) strcat(filename,"%d");
local_info=(*image_info);
local_info.interlace=PartitionInterlace;
for (i=0; i < image->number_scenes; i++)
{
handler=SetMonitorHandler((MonitorHandler) NULL);
component_image=(*image);
component_image.previous=(Image *) NULL;
component_image.next=(Image *) NULL;
(void) sprintf(component_image.filename,filename,i);
(void) WriteYUVImage(&local_info,&component_image);
if (image->next != (Image *) NULL)
image=image->next;
(void) SetMonitorHandler(handler);
ProgressMonitor(SaveImageText,i,image->number_scenes);
}
/*
Write MPEG image.
*/
(void) sprintf(command,"mpeg -a %u -b %u -h %u -v %u -PF %s -s %s",scene,
image->scene,image->columns,image->rows,basename,image->filename);
status=SystemCommand(command);
/*
Remove component files.
*/
for (i=0; i < image->number_scenes; i++)
{
(void) sprintf(component_image.filename,filename,i);
(void) strcat(component_image.filename,".Y");
(void) remove(component_image.filename);
(void) sprintf(component_image.filename,filename,i);
(void) strcat(component_image.filename,".U");
(void) remove(component_image.filename);
(void) sprintf(component_image.filename,filename,i);
(void) strcat(component_image.filename,".V");
(void) remove(component_image.filename);
}
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e M T V I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WriteMTVImage writes an image to a file in red, green, and blue
% MTV rasterfile format.
%
% The format of the WriteMTVImage routine is:
%
% status=WriteMTVImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WriteMTVImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WriteMTVImage(const ImageInfo *image_info,Image *image)
{
register int
i,
j;
register RunlengthPacket
*p;
unsigned int
scene;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
scene=0;
do
{
/*
Convert MIFF to MTV raster pixels.
*/
(void) fprintf(image->file,"%u %u\n",image->columns,image->rows);
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
(void) fputc(DownScale(p->red),image->file);
(void) fputc(DownScale(p->green),image->file);
(void) fputc(DownScale(p->blue),image->file);
}
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
if (image->next == (Image *) NULL)
break;
image->next->file=image->file;
image=image->next;
ProgressMonitor(SaveImageText,scene++,image->number_scenes);
} while (image_info->adjoin);
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e P C D I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WritePCDImage writes an image in the Photo CD encoded image
% format.
%
% The format of the WritePCDImage routine is:
%
% status=WritePCDImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WritePCDImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WritePCDTile(Image *image,char *geometry,
char *tile_geometry)
{
Image
*downsampled_image,
*tile_image;
int
x,
y;
register int
i;
register RunlengthPacket
*p,
*q;
unsigned int
height,
width;
/*
Scale image to tile size.
*/
width=image->columns;
height=image->rows;
(void) ParseImageGeometry(geometry,&x,&y,&width,&height);
if ((width % 2) != 0)
width--;
if ((height % 2) != 0)
height--;
image->orphan=True;
tile_image=ZoomImage(image,width,height,MitchellFilter);
image->orphan=False;
if (tile_image == (Image *) NULL)
PrematureExit("Unable to scale image",image);
(void) sscanf(geometry,"%ux%u",&width,&height);
if ((tile_image->columns != width) || (tile_image->rows != height))
{
Image
*bordered_image;
RectangleInfo
border_info;
/*
Put a border around the image.
*/
border_info.width=(width-tile_image->columns+1) >> 1;
border_info.height=(height-tile_image->rows+1) >> 1;
bordered_image=BorderImage(tile_image,&border_info);
if (bordered_image == (Image *) NULL)
PrematureExit("Unable to border image",image);
DestroyImage(tile_image);
tile_image=bordered_image;
}
TransformImage(&tile_image,(char *) NULL,tile_geometry);
RGBTransformImage(tile_image,YCCColorspace);
downsampled_image=MinifyImage(tile_image);
if (downsampled_image == (Image *) NULL)
PrematureExit("Unable to scale image",image);
if (!UncompressImage(tile_image))
return(False);
if (!UncompressImage(downsampled_image))
return(False);
/*
Write tile to PCD file.
*/
p=tile_image->pixels;
for (y=0; y < tile_image->rows; y+=2)
{
for (x=0; x < (tile_image->columns << 1); x++)
{
(void) fputc(DownScale(p->red),image->file);
p++;
}
q=downsampled_image->pixels+(y >> 1)*downsampled_image->columns;
for (x=0; x < downsampled_image->columns; x++)
{
(void) fputc(DownScale(q->green),image->file);
q++;
}
q=downsampled_image->pixels+(y >> 1)*downsampled_image->columns;
for (x=0; x < downsampled_image->columns; x++)
{
(void) fputc(DownScale(q->blue),image->file);
q++;
}
ProgressMonitor(SaveImageText,y,tile_image->rows);
}
for (i=0; i < 0x800; i++)
(void) fputc('\0',image->file);
DestroyImage(downsampled_image);
DestroyImage(tile_image);
return(True);
}
static unsigned int WritePCDImage(const ImageInfo *image_info,Image *image)
{
Image
*pcd_image;
register int
i;
unsigned int
status;
pcd_image=image;
if (image->columns < image->rows)
{
Image
*rotated_image;
/*
Rotate portrait to landscape.
*/
image->orphan=True;
rotated_image=RotateImage(image,90.0,False,True);
image->orphan=False;
if (rotated_image == (Image *) NULL)
PrematureExit("Unable to rotate image",image);
pcd_image=rotated_image;
}
/*
Open output image file.
*/
OpenImage(image_info,pcd_image,WriteBinaryType);
if (pcd_image->file == (FILE *) NULL)
PrematureExit("Unable to open file",pcd_image);
/*
Write PCD image header.
*/
for (i=0; i < 0x800; i++)
(void) fputc('\0',pcd_image->file);
(void) fwrite("PCD_IPI",1,7,pcd_image->file);
for (i=0; i < 1531; i++)
(void) fputc('\0',pcd_image->file);
if (image->columns < image->rows)
(void) fputc('\1',pcd_image->file);
else
(void) fputc('\0',pcd_image->file);
for (i=0; i < 3*0x800-1539; i++)
(void) fputc('\0',pcd_image->file);
/*
Write PCD tiles.
*/
status=WritePCDTile(pcd_image,"768x512>","192x128");
status|=WritePCDTile(pcd_image,"768x512>","384x256");
status|=WritePCDTile(pcd_image,"768x512>","768x512");
CloseImage(pcd_image);
if (image->columns < image->rows)
DestroyImage(pcd_image);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e P C L I m a g e %
% %
% %
% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WritePCLImage writes an image in the Page Control Language encoded
% image format.
%
% The format of the WritePCLImage routine is:
%
% status=WritePCLImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WritePCLImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
%
*/
static unsigned int WritePCLImage(const ImageInfo *image_info,Image *image)
{
int
delta_x,
delta_y,
flags,
sans_offset,
x,
y;
register int
i,
j;
register RunlengthPacket
*p;
unsigned int
density,
height,
page_height,
page_size,
page_width,
text_size,
width;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
/*
Initialize the printer.
*/
(void) fprintf(image->file,"\033E"); /* reset */
(void) fprintf(image->file,"\033&l0O"); /* portrait orientation */
(void) fprintf(image->file,"\033&l0E"); /* top margin 0 */
/*
Center image on PCL page.
*/
text_size=0;
if (image->label != (char *) NULL)
text_size=MultilineCensus(image->label)*image_info->pointsize+12;
x=0;
y=0;
width=image->columns;
height=image->rows;
(void) XParseGeometry(PCLPageGeometry,&x,&y,&page_width,&page_height);
flags=NoValue;
if (image_info->page != (char *) NULL)
flags=XParseGeometry(image_info->page,&x,&y,&page_width,&page_height);
if (image->page != (char *) NULL)
flags=XParseGeometry(image->page,&x,&y,&page_width,&page_height);
if (((page_width-(x << 1)) < width) ||
((page_height-(y << 1)-text_size) < height))
{
unsigned long
scale_factor;
/*
Scale image relative to PCL page.
*/
scale_factor=UpShift(page_width-(x << 1))/width;
if (scale_factor > (UpShift(page_height-(y << 1)-text_size)/height))
scale_factor=UpShift(page_height-(y << 1)-text_size)/height;
width=DownShift(width*scale_factor);
height=DownShift(height*scale_factor);
}
if ((flags & XValue) == 0)
{
/*
Center image in the X direction.
*/
delta_x=page_width-(width+(x << 1));
if (delta_x >= 0)
x=(delta_x >> 1)+x;
}
if ((flags & YValue) == 0)
{
/*
Center image in the X direction.
*/
delta_y=page_height-(height+(y << 1))-text_size;
if (delta_y >= 0)
y=(delta_y >> 1)+y;
}
page_size=2;
if ((page_width == 540) && (page_height == 720))
page_size=1; /* executive */
if ((page_width == 612) && (page_height == 792))
page_size=2; /* letter */
if ((page_width == 612) && (page_height == 1008))
page_size=3; /* legal */
if ((page_width == 1224) && (page_height == 792))
page_size=6; /* ledger */
if ((page_width == 595) && (page_height == 842))
page_size=26; /* A4 */
if ((page_width == 842) && (page_height == 1191))
page_size=27; /* A3 */
if ((page_width == 729) && (page_height == 1032))
page_size=45; /* B5 */
if ((page_width == 516) && (page_height == 729))
page_size=46; /* B4 */
(void) fprintf(image->file,"\033&l%uA",page_size); /* papersize */
(void) XParseGeometry(PCLDensityGeometry,&sans_offset,&sans_offset,
&density,&density);
if (image_info->density != (char *) NULL)
(void) XParseGeometry(image_info->density,&sans_offset,&sans_offset,
&density,&density);
(void) fprintf(image->file,"\033*p%dx%dY",x,y);
if (image->label != (char *) NULL)
{
/*
Print label.
*/
(void) fprintf(image->file,"\033&k2G");
(void) fprintf(image->file,"\033(s1p%uv5t3b",image_info->pointsize);
(void) fprintf(image->file,"\n%s\n",image->label);
(void) fprintf(image->file,"\033(s0B");
}
(void) fprintf(image->file,"\033*t%uR",density); /* graphic resolution */
width=(density*width)/75;
height=(density*height)/75;
if (!IsGrayImage(image))
{
/*
Write PCL color image.
*/
(void) fprintf(image->file,"\033*r%us%uT",image->columns,image->rows);
(void) fprintf(image->file,"\033*t%uh%uV",width,height);
(void) fprintf(image->file,"\033*v6W");
(void) fputc('\000',image->file); /* color model */
(void) fputc('\003',image->file); /* direct pixel encoding */
(void) fputc('\000',image->file); /* bits per index */
(void) fputc('\010',image->file); /* bits red*/
(void) fputc('\010',image->file); /* bits green*/
(void) fputc('\010',image->file); /* bits blue */
(void) fprintf(image->file,"\033*r2A"); /* start graphics */
(void) fprintf(image->file,"\033*b0M"); /* no compression */
(void) fprintf(image->file,"\033*b%uW",3*image->columns);
x=0;
p=image->pixels;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
(void) fprintf(image->file,"%c%c%c",(int) DownScale(p->red),
(int) DownScale(p->green),(int) DownScale(p->blue));
x++;
if (x == image->columns)
{
(void) fprintf(image->file,"\033*b%uW",3*image->columns);
x=0;
}
p++;
if (QuantumTick(i,image))
ProgressMonitor(SaveImageText,i,image->packets);
}
(void) fprintf(image->file,"\033*rC"); /* end graphics */
}
else
{
char
geometry[MaxTextExtent];
register unsigned char
bit,
byte,
polarity;
/*
Write PCL monochrome image.
*/
if ((width != image->columns) || (height != image->rows))
{
FILE
*file;
/*
Scale image.
*/
file=image->file;
image->file=(FILE *) NULL; /* prevents closing */
(void) sprintf(geometry,"%ux%u",width,height);
TransformImage(&image,(char *) NULL,geometry);
image->file=file;
}
if (image->colors > 2)
{
QuantizeInfo
quantize_info;
GetQuantizeInfo(&quantize_info);
quantize_info.number_colors=2;
quantize_info.dither=image_info->dither;
quantize_info.colorspace=GRAYColorspace;
QuantizeImage(&quantize_info,image);
SyncImage(image);
}
p=image->pixels;
polarity=0;
if (image->colors == 2)
polarity=
Intensity(image->colormap[0]) > Intensity(image->colormap[1]);
bit=0;
byte=0;
x=0;
y=0;
(void) fprintf(image->file,"\033*r%us%uT",image->columns,image->rows);
(void) fprintf(image->file,"\033*r1A"); /* start graphics */
(void) fprintf(image->file,"\033*b0M"); /* no compression */
(void) fprintf(image->file,"\033*b%uW",(image->columns+7)/8);
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
byte<<=1;
if (p->index == polarity)
byte|=0x01;
bit++;
if (bit == 8)
{
(void) fputc(byte,image->file);
bit=0;
byte=0;
}
x++;
if (x == image->columns)
{
/*
Advance to the next scanline.
*/
if (bit != 0)
(void) fputc(byte << (8-bit),image->file);
bit=0;
byte=0;
x=0;
y++;
if (y < image->rows)
(void) fprintf(image->file,"\033*b%uW",(image->columns+7)/8);
}
}
p++;
if (QuantumTick(i,image))
ProgressMonitor(SaveImageText,i,image->packets);
}
(void) fprintf(image->file,"\033*rB"); /* end graphics */
}
(void) fprintf(image->file,"\033&l0H");
(void) fprintf(image->file,"\033E"); /* reset */
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e P C X I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WritePCXImage writes an image in the ZSoft IBM PC Paintbrush file
% format.
%
% The format of the WritePCXImage routine is:
%
% status=WritePCXImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WritePCXImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WritePCXImage(const ImageInfo *image_info,Image *image)
{
typedef struct _PCXHeader
{
unsigned char
identifier,
version,
encoding,
bits_per_pixel;
short int
left,
top,
right,
bottom,
horizontal_resolution,
vertical_resolution;
unsigned char
reserved,
planes;
short int
bytes_per_line,
palette_info;
unsigned char
colormap_signature;
} PCXHeader;
PCXHeader
pcx_header;
register int
i,
j,
x,
y;
register RunlengthPacket
*p;
register unsigned char
*q;
unsigned char
count,
packet,
*pcx_colormap,
*pcx_pixels,
previous;
unsigned int
packets,
scene;
unsigned long
*page_table;
/*
Open output image file.
*/
OpenImage(image_info,image,WriteBinaryType);
if (image->file == (FILE *) NULL)
PrematureExit("Unable to open file",image);
page_table=(unsigned long *) NULL;
if (image_info->adjoin)
{
/*
Write the DCX page table.
*/
LSBFirstWriteLong(0x3ADE68B1L,image->file);
page_table=(unsigned long *) malloc(1024*sizeof(unsigned long));
if (page_table == (unsigned long *) NULL)
PrematureExit("Unable to allocate memory",image);
for (scene=0; scene < 1024; scene++)
LSBFirstWriteLong(0x00000000L,image->file);
}
scene=0;
do
{
if (page_table != (unsigned long *) NULL)
page_table[scene]=ftell(image->file);
/*
Initialize PCX raster file header.
*/
pcx_header.identifier=0x0a;
pcx_header.version=5;
pcx_header.encoding=1;
pcx_header.bits_per_pixel=8;
if (IsMonochromeImage(image))
pcx_header.bits_per_pixel=1;
pcx_header.left=0;
pcx_header.top=0;
pcx_header.right=image->columns-1;
pcx_header.bottom=image->rows-1;
pcx_header.horizontal_resolution=(short) image->columns;
pcx_header.vertical_resolution=(short) image->rows;
if (image->units == PixelsPerInchResolution)
{
pcx_header.horizontal_resolution=(short) image->x_resolution;
pcx_header.vertical_resolution=(short) image->y_resolution;
}
if (image->units == PixelsPerCentimeterResolution)
{
pcx_header.horizontal_resolution=(short) (2.54*image->x_resolution);
pcx_header.vertical_resolution=(short) (2.54*image->y_resolution);
}
pcx_header.reserved=0;
pcx_header.planes=1;
if (!IsPseudoClass(image))
{
pcx_header.planes=3;
if (image->matte)
pcx_header.planes++;
}
pcx_header.bytes_per_line=(image->columns*pcx_header.bits_per_pixel+7)/8;
pcx_header.palette_info=1;
pcx_header.colormap_signature=0x0c;
/*
Write PCX header.
*/
(void) fwrite(&pcx_header.identifier,1,1,image->file);
(void) fwrite(&pcx_header.version,1,1,image->file);
(void) fwrite(&pcx_header.encoding,1,1,image->file);
(void) fwrite(&pcx_header.bits_per_pixel,1,1,image->file);
LSBFirstWriteShort((unsigned int) pcx_header.left,image->file);
LSBFirstWriteShort((unsigned int) pcx_header.top,image->file);
LSBFirstWriteShort((unsigned int) pcx_header.right,image->file);
LSBFirstWriteShort((unsigned int) pcx_header.bottom,image->file);
LSBFirstWriteShort((unsigned int) pcx_header.horizontal_resolution,
image->file);
LSBFirstWriteShort((unsigned int) pcx_header.vertical_resolution,
image->file);
/*
Dump colormap to file.
*/
pcx_colormap=(unsigned char *) malloc(3*256*sizeof(unsigned char));
if (pcx_colormap == (unsigned char *) NULL)
PrematureExit("Unable to allocate memory",image);
for (i=0; i < (3*256); i++)
pcx_colormap[i]=0;
q=pcx_colormap;
if (image->class == PseudoClass)
for (i=0; i < image->colors; i++)
{
*q++=DownScale(image->colormap[i].red);
*q++=DownScale(image->colormap[i].green);
*q++=DownScale(image->colormap[i].blue);
}
(void) fwrite((char *) pcx_colormap,3,16,image->file);
(void) fwrite(&pcx_header.reserved,1,1,image->file);
(void) fwrite(&pcx_header.planes,1,1,image->file);
LSBFirstWriteShort((unsigned int) pcx_header.bytes_per_line,image->file);
LSBFirstWriteShort((unsigned int) pcx_header.palette_info,image->file);
for (i=0; i < 58; i++)
(void) fwrite("\0",1,1,image->file);
packets=image->rows*pcx_header.bytes_per_line*pcx_header.planes;
pcx_pixels=(unsigned char *) malloc(packets*sizeof(unsigned char));
if (pcx_pixels == (unsigned char *) NULL)
PrematureExit("Unable to allocate memory",image);
x=0;
y=0;
p=image->pixels;
q=pcx_pixels;
if (image->class == DirectClass)
{
/*
Convert DirectClass image to PCX raster pixels.
*/
if (!UncompressImage(image))
return(False);
for (y=0; y < image->rows; y++)
{
q=pcx_pixels+(y*pcx_header.bytes_per_line*pcx_header.planes);
for (i=0; i < (int) pcx_header.planes; i++)
{
p=image->pixels+y*image->columns;
for (x=0; x < pcx_header.bytes_per_line; x++)
{
switch (i)
{
case 0:
{
*q++=DownScale(p->red);
break;
}
case 1:
{
*q++=DownScale(p->green);
break;
}
case 2:
{
*q++=DownScale(p->blue);
break;
}
case 3:
default:
{
*q++=DownScale(p->index);
break;
}
}
p++;
}
}
ProgressMonitor(SaveImageText,y,image->rows);
}
}
else
if (pcx_header.bits_per_pixel > 1)
for (i=0; i < image->packets; i++)
{
/*
Convert PseudoClass image to PCX raster pixels.
*/
for (j=0; j <= ((int) p->length); j++)
{
*q++=p->index;
x++;
if (x == image->columns)
{
x=0;
y++;
q=pcx_pixels+y*pcx_header.bytes_per_line;
}
}
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
else
{
register unsigned char
bit,
byte,
polarity;
/*
Convert PseudoClass image to a PCX monochrome image.
*/
polarity=0;
if (image->colors == 2)
polarity=Intensity(image->colormap[0]) <
Intensity(image->colormap[1]);
bit=0;
byte=0;
for (i=0; i < image->packets; i++)
{
for (j=0; j <= ((int) p->length); j++)
{
byte<<=1;
if (p->index == polarity)
byte|=0x01;
bit++;
if (bit == 8)
{
*q++=byte;
bit=0;
byte=0;
}
x++;
if (x == image->columns)
{
/*
Advance to the next scanline.
*/
if (bit != 0)
*q++=byte << (8-bit);
bit=0;
byte=0;
x=0;
y++;
q=pcx_pixels+y*pcx_header.bytes_per_line;
}
}
p++;
if (QuantumTick(i,image) && (image->previous == (Image *) NULL))
ProgressMonitor(SaveImageText,i,image->packets);
}
}
/*
Runlength-encoded PCX pixels.
*/
for (y=0; y < image->rows; y++)
{
q=pcx_pixels+(y*pcx_header.bytes_per_line*pcx_header.planes);
for (i=0; i < (int) pcx_header.planes; i++)
{
previous=(*q++);
count=1;
for (x=0; x < (pcx_header.bytes_per_line-1); x++)
{
packet=(*q++);
if ((packet == previous) && (count < 63))
{
count++;
continue;
}
if ((count > 1) || ((previous & 0xc0) == 0xc0))
{
count|=0xc0;
(void) fwrite(&count,1,1,image->file);
}
(void) fwrite(&previous,1,1,image->file);
previous=packet;
count=1;
}
if ((count > 1) || ((previous & 0xc0) == 0xc0))
{
count|=0xc0;
(void) fwrite(&count,1,1,image->file);
}
(void) fwrite(&previous,1,1,image->file);
ProgressMonitor(SaveImageText,y,image->rows);
}
}
if (image->colors > 16)
{
(void) fwrite(&pcx_header.colormap_signature,1,1,image->file);
(void) fwrite((char *) pcx_colormap,3,256,image->file);
}
free((char *) pcx_pixels);
free((char *) pcx_colormap);
if (image->next == (Image *) NULL)
break;
image->next->file=image->file;
image=image->next;
ProgressMonitor(SaveImageText,scene++,image->number_scenes);
if (scene >= 1023)
break;
} while (image_info->adjoin);
if (page_table != (unsigned long *) NULL)
{
/*
Write the DCX page table.
*/
page_table[scene+1]=0;
(void) fseek(image->file,0L,SEEK_SET);
LSBFirstWriteLong(0x3ADE68B1L,image->file);
for (i=0; i <= (int) scene; i++)
LSBFirstWriteLong(page_table[i],image->file);
free((char *) page_table);
}
CloseImage(image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e P D F I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WritePDFImage writes an image in the Portable Document image
% format.
%
% The format of the WritePDFImage routine is:
%
% status=WritePDFImage(image_info,image)
%
% A description of each parameter follows.
%
% o status: Function WritePDFImage return True if the image is written.
% False is returned is there is a memory shortage or if the image file
% fails to write.
%
% o image_info: Specifies a pointer to an ImageInfo structure.
%
% o image: A pointer to a Image structure.
%
%
*/
static unsigned int WritePDFImage(const ImageInfo *image_info,Image *image)
{
#define DefaultThumbnailGeometry "106x106"
#define ObjectsPerImage 12
char
date[MaxTextExtent],
density[MaxTextExtent],
**labels;
f