3341 lines
47 KiB
C
3341 lines
47 KiB
C
|
/**
|
||
|
|
||
|
** $Header: /roq/libim/immiff.c 1 11/02/99 4:38p Zaphod $
|
||
|
|
||
|
** Copyright (c) 1989-1995 San Diego Supercomputer Center (SDSC)
|
||
|
|
||
|
** a division of General Atomics, San Diego, California, USA
|
||
|
|
||
|
**
|
||
|
|
||
|
** Users and possessors of this source code are hereby granted a
|
||
|
|
||
|
** nonexclusive, royalty-free copyright and design patent license to
|
||
|
|
||
|
** use this code in individual software. License is not granted for
|
||
|
|
||
|
** commercial resale, in whole or in part, without prior written
|
||
|
|
||
|
** permission from SDSC. This source is provided "AS IS" without express
|
||
|
|
||
|
** or implied warranty of any kind.
|
||
|
|
||
|
**
|
||
|
|
||
|
** For further information contact:
|
||
|
|
||
|
** E-Mail: info@sds.sdsc.edu
|
||
|
|
||
|
**
|
||
|
|
||
|
** Surface Mail: Information Center
|
||
|
|
||
|
** San Diego Supercomputer Center
|
||
|
|
||
|
** P.O. Box 85608
|
||
|
|
||
|
** San Diego, CA 92138-5608
|
||
|
|
||
|
** (619) 534-5000
|
||
|
|
||
|
**/
|
||
|
|
||
|
|
||
|
|
||
|
#define HEADER " $Header: /roq/libim/immiff.c 1 11/02/99 4:38p Zaphod $"
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
|
||
|
** FILE
|
||
|
|
||
|
** immiff.c- ImageMagick's Machine Independent File Format file i/o
|
||
|
|
||
|
**
|
||
|
|
||
|
** PROJECT
|
||
|
|
||
|
** libim - SDSC image manipulation library
|
||
|
|
||
|
**
|
||
|
|
||
|
** DESCRIPTION
|
||
|
|
||
|
** immiff.c contains routines to read and write ImageMagick's MIFF
|
||
|
|
||
|
** files for the image manipulation library. Raster data read in
|
||
|
|
||
|
** is stored in a VFB. Raster data written out is taken from a tag table.
|
||
|
|
||
|
**
|
||
|
|
||
|
** PUBLIC CONTENTS
|
||
|
|
||
|
** d =defined constant
|
||
|
|
||
|
** f =function
|
||
|
|
||
|
** m =defined macro
|
||
|
|
||
|
** t =typedef/struct/union
|
||
|
|
||
|
** v =variable
|
||
|
|
||
|
** ? =other
|
||
|
|
||
|
**
|
||
|
|
||
|
** none
|
||
|
|
||
|
**
|
||
|
|
||
|
** PRIVATE CONTENTS
|
||
|
|
||
|
** imMiffRead f read a MIFF file
|
||
|
|
||
|
** imMiffWriteRGB f write an RGB MIFF file
|
||
|
|
||
|
** imMiffWriteIndex f write an Indexed MIFF file
|
||
|
|
||
|
**
|
||
|
|
||
|
** HISTORY
|
||
|
|
||
|
** $Log: /roq/libim/immiff.c $
|
||
|
*
|
||
|
* 1 11/02/99 4:38p Zaphod
|
||
|
|
||
|
* Revision 1.6 1995/06/30 22:09:07 bduggan
|
||
|
|
||
|
* removed strings.h
|
||
|
|
||
|
*
|
||
|
|
||
|
* Revision 1.5 1995/06/29 00:28:04 bduggan
|
||
|
|
||
|
* updated copyright year
|
||
|
|
||
|
*
|
||
|
|
||
|
* Revision 1.4 1995/06/29 00:20:26 bduggan
|
||
|
|
||
|
* changed comment
|
||
|
|
||
|
*
|
||
|
|
||
|
* Revision 1.3 1995/06/15 20:10:59 bduggan
|
||
|
|
||
|
* took out some useless vars
|
||
|
|
||
|
*
|
||
|
|
||
|
* Revision 1.2 1995/05/17 23:45:35 bduggan
|
||
|
|
||
|
* Used library 'imSameRGB' calls instead of local miff calls
|
||
|
|
||
|
*
|
||
|
|
||
|
** Revision 1.1 1995/04/03 21:29:34 bduggan
|
||
|
|
||
|
** Initial revision
|
||
|
|
||
|
**
|
||
|
|
||
|
**
|
||
|
|
||
|
**/
|
||
|
|
||
|
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "iminternal.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
|
||
|
** FORMAT
|
||
|
|
||
|
** MIFF - Magick Image File Format
|
||
|
|
||
|
**
|
||
|
|
||
|
** AKA
|
||
|
|
||
|
** (none)
|
||
|
|
||
|
**
|
||
|
|
||
|
** FORMAT REFERENCES
|
||
|
|
||
|
** Anonymous ftp at ftp.x.org,
|
||
|
|
||
|
** file: contrib/applications/ImageMagick/ImageMagick-3.6.tar.gz
|
||
|
|
||
|
**
|
||
|
|
||
|
** CODE CREDITS
|
||
|
|
||
|
** Brian Duggan, Custom Development, San Diego Supercomputer Center, 1995.
|
||
|
|
||
|
**
|
||
|
|
||
|
** DESCRIPTION
|
||
|
|
||
|
** MIFF files may contain multiple images. To store multiple images,
|
||
|
|
||
|
** one can simply create several MIFF's, then concatenate them together.
|
||
|
|
||
|
** A single MIFF file contains a header, followed by a clt (optional),
|
||
|
|
||
|
** followed by pixel data.
|
||
|
|
||
|
**
|
||
|
|
||
|
** Header
|
||
|
|
||
|
** ------
|
||
|
|
||
|
** The header is text based. The idea is that if you `more` a
|
||
|
|
||
|
** .miff, you'll be able to see what type of file it is.
|
||
|
|
||
|
**
|
||
|
|
||
|
** A miff header consists of labels of the form, "field=value",
|
||
|
|
||
|
** and comments contained in curly braces ({}). The header ends
|
||
|
|
||
|
** with a colon (:) followed by a newline character.
|
||
|
|
||
|
**
|
||
|
|
||
|
** By convention, a formfeed character and a newline character
|
||
|
|
||
|
** appear before the colon. (Hence, using 'more' will pause
|
||
|
|
||
|
** before the binary data.)
|
||
|
|
||
|
**
|
||
|
|
||
|
** The header fields are as follows:
|
||
|
|
||
|
** id=ImageMagick
|
||
|
|
||
|
** This indicates that we have a MIFF file.
|
||
|
|
||
|
** This field is mandatory.
|
||
|
|
||
|
**
|
||
|
|
||
|
** class=<class>
|
||
|
|
||
|
** <class> can be one of:
|
||
|
|
||
|
** DirectClass (RGB Image)
|
||
|
|
||
|
** PseudoClass (Indexed Image)
|
||
|
|
||
|
** If this field is omitted, the image is RGB.
|
||
|
|
||
|
**
|
||
|
|
||
|
** colors=<size of clt>
|
||
|
|
||
|
** If this is not present, there is not clt.
|
||
|
|
||
|
** (i.e. the image is RGB or grayscale)
|
||
|
|
||
|
** If this is present and the image is RGB, then
|
||
|
|
||
|
** this field is supposed to contain the number
|
||
|
|
||
|
** of colors in the image.
|
||
|
|
||
|
**
|
||
|
|
||
|
** columns=<image width>
|
||
|
|
||
|
** rows=<image height>
|
||
|
|
||
|
** These fields are required.
|
||
|
|
||
|
**
|
||
|
|
||
|
** compression=<compression type>
|
||
|
|
||
|
** <compression type> can be one of
|
||
|
|
||
|
** RunlengthEncoded
|
||
|
|
||
|
** QEncoded
|
||
|
|
||
|
** The RLE algorithm for RunlengthEncoded images is explained below.
|
||
|
|
||
|
** The algorithm for QEncoded images is similar to JPEG encoding. It
|
||
|
|
||
|
** is not supported here.
|
||
|
|
||
|
** If this field is omitted, there is no compression.
|
||
|
|
||
|
**
|
||
|
|
||
|
** matte=<value>
|
||
|
|
||
|
** if <value> is True, we have an alpha channel.
|
||
|
|
||
|
** Otherwise, we don't. Color indexed images
|
||
|
|
||
|
** can't have alpha channels.
|
||
|
|
||
|
**
|
||
|
|
||
|
** packets=<value>
|
||
|
|
||
|
** This is used for QEncoding. We ignore it.
|
||
|
|
||
|
**
|
||
|
|
||
|
** montage=<width>x<height>{+-}<x offset>{+-}<y offset>
|
||
|
|
||
|
** This is miff's handy way of storying a storyboard
|
||
|
|
||
|
** of pictures as one file, while seperating
|
||
|
|
||
|
** them within the file. It is not supported here.
|
||
|
|
||
|
**
|
||
|
|
||
|
** scene=<value>
|
||
|
|
||
|
** signature=<value>
|
||
|
|
||
|
** These fields are used when a miff is part of
|
||
|
|
||
|
** a sequence of pictures, and hence may have
|
||
|
|
||
|
** a CLT stored in a different frame. These
|
||
|
|
||
|
** options are not supported here.
|
||
|
|
||
|
**
|
||
|
|
||
|
** Sample MIFF header:
|
||
|
|
||
|
** {
|
||
|
|
||
|
** This is a color indexed image.
|
||
|
|
||
|
** }
|
||
|
|
||
|
** id=ImageMagick
|
||
|
|
||
|
** class=PseudoClass colors=2
|
||
|
|
||
|
** compression=RunlengthEncoded
|
||
|
|
||
|
** columns=768 rows=640
|
||
|
|
||
|
** <FF>
|
||
|
|
||
|
** :
|
||
|
|
||
|
** Notice that fields are seperate by spaces and/or
|
||
|
|
||
|
** carriage returns, and may occur in any order.
|
||
|
|
||
|
**
|
||
|
|
||
|
** Pixel Storage
|
||
|
|
||
|
** -------------
|
||
|
|
||
|
** If there is no compression, the pixels are simply stored
|
||
|
|
||
|
** as RGBRGB or RGBARGBA or IIIII (I = index). If there is
|
||
|
|
||
|
** RLE encoding then the following scheme is used:
|
||
|
|
||
|
**
|
||
|
|
||
|
** RLE encoding scheme:
|
||
|
|
||
|
**
|
||
|
|
||
|
** For RGB images, the data are encoded in 4 byte packages.
|
||
|
|
||
|
** (or 5 bytes if there is an alpha channel.) The first three
|
||
|
|
||
|
** (or four) bytes contain the data for a pixel. The fourth
|
||
|
|
||
|
** (fifth) byte contains one less than the number of pixels in
|
||
|
|
||
|
** the run. This value is in the range 0-255.
|
||
|
|
||
|
**
|
||
|
|
||
|
** For instance 4A 0D 00 05 indicates a run of six pixels
|
||
|
|
||
|
** with red component 4A, green component 0D, and blue component
|
||
|
|
||
|
** 00.
|
||
|
|
||
|
**
|
||
|
|
||
|
** The same scheme is used for encoding color-indexed images.
|
||
|
|
||
|
** The number of bytes in a package is either two or three
|
||
|
|
||
|
** depending on whether this is a 16-bit or an 8-bit color
|
||
|
|
||
|
** indexed image.
|
||
|
|
||
|
**
|
||
|
|
||
|
** Storage of the color lookup table:
|
||
|
|
||
|
**
|
||
|
|
||
|
** The CLT is stored directly after the header (if there
|
||
|
|
||
|
** is a CLT). It is simply a series of R, G, and B values.
|
||
|
|
||
|
** The number of triplets is indicated by the "colors" field
|
||
|
|
||
|
** in the header.
|
||
|
|
||
|
**/
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* MIFF - ImageMagick's MIFF file format
|
||
|
|
||
|
* For information on these structures, how to use them, etc. please
|
||
|
|
||
|
* see imfmt.c.
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
static int imMiffRead( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable );
|
||
|
|
||
|
static int imMiffWriteRGB( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp,
|
||
|
|
||
|
TagTable *flagsTable, TagTable *tagTable);
|
||
|
|
||
|
static int imMiffWriteRawRGB( ImVfb* vfb, int fd, FILE* fp, int numChans, int ioType);
|
||
|
|
||
|
static int imMiffWriteRLERGB( ImVfb* vfb, int fd, FILE* fp, int ioType);
|
||
|
|
||
|
static int imMiffWriteRLERGBA( ImVfb* vfb, int fd, FILE* fp, int ioType);
|
||
|
|
||
|
static int imMiffWriteRawIndex8(ImVfb* vfb, int fd, FILE* fp, int ioType);
|
||
|
|
||
|
static int imMiffWriteRawIndex16(ImVfb* vfb, int fd, FILE* fp, int ioType);
|
||
|
|
||
|
static int imMiffWriteRLEIndex8(ImVfb* vfb, int fd, FILE* fp, int ioType);
|
||
|
|
||
|
static int imMiffWriteRLEIndex16(ImVfb* vfb, int fd, FILE* fp, int ioType);
|
||
|
|
||
|
static int imMiffWriteIndex( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp,
|
||
|
|
||
|
TagTable *flagsTable, TagTable *tagTable);
|
||
|
|
||
|
static char* imMiffGetHeaderField( char* header, char* field);
|
||
|
|
||
|
static ImClt * imMiffReadClt( int ioType, int fd, FILE* fp, int cltSize );
|
||
|
|
||
|
static ImVfb* imMiffReadRLE(int ioType, int fd, FILE* fp, int width,int height,int numChans, int chanDepth);
|
||
|
|
||
|
static ImVfb* imMiffReadRaw(int ioType, int fd, FILE* fp, int width,int height,int numChans, int chanDepth);
|
||
|
|
||
|
static char* strToLower( char* str);
|
||
|
|
||
|
|
||
|
|
||
|
#else
|
||
|
|
||
|
|
||
|
|
||
|
static int imMiffRead( );
|
||
|
|
||
|
static int imMiffWriteRGB( );
|
||
|
|
||
|
static char* imMiffGetHeaderField( );
|
||
|
|
||
|
static ImClt * imMiffReadClt( );
|
||
|
|
||
|
static ImVfb* imMiffReadRLE( );
|
||
|
|
||
|
static ImVfb* imMiffReadRaw( );
|
||
|
|
||
|
static char* strToLower( );
|
||
|
|
||
|
static int imMiffWriteIndex();
|
||
|
|
||
|
static int imMiffWriteRawRGB( );
|
||
|
|
||
|
static int imMiffWriteRLERGB( );
|
||
|
|
||
|
static int imMiffWriteRLERGBA( );
|
||
|
|
||
|
static int imMiffWriteRLEIndex8();
|
||
|
|
||
|
static int imMiffWriteRLEIndex16();
|
||
|
|
||
|
static int imMiffWriteRawIndex8();
|
||
|
|
||
|
static int imMiffWriteRawIndex16();
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
static char *imMiffNames[ ] = { "miff", NULL };
|
||
|
|
||
|
static ImFileFormatReadMap imMiffReadMap[ ] =
|
||
|
|
||
|
{
|
||
|
|
||
|
/* in out */
|
||
|
|
||
|
/* type,ch,dep, attr. VFB type attr. */
|
||
|
|
||
|
{ IN,1,8, 0, IMVFBINDEX8, 0 },
|
||
|
|
||
|
{ IN,1,8, RLE, IMVFBINDEX8, 0 },
|
||
|
|
||
|
{ IN,1,8, C, IMVFBINDEX8, 0 },
|
||
|
|
||
|
{ IN,1,8, RLE|C, IMVFBINDEX8, 0 },
|
||
|
|
||
|
{ IN,1,16, C, IMVFBINDEX16, 0 },
|
||
|
|
||
|
{ IN,1,16, RLE | C,IMVFBINDEX16, 0 },
|
||
|
|
||
|
{ RGB,3,8, 0, IMVFBRGB, 0 },
|
||
|
|
||
|
{ RGB,3,8, RLE, IMVFBRGB, 0 },
|
||
|
|
||
|
{ RGB,4,8, A, IMVFBRGB, A },
|
||
|
|
||
|
{ RGB,4,8, RLE|A, IMVFBRGB, A },
|
||
|
|
||
|
{ -1, 0, -1, 0 },
|
||
|
|
||
|
};
|
||
|
|
||
|
static ImFileFormatWriteMap imMiffWriteMap[ ] =
|
||
|
|
||
|
{
|
||
|
|
||
|
/* in out */
|
||
|
|
||
|
/* VFB type, attr., type,ch,dep, attr., func */
|
||
|
|
||
|
{ IMVFBRGB, 0, RGB,3,8, RLE, imMiffWriteRGB},
|
||
|
|
||
|
{ IMVFBRGB, A, RGB,4,8, A|RLE, imMiffWriteRGB},
|
||
|
|
||
|
{ IMVFBRGB, 0, RGB,3,8, 0, imMiffWriteRGB},
|
||
|
|
||
|
{ IMVFBRGB, A, RGB,4,8, A, imMiffWriteRGB},
|
||
|
|
||
|
{ IMVFBINDEX8, 0, IN,1,8, RLE, imMiffWriteIndex},
|
||
|
|
||
|
{ IMVFBINDEX8, C, IN,1,8, C|RLE, imMiffWriteIndex},
|
||
|
|
||
|
{ IMVFBINDEX8, 0, IN,1,8, 0, imMiffWriteIndex},
|
||
|
|
||
|
{ IMVFBINDEX8, C, IN,1,8, C, imMiffWriteIndex},
|
||
|
|
||
|
{ IMVFBINDEX16, C, IN,1,16, C|RLE, imMiffWriteIndex},
|
||
|
|
||
|
{ IMVFBINDEX16, C, IN,1,16, C, imMiffWriteIndex},
|
||
|
|
||
|
{ -1, 0, -1, 0, NULL },
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
static ImFileMagic imFileMiffMagic []=
|
||
|
|
||
|
{
|
||
|
|
||
|
{ 0, 0, NULL },
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
ImFileFormat ImFileMiffFormat =
|
||
|
|
||
|
{
|
||
|
|
||
|
imMiffNames, "ImageMagick's MIFF file format",
|
||
|
|
||
|
"John Cristy",
|
||
|
|
||
|
"8 or 16-bit color index with optional CLT and 24-bit RGB color images with optional alpha channels,\n\
|
||
|
uncompressed (verbatim) and RLE-compressed.",
|
||
|
"8 or 16-bit color index with optional CLT and 24-bit RGB color images with optional alpha channels,\n\
|
||
|
uncompressed (verbatim) and RLE-compressed.",
|
||
|
|
||
|
imFileMiffMagic,
|
||
|
|
||
|
IMMULTI, IMPIPE,
|
||
|
|
||
|
IMMULTI, IMPIPE,
|
||
|
|
||
|
imMiffRead, imMiffReadMap, imMiffWriteMap
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffRead - Read a MIFF file
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* The file header is read and the size of the image determined.
|
||
|
|
||
|
* Space is allocated for the VFB and the run codes read in to
|
||
|
|
||
|
* a run buffer. The run buffer is then expanded into straight
|
||
|
|
||
|
* RGB values in the VFB and the completed VFB added to the tag list.
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
static int /* Returns # tags read in */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffRead( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable )
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffRead( ioType, fd, fp, flagsTable, tagTable )
|
||
|
|
||
|
int ioType; /* I/O flags */
|
||
|
|
||
|
int fd; /* Input file descriptor */
|
||
|
|
||
|
FILE *fp; /* Input file pointer */
|
||
|
|
||
|
TagTable *flagsTable; /* Flags */
|
||
|
|
||
|
TagTable *tagTable; /* Tag table to add to */
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
char *header; /* Contains the (text) header */
|
||
|
|
||
|
char c; /* Contains a single char */
|
||
|
|
||
|
int skippingComment; /* flag that says we're skipping stuff */
|
||
|
|
||
|
int index; /* index into character array */
|
||
|
|
||
|
char* fieldValue; /* value of a field in the header */
|
||
|
|
||
|
int numChans; /* 1,3 or 4 (Indexed, rgb or rgba) */
|
||
|
|
||
|
int chanDepth; /* 8 or 16 (16 for index16) */
|
||
|
|
||
|
int compression; /* IMCOMPNONE or IMCOMPRLE */
|
||
|
|
||
|
int width, height; /* Dimensions */
|
||
|
|
||
|
int cltSize; /* 0 means no CLT */
|
||
|
|
||
|
char message[300]; /* Holds message */
|
||
|
|
||
|
ImVfb *vfb; /* new vfb */
|
||
|
|
||
|
ImClt* clt; /* new clt */
|
||
|
|
||
|
int moreImages; /* flag saying to continue reading */
|
||
|
|
||
|
int numImages; /* number of images read */
|
||
|
|
||
|
int retVal; /* return value from BinRead call */
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Read in the header.
|
||
|
|
||
|
*/
|
||
|
|
||
|
ImMalloc (header, char* , 1024*sizeof(char));
|
||
|
|
||
|
numImages = 0;
|
||
|
|
||
|
moreImages = 1;
|
||
|
|
||
|
|
||
|
|
||
|
while (moreImages)
|
||
|
|
||
|
{
|
||
|
|
||
|
index = 0;
|
||
|
|
||
|
c = '\0';
|
||
|
|
||
|
skippingComment = 0;
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Read the next character if ...
|
||
|
|
||
|
* we haven't read a :, and we're not inside a comment block
|
||
|
|
||
|
* OR
|
||
|
|
||
|
* we are inside a comment block
|
||
|
|
||
|
*
|
||
|
|
||
|
* This loop reads in anything that is not contained between two
|
||
|
|
||
|
* curly braces. (It also skips any left curly braces.)
|
||
|
|
||
|
*/
|
||
|
|
||
|
while ( (c!=':' && !skippingComment) || skippingComment)
|
||
|
|
||
|
{
|
||
|
|
||
|
if( (retVal = ImBinRead( ioType,fd,fp,&c,CHAR,sizeof(char),1))<0)
|
||
|
|
||
|
ImReturnBinError( );
|
||
|
|
||
|
if (retVal==0)
|
||
|
|
||
|
break;
|
||
|
|
||
|
if (skippingComment==1 && c=='}')
|
||
|
|
||
|
skippingComment = 0;
|
||
|
|
||
|
if (c=='{')
|
||
|
|
||
|
skippingComment = 1;
|
||
|
|
||
|
if (skippingComment==0 && c!='}')
|
||
|
|
||
|
{ /* Add this character to our array */
|
||
|
|
||
|
header[index++] = c;
|
||
|
|
||
|
if (index >= 1024)
|
||
|
|
||
|
{
|
||
|
|
||
|
/* This'll only happen if there
|
||
|
|
||
|
* are an extraordinary number of
|
||
|
|
||
|
* whitespace characters in the
|
||
|
|
||
|
* header, or if there are a lot
|
||
|
|
||
|
* of illegal fields. We shan't
|
||
|
|
||
|
* cater to such miff files.
|
||
|
|
||
|
*/
|
||
|
|
||
|
ImErrorFatal(ImQError(), -1, IMEMALLOC);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
header[index] = '\0';
|
||
|
|
||
|
if (retVal==0)
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* We just read in a ':'. Read in a newline character,
|
||
|
|
||
|
* then we'll be done with the header.
|
||
|
|
||
|
*/
|
||
|
|
||
|
if( ImBinRead( ioType,fd,fp,&c,CHAR,sizeof(char),1)<=0)
|
||
|
|
||
|
ImReturnBinError( );
|
||
|
|
||
|
|
||
|
|
||
|
numImages++; /* If we made it this far, hopefully there's an image. */
|
||
|
|
||
|
if (numImages > 1)
|
||
|
|
||
|
{
|
||
|
|
||
|
sprintf(message,"%d",numImages);
|
||
|
|
||
|
ImInfo ("Image", message);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Get the image dimensions
|
||
|
|
||
|
*/
|
||
|
|
||
|
fieldValue = imMiffGetHeaderField(header,"rows");
|
||
|
|
||
|
if (fieldValue==NULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImErrorFatal (ImQError( ), -1, IMENOIMAGE);
|
||
|
|
||
|
}
|
||
|
|
||
|
height = atoi(fieldValue);
|
||
|
|
||
|
|
||
|
|
||
|
fieldValue = imMiffGetHeaderField(header,"columns");
|
||
|
|
||
|
if (fieldValue==NULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImErrorFatal (ImQError( ), -1, IMENOIMAGE);
|
||
|
|
||
|
}
|
||
|
|
||
|
width = atoi(fieldValue);
|
||
|
|
||
|
|
||
|
|
||
|
sprintf(message,"%d x %d",width, height);
|
||
|
|
||
|
ImInfo("Resolution",message);
|
||
|
|
||
|
|
||
|
|
||
|
fieldValue = imMiffGetHeaderField(header,"class");
|
||
|
|
||
|
if (fieldValue==NULL || strcmp(fieldValue,"directclass")==0)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImInfo ("Type","24-bit RGB");
|
||
|
|
||
|
|
||
|
|
||
|
/* Is there an alpha channel ? */
|
||
|
|
||
|
fieldValue = imMiffGetHeaderField(header,"matte");
|
||
|
|
||
|
if (fieldValue && strcmp(fieldValue,"true")==0)
|
||
|
|
||
|
{
|
||
|
|
||
|
numChans = 4;
|
||
|
|
||
|
ImInfo ("Alpha Channel","8-bit");
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
numChans = 3;
|
||
|
|
||
|
ImInfo ("Alpha Channel","none");
|
||
|
|
||
|
}
|
||
|
|
||
|
chanDepth = 8;
|
||
|
|
||
|
|
||
|
|
||
|
/* Can't a have a clt with an RGB image */
|
||
|
|
||
|
cltSize = 0;
|
||
|
|
||
|
ImInfo("Color Table", "none");
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
/* Color indexed */
|
||
|
|
||
|
numChans = 1;
|
||
|
|
||
|
|
||
|
|
||
|
/* Are we 8 or 16 bit? */
|
||
|
|
||
|
fieldValue = imMiffGetHeaderField(header,"colors");
|
||
|
|
||
|
if (fieldValue==NULL)
|
||
|
|
||
|
cltSize = 0;
|
||
|
|
||
|
else
|
||
|
|
||
|
cltSize = atoi(fieldValue);
|
||
|
|
||
|
|
||
|
|
||
|
if (cltSize > (1<<8))
|
||
|
|
||
|
chanDepth = 16;
|
||
|
|
||
|
else
|
||
|
|
||
|
chanDepth = 8;
|
||
|
|
||
|
|
||
|
|
||
|
sprintf(message,"%d-bit color indexed",chanDepth);
|
||
|
|
||
|
ImInfo ("Type",message);
|
||
|
|
||
|
|
||
|
|
||
|
/* Do we have a clt? */
|
||
|
|
||
|
if (cltSize==0)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImInfo("Color Table","none");
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
sprintf(message,"%d entries",cltSize);
|
||
|
|
||
|
ImInfo("Color Table", message);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Is there compression?
|
||
|
|
||
|
*/
|
||
|
|
||
|
fieldValue = imMiffGetHeaderField(header,"compression");
|
||
|
|
||
|
if (fieldValue==NULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
compression = IMCOMPNONE;
|
||
|
|
||
|
ImInfo ("Compression","none");
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
if (strcmp(fieldValue,"runlengthencoded")==0)
|
||
|
|
||
|
{
|
||
|
|
||
|
compression = IMCOMPRLE;
|
||
|
|
||
|
ImInfo ("Compression","Run Length Encoded");
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
ImErrorFatal ("Unsupported compression scheme", -1, IMENOIMAGE);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Read the clt if there is one
|
||
|
|
||
|
*/
|
||
|
|
||
|
if (cltSize!=0)
|
||
|
|
||
|
{
|
||
|
|
||
|
clt = imMiffReadClt( ioType, fd, fp, cltSize );
|
||
|
|
||
|
if (clt==IMCLTNULL) /* error */
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
clt = IMCLTNULL;
|
||
|
|
||
|
|
||
|
|
||
|
/* Read the vfb! */
|
||
|
|
||
|
if (compression==IMCOMPRLE)
|
||
|
|
||
|
{
|
||
|
|
||
|
vfb = imMiffReadRLE(ioType, fd, fp, width, height, numChans, chanDepth);
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
vfb = imMiffReadRaw(ioType, fd, fp, width, height, numChans, chanDepth);
|
||
|
|
||
|
}
|
||
|
|
||
|
if (vfb==IMVFBNULL)
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
|
||
|
|
||
|
if (clt!=IMCLTNULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfbSClt (vfb, clt);
|
||
|
|
||
|
TagTableAppend( tagTable, TagEntryAlloc( "image clt", POINTER, &clt));
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfbSClt (vfb, IMCLTNULL);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
TagTableAppend( tagTable, TagEntryAlloc( "image vfb", POINTER, &vfb));
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Are there any more images ?
|
||
|
|
||
|
*/
|
||
|
|
||
|
moreImages = 1; /* Yes. The only way to exit the loop is by */
|
||
|
|
||
|
/* failing to read the header. */
|
||
|
|
||
|
} /* End of while-more images */
|
||
|
|
||
|
|
||
|
|
||
|
return numImages;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffGetHeaderField
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Parse the string, looking for something of
|
||
|
|
||
|
* the form field=value. Return value (in lower case).
|
||
|
|
||
|
* If field is not found, return NULL.
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
static char* /* returns value for this field in lower case */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffGetHeaderField( char* header, char* field)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffGetHeaderField( header, field)
|
||
|
|
||
|
char* header;
|
||
|
|
||
|
char* field;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
char* ptr; /* points into the string */
|
||
|
|
||
|
static char ret[100]; /* string to return */
|
||
|
|
||
|
|
||
|
|
||
|
if (header==NULL) return NULL;
|
||
|
|
||
|
if (field==NULL) return NULL;
|
||
|
|
||
|
|
||
|
|
||
|
ptr = strstr(header,field);
|
||
|
|
||
|
|
||
|
|
||
|
if (ptr==NULL)
|
||
|
|
||
|
return NULL;
|
||
|
|
||
|
ptr += strlen(field);
|
||
|
|
||
|
|
||
|
|
||
|
if ((*ptr)!='=') return NULL; /* need an '=' */
|
||
|
|
||
|
sscanf (ptr+1,"%s",ret); /* Read the next word */
|
||
|
|
||
|
|
||
|
|
||
|
return strToLower(ret);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffReadClt
|
||
|
|
||
|
*
|
||
|
|
||
|
* DECSRIPTION
|
||
|
|
||
|
* Read in the clt from a MIFF image file
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
static ImClt * /* Returns a brand new clt */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffReadClt( int ioType, int fd, FILE* fp,int cltSize )
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffReadClt( ioType, fd, fp, cltSize )
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE* fp;
|
||
|
|
||
|
int cltSize;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
ImClt* clt; /* Our new clt */
|
||
|
|
||
|
ImCltPtr cltPtr; /* points at our new clt */
|
||
|
|
||
|
unsigned char* rbuf; /* holds the clt data */
|
||
|
|
||
|
unsigned char* rbufptr; /* points into rbuf */
|
||
|
|
||
|
int i; /* loop index */
|
||
|
|
||
|
|
||
|
|
||
|
clt = ImCltAlloc (cltSize);
|
||
|
|
||
|
|
||
|
|
||
|
/* Read in the values */
|
||
|
|
||
|
cltPtr = ImCltQFirst(clt);
|
||
|
|
||
|
ImMallocRetOnError (rbuf, unsigned char*, 3 * cltSize, IMCLTNULL);
|
||
|
|
||
|
rbufptr = rbuf;
|
||
|
|
||
|
if ( ImBinRead (ioType, fd, fp, rbuf, UCHAR, 1, 3 * cltSize) == -1)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImReturnValBinError( IMCLTNULL );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Now we've read in the data. Put it in the clt.
|
||
|
|
||
|
*/
|
||
|
|
||
|
for (i=0; i<cltSize; i++)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImCltSRed ( cltPtr, *rbufptr++);
|
||
|
|
||
|
ImCltSGreen ( cltPtr, *rbufptr++);
|
||
|
|
||
|
ImCltSBlue ( cltPtr, *rbufptr++);
|
||
|
|
||
|
cltPtr = ImCltQNext( clt, cltPtr );
|
||
|
|
||
|
}
|
||
|
|
||
|
free (rbuf);
|
||
|
|
||
|
return clt;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffReadRLE
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Read an RLE encoded MIFF vfb
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
static ImVfb* /* Returns a new vfb */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffReadRLE(int ioType, int fd, FILE* fp, int width,int height,int numChans, int chanDepth)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffReadRLE(ioType, fd, fp, width, height, numChans, chanDepth)
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE *fp;
|
||
|
|
||
|
int width;
|
||
|
|
||
|
int height;
|
||
|
|
||
|
int numChans;
|
||
|
|
||
|
int chanDepth;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfb* vfb; /* new vfb */
|
||
|
|
||
|
ImVfbPtr vfbPtr; /* points into the new vfb */
|
||
|
|
||
|
unsigned char rbuf[7]; /* Holds some data */
|
||
|
|
||
|
int i; /* loop index */
|
||
|
|
||
|
unsigned int uintval; /* holds an index16 value */
|
||
|
|
||
|
|
||
|
|
||
|
switch (numChans)
|
||
|
|
||
|
{
|
||
|
|
||
|
case 1 : /* Color indexed */
|
||
|
|
||
|
if (chanDepth==8)
|
||
|
|
||
|
{ /* index8 */
|
||
|
|
||
|
if ((vfb=ImVfbAlloc( width, height, IMVFBINDEX8 ))==IMVFBNULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImErrorFatal (ImQError( ), IMVFBNULL, ImErrNo);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* Read packets of size 2 */
|
||
|
|
||
|
|
||
|
|
||
|
vfbPtr = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
while ( ImBinRead (ioType, fd, fp, rbuf, UCHAR, 1, 2) > 0)
|
||
|
|
||
|
{
|
||
|
|
||
|
for (i=0; i < rbuf[1] + 1; i++)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfbSIndex8( vfb, vfbPtr, rbuf[0]);
|
||
|
|
||
|
vfbPtr = ImVfbQNext( vfb, vfbPtr);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{ /* index16 */
|
||
|
|
||
|
if ((vfb=ImVfbAlloc( width, height, IMVFBINDEX16 ))==IMVFBNULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImErrorFatal (ImQError( ), IMVFBNULL, ImErrNo);
|
||
|
|
||
|
}
|
||
|
|
||
|
vfbPtr = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
|
||
|
|
||
|
/* Read packets of size 3 */
|
||
|
|
||
|
|
||
|
|
||
|
while ( ImBinRead (ioType, fd, fp, rbuf, UCHAR, 1, 3) > 0)
|
||
|
|
||
|
{
|
||
|
|
||
|
uintval = rbuf[1];
|
||
|
|
||
|
uintval |= rbuf[0] << 8;
|
||
|
|
||
|
for (i=0; i < rbuf[2] + 1; i++)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfbSIndex16( vfb, vfbPtr, uintval);
|
||
|
|
||
|
vfbPtr = ImVfbQNext( vfb, vfbPtr);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} /* End of index16 */
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
|
||
|
case 3 : /* RGB */
|
||
|
|
||
|
if ((vfb=ImVfbAlloc( width, height, IMVFBRGB ))==IMVFBNULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImErrorFatal (ImQError( ), IMVFBNULL, ImErrNo);
|
||
|
|
||
|
}
|
||
|
|
||
|
vfbPtr = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
|
||
|
|
||
|
/* Read packets of size 4 */
|
||
|
|
||
|
|
||
|
|
||
|
while ( ImBinRead (ioType, fd, fp, rbuf, UCHAR, 1, 4) > 0)
|
||
|
|
||
|
{
|
||
|
|
||
|
for (i=0;i<rbuf[3]+1;i++)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfbSRed ( vfb, vfbPtr, rbuf[0]);
|
||
|
|
||
|
ImVfbSGreen( vfb, vfbPtr, rbuf[1]);
|
||
|
|
||
|
ImVfbSBlue ( vfb, vfbPtr, rbuf[2]);
|
||
|
|
||
|
vfbPtr = ImVfbQNext( vfb, vfbPtr);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
|
||
|
case 4 : /* RGBA */
|
||
|
|
||
|
if ((vfb=ImVfbAlloc( width, height, IMVFBRGB|IMVFBALPHA ))==IMVFBNULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImErrorFatal (ImQError( ), IMVFBNULL, ImErrNo);
|
||
|
|
||
|
}
|
||
|
|
||
|
vfbPtr = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
|
||
|
|
||
|
/* Read packets of size 5 */
|
||
|
|
||
|
|
||
|
|
||
|
while ( ImBinRead (ioType, fd, fp, rbuf, UCHAR, 1, 5) > 0)
|
||
|
|
||
|
{
|
||
|
|
||
|
for (i=0;i<rbuf[4]+1;i++)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfbSRed ( vfb, vfbPtr, rbuf[0]);
|
||
|
|
||
|
ImVfbSGreen( vfb, vfbPtr, rbuf[1]);
|
||
|
|
||
|
ImVfbSBlue ( vfb, vfbPtr, rbuf[2]);
|
||
|
|
||
|
ImVfbSAlpha( vfb, vfbPtr, rbuf[3]);
|
||
|
|
||
|
vfbPtr = ImVfbQNext( vfb, vfbPtr);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
} /* End of switch */
|
||
|
|
||
|
|
||
|
|
||
|
return vfb;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffReadRaw
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Read an unencoded MIFF vfb
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
static ImVfb* /* returns a new vfb */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffReadRaw(int ioType, int fd, FILE* fp, int width,int height,int numChans, int chanDepth)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffReadRaw(ioType, fd, fp, width, height, numChans, chanDepth)
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE *fp;
|
||
|
|
||
|
int width;
|
||
|
|
||
|
int height;
|
||
|
|
||
|
int numChans;
|
||
|
|
||
|
int chanDepth;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfb* vfb; /* new vfb */
|
||
|
|
||
|
ImVfbPtr vfbPtr; /* points into the new vfb */
|
||
|
|
||
|
unsigned char* rbuf; /* Holds the data */
|
||
|
|
||
|
unsigned char* rbufptr; /* Points at the data */
|
||
|
|
||
|
int i; /* index */
|
||
|
|
||
|
unsigned int uintval; /* holds an index16 value */
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
ImCallocRetOnError(rbuf, unsigned char*, numChans * width * height * (chanDepth / 8), sizeof(char), IMVFBNULL);
|
||
|
|
||
|
|
||
|
|
||
|
if (ImBinRead(ioType, fd, fp, rbuf, UCHAR, 1,
|
||
|
|
||
|
numChans * width * height * (chanDepth / 8))==-1)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImReturnValBinError( IMVFBNULL );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* rbuf now contains all the data we need.
|
||
|
|
||
|
* Store it in the vfb in the correct manner
|
||
|
|
||
|
* depending on what type of vfb we have.
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
/* Initialize rbufptr, and vfbPtr */
|
||
|
|
||
|
rbufptr = rbuf;
|
||
|
|
||
|
switch (numChans)
|
||
|
|
||
|
{
|
||
|
|
||
|
case 1 : /* Color indexed */
|
||
|
|
||
|
if (chanDepth==8)
|
||
|
|
||
|
{ /* index8 */
|
||
|
|
||
|
if ((vfb=ImVfbAlloc( width, height, IMVFBINDEX8 ))==IMVFBNULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImErrorFatal (ImQError( ), IMVFBNULL, ImErrNo);
|
||
|
|
||
|
}
|
||
|
|
||
|
vfbPtr = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
for (i=0; i < width * height; i++)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfbSIndex8( vfb, vfbPtr, *rbufptr++);
|
||
|
|
||
|
vfbPtr = ImVfbQNext( vfb, vfbPtr);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{ /* index16 */
|
||
|
|
||
|
if ((vfb=ImVfbAlloc( width, height, IMVFBINDEX16 ))==IMVFBNULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImErrorFatal (ImQError( ), IMVFBNULL, ImErrNo);
|
||
|
|
||
|
}
|
||
|
|
||
|
vfbPtr = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
for (i=0; i < width * height; i++)
|
||
|
|
||
|
{
|
||
|
|
||
|
uintval = *rbufptr++ << 8;
|
||
|
|
||
|
uintval |= (*rbufptr++);
|
||
|
|
||
|
ImVfbSIndex16( vfb, vfbPtr, uintval);
|
||
|
|
||
|
vfbPtr = ImVfbQNext( vfb, vfbPtr);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
|
||
|
case 3 : /* RGB */
|
||
|
|
||
|
if ((vfb=ImVfbAlloc( width, height, IMVFBRGB ))==IMVFBNULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImErrorFatal (ImQError( ), IMVFBNULL, ImErrNo);
|
||
|
|
||
|
}
|
||
|
|
||
|
vfbPtr = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
for (i=0; i < width * height; i++)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfbSRed ( vfb, vfbPtr, *rbufptr++);
|
||
|
|
||
|
ImVfbSGreen( vfb, vfbPtr, *rbufptr++);
|
||
|
|
||
|
ImVfbSBlue ( vfb, vfbPtr, *rbufptr++);
|
||
|
|
||
|
vfbPtr = ImVfbQNext( vfb, vfbPtr);
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
|
||
|
case 4 : /* RGBA */
|
||
|
|
||
|
if ((vfb=ImVfbAlloc( width, height, IMVFBRGB|IMVFBALPHA ))==IMVFBNULL)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImErrorFatal (ImQError( ), IMVFBNULL, ImErrNo);
|
||
|
|
||
|
}
|
||
|
|
||
|
vfbPtr = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
for (i=0; i < width * height; i++)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfbSRed ( vfb, vfbPtr, *rbufptr++);
|
||
|
|
||
|
ImVfbSGreen( vfb, vfbPtr, *rbufptr++);
|
||
|
|
||
|
ImVfbSBlue ( vfb, vfbPtr, *rbufptr++);
|
||
|
|
||
|
ImVfbSAlpha( vfb, vfbPtr, *rbufptr++);
|
||
|
|
||
|
vfbPtr = ImVfbQNext( vfb, vfbPtr);
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
free (rbuf);
|
||
|
|
||
|
|
||
|
|
||
|
return vfb;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffWriteRGB
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Write an RGB miff file with...
|
||
|
|
||
|
* - RLE or no compression
|
||
|
|
||
|
* - possibly an alpha channel
|
||
|
|
||
|
*/
|
||
|
|
||
|
static int /* returns number of tags used */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffWriteRGB( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp,
|
||
|
|
||
|
TagTable *flagsTable, TagTable *tagTable)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffWriteRGB( pMap, ioType, fd, fp, flagsTable, tagTable)
|
||
|
|
||
|
ImFileFormatWriteMap * pMap;
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE* fp;
|
||
|
|
||
|
TagTable* flagsTable;
|
||
|
|
||
|
TagTable* tagTable;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfb* vfb; /* image vfb */
|
||
|
|
||
|
ImVfbPtr vfbptr; /* points into a vfb */
|
||
|
|
||
|
char header[400]; /* header (text based) */
|
||
|
|
||
|
int x, y; /* dimensions of vfb */
|
||
|
|
||
|
char message[100]; /* another buffer */
|
||
|
|
||
|
char* filename; /* filename */
|
||
|
|
||
|
int numChans; /* 3 or 4 channels. */
|
||
|
|
||
|
int numImages; /* number of images */
|
||
|
|
||
|
int curImage; /* loop index */
|
||
|
|
||
|
|
||
|
|
||
|
BinByteOrder( BINMBF );
|
||
|
|
||
|
numImages = TagTableQNEntry (tagTable, "image vfb");
|
||
|
|
||
|
|
||
|
|
||
|
for (curImage=0;curImage<numImages;curImage++)
|
||
|
|
||
|
{
|
||
|
|
||
|
/* Get the vfb */
|
||
|
|
||
|
TagEntryQValue( TagTableQDirect( tagTable, "image vfb", curImage ), &vfb );
|
||
|
|
||
|
x = ImVfbQWidth(vfb);
|
||
|
|
||
|
y = ImVfbQHeight(vfb);
|
||
|
|
||
|
|
||
|
|
||
|
if (numImages > 1)
|
||
|
|
||
|
{
|
||
|
|
||
|
sprintf(message,"%d of %d",curImage+1, numImages);
|
||
|
|
||
|
ImInfo("Image",message);
|
||
|
|
||
|
}
|
||
|
|
||
|
sprintf(message,"%d x %d", x, y);
|
||
|
|
||
|
ImInfo ("Resolution", message);
|
||
|
|
||
|
ImInfo ("Type", "24-bit RGB");
|
||
|
|
||
|
ImInfo ("Color Table","none");
|
||
|
|
||
|
if (pMap->map_outAttributes & IMCOMPRLE)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImInfo ("Compression Type", "Run Length Encoded");
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
ImInfo ("Compression Type", "none");
|
||
|
|
||
|
}
|
||
|
|
||
|
if (pMap->map_outAttributes & IMALPHAYES)
|
||
|
|
||
|
{
|
||
|
|
||
|
numChans = 4;
|
||
|
|
||
|
ImInfo ("Alpha Channel", "8-bit");
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
numChans = 3;
|
||
|
|
||
|
ImInfo ("Alpha Channel", "none");
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
if (!flagsTable || TagTableQNEntry (flagsTable, "file name")==0)
|
||
|
|
||
|
{
|
||
|
|
||
|
filename = NULL;
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
TagEntryQValue( TagTableQDirect ( flagsTable, "file name", 0 ), &filename);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Write the header
|
||
|
|
||
|
*/
|
||
|
|
||
|
sprintf(header, "{\n %s\n %s\n}\nid=ImageMagick\nclass=DirectClass\nrows=%d\ncolumns=%d\n%s%s\f\n:\n",
|
||
|
|
||
|
filename ? filename : "(untitled)",
|
||
|
|
||
|
"This file was created by the SDSC Image Tools.",
|
||
|
|
||
|
y, /* rows */
|
||
|
|
||
|
x, /* columns */
|
||
|
|
||
|
numChans==4 ? "matte=True\n" : "matte=False\n",
|
||
|
|
||
|
(pMap->map_outAttributes & IMCOMPRLE) ? "compression=RunlengthEncoded\n" : ""
|
||
|
|
||
|
);
|
||
|
|
||
|
|
||
|
|
||
|
if ( ImBinWrite( ioType, fd, fp, header, CHAR, 1, strlen(header))==-1)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImReturnBinError( );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Write the pixels
|
||
|
|
||
|
*/
|
||
|
|
||
|
if (!(pMap->map_outAttributes & IMCOMPRLE))
|
||
|
|
||
|
{
|
||
|
|
||
|
if (imMiffWriteRawRGB(vfb, fd, fp, numChans, ioType)==-1)
|
||
|
|
||
|
return -1;
|
||
|
|
||
|
}
|
||
|
|
||
|
else /* RLE compress */
|
||
|
|
||
|
{
|
||
|
|
||
|
if (pMap->map_outAttributes & IMALPHAYES)
|
||
|
|
||
|
{
|
||
|
|
||
|
if (imMiffWriteRLERGBA(vfb, fd, fp, ioType)==-1)
|
||
|
|
||
|
return -1;
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
if (imMiffWriteRLERGB(vfb, fd, fp, ioType)==-1)
|
||
|
|
||
|
return -1;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
return numImages;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffWriteRawRGB
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Write the pixels of the vfb without compressing them.
|
||
|
|
||
|
*/
|
||
|
|
||
|
static int /* returns status */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffWriteRawRGB( ImVfb* vfb, int fd, FILE* fp, int numChans, int ioType)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffWriteRawRGB( vfb, fd, fp, numChans, ioType)
|
||
|
|
||
|
ImVfb* vfb;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE* fp;
|
||
|
|
||
|
int numChans;
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
unsigned char* runBuffer; /* holds pixels */
|
||
|
|
||
|
ImVfbPtr vfbptr; /* points into a vfb */
|
||
|
|
||
|
int runIndex, i,j,x,y; /* indexes, dimensions */
|
||
|
|
||
|
|
||
|
|
||
|
x = ImVfbQWidth(vfb);
|
||
|
|
||
|
y = ImVfbQHeight(vfb);
|
||
|
|
||
|
|
||
|
|
||
|
ImMalloc( runBuffer, unsigned char *, sizeof (unsigned char) * x * numChans);
|
||
|
|
||
|
vfbptr = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
for (i=0; i<y; i++) /* i goes through the rows */
|
||
|
|
||
|
{
|
||
|
|
||
|
runIndex = 0;
|
||
|
|
||
|
for (j=0;j<x;j++) /* Fill a buffer for this row. */
|
||
|
|
||
|
{
|
||
|
|
||
|
runBuffer[runIndex++] = ImVfbQRed(vfb, vfbptr);
|
||
|
|
||
|
runBuffer[runIndex++] = ImVfbQGreen(vfb, vfbptr);
|
||
|
|
||
|
runBuffer[runIndex++] = ImVfbQBlue(vfb, vfbptr);
|
||
|
|
||
|
if (numChans == 4)
|
||
|
|
||
|
runBuffer[runIndex++] = ImVfbQAlpha( vfb, vfbptr);
|
||
|
|
||
|
vfbptr = ImVfbQNext(vfb,vfbptr);
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, x * numChans)==-1)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImReturnBinError( );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
free(runBuffer);
|
||
|
|
||
|
return 1;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* MACROS
|
||
|
|
||
|
* imMiffDumpRun3
|
||
|
|
||
|
* imMiffDumpRun4
|
||
|
|
||
|
* imMiffDumpRun1
|
||
|
|
||
|
* imMiffDumpRun2
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Dump RGB, RGBA, Index, and Index16 runs respectively.
|
||
|
|
||
|
* (These all use the file-wide variable 'dumpBuf')
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
static unsigned char dumpBuf[7];
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#define imMiffDumpRun3(r,g,b,len) \
|
||
|
dumpBuf[0] = r; dumpBuf[1] = g; dumpBuf[2] = b; \
|
||
|
dumpBuf[3] = len; \
|
||
|
if ( ImBinWrite( ioType, fd, fp, dumpBuf, UCHAR, 1, 4)==-1) \
|
||
|
{ \
|
||
|
ImReturnBinError( ); \
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#define imMiffDumpRun4(r,g,b,a,len) \
|
||
|
dumpBuf[0] = r; dumpBuf[1] = g; dumpBuf[2] = b; \
|
||
|
dumpBuf[3] = a; dumpBuf[4] = len; \
|
||
|
if ( ImBinWrite( ioType, fd, fp, dumpBuf, UCHAR, 1, 5)==-1) \
|
||
|
{ \
|
||
|
ImReturnBinError( ); \
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#define imMiffDumpRun1(v,len) \
|
||
|
dumpBuf[0] = v; \
|
||
|
dumpBuf[1] = len; \
|
||
|
if ( ImBinWrite( ioType, fd, fp, dumpBuf, UCHAR, 1, 2)==-1) \
|
||
|
{ \
|
||
|
ImReturnBinError( ); \
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#define imMiffDumpRun2(v,len) \
|
||
|
dumpBuf[0] = ((v & 0xff00) >> 8); \
|
||
|
dumpBuf[1] = (v & 0x00ff); \
|
||
|
dumpBuf[2] = len; \
|
||
|
if ( ImBinWrite( ioType, fd, fp, dumpBuf, UCHAR, 1, 3)==-1) \
|
||
|
{ \
|
||
|
ImReturnBinError( ); \
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffWriteRLERGB
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Write the pixels of the vfb using RLE compression.
|
||
|
|
||
|
*/
|
||
|
|
||
|
static int /* returns status */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffWriteRLERGB( ImVfb* vfb, int fd, FILE* fp, int ioType)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffWriteRLERGB( vfb, fd, fp, ioType)
|
||
|
|
||
|
ImVfb* vfb;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE* fp;
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
int runLength, i,x,y; /* index, dimensions */
|
||
|
|
||
|
ImVfbPtr thisPixel; /* this pixel */
|
||
|
|
||
|
ImVfbPtr lastPixel; /* last pixel */
|
||
|
|
||
|
unsigned char dumpBuf[10]; /* Buffer for output */
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* The unsigned ints above are used to store red,green, and blue
|
||
|
|
||
|
* values for pixels. i.e. three of the bytes are used for these
|
||
|
|
||
|
* values.
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
x = ImVfbQWidth(vfb);
|
||
|
|
||
|
y = ImVfbQHeight(vfb);
|
||
|
|
||
|
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
|
||
|
|
||
|
lastPixel = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
thisPixel = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
for (i=1; i<x*y; i++) /* Skip the first pixel */
|
||
|
|
||
|
{
|
||
|
|
||
|
thisPixel = ImVfbQNext(vfb,thisPixel);
|
||
|
|
||
|
if (ImVfbSameRGB(vfb, lastPixel,thisPixel))
|
||
|
|
||
|
{
|
||
|
|
||
|
runLength++;
|
||
|
|
||
|
if (runLength > 0xff)
|
||
|
|
||
|
{
|
||
|
|
||
|
runLength--;
|
||
|
|
||
|
/* Dump run */
|
||
|
|
||
|
imMiffDumpRun3(ImVfbQRed(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQGreen(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQBlue(vfb,lastPixel),
|
||
|
|
||
|
runLength);
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
else /* new run. Dump the last one. */
|
||
|
|
||
|
{
|
||
|
|
||
|
imMiffDumpRun3(ImVfbQRed(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQGreen(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQBlue(vfb,lastPixel),
|
||
|
|
||
|
runLength);
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
lastPixel = thisPixel;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* Dump the last run */
|
||
|
|
||
|
imMiffDumpRun3(ImVfbQRed(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQGreen(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQBlue(vfb,lastPixel),
|
||
|
|
||
|
runLength);
|
||
|
|
||
|
return 1;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffWriteRLERGBA
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Write the pixels of the vfb (with alpha) using RLE compression.
|
||
|
|
||
|
*/
|
||
|
|
||
|
static int /* returns status */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffWriteRLERGBA( ImVfb* vfb, int fd, FILE* fp, int ioType)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffWriteRLERGBA( vfb, fd, fp, ioType)
|
||
|
|
||
|
ImVfb* vfb;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE* fp;
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfbPtr vfbptr; /* points into a vfb */
|
||
|
|
||
|
int runLength, i,x,y; /* indexes, dimensions */
|
||
|
|
||
|
ImVfbPtr thisPixel; /* this pixel */
|
||
|
|
||
|
ImVfbPtr lastPixel; /* last pixel */
|
||
|
|
||
|
unsigned char dumpBuf[10]; /* Buffer for output */
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* The unsigned ints above are used to store red,green, and blue
|
||
|
|
||
|
* values for pixels. i.e. three of the bytes are used for these
|
||
|
|
||
|
* values.
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
x = ImVfbQWidth(vfb);
|
||
|
|
||
|
y = ImVfbQHeight(vfb);
|
||
|
|
||
|
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
|
||
|
|
||
|
lastPixel = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
thisPixel = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
for (i=1; i<x*y; i++) /* Skip the first pixel */
|
||
|
|
||
|
{
|
||
|
|
||
|
thisPixel = ImVfbQNext(vfb,thisPixel);
|
||
|
|
||
|
if (ImVfbSameRGBA(vfb, lastPixel,thisPixel))
|
||
|
|
||
|
{
|
||
|
|
||
|
runLength++;
|
||
|
|
||
|
if (runLength > 0xff)
|
||
|
|
||
|
{
|
||
|
|
||
|
runLength--;
|
||
|
|
||
|
/* Dump run */
|
||
|
|
||
|
imMiffDumpRun4(ImVfbQRed(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQGreen(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQBlue(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQAlpha(vfb,lastPixel),
|
||
|
|
||
|
runLength);
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
else /* new run. Dump the last one. */
|
||
|
|
||
|
{
|
||
|
|
||
|
imMiffDumpRun4(ImVfbQRed(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQGreen(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQBlue(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQAlpha(vfb,lastPixel),
|
||
|
|
||
|
runLength);
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
lastPixel = thisPixel;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* Dump the last run */
|
||
|
|
||
|
imMiffDumpRun4(ImVfbQRed(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQGreen(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQBlue(vfb,lastPixel),
|
||
|
|
||
|
ImVfbQAlpha(vfb,lastPixel),
|
||
|
|
||
|
runLength);
|
||
|
|
||
|
return 1;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffWriteIndex
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Write an indexed miff file with...
|
||
|
|
||
|
* - no compression
|
||
|
|
||
|
* - possibly a clt
|
||
|
|
||
|
*/
|
||
|
|
||
|
static int /* returns number of tags used */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffWriteIndex( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp,
|
||
|
|
||
|
TagTable *flagsTable, TagTable *tagTable)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffWriteIndex( pMap, ioType, fd, fp, flagsTable, tagTable)
|
||
|
|
||
|
ImFileFormatWriteMap * pMap;
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE* fp;
|
||
|
|
||
|
TagTable* flagsTable;
|
||
|
|
||
|
TagTable* tagTable;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
ImVfb* vfb; /* image vfb */
|
||
|
|
||
|
char header[400]; /* header (text based) */
|
||
|
|
||
|
int i; /* loop indexes */
|
||
|
|
||
|
int runIndex; /* yet another index */
|
||
|
|
||
|
unsigned char* runBuffer;/* buffer */
|
||
|
|
||
|
char message[100]; /* another buffer */
|
||
|
|
||
|
char* filename; /* filename */
|
||
|
|
||
|
ImClt* clt; /* image clt */
|
||
|
|
||
|
ImCltPtr cltptr; /* points into the clt */
|
||
|
|
||
|
char colorstring[30]; /* string for the header */
|
||
|
|
||
|
int numColors; /* num of colors in clt*/
|
||
|
|
||
|
int chanDepth; /* 8 or 16 */
|
||
|
|
||
|
int numImages; /* number of images */
|
||
|
|
||
|
int curImage; /* loop index */
|
||
|
|
||
|
int numZeros; /* how much to pad the clt */
|
||
|
|
||
|
|
||
|
|
||
|
BinByteOrder( BINMBF );
|
||
|
|
||
|
numImages = TagTableQNEntry (tagTable, "image vfb");
|
||
|
|
||
|
|
||
|
|
||
|
for (curImage=0;curImage<numImages;curImage++)
|
||
|
|
||
|
{
|
||
|
|
||
|
/* Get the vfb */
|
||
|
|
||
|
TagEntryQValue( TagTableQDirect( tagTable, "image vfb", curImage ), &vfb );
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Write the clt, if there is one.
|
||
|
|
||
|
*/
|
||
|
|
||
|
if (pMap->map_outAttributes & IMCLTYES)
|
||
|
|
||
|
{
|
||
|
|
||
|
clt = ImVfbQClt(vfb);
|
||
|
|
||
|
numColors = ImCltQNColors(clt);
|
||
|
|
||
|
|
||
|
|
||
|
if (pMap->map_outChannelDepth==16)
|
||
|
|
||
|
{
|
||
|
|
||
|
chanDepth = 16;
|
||
|
|
||
|
ImInfo ("Type", "16-bit Color Indexed");
|
||
|
|
||
|
/* Need to pad the color table if we don't have enough colors */
|
||
|
|
||
|
if (numColors <= 256)
|
||
|
|
||
|
numZeros = 257-numColors;
|
||
|
|
||
|
else
|
||
|
|
||
|
numZeros = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
chanDepth = 8;
|
||
|
|
||
|
ImInfo ("Type", "8-bit Color Indexed");
|
||
|
|
||
|
numZeros = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
sprintf(message,"%d entries",numColors+numZeros);
|
||
|
|
||
|
ImInfo ("Color Table",message);
|
||
|
|
||
|
sprintf(colorstring,"colors=%d\n",numColors+numZeros);
|
||
|
|
||
|
}
|
||
|
|
||
|
else /* no clt */
|
||
|
|
||
|
{
|
||
|
|
||
|
strcpy(colorstring, "" );
|
||
|
|
||
|
chanDepth = pMap -> map_outChannelDepth;
|
||
|
|
||
|
sprintf(message,"%d-bit Greyscale",chanDepth);
|
||
|
|
||
|
ImInfo ("Color Table","none");
|
||
|
|
||
|
ImInfo ("Type",message);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
sprintf(message,"%d x %d", ImVfbQWidth(vfb), ImVfbQHeight(vfb));
|
||
|
|
||
|
ImInfo ("Resolution", message);
|
||
|
|
||
|
ImInfo ("Alpha Channel", "none");
|
||
|
|
||
|
|
||
|
|
||
|
if (!flagsTable || TagTableQNEntry (flagsTable, "file name")==0)
|
||
|
|
||
|
{
|
||
|
|
||
|
filename = NULL;
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
TagEntryQValue( TagTableQDirect ( flagsTable, "file name", 0 ), &filename);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Write the header
|
||
|
|
||
|
*/
|
||
|
|
||
|
sprintf(header, "{\n %s\n %s\n}\nid=ImageMagick\nclass=PseudoClass\nrows=%d\ncolumns=%d\n%s%s\f\n:\n",
|
||
|
|
||
|
filename ? filename : "(untitled)",
|
||
|
|
||
|
"This file was created by the SDSC Image Tools.",
|
||
|
|
||
|
ImVfbQHeight(vfb), /* rows */
|
||
|
|
||
|
ImVfbQWidth(vfb), /* columns */
|
||
|
|
||
|
(pMap->map_outAttributes & IMCOMPRLE) ? "compression=RunlengthEncoded\n" : "",
|
||
|
|
||
|
colorstring
|
||
|
|
||
|
);
|
||
|
|
||
|
|
||
|
|
||
|
if ( ImBinWrite( ioType, fd, fp, header, CHAR, 1, strlen(header))==-1)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImReturnBinError( );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
if (pMap->map_outAttributes & IMCLTYES)
|
||
|
|
||
|
{
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Write the clt
|
||
|
|
||
|
*/
|
||
|
|
||
|
cltptr = ImCltQFirst( clt );
|
||
|
|
||
|
ImCalloc ( runBuffer, unsigned char *, (numColors + numZeros) * 3, 1);
|
||
|
|
||
|
runIndex = 0;
|
||
|
|
||
|
for (i=0;i<numColors;i++)
|
||
|
|
||
|
{
|
||
|
|
||
|
runBuffer[runIndex++] = ImCltQRed (cltptr);
|
||
|
|
||
|
runBuffer[runIndex++] = ImCltQGreen(cltptr);
|
||
|
|
||
|
runBuffer[runIndex++] = ImCltQBlue (cltptr);
|
||
|
|
||
|
cltptr = ImCltQNext( clt, cltptr);
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, (numColors+numZeros) * 3)==-1)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImReturnBinError( );
|
||
|
|
||
|
}
|
||
|
|
||
|
free(runBuffer);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Write the pixels
|
||
|
|
||
|
*/
|
||
|
|
||
|
if (chanDepth==8)
|
||
|
|
||
|
{
|
||
|
|
||
|
if (pMap->map_outAttributes & IMCOMPRLE)
|
||
|
|
||
|
{
|
||
|
|
||
|
if (imMiffWriteRLEIndex8(vfb, fd, fp, ioType)<0)
|
||
|
|
||
|
return -1;
|
||
|
|
||
|
ImInfo ("Compression Type", "Run Length Encoded");
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
ImInfo ("Compression Type", "none");
|
||
|
|
||
|
if (imMiffWriteRawIndex8(vfb, fd, fp, ioType)<0)
|
||
|
|
||
|
return -1;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
else /* 16-bit */
|
||
|
|
||
|
{
|
||
|
|
||
|
if (pMap->map_outAttributes & IMCOMPRLE)
|
||
|
|
||
|
{
|
||
|
|
||
|
if (imMiffWriteRLEIndex16(vfb, fd, fp, ioType)<0)
|
||
|
|
||
|
return -1;
|
||
|
|
||
|
ImInfo ("Compression Type", "Run Length Encoded");
|
||
|
|
||
|
}
|
||
|
|
||
|
else
|
||
|
|
||
|
{
|
||
|
|
||
|
if (imMiffWriteRawIndex16(vfb, fd, fp, ioType)<0)
|
||
|
|
||
|
return -1;
|
||
|
|
||
|
ImInfo ("Compression Type", "none");
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
return numImages;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffWriteRawIndex8
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Write the pixels of an indexed vfb with no compression
|
||
|
|
||
|
*/
|
||
|
|
||
|
static int /* returns status */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffWriteRawIndex8(ImVfb* vfb, int fd, FILE* fp, int ioType)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffWriteRawIndex8(vfb, fd, fp, ioType)
|
||
|
|
||
|
ImVfb* vfb;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE* fp;
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
int runIndex; /* index */
|
||
|
|
||
|
unsigned char* runBuffer;/* buffer */
|
||
|
|
||
|
ImVfbPtr vfbptr; /* points into a vfb */
|
||
|
|
||
|
int x, y; /* dimensions of vfb */
|
||
|
|
||
|
int i,j; /* loop indexes */
|
||
|
|
||
|
|
||
|
|
||
|
x = ImVfbQWidth(vfb);
|
||
|
|
||
|
y = ImVfbQHeight(vfb);
|
||
|
|
||
|
|
||
|
|
||
|
vfbptr = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
ImMalloc( runBuffer, unsigned char *, sizeof (unsigned char) * x );
|
||
|
|
||
|
|
||
|
|
||
|
for (i=0; i<y; i++) /* i goes through the rows */
|
||
|
|
||
|
{
|
||
|
|
||
|
runIndex = 0;
|
||
|
|
||
|
for (j=0;j<x;j++) /* Fill a buffer for this row. */
|
||
|
|
||
|
{
|
||
|
|
||
|
runBuffer[runIndex++] = ImVfbQIndex(vfb, vfbptr);
|
||
|
|
||
|
vfbptr = ImVfbQNext(vfb,vfbptr);
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, x )==-1)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImReturnBinError( );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
free(runBuffer);
|
||
|
|
||
|
return 1;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffWriteRawIndex16
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Write the pixels of an indexed vfb with no compression
|
||
|
|
||
|
*/
|
||
|
|
||
|
static int /* returns status */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffWriteRawIndex16(ImVfb* vfb, int fd, FILE* fp, int ioType)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffWriteRawIndex16(vfb, fd, fp, ioType)
|
||
|
|
||
|
ImVfb* vfb;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE* fp;
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
int runIndex; /* index */
|
||
|
|
||
|
unsigned char* runBuffer;/* buffer */
|
||
|
|
||
|
ImVfbPtr vfbptr; /* points into a vfb */
|
||
|
|
||
|
int x, y; /* dimensions of vfb */
|
||
|
|
||
|
int i,j; /* loop indexes */
|
||
|
|
||
|
|
||
|
|
||
|
x = ImVfbQWidth(vfb);
|
||
|
|
||
|
y = ImVfbQHeight(vfb);
|
||
|
|
||
|
|
||
|
|
||
|
vfbptr = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
ImMalloc( runBuffer, unsigned char *, sizeof (unsigned char) * x * 2 );
|
||
|
|
||
|
|
||
|
|
||
|
for (i=0; i<y; i++) /* i goes through the rows */
|
||
|
|
||
|
{
|
||
|
|
||
|
runIndex = 0;
|
||
|
|
||
|
for (j=0;j<x;j++) /* Fill a buffer for this row. */
|
||
|
|
||
|
{
|
||
|
|
||
|
runBuffer[runIndex++] = ((ImVfbQIndex16(vfb, vfbptr)) & 0xff00) >> 8;
|
||
|
|
||
|
runBuffer[runIndex++] = (ImVfbQIndex16(vfb, vfbptr)) & 0x00ff;
|
||
|
|
||
|
vfbptr = ImVfbQNext(vfb,vfbptr);
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, x*2 )==-1)
|
||
|
|
||
|
{
|
||
|
|
||
|
ImReturnBinError( );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
free(runBuffer);
|
||
|
|
||
|
return 1;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffWriteRLEIndex8
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Write the pixels of the vfb using RLE compression.
|
||
|
|
||
|
*/
|
||
|
|
||
|
static int /* returns status */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffWriteRLEIndex8( ImVfb* vfb, int fd, FILE* fp, int ioType)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffWriteRLEIndex8( vfb, fd, fp, ioType)
|
||
|
|
||
|
ImVfb* vfb;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE* fp;
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
int runLength, i,x,y; /* indexes, dimensions */
|
||
|
|
||
|
ImVfbPtr thisPixel; /* this pixel */
|
||
|
|
||
|
ImVfbPtr lastPixel; /* last pixel */
|
||
|
|
||
|
unsigned char dumpBuf[10]; /* Buffer for output */
|
||
|
|
||
|
|
||
|
|
||
|
x = ImVfbQWidth(vfb);
|
||
|
|
||
|
y = ImVfbQHeight(vfb);
|
||
|
|
||
|
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
|
||
|
|
||
|
lastPixel = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
thisPixel = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
for (i=1; i<x*y; i++) /* Skip the first pixel */
|
||
|
|
||
|
{
|
||
|
|
||
|
thisPixel = ImVfbQNext(vfb,thisPixel);
|
||
|
|
||
|
if (ImVfbSameIndex8(vfb, lastPixel,thisPixel))
|
||
|
|
||
|
{
|
||
|
|
||
|
runLength++;
|
||
|
|
||
|
if (runLength > 0xff)
|
||
|
|
||
|
{
|
||
|
|
||
|
runLength--;
|
||
|
|
||
|
/* Dump run */
|
||
|
|
||
|
imMiffDumpRun1(ImVfbQIndex(vfb,lastPixel),
|
||
|
|
||
|
runLength);
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
else /* new run. Dump the last one. */
|
||
|
|
||
|
{
|
||
|
|
||
|
imMiffDumpRun1(ImVfbQIndex(vfb,lastPixel),
|
||
|
|
||
|
runLength);
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
lastPixel = thisPixel;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* Dump the last run */
|
||
|
|
||
|
imMiffDumpRun1(ImVfbQIndex8(vfb,lastPixel), runLength);
|
||
|
|
||
|
|
||
|
|
||
|
return 1;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* imMiffWriteRLEIndex16
|
||
|
|
||
|
*
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* Write the pixels of the vfb using RLE compression.
|
||
|
|
||
|
*/
|
||
|
|
||
|
static int /* returns status */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
imMiffWriteRLEIndex16( ImVfb* vfb, int fd, FILE* fp, int ioType)
|
||
|
|
||
|
#else
|
||
|
|
||
|
imMiffWriteRLEIndex16( vfb, fd, fp, ioType)
|
||
|
|
||
|
ImVfb* vfb;
|
||
|
|
||
|
int fd;
|
||
|
|
||
|
FILE* fp;
|
||
|
|
||
|
int ioType;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
int runLength, i,x,y; /* indexes, dimensions */
|
||
|
|
||
|
ImVfbPtr thisPixel; /* this pixel */
|
||
|
|
||
|
ImVfbPtr lastPixel; /* last pixel */
|
||
|
|
||
|
unsigned char dumpBuf[10]; /* Buffer for output */
|
||
|
|
||
|
|
||
|
|
||
|
x = ImVfbQWidth(vfb);
|
||
|
|
||
|
y = ImVfbQHeight(vfb);
|
||
|
|
||
|
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
|
||
|
|
||
|
lastPixel = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
thisPixel = ImVfbQPtr( vfb, 0, 0);
|
||
|
|
||
|
for (i=1; i<x*y; i++) /* Skip the first pixel */
|
||
|
|
||
|
{
|
||
|
|
||
|
thisPixel = ImVfbQNext(vfb,thisPixel);
|
||
|
|
||
|
if (ImVfbSameIndex16(vfb, lastPixel,thisPixel))
|
||
|
|
||
|
{
|
||
|
|
||
|
runLength++;
|
||
|
|
||
|
if (runLength > 0xff)
|
||
|
|
||
|
{
|
||
|
|
||
|
runLength--;
|
||
|
|
||
|
/* Dump run */
|
||
|
|
||
|
imMiffDumpRun2(ImVfbQIndex16(vfb,lastPixel),
|
||
|
|
||
|
runLength);
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
else /* new run. Dump the last one. */
|
||
|
|
||
|
{
|
||
|
|
||
|
imMiffDumpRun2(ImVfbQIndex16(vfb,lastPixel),
|
||
|
|
||
|
runLength);
|
||
|
|
||
|
runLength = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
lastPixel = thisPixel;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* Dump the last run */
|
||
|
|
||
|
imMiffDumpRun2(ImVfbQIndex16(vfb,lastPixel), runLength);
|
||
|
|
||
|
|
||
|
|
||
|
return 1;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* FUNCTION
|
||
|
|
||
|
* strToLower
|
||
|
|
||
|
* DESCRIPTION
|
||
|
|
||
|
* convert a string into lower case
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
static char* /* returns the string */
|
||
|
|
||
|
#ifdef __STDC__
|
||
|
|
||
|
strToLower(char* str)
|
||
|
|
||
|
#else
|
||
|
|
||
|
strToLower(str)
|
||
|
|
||
|
char* str;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
|
||
|
char* ptr;
|
||
|
|
||
|
if (str==NULL)
|
||
|
|
||
|
return NULL;
|
||
|
|
||
|
ptr = str;
|
||
|
|
||
|
while (*ptr!='\0')
|
||
|
|
||
|
{
|
||
|
|
||
|
if (( *ptr >= 'A') && (*ptr <= 'Z'))
|
||
|
|
||
|
*ptr -= ('A' - 'a');
|
||
|
|
||
|
ptr++;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
return str;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|