diff options
author | Rushabh Doshi <rushabh@ncsa.uiuc.edu> | 2001-05-12 17:55:47 (GMT) |
---|---|---|
committer | Rushabh Doshi <rushabh@ncsa.uiuc.edu> | 2001-05-12 17:55:47 (GMT) |
commit | 2eb5516b099b36d0d5222b89901a2302462098a2 (patch) | |
tree | b211e58feb139f86fbf2e3f32ae5ec9483e18a71 | |
parent | 00eeb08a51a6bc58112db4556875243edca61221 (diff) | |
download | hdf5-2eb5516b099b36d0d5222b89901a2302462098a2.zip hdf5-2eb5516b099b36d0d5222b89901a2302462098a2.tar.gz hdf5-2eb5516b099b36d0d5222b89901a2302462098a2.tar.bz2 |
[svn-r3919]
Purpose:
Adding new feature
Description:
Added gif2h5 and h52gif conversion utilities
Solution:
The utilites follow the framework built for the gif2hdf and hdf2gif
utilities for hdf4. The main files modified were those that read the
H5 file and those that write H5 file. In the future, if you wish to
continue with the framework and extend it to .png or some other fileformat
the main files to edit will be the gif reader and writer.
One point to note with h52gif. You have to specify the exact location of
the image and the palette that it links to. You can choose not to specify
a palette (uniform grayscale chosen in this case) but you must specify
image location. In the future, someone could edit the readhdf.c source
to enable the reader to parse the hdf file and select all images with
corresponding palettes.
Platforms tested:
modi4 , eirene , hawkwind , arabica , Ren (NT 4.0) , Personal box (win2k)
28 files changed, 5700 insertions, 2 deletions
@@ -968,6 +968,19 @@ ./tools/Dependencies ./tools/Makefile.in +./tools/gifconv/Dependencies +./tools/gifconv/Makefile.in +./tools/gifconv/decompress.c +./tools/gifconf/gif.h +./tools/gifconv/gif2hdf.c +./tools/gifconv/gif2mem.c +./tools/gifconv/gifread.c +./tools/gifconv/hdf2gif.c +./tools/gifconv/hdfgifwr.c +./tools/gifconv/readhdf.c +./tools/gifconv/writehdf.c + + ./tools/h4toh5/Dependencies ./tools/h4toh5/Makefile.in ./tools/h4toh5/h4toh5anno.c diff --git a/RELEASE.txt b/RELEASE.txt index c223111..e27d159 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -92,7 +92,9 @@ New Features an hdf5 library or hdf5 application binary. Also added a verification of the consistency between H5_lib_vers_info_g and other version information in the source code. - + * H5 <-> GIF convertor has been added. This is available under + tools/gifconv. The convertor supports the ability to create animated + gifs as well. Platforms Tested ================ Binary files differdiff --git a/all_withf90.zip b/all_withf90.zip Binary files differindex eb80abf..8849236 100644 --- a/all_withf90.zip +++ b/all_withf90.zip @@ -9964,6 +9964,7 @@ trap 'rm -fr `echo "src/libhdf5.settings tools/h5ls/Makefile tools/lib/Makefile tools/misc/Makefile + tools/gifconv/Makefile $EXTRA_H4_MAKEFILES examples/Makefile doc/Makefile @@ -10130,6 +10131,7 @@ CONFIG_FILES=\${CONFIG_FILES-"src/libhdf5.settings tools/h5ls/Makefile tools/lib/Makefile tools/misc/Makefile + tools/gifconv/Makefile $EXTRA_H4_MAKEFILES examples/Makefile doc/Makefile diff --git a/configure.in b/configure.in index 1937629..a2e49a5 100644 --- a/configure.in +++ b/configure.in @@ -1617,6 +1617,7 @@ AC_OUTPUT(src/libhdf5.settings tools/h5ls/Makefile tools/lib/Makefile tools/misc/Makefile + tools/gifconv/Makefile $EXTRA_H4_MAKEFILES examples/Makefile doc/Makefile diff --git a/hl/tools/gif2h5/Makefile.in b/hl/tools/gif2h5/Makefile.in new file mode 100644 index 0000000..effeada --- /dev/null +++ b/hl/tools/gif2h5/Makefile.in @@ -0,0 +1,65 @@ +## HDF5 Library Makefile(.in) +## +## Copyright (C) 2001 National Center for Supercomputing Applications. +## All rights reserved. +## +## +top_srcdir=@top_srcdir@ +top_builddir=../.. +srcdir=@srcdir@ +SUBDIRS= +@COMMENCE@ + +## Add include directory to the C preprocessor flags, add -lh5tools and +## -lhdf5 to the list of libraries. +## +CPPFLAGS=-I. -I$(srcdir) -I$(top_builddir)/src -I$(top_srcdir)/src \ + -I$(top_srcdir)/tools/lib @CPPFLAGS@ + +## Test programs and scripts. +## +TEST_PROGS= +TEST_SCRIPTS= + +## These are our main targets: library and tools. +## +LIBTOOLS=../lib/libh5tools.la +LIBHDF5=$(top_builddir)/src/libhdf5.la + +PUB_PROGS= gif2h5 h52gif +PROGS=$(PUB_PROGS) $(TEST_PROGS) + +## Source and object files for the library; do not install +## +LIB_SRC= +LIB_OBJ=$(LIB_SRC:.c=.lo) +PUB_LIB= + +## Source and object files for programs... +## +PROG_SRC=decompress.c gif2hdf.c gif2mem.c gifread.c hdf2gif.c hdfgifwr.c readhdf.c writehdf.c +PROG_OBJ=$(PROG_SRC:.c=.lo) + +PRIVATE_HDR=gif.h + +## Source and object files for the tests +## +TEST_SRC= +TEST_OBJ=$(TEST_SRC:.c=.lo) + +## Programs have to be built before they can be tested! +## +check test _test: $(PROGS) + +## How to build the programs...They all depend on the hdf5 library and +## the tools library compiled in this directory. +## +$(PROGS): $(LIBTOOLS) $(LIBHDF5) + +gif2h5: gif2hdf.lo gif2mem.lo decompress.lo gifread.lo writehdf.lo + @$(LT_LINK_EXE) $(CFLAGS) -o $@ gif2hdf.lo gif2mem.lo decompress.lo gifread.lo writehdf.lo $(LIBTOOLS) $(LIBHDF5) $(LDFLAGS) $(LIBS) + +h52gif: hdf2gif.lo hdfgifwr.lo readhdf.lo + @$(LT_LINK_EXE) $(CFLAGS) -o $@ hdf2gif.lo hdfgifwr.lo readhdf.lo $(LIBTOOLS) $(LIBHDF5) $(LDFLAGS) $(LIBS) + +@CONCLUDE@ diff --git a/hl/tools/gif2h5/decompress.c b/hl/tools/gif2h5/decompress.c new file mode 100644 index 0000000..18dbb3e --- /dev/null +++ b/hl/tools/gif2h5/decompress.c @@ -0,0 +1,299 @@ +#include <stdio.h> +#include <stdlib.h> +#include "gif.h" + +#define NEXTBYTE (*ptr++) +#define IMAGESEP 0x2c +#define INTERLACEMASK 0x40 +#define COLORMAPMASK 0x80 +#define False 0 +#define True 1 + +WORD iWIDE,iHIGH,eWIDE,eHIGH,expand,numcols,strip,nostrip; +unsigned long cols[256]; +char *cmd; + +FILE *fp; + +static int BitOffset = 0, /* Bit Offset of next code */ +XC = 0, YC = 0, /* Output X and Y coords of current pixel */ +Pass = 0, /* Used by output routine if WORDerlaced pic */ +OutCount = 0, /* Decompressor output 'stack count' */ +RWidth, RHeight, /* screen dimensions */ +IWidth, IHeight, /* image dimensions */ +LeftOfs, TopOfs, /* image offset */ +BitsPerPixel, /* Bits per pixel, read from GIF header */ +BytesPerScanline, /* Bytes per scanline in output raster */ +ColorMapSize, /* number of colors */ +Background, /* background color */ +CodeSize, /* Code size, read from GIF header */ +InitCodeSize, /* Starting code size, used during Clear */ +Code, /* Value returned by ReadCode */ +MaxCode, /* limiting value for current code size */ +ClearCode, /* GIF clear code */ +EOFCode, /* GIF end-of-information code */ +CurCode, OldCode, InCode, /* Decompressor variables */ +FirstFree, /* First free code, generated per GIF spec */ +FreeCode, /* Decompressor, next free slot in hash table */ +FinChar, /* Decompressor variable */ +DataMask, /* AND mask for data size */ +ReadMask; /* Code AND mask for current code size */ + +/*MODIFICATIONS*/ +BYTE tempbyte[10]; +BYTE * tempBYTEptr[10]; +WORD tempint[10]; +WORD ImageCount = 0; +/*END MODIFICATION*/ + +boolean Interlace, HasColormap; + + +BYTE *Image; /* The result array */ +BYTE *RawGIF; /* The heap array to hold it, raw */ +BYTE *Raster; /* The raster data stream, unblocked */ + +/* The hash table used by the decompressor */ + +int Prefix[4096]; +int Suffix[4096]; + +/* An output array used by the decompressor */ + +int OutCode[1025]; + +/* The color map, read from the GIF header */ + +int numused; + +/* Fetch the next code from the raster data stream. The codes can be +* any length from 3 to 12 bits, packed WORDo 8-bit BYTEs, so we have to +* maWORDain our location in the Raster array as a BIT Offset. We compute +* the BYTE Offset WORDo the raster array by dividing this by 8, pick up +* three BYTEs, compute the bit Offset WORDo our 24-bit chunk, shift to +* bring the desired code to the bottom, then mask it off and return it. +*/ +ReadCode() +{ + int RawCode, ByteOffset; + + ByteOffset = BitOffset / 8; + RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]); + if (CodeSize >= 8) + RawCode += (0x10000 * Raster[ByteOffset + 2]); + RawCode >>= (BitOffset % 8); + BitOffset += CodeSize; + return(RawCode & ReadMask); +} + + +AddToPixel(Index) +BYTE Index; +{ + if (YC<IHeight) + *(Image + YC * BytesPerScanline + XC) = Index; + + + + /* Update the X-coordinate, and if it overflows, update the Y-coordinate */ + if (++XC == IWidth) { + + /* If a non-WORDerlaced picture, just increment YC to the next scan line. + * If it's WORDerlaced, deal with the WORDerlace as described in the GIF + * spec. Put the decoded scan line out to the screen if we haven't gone + * past the bottom of it. + */ + + XC = 0; + if (!Interlace) YC++; + else { + switch (Pass) { + case 0: + YC += 8; + if (YC >= IHeight) { + Pass++; + YC = 4; + } + break; + case 1: + YC += 8; + if (YC >= IHeight) { + Pass++; + YC = 2; + } + break; + + case 2: + YC += 4; + if (YC >= IHeight) { + Pass++; + YC = 1; + } + break; + case 3: + YC += 2; + break; + default: + break; + } + } + } +} + +/* Main routine. Convert a GIF image to an HDF image */ + +BYTE* Decompress(GifImageDesc , GifHead) +GIFIMAGEDESC *GifImageDesc; +GIFHEAD *GifHead; +{ + int i; + + XC = 0; + YC = 0; + Pass = 0; + OutCount = 0; + BitOffset = 0; + + DataMask = (WORD)((1L << ((GifHead->PackedField & 0x07) +1)) -1); + Raster = GifImageDesc->GIFImage; + + + /* Check for image seperator */ + + /* Now read in values from the image descriptor */ + IWidth = GifImageDesc->ImageWidth; + IHeight = GifImageDesc->ImageHeight; + Interlace = GifImageDesc->PackedField & 0x40; + + /* Note that I ignore the possible existence of a local color map. + * I'm told there aren't many files around that use them, and the spec + * says it's defined for future use. This could lead to an error + * reading some files. + */ + + /* Start reading the raster data. First we get the WORDial code size + * and compute decompressor constant values, based on this code size. + */ + + CodeSize = GifImageDesc->CodeSize; + ClearCode = (1 << CodeSize); + EOFCode = ClearCode + 1; + FreeCode = FirstFree = ClearCode + 2; + + /* The GIF spec has it that the code size is the code size used to + * compute the above values is the code size given in the file, but the + * code size used in compression/decompression is the code size given in + * the file plus one. (thus the ++). + */ + + CodeSize++; + InitCodeSize = CodeSize; + MaxCode = (1 << CodeSize); + ReadMask = MaxCode - 1; + + /* Read the raster data. Here we just transpose it from the GIF array + * to the Raster array, turning it from a series of blocks WORDo one long + * data stream, which makes life much easier for ReadCode(). + */ + + + + /* free(RawGIF); We're not done just yet - change made */ + + /* Allocate the Image */ + + if (!(Image = (BYTE *)malloc(IWidth*IHeight))) { + printf("Out of memory"); + exit(-1); + } + + BytesPerScanline = IWidth; + + /* Decompress the file, continuing until you see the GIF EOF code. + * One obvious enhancement is to add checking for corrupt files here. + */ + + Code = ReadCode(); + while (Code != EOFCode) { + + /* Clear code sets everything back to its initial value, then reads the + * immediately subsequent code as uncompressed data. + */ + + if (Code == ClearCode) { + CodeSize = InitCodeSize; + MaxCode = (1 << CodeSize); + ReadMask = MaxCode - 1; + FreeCode = FirstFree; + CurCode = OldCode = Code = ReadCode(); + FinChar = CurCode & DataMask; + AddToPixel(FinChar); + } + else { + + /* If not a clear code, then must be data: save same as CurCode and InCode */ + + CurCode = InCode = Code; + + /* If greater or equal to FreeCode, not in the hash table yet; + * repeat the last character decoded + */ + + if (CurCode >= FreeCode) { + CurCode = OldCode; + OutCode[OutCount++] = FinChar; + } + + /* Unless this code is raw data, pursue the chain poWORDed to by CurCode + * through the hash table to its end; each code in the chain puts its + * associated output code on the output queue. + */ + + while (CurCode > DataMask) { + if (OutCount > 1024) { + /*return error message*/ + } + OutCode[OutCount++] = Suffix[CurCode]; + CurCode = Prefix[CurCode]; + } + + /* The last code in the chain is treated as raw data. */ + + FinChar = CurCode & DataMask; + OutCode[OutCount++] = FinChar; + + /* Now we put the data out to the Output routine. + * It's been stacked LIFO, so deal with it that way... + */ + + for (i = OutCount - 1; i >= 0; i--) + AddToPixel(OutCode[i]); + OutCount = 0; + + /* Build the hash table on-the-fly. No table is stored in the file. */ + + Prefix[FreeCode] = OldCode; + Suffix[FreeCode] = FinChar; + OldCode = InCode; + + /* PoWORD to the next slot in the table. If we exceed the current + * MaxCode value, increment the code size unless it's already 12. If it + * is, do nothing: the next code decompressed better be CLEAR + */ + + FreeCode++; + if (FreeCode >= MaxCode) { + if (CodeSize < 12) { + CodeSize++; + MaxCode *= 2; + ReadMask = (1 << CodeSize) - 1; + } + } + } + Code = ReadCode(); + } + + return Image; +} + + diff --git a/hl/tools/gif2h5/gif.h b/hl/tools/gif2h5/gif.h new file mode 100644 index 0000000..f697881 --- /dev/null +++ b/hl/tools/gif2h5/gif.h @@ -0,0 +1,179 @@ +/****************************************************************************\ +** Title: GIF.H ** +** Purpose: GIF Header file ** +\****************************************************************************/ + +#ifndef GIF_H +#define GIF_H 1 + +#include <hdf5.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#define MAX_PAL 768 + +/*#include "datatype.h" Data type definitions */ + +/* set the name length restriction to 64 charachters */ +#define VSNAMELENMAX 64 /* this is a carryover from HDF4 */ + +/* typedef H5T_NATIVE_UINT8 BYTE; */ +typedef unsigned char BYTE; + +/* typedef H5T_NATIVE_UINT16 WORD; */ +typedef unsigned long WORD; + +typedef char CHAR; +typedef unsigned char boolean; + +#define false 0; +#define true 1; + +/* Set the EndianOrder. +** The GIF Reader file should do this. +** Set EndianOrder = 0 if machine is little endian +** EndianOrder = 1 if machine is big endian. +*/ +extern int EndianOrder; + +/* +** The GIF header format. +** +** This structure actually contains the header, logical screen +** descriptor, and the global color table for the GIF image. +*/ +typedef struct _GifHeader /* Offset Description */ +{ + BYTE PackedField; /* 0Ah Color Information */ + WORD TableSize; + BYTE ImageCount; /* Keep a count of the number of images */ + BYTE CommentCount; + BYTE ApplicationCount; + BYTE PlainTextCount; + BYTE HDFPalette[256][3]; + BYTE HeaderDump[6]; /* BYTE array to dump header contents */ + BYTE LSDDump[7]; /* Logical Screen Descriptor dump */ +} GIFHEAD; + + +/* +** The GIF Image Descriptor. +*/ +typedef struct _GifImageDescriptor +{ + WORD ImageWidth; /* Width of the image in pixels */ + WORD ImageHeight; /* Height of the image in pixels */ + BYTE PackedField; /* Image and Color Table Data Information */ + WORD TableSize; + WORD CodeSize; /* Minimum LZW CodeSize for image data */ + BYTE HDFPalette[256][3]; + BYTE GIDDump[9]; /* GifImageDescriptor dump */ + + BYTE *Image; /* Decompressed Raster Image */ + BYTE *GIFImage; +} GIFIMAGEDESC; + + +/* +** GIF 89a Graphic Control Extension Block +*/ +typedef struct _GifGraphicControlExtension +{ + BYTE GCEDump[5]; /* Graphic Control Extension Dump */ +} GIFGRAPHICCONTROL; + + +/* +** GIF 89a Plain Text Extension Block +*/ +typedef struct _GifPlainTextExtension +{ + BYTE PTEDump[15]; /* Plain Text Extension Dump */ + BYTE *PlainTextData; /* Plain Text data sub-blocks */ + WORD DataSize; +} GIFPLAINTEXT; + + +/* +** GIF 89a Application Extension Block +*/ +typedef struct _GifApplicationExtension +{ + BYTE AEDump[14]; /* Application Extension Dump */ + BYTE *ApplicationData; /* Application data sub-blocks */ + WORD DataSize; +} GIFAPPLICATION; + +/* +** GIF 89a Comment Extension Block +*/ +typedef struct _GifCommentExtension +{ + BYTE CEDump[2]; /* Comment Extension Dump */ + BYTE *CommentData; /* Comment data sub-blocks */ + WORD DataSize; + BYTE Terminator; /* Block Terminator (always 0) */ +} GIFCOMMENT; + +/* +** GIF to HDF Memory Struct +** Purpose : The gif to hdf structure is used to pass all the +** gif data to the memory, which gets caught by the hdf driver +** Its the drivers job to put the data in the appropriate places +** in the HDF file. +** I have assumed that the ImageDescriptors and GraphicControls follow +** one another, ie. I have not associated them with each other. The driver +** must assume a 1-1 correspondance. The same discussion with plain text +** extension. +*/ +typedef struct _GifToMem +{ + GIFHEAD *GifHeader; + GIFIMAGEDESC **GifImageDesc; + GIFGRAPHICCONTROL **GifGraphicControlExtension; + GIFPLAINTEXT **GifPlainTextExtension; + GIFAPPLICATION **GifApplicationExtension; + GIFCOMMENT **GifCommentExtension; +} GIFTOMEM; + + +/* +** Function Prototypes +*/ +/* GIF2MEM.C */ +GIFTOMEM Gif2Mem(BYTE *); + +/* GIFREAD.C */ +int ReadGifHeader(GIFHEAD *, BYTE **); +int ReadGifImageDesc(GIFIMAGEDESC *, BYTE **); +int ReadGifGraphicControl(GIFGRAPHICCONTROL *, BYTE **); +int ReadGifPlainText(GIFPLAINTEXT *, BYTE **); +int ReadGifApplication(GIFAPPLICATION *, BYTE **); +int ReadGifComment(GIFCOMMENT *, BYTE **); + +/* WRITEHDF.C */ +int WriteHDF(GIFTOMEM , CHAR * , CHAR *); + +/* Function : ReadHDF +** Return: 0 on completion without error, -1 on error +** Input: CHAR *h5_file - HDF file name +** CHAR *dset_name - Name of the HDF Image dataset +** CHAR *pal_name - Name of the HDF palette +** Output : BYTE* data - the HDF Image to be converted +** BYTE palette[256][3] - the corresponding palette +** hsize_t* image_size - the size of each dimension of the image +** +*/ +int ReadHDF(BYTE** data , BYTE palette[256][3] , hsize_t *image_size , CHAR *h5_file , CHAR *dset_name , CHAR *pal_name); + +BYTE *ReadDataSubBlocks(BYTE ** , WORD *); +BYTE *Decompress (GIFIMAGEDESC * , GIFHEAD *); +BYTE GetByte(BYTE *); +WORD GetWord(BYTE *); + +void cleanup(BYTE*); +#endif /* GIF_H */ + diff --git a/hl/tools/gif2h5/gif2hdf.c b/hl/tools/gif2h5/gif2hdf.c new file mode 100644 index 0000000..0211143 --- /dev/null +++ b/hl/tools/gif2h5/gif2hdf.c @@ -0,0 +1,114 @@ +/* #include <hdf.h> */ +#include "gif.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +int +main(argv , argc) +int argv; +char *argc[]; +{ + + GIFTOMEM GifMemoryStruct; + GIFIMAGEDESC gifImageDesc; + + FILE *fpGif; + + /* replacing int32 with long */ + long i,ImageCount; + long filesize; + + BYTE *MemGif; + BYTE *StartPos; + + /* VSNAMELENMAX is a carryover from HDF4 and is #defined to 256 in gif.h */ + char GIFFileName[VSNAMELENMAX]; + char HDFFileName[VSNAMELENMAX]; + + /* Initialize all GifMemoryStruct pointers to null + ** to prevent hassles later on + */ + GifMemoryStruct.GifHeader = NULL; + GifMemoryStruct.GifImageDesc = NULL; + GifMemoryStruct.GifGraphicControlExtension = NULL; + GifMemoryStruct.GifPlainTextExtension = NULL; + GifMemoryStruct.GifApplicationExtension = NULL; + GifMemoryStruct.GifCommentExtension = NULL; + + + if (argv<3) + { + printf("\n\nWrong Usage. Use:\ngif2hdf <GIFFILE> <HDFFILE>\n\n"); + return(-1); + } + + + + strncpy(GIFFileName , argc[1] , VSNAMELENMAX - 1); + strncpy(HDFFileName , argc[2] , VSNAMELENMAX - 1); + GIFFileName[VSNAMELENMAX - 1] = '\0'; + HDFFileName[VSNAMELENMAX - 1] = '\0'; + + if (!(fpGif = fopen(GIFFileName,"rb"))) { + printf("Unable to open GIF file for reading.\n"); + printf("Filename (including path) must be less than %d charachters in length\n",VSNAMELENMAX); + exit(-1); + } + + /* Get the whole file into memory. Mem's much faster than I/O */ + fseek(fpGif, 0L , 2); + filesize = ftell(fpGif); + fseek(fpGif, 0L , 0); + if (filesize == 0) printf("File Size Zero"); + if (!(MemGif = StartPos = (BYTE *)malloc(filesize))) { + printf("Out of memory"); + exit (-1); + } + if (fread(MemGif,filesize,1,fpGif) != 1) { + printf("Corrupted Input File"); + exit(-1); + } + + fseek(fpGif,0L,0); + + /* + ** Call Gif2Mem and break the whole file into parts. + ** Gif2Mem also calls decompresses the images so we don't + ** have to worry about that + */ + GifMemoryStruct = Gif2Mem(MemGif); + if (ferror(fpGif)) { + printf("File Stream Error\n\n"); + exit(-1); + } + fclose(fpGif); + + /* Call WriteHDF from here. Go ahead and change WriteHDF to write + ** whatever format you want + */ + if (WriteHDF(GifMemoryStruct , argc[2] , argc[1])) + printf("HDF Write Error\n\n"); + + /* Free all buffers */ + /* replacing int32 with long */ + ImageCount = (long)((GifMemoryStruct.GifHeader)->ImageCount); + + for(i = 0 ; i < ImageCount ; i++) + { + gifImageDesc = *(GifMemoryStruct.GifImageDesc[i]); + if (gifImageDesc.Image != NULL) + free(gifImageDesc.Image); + + if (GifMemoryStruct.GifGraphicControlExtension[i] != NULL) + free(GifMemoryStruct.GifGraphicControlExtension[i]); + + } + free(StartPos); + + free (GifMemoryStruct.GifHeader); + + if (GifMemoryStruct.GifApplicationExtension != NULL) + free (GifMemoryStruct.GifApplicationExtension); + + return (0); +} diff --git a/hl/tools/gif2h5/gif2mem.c b/hl/tools/gif2h5/gif2mem.c new file mode 100644 index 0000000..92ca8e5 --- /dev/null +++ b/hl/tools/gif2h5/gif2mem.c @@ -0,0 +1,344 @@ +/* +** This file contains snippets of code from James Murray's original file +** to display the GIF header information, but most of it has been modified to +** suit gif2hdf +*/ + + + +/****************************************************************************\ +** Title: GIFHEAD.C ** +** Purpose: Display the data in a GIF image file. ** +** Version: 1.0 ** +** Date: March 1992 ** +** Author: James D. Murray, Anaheim, CA, USA ** +** C Compilers: Borland C++ v2.0, Microsoft C v6.00a ** +** ** +** GIFHEAD displays all real information contained within a GIF image ** +** file, including all color tables and extension block information. ** +** GIFHEAD reads both GIF 87a abd 89a-format files. ** +** ** +** Copyright (C) 1991-92 by Graphics Software Labs. All rights reserved. ** +\****************************************************************************/ +#include <stdio.h> +#include "gif.h" +/* #include <hdf.h> */ + +#define VERSION "1.00" +extern int EndianOrder; + +GIFTOMEM +Gif2Mem(MemGif) +BYTE *MemGif; +{ + /* + ** The gif structure outline for passing data to memory + ** is given in gif.h + ** These pointers are redunant, should take them out in ver. 2 + */ + GIFHEAD *gifHead; /* GIF Header structure */ + GIFIMAGEDESC **gifImageDesc; /* Logical Image Descriptor struct */ + GIFPLAINTEXT **gifPlainText; /* Plain Text Extension structure */ + GIFAPPLICATION **gifApplication; /* Application Extension structure */ + GIFCOMMENT **gifComment; /* Comment Extension structure */ + GIFGRAPHICCONTROL **gifGraphicControl; /* Graphic Control Extension strct */ + + GIFTOMEM GifMemoryStruct; + + + + register WORD i; /* Loop counter */ + BYTE Identifier; /* Extension block identifier holder */ + BYTE Label; /* Extension block label holder */ + BYTE ImageCount; /* Count of the number of images in the file */ + BYTE ImageArray; /* Keep the size of the array to store Images */ + BYTE CommentCount; + BYTE CommentArray; + BYTE ApplicationCount; + BYTE ApplicationArray; + BYTE PlainTextCount; + BYTE PlainTextArray; + BYTE GCEflag; + BYTE aTemp; + BYTE j; + + BYTE w; /* Two more variables needed only while testing */ + BYTE *b; /* Endian Ordering */ + + /* Allocate memory for the GIF structures */ + /* Plug the structs into GifMemoryStruct at the end */ + /****************************************************/ + if (!(gifHead = (GIFHEAD *)malloc(sizeof(GIFHEAD)))) + { + printf("Could not allocate memory for gifHead\n"); + exit(-1); + } + + /* + ** The next three have to grow dynamically so we leave them + ** for now and let realloc handle it later on. + */ + gifImageDesc = NULL; + gifPlainText = NULL; + gifGraphicControl = NULL; + gifComment = NULL; + gifApplication = NULL; + + /******************************/ + /* Memory allocation complete */ + + + /* Carry out Endian Testing and set Endian Order */ + w = 0x0001; + b = (BYTE *) &w; + EndianOrder = (b[0] ? 1 : 0); + + /* Read the GIF image file header information */ + ReadGifHeader(gifHead, &MemGif); + + /* Check for FILE stream error */ + /* + if (ferror(fpGif)) + { + fputs("GIFHEAD: Error reading header information!\n", stderr); + exit(-3); + } + */ + + /* + ** Identify, read, and display block information. + */ + ImageCount = ImageArray = 0; + CommentCount = CommentArray = 0; + ApplicationCount = ApplicationArray = 0; + PlainTextCount = PlainTextArray = 0; + GCEflag = 0; + + for (;;) + { + Identifier = *MemGif++; + + switch (Identifier) + { + case 0x3B: /* Trailer */ + /* The counts are stored to make it easier while + ** putting stuff into the HDF file and then + ** deallocating space. + */ + gifHead->ImageCount = ImageCount; + gifHead->CommentCount = CommentCount; + gifHead->ApplicationCount = ApplicationCount; + gifHead->PlainTextCount = PlainTextCount; + + /* putting stuff into the gif2mem structure */ + GifMemoryStruct.GifHeader = gifHead; + GifMemoryStruct.GifImageDesc = gifImageDesc; + GifMemoryStruct.GifPlainTextExtension = gifPlainText; + GifMemoryStruct.GifApplicationExtension = gifApplication; + GifMemoryStruct.GifCommentExtension = gifComment; + GifMemoryStruct.GifGraphicControlExtension = gifGraphicControl; + + /* return the struct */ + return GifMemoryStruct; + + + + case 0x2C: /* Image Descriptor */ + /* If there was no image descriptor before this increase image count. + ** If an imagedescriptor was present, reset GCEflag + */ + if (GCEflag == 0) + ImageCount++; + else + GCEflag = 0; + + if (ImageCount > ImageArray) { + aTemp = ImageArray; + ImageArray = (ImageArray << 1) + 1; + if (!(gifImageDesc = (GIFIMAGEDESC **)realloc(gifImageDesc , sizeof(GIFIMAGEDESC *) * ImageArray))) + { + printf("Out of memory!"); + exit(-1); + } + if (!(gifGraphicControl = (GIFGRAPHICCONTROL **)realloc(gifGraphicControl , sizeof(GIFGRAPHICCONTROL *) * ImageArray))) + { + printf("Out of memory!"); + exit(-1); + } + + for (j = aTemp ; j < ImageArray ; j++) { + gifGraphicControl[j] = NULL; + gifImageDesc[j] = NULL; + } + } + + if(!(gifImageDesc[ImageCount-1] = (GIFIMAGEDESC*)malloc(sizeof(GIFIMAGEDESC)))) + { + printf("Out of memory!"); + exit(-1); + } + + + if (ReadGifImageDesc(gifImageDesc[ImageCount-1], &MemGif) == -1) + fputs("Error reading Image Descriptor information\n", stderr); + + /* + ** Decompress the Image + */ + gifImageDesc[ImageCount-1]->Image = Decompress(gifImageDesc[ImageCount-1] , gifHead); + free(gifImageDesc[ImageCount-1]->GIFImage); + + /* + ** Convert the local palette into an HDF compatible palette + ** In case the local color table is present, it is written out as the HDFPalette + ** If it is absent the global table is written as the HDFPalette. + */ + if (!((gifImageDesc[ImageCount-1]->PackedField) & 0x80)) + { + /* Check to see if the global color table exists.... */ + if (gifHead->PackedField & 0x80) { + for (i=0 ; i<gifHead->TableSize ; i++) + { + gifImageDesc[ImageCount-1]->HDFPalette[i][0] = gifHead->HDFPalette[i][0]; + gifImageDesc[ImageCount-1]->HDFPalette[i][1] = gifHead->HDFPalette[i][1]; + gifImageDesc[ImageCount-1]->HDFPalette[i][2] = gifHead->HDFPalette[i][2]; + } + } + gifImageDesc[ImageCount-1]->TableSize = gifHead->TableSize; + } + + break; + + case 0x21: /* Extension Block */ + Label = *MemGif++; + switch (Label) + { + case 0x01: /* Plain Text Extension */ + puts("Plain Text Extension\n"); + + PlainTextCount++; + if (PlainTextCount > PlainTextArray) + PlainTextArray = (PlainTextArray << 1) + 1; + + if (!(gifPlainText = (GIFPLAINTEXT **)realloc(gifPlainText , sizeof(GIFPLAINTEXT *) * PlainTextArray))) + { + printf("Out of memory!"); + exit(-1); + } + + if(!(gifPlainText[PlainTextCount - 1] = (GIFPLAINTEXT*)malloc(sizeof(GIFPLAINTEXT)))) + { + printf("Out of memory!"); + exit(-1); + } + + + + if (ReadGifPlainText(gifPlainText[PlainTextCount - 1], &MemGif)) + fprintf(stderr, + "Error reading Plain Text Extension information.\n"); + + break; + + case 0xFE: /* Comment Extension */ + CommentCount++; + if (CommentCount > CommentArray) + CommentArray = (CommentArray << 1) + 1; + + if (!(gifComment = (GIFCOMMENT **)realloc(gifComment , sizeof(GIFCOMMENT *) * CommentArray))) + { + printf("Out of memory!"); + exit(-1); + } + + if(!(gifComment[CommentCount - 1] = (GIFCOMMENT *)malloc(sizeof(GIFCOMMENT)))) + { + printf("Out of memory!"); + exit(-1); + } + + + if (ReadGifComment(gifComment[CommentCount - 1], &MemGif)) + fprintf(stderr, + "Error reading Comment Extension information\n"); + break; + + case 0xF9: /* Graphic Control Extension */ + if (GCEflag == 0 ) + ImageCount++; + + GCEflag = 1; + + if (ImageCount > ImageArray) { + aTemp = ImageArray; + ImageArray = (ImageArray << 1) + 1; + if (!(gifGraphicControl = (GIFGRAPHICCONTROL **)realloc(gifGraphicControl , sizeof(GIFGRAPHICCONTROL *) * ImageArray))) + { + printf("Out of memory!"); + exit(-1); + } + if (!(gifImageDesc = (GIFIMAGEDESC **)realloc(gifImageDesc , sizeof(GIFIMAGEDESC *) * ImageArray))) + { + printf("Out of memory!"); + exit(-1); + } + for (j = aTemp ; j < ImageArray ; j++) { + gifGraphicControl[j] = NULL; + gifImageDesc[j] = NULL; + } + } + + if(!(gifGraphicControl[ImageCount-1] = (GIFGRAPHICCONTROL*)malloc(sizeof(GIFGRAPHICCONTROL)))) + { + printf("Out of memory!"); + exit(-1); + } + + + if (ReadGifGraphicControl(gifGraphicControl[ImageCount-1], &MemGif)) + fprintf(stderr, + "Error reading Graphic Control Extension information\n"); + + if (!*MemGif++ == 0) + fprintf(stderr, + "Error reading Graphic Control Extension\n"); + + break; + + case 0xFF: /* Application Extension */ + ApplicationCount++; + if (ApplicationCount > ApplicationArray) + ApplicationArray = (ApplicationArray << 1) + 1; + + if (!(gifApplication = (GIFAPPLICATION **)realloc(gifApplication , sizeof(GIFAPPLICATION *) * ApplicationArray))) + { + printf("Out of memory!"); + exit(-1); + } + + if(!(gifApplication[ApplicationCount - 1] = (GIFAPPLICATION *)malloc(sizeof(GIFAPPLICATION)))) + { + printf("Out of memory!"); + exit(-1); + } + + + if (ReadGifApplication(gifApplication[ApplicationCount - 1], &MemGif)) + fprintf(stderr, + "Error reading Application Extension information\n"); + break; + + default: + + printf("Unknown Extension Label: 0x%02x\n", Label); + break; + } + break; + default: + fprintf(stderr, "Unknown Block Separator Character: 0x%02x\n", + Identifier); + } + } + + +} diff --git a/hl/tools/gif2h5/gifread.c b/hl/tools/gif2h5/gifread.c new file mode 100644 index 0000000..1196241 --- /dev/null +++ b/hl/tools/gif2h5/gifread.c @@ -0,0 +1,382 @@ +#include <stdio.h> +#include <stdlib.h> +#include "gif.h" + +int EndianOrder; +int i; + + +WORD +GetWord (MemGif) +BYTE *MemGif; +{ + register WORD w; + if (EndianOrder == 1) /* LittleEndian */ + { + w = (WORD) (*MemGif++ & 0xFF); + w |= (WORD) ((*MemGif++ & 0xFF) << 0x08); + } + else + { + w = (WORD) (*MemGif++ & 0xFF); + w = ((WORD) (*MemGif++ & 0xFF)) | (w << 0x08); + } + return w; +} + +BYTE +GetByte (MemGif) +BYTE *MemGif; +{ + return *MemGif; +} + +/* +** Read a GIF image BYTE Header. +** +** This function reads the Header, Logical Screen Descriptor, and +** Global Color Table (if any) from a GIF image file. The information +** is stored in a GIFHEAD structure. +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifHeader(GifHead, MemGif2) +GIFHEAD *GifHead; /* Pointer to GIF header structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + register WORD i; /* Loop counter */ + WORD tableSize; /* Number of entires in the Global Color Table */ + + GifHead->TableSize = 0; + for (i = 0 ; i < 6 ; i++) { + GifHead->HeaderDump[i] = *(*MemGif2)++; + } + if (strncmp(GifHead->HeaderDump , "GIF" , 3)) { + printf("The file does not appear to be a valid GIF file.\n"); + exit(-1); + } + + for (i = 0 ; i < 7 ; i++) { + GifHead->LSDDump[i] = *(*MemGif2)++; + } + + GifHead->PackedField = GifHead->LSDDump[4]; + /* Check if a Global Color Table is present */ + if (GifHead->PackedField & 0x80) + { + /* Read number of color table entries */ + tableSize = (WORD) (1L << ((GifHead->PackedField & 0x07) + 1)); + GifHead->TableSize = tableSize; + /* Read the Global Color Table */ + /* + ** There are some changes made here apart from just + ** reading in the global color table as would + ** seem intuitively obvious. + ** The colors are stored in the bottom part of the + ** palette as opposed to the top + */ + + for (i = 0; i < tableSize; i++) + { + GifHead->HDFPalette[i][0] = *(*MemGif2)++; + GifHead->HDFPalette[i][1] = *(*MemGif2)++; + GifHead->HDFPalette[i][2] = *(*MemGif2)++; + } + } + + /* Check for a FILE stream error */ + /* + if (ferror(FpGif)) + return(-1); + */ + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read a GIF Local Image Descriptor. +** +** This function reads the Local Image Descriptor, and Local Color +** Table (if any) from a GIF image file. The information is stored +** in a GIFIMAGEDESC structure. +** +** Note that the ImageSeparator field value in the GIFIMAGEDESC +** structure is assigned by the function calling ReadGifImageDesc(). +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifImageDesc(GifImageDesc, MemGif2) +GIFIMAGEDESC *GifImageDesc; /* Pointer to GIF image descriptor structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + register WORD i; /* Loop counter */ + WORD tableSize; /* Number of entries in the Local Color Table */ + BYTE Interlace; /* PackedField & 0x20 gives information on interlacing */ + BYTE *TempPtr; + int ch , ch1; + + GifImageDesc->TableSize = 0; + for (i = 0 ; i < 9 ; i++) { + GifImageDesc->GIDDump[i] = *(*MemGif2)++; + } + + /* + ** Get the relevant fields. I need ImageWidth and Height actively hence I have + ** taken information from those fields. I intend to keep the GifImageDesc data + ** structure as it is so that anyone needing the rest of the fields can do so + ** quickly. + */ + + if (EndianOrder == 1) /* LittleEndian */ + { + GifImageDesc->ImageWidth = (WORD) (GifImageDesc->GIDDump[4] & 0xFF); + GifImageDesc->ImageWidth |= (WORD) ((GifImageDesc->GIDDump[5] & 0xFF) << 0x08); + + GifImageDesc->ImageHeight = (WORD) (GifImageDesc->GIDDump[6] & 0xFF); + GifImageDesc->ImageHeight |= (WORD) ((GifImageDesc->GIDDump[7] & 0xFF) << 0x08); + + } + else + { + GifImageDesc->ImageWidth = (WORD) (GifImageDesc->GIDDump[4] & 0xFF); + GifImageDesc->ImageWidth = ((WORD) (GifImageDesc->GIDDump[5] & 0xFF)) | (GifImageDesc->ImageWidth << 0x08); + + GifImageDesc->ImageHeight = (WORD) (GifImageDesc->GIDDump[6] & 0xFF); + GifImageDesc->ImageHeight = ((WORD) (GifImageDesc->GIDDump[7] & 0xFF)) | (GifImageDesc->ImageWidth << 0x08); + + + } + + GifImageDesc->PackedField = GifImageDesc->GIDDump[8]; + + /* Interlace = GifImageDesc->PackedField & 0x20; */ + + /* Check if a Local Color Table is present */ + if (GifImageDesc->PackedField & 0x80) + { + /* Read number of color table entries */ + tableSize = (WORD) (1L << ((GifImageDesc->PackedField & 0x07) + 1)); + GifImageDesc->TableSize = tableSize; + /* Read the Local Color Table */ + for (i = 0; i < tableSize; i++) + { + GifImageDesc->HDFPalette[i][0] = *(*MemGif2)++; + GifImageDesc->HDFPalette[i][1] = *(*MemGif2)++; + GifImageDesc->HDFPalette[i][2] = *(*MemGif2)++; + } + } + + /* + ** Get LZW minimum Code Size + */ + GifImageDesc->CodeSize = (WORD)*(*MemGif2)++; + + /*GifImageDesc->GIFImage = ReadDataSubBlocks(FpGif);*/ + if (!(GifImageDesc->GIFImage = (BYTE *)malloc((GifImageDesc->ImageWidth) * (GifImageDesc->ImageHeight)))) { + printf("Out of memory"); + exit(-1); + } + + + TempPtr = GifImageDesc->GIFImage; + do + { + ch = ch1 = (int)*(*MemGif2)++; + while (ch--) *TempPtr++ = *(*MemGif2)++; + } + while (ch1); + + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read a GIF Graphic Control Extension block. +** +** Note that the Introducer and Label field values in the GIFGRAPHICCONTROL +** structure are assigned by the function calling ReadGifGraphicControl(). +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifGraphicControl(GifGraphicControl, MemGif2) +GIFGRAPHICCONTROL *GifGraphicControl; /* Pointer to GC Extension structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + + + for (i = 0 ; i < 5 ; i++) { + GifGraphicControl->GCEDump[i] = *(*MemGif2)++; + } + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read a GIF Plain Text Extension block. +** +** Note that the Introducer and Label field values in the GIFLPLAINTEXT +** structure are assigned by the function calling ReadGifPlainText(). +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifPlainText(GifPlainText, MemGif2) +GIFPLAINTEXT *GifPlainText; /* Pointer to Plain Text Extension structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + for (i = 0 ; i < 13 ; i++) { + GifPlainText->PTEDump[i] = *(*MemGif2)++; + } + + /* Read in the Plain Text data sub-blocks */ + if (!(GifPlainText->PlainTextData = ReadDataSubBlocks(MemGif2 , &(GifPlainText->DataSize)))) + return(1); + + /* + GifPlainText->Terminator = 0; + */ + + /* Check for a FILE stream error */ + /* + if (ferror(FpGif)) + return(-1); + */ + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read a GIF Application Extension block. +** +** Note that the Introducer and Label field values in the GIFAPPLICATION +** structure are assigned by the function calling ReadGifApplication(). +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifApplication(GifApplication, MemGif2) +GIFAPPLICATION *GifApplication; /* Pointer to Application Extension structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + for (i = 0 ; i < 12 ; i++) { + GifApplication->AEDump[i] = *(*MemGif2)++; + } + + /* Read in the Plain Text data sub-blocks */ + if (!(GifApplication->ApplicationData = ReadDataSubBlocks(MemGif2 , &(GifApplication->DataSize)))) + return(1); + /* + GifApplication->Terminator = 0; + */ + + /* Check for a FILE stream error */ + /* + if (ferror(FpGif)) + return(-1); + */ + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read a GIF Comment Extension block. +** +** Note that the Introducer and Label field values in the GIFCOMMENT +** structure are assigned by the function calling ReadGifComment(). +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifComment(GifComment, MemGif2) +GIFCOMMENT *GifComment; /* Pointer to GIF Comment Extension structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + + /* Read in the Plain Text data sub-blocks */ + if (!(GifComment->CommentData = ReadDataSubBlocks(MemGif2 , &(GifComment->DataSize)))) + return(1); + + GifComment->Terminator = 0; + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read one or more GIF data sub-blocks and write the information +** to a buffer. +** +** A GIF "sub-block" is a single count byte followed by 1 to 255 +** additional data bytes. +** +** Returns: A NULL pointer if a memory allocation error occured, +** otherwise a valid pointer if no error occured. +*/ +static BYTE * +ReadDataSubBlocks(MemGif2 , DSize) +BYTE **MemGif2; /* GIF image file input FILE stream */ +WORD *DSize; +{ + BYTE *ptr1; /* Pointer used to "walk the heap" */ + BYTE *ptr2; /* Pointer used to mark the top of the heap */ + BYTE dataSize; /* Size of the current data sub-block being read */ + WORD bufSize; /* Total size of the Plain Text data buffer */ + int tempcount = 0; + + bufSize = 0; /* The output buffer is empty */ + + dataSize = *(*MemGif2)++; /* Get the size of the first sub-block */ + + /* Allocate initial data buffer */ + if (!(ptr1 = ptr2 = (BYTE *) malloc(dataSize + 1))) { + printf("Out of memory. Allocation of memory for data sub-blocks for\neither Comment, Plain Text or Application Extensions failed"); + return((BYTE *) NULL); + } + for (;;) + { + tempcount++; + bufSize += (dataSize); /* Running total of the buffer size */ + *DSize = bufSize; + + /* *ptr1++ = dataSize; /* Write the data count */ + while (dataSize--) /* Read/write the Plain Text data */ + *ptr1++ = *(*MemGif2)++; + + /* Check if there is another data sub-block */ + if ((dataSize = *(*MemGif2)++) == 0) + break; /* Block Terminator encountered */ + + /* Increase the buffer size to accomodate the next sub-block */ + if (!(ptr1 = ptr2 = (BYTE *) realloc(ptr2, bufSize + dataSize + 1))) + return((BYTE *) NULL); + + + ptr1 += bufSize; /* Move pointer to the end of the data */ + + + } + + /**ptr1++ = (BYTE) NULL; /* Add NULL to simulate Terminator value */ + *ptr1++ = '\0'; + + return(ptr2); /* Return a pointer to the sub-block data */ +} + + + + + diff --git a/hl/tools/gif2h5/hdf2gif.c b/hl/tools/gif2h5/hdf2gif.c new file mode 100644 index 0000000..9c4133e --- /dev/null +++ b/hl/tools/gif2h5/hdf2gif.c @@ -0,0 +1,354 @@ +/* NOTES: +** 04/01 - 04/10: been working on it a lot. I think it does gif89 images just fine with +** palettes. So that's cool. Putting in multiple images and animation support right now +** 03/29: For some reason I can write .GIF files which IE will open and see but +** kodak imaging does not like. I'm sure its a problem with the GIF file, +** I can't figure out what. +** 03/17: Explicitely deallocate the GIFTOMEM* struct in the main loop. +** Check for both success and failure conditions +*/ + +#include "gif.h" +#include <stdio.h> + +#define MAX_FILE_LEN 256 +#define MAX_NUMBER_IMAGES 50 + +extern int hdfWriteGIF(FILE *fp, BYTE *pic, int ptype, int w, int h, BYTE *rmap, + BYTE *gmap, BYTE *bmap, BYTE *pc2ncmap, int numcols, int colorstyle, int BitsPerPixel); + +int EndianOrder; + +void PutByte(BYTE b , FILE *fpGif) +{ + if (fputc(b , fpGif) == EOF) { + printf("File Writing Error, cannot continue"); + exit(-1); + } +} + + +void putword(int w, FILE *fp) +{ + /* writes a 16-bit integer in GIF order (LSB first) */ + + fputc(w &0xff, fp); + + fputc((w>>8)&0xff,fp); +} + +void usage() { + printf("Usage: h52gif <h5_file> <gif_file> -i <h5_image> [-p <h5_palette>]\n"); + printf("h52gif expects *at least* one h5_image. You may repeat -i <h5_image> [-p <h5_palette>] at most 50 times (maximum of 50 images).\n"); +} + +int main(int argc , char **argv) { + + FILE *fpGif; + + hsize_t dim_sizes[2]; + + BYTE *Image; + /* compression structs */ + + CHAR *HDFName = NULL; + CHAR *GIFName = NULL; + CHAR *image_path = NULL; + CHAR *pal_path = NULL; + /* reference variables */ + + int has_local_palette; /* treated as a flag */ + int loop_times; /* number of times to loop, i'm going to treat it as a yes or no */ + + BYTE* b; + + BYTE GlobalPalette[256][3]; + BYTE Red[256]; + BYTE Green[256]; + BYTE Blue[256]; + + int RWidth, RHeight; + int LeftOfs, TopOfs; + int ColorMapSize, InitCodeSize, Background, BitsPerPixel; + int j,nc; + int w,h,i; + int numcols = 256; + int CountDown; + int curx , cury; + int time_out = 0; /* time between two images in the animation */ + int n_images , index; + + BYTE pc2nc[256] , r1[256] , g1[256] , b1[256]; + + /* initial stuff */ + int number_of_images = 0; + int arg_index = 2; + int bool_is_image = 0; /* 0 = false , 1 = true */ + int bool_is_palette = 0; + CHAR* image_name_arr[MAX_NUMBER_IMAGES]; + CHAR* pal_name_arr[MAX_NUMBER_IMAGES]; + + if (argc < 5) { + /* they didn't supply at least one image -- bail */ + usage(); + return 0; + } + + memset(image_name_arr , NULL , MAX_NUMBER_IMAGES); + memset(pal_name_arr , NULL , MAX_NUMBER_IMAGES); + + HDFName = (CHAR*) malloc (strlen(argv[1]) + 1); + GIFName = (CHAR*) malloc (strlen(argv[2]) + 1); + + if (strlen(argv[1] + 1) > MAX_FILE_LEN || strlen(argv[2] + 1) > MAX_FILE_LEN) { + /* supplied file names are too long. bail. */ + usage(); + printf("Supplied filenames exceed maximum length of 256 bytes\n"); + } + + strcpy(HDFName , argv[1]); + strcpy(GIFName , argv[2]); + + /* get the options */ + while (arg_index++ < argc - 1 && number_of_images < MAX_NUMBER_IMAGES) { + if (!strcmp(argv[arg_index] , "-i")) { + bool_is_image = 1; + continue; + } + if (!strcmp(argv[arg_index] , "-p")) { + bool_is_palette = 1; + continue; + } + if (!strcmp(argv[arg_index] , "-a")) { + time_out = 10; + continue; + } + if (bool_is_image) { + /* this is an image */ + /* allocate space to store the image name */ + image_name_arr[number_of_images] = (CHAR*) malloc(strlen(argv[arg_index] + 1)); + strcpy(image_name_arr[number_of_images] , argv[arg_index]); + /* make the palette array for this NULL */ + pal_name_arr[number_of_images] = NULL; + number_of_images++; + bool_is_image = 0; + continue; + } + if (bool_is_palette) { + /* this is a palette */ + /* allocate space to store the pal name */ + /* the palette was probably allocated for a previous image */ + pal_name_arr[number_of_images-1] = (CHAR*) malloc(strlen(argv[arg_index] + 1)); + strcpy(pal_name_arr[number_of_images - 1] , argv[arg_index]); + bool_is_palette = 0; + continue; + } + /* oops. This was not meant to happen */ + usage(); + /* + while (number_of_images--) { + cleanup(image_name_arr[number_of_images]); + cleanup(pal_name_arr[number_of_images]); + } + */ + return -1; + + } + + /* we shall always have a palette - read hdf will see to that */ + has_local_palette = true; + + /* Do Endian Order testing and set Endian Order */ + w = 0x0001; + b = (BYTE *) &w; + EndianOrder = (b[0] ? 1:0); + + if (!(fpGif = fopen(GIFName , "wb"))) { + printf("Error opening gif file for output. Aborting.\n"); + return -1; + } + + /* hardwire n_images to 1 for now. */ + n_images = number_of_images; + + Background = 0; + for (index = 0 ; index < n_images ; index++) { + + /* try to read the image and the palette */ + /* Lots of funky stuff to support multiple images has been taken off. + ** Just in case you're extending code, here's what you need to do in short: + ** figure out if there is a global palette or not, if there is one store that one + ** only. + ** If they are all local or a combination of local and global palettes, you will have + ** to write the global palette out and then independantly write the smaller local + ** palettes + */ + if (ReadHDF(&Image , GlobalPalette , dim_sizes , HDFName , image_name_arr[index] , pal_name_arr[index]) < 0) { + fprintf(stderr , "Unable to read HDF file\n"); + return -1; + } + + w = dim_sizes[1]; + h = dim_sizes[0]; + + RWidth = dim_sizes[1]; + RHeight = dim_sizes[0]; + LeftOfs = TopOfs = 0; + + + /* If the first image does not have a palette, I make my own global color table + ** Obviously this is not the best thing to do, better steps would be: + ** 1. Check for either a global palette or a global attribute called palette + ** 2. Check for palettes in any of the other images. + */ + if (!has_local_palette) { + for (i = 0 ; i < 256 ; i++) { + Red[i] = 255 - i; + Green[i] = 255 - i; + Blue[i] = 255 - i; + } + } + else { + for (i = 0 ; i < 256 ; i++){ + Red[i] = GlobalPalette[i][0]; + Green[i] = GlobalPalette[i][1]; + Blue[i] = GlobalPalette[i][2]; + } + } + + for (i=0; i<256; i++) { pc2nc[i] = r1[i] = g1[i] = b1[i] = 0; } + /* compute number of unique colors */ + nc = 0; + for (i=0; i<numcols; i++) { + /* see if color #i is already used */ + for (j=0; j<i; j++) { + if (Red[i] == Red[j] && Green[i] == Green[j] && + Blue[i] == Blue[j]) break; + } + if (j==i) { /* wasn't found */ + pc2nc[i] = nc; + r1[nc] = Red[i]; + g1[nc] = Green[i]; + b1[nc] = Blue[i]; + nc++; + } + else pc2nc[i] = pc2nc[j]; + } + /* figure out 'BitsPerPixel' */ + for (i=1; i<8; i++) { + if ( (1<<i) >= nc) break; + } + BitsPerPixel = i; + ColorMapSize = 1 << BitsPerPixel; + + + CountDown = w * h; /* # of pixels we'll be doing */ + + if (BitsPerPixel <= 1) InitCodeSize = 2; + else InitCodeSize = BitsPerPixel; + + curx = cury = 0; + + if (!fpGif) { + fprintf(stderr, "WriteGIF: file not open for writing\n" ); + return (1); + } + + /* If it is the first image we do all the header stuff that isn't required for the + ** rest of the images. + */ + if (index == 0) { + /* Write out the GIF header and logical screen descriptor */ + if (n_images > 1) { + fwrite("GIF89a", 1, 6, fpGif); /* the GIF magic number */ + loop_times = 0; + } + else { + fwrite("GIF87a", 1, 6, fpGif); /* the GIF magic number */ + loop_times = 1; + } + + putword(RWidth, fpGif); /* screen descriptor */ + putword(RHeight, fpGif); + + i = 0x00; /* No, there is no color map */ + i |= (8-1)<<4; /* OR in the color resolution (hardwired 8) */ + i |= (BitsPerPixel - 1); /* OR in the # of bits per pixel */ + fputc(i,fpGif); + + fputc(Background,fpGif); /* background color */ + + fputc(0, fpGif); /* future expansion byte */ + + + /* If loop_times is 0 , put in the application extension to make the gif anime loop + ** indefinitely + */ + if (time_out > 0) { + fputc(0x21 , fpGif); + fputc(0xFF , fpGif); + fputc(11 , fpGif); + fwrite("NETSCAPE2.0" , 1 , 11 , fpGif); + fputc(3 , fpGif); + fputc(1 , fpGif); + fputc(0 , fpGif); + fputc(0 , fpGif); + fputc(0 , fpGif); + + } + + + } + + if (n_images > 1) { + /* write a graphic control block */ + fputc(0x21 , fpGif); + fputc(0xF9 , fpGif); + fputc(4 , fpGif); + fputc(4 , fpGif); + putword(time_out , fpGif); + fputc(255, fpGif); + fputc(0 , fpGif); + } + + /* Put Image Descriptor + ** Hardwiring Left Offset and Top Offset to 0x00 + */ + + fputc (0x2c , fpGif); + putword (0x00 , fpGif); + putword (0x00 , fpGif); + putword (RWidth , fpGif); + putword (RHeight , fpGif); + + /* since we always have a local color palette ... */ + fputc ((0x80 | (BitsPerPixel - 1)) , fpGif); + for (i=0; i<ColorMapSize; i++) { /* write out Global colormap */ + fputc(r1[i], fpGif); + fputc(g1[i], fpGif); + fputc(b1[i], fpGif); + } + + fputc (InitCodeSize , fpGif); + + i = hdfWriteGIF(fpGif , Image , 0 , dim_sizes[0] , dim_sizes[1] , r1, g1 , b1 , pc2nc , 256 , 8 , BitsPerPixel); + fputc(0x00 , fpGif); + free (Image); + } + + if (fputc(';',fpGif) == EOF) { /* Write GIF file terminator */ + fprintf(stderr , "Error!"); + return -1; + } + + fclose (fpGif); + + while (number_of_images--) { + /*if (image_name_arr[number_of_images]) + free(image_name_arr[number_of_images]);*/ + /*if (pal_name_arr[number_of_images]) + free(pal_name_arr[number_of_images]);*/ + } + + return(0); +} diff --git a/hl/tools/gif2h5/hdfgifwr.c b/hl/tools/gif2h5/hdfgifwr.c new file mode 100644 index 0000000..28d556e --- /dev/null +++ b/hl/tools/gif2h5/hdfgifwr.c @@ -0,0 +1,516 @@ +/* + * hdfgifwr.c - handles writing of GIF files. + * + * Contains: + * hdfWriteGIF(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle, + * comment) + * + * Note: slightly brain-damaged, in that it'll only write non-interlaced + * GIF files (in the interests of speed, or something) + * + */ + + + +/***************************************************************** + * Portions of this code Copyright (C) 1989 by Michael Mauldin. + * Permission is granted to use this file in whole or in + * part for any purpose, educational, recreational or commercial, + * provided that this copyright notice is retained unchanged. + * This software is available to all free of charge by anonymous + * FTP and in the UUNET archives. + * + * + * Authors: Michael Mauldin (mlm@cs.cmu.edu) + * David Rowley (mgardi@watdcsu.waterloo.edu) + * + * Based on: compress.c - File compression ala IEEE Computer, June 1984. + * + * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) + * Jim McKie (decvax!mcvax!jim) + * Steve Davies (decvax!vax135!petsd!peora!srd) + * Ken Turkowski (decvax!decwrl!turtlevax!ken) + * James A. Woods (decvax!ihnp4!ames!jaw) + * Joe Orost (decvax!vax135!petsd!joe) + *****************************************************************/ + + +#include <stdio.h> +#include "gif.h" +#include <stdlib.h> +#include <string.h> + +typedef BYTE byte; +typedef long int count_int; + +/* indicies into conv24MB */ +#define CONV24_8BIT 0 +#define CONV24_24BIT 1 +#define CONV24_SEP1 2 +#define CONV24_LOCK 3 +#define CONV24_SEP2 4 +#define CONV24_FAST 5 +#define CONV24_SLOW 6 +#define CONV24_BEST 7 +#define CONV24_MAX 8 + +/* values 'picType' can take */ +#define PIC8 CONV24_8BIT +#define PIC24 CONV24_24BIT + +/* MONO returns total intensity of r,g,b components */ +#define MONO(rd,gn,bl) (((rd)*11 + (gn)*16 + (bl)*5) >> 5) /*.33R+ .5G+ .17B*/ + +static int Width, Height; +static int curx, cury; +static long CountDown; +static int Interlace; + +#ifdef __STDC__ +static void putword(int, FILE *); +static void compress(int, FILE *, byte *, int); +static void output(int); +static void cl_block(void); +static void cl_hash(count_int); +static void char_init(void); +static void char_out(int); +static void flush_char(void); +#else +static void putword(), compress(), output(), cl_block(), cl_hash(); +static void char_init(), char_out(), flush_char(); +#endif + +static byte pc2nc[256],r1[256],g1[256],b1[256]; + +void xvbzero(s, len) + char *s; + int len; +{ + for ( ; len>0; len--) *s++ = 0; +} + +/*************************************************************/ +int hdfWriteGIF(fp, pic, ptype, w, h, rmap, gmap, bmap, pc2ncmap, numcols, colorstyle, BitsPerPixel) + FILE *fp; + byte *pic; + int ptype, w,h; + byte *rmap, *gmap, *bmap , *pc2ncmap; + int numcols, colorstyle; + int BitsPerPixel; +{ + int RWidth, RHeight; + int LeftOfs, TopOfs; + int ColorMapSize, InitCodeSize, Background; + int i; + byte *pic8; + pic8 = pic; + + Interlace = 0; + Background = 0; + + for (i=0; i<256; i++) { + pc2nc[i] = pc2ncmap[i]; + r1[i] = rmap[i]; + g1[i] = gmap[i]; + b1[i] = bmap[i]; + } + + ColorMapSize = 1 << BitsPerPixel; + + RWidth = Width = w; + RHeight = Height = h; + LeftOfs = TopOfs = 0; + + CountDown = w * h; /* # of pixels we'll be doing */ + + if (BitsPerPixel <= 1) InitCodeSize = 2; + else InitCodeSize = BitsPerPixel; + + curx = cury = 0; + + if (!fp) { + fprintf(stderr, "WriteGIF: file not open for writing\n" ); + return (1); + } + + compress(InitCodeSize+1, fp, pic8, w*h); + + + if (ferror(fp)) return -1; + return (0); +} + + + + +/******************************/ +static void putword(w, fp) +int w; +FILE *fp; +{ + /* writes a 16-bit integer in GIF order (LSB first) */ + + fputc(w &0xff, fp); + + fputc((w>>8)&0xff,fp); +} + + + + +/***********************************************************************/ +static unsigned long cur_accum = 0; +static int cur_bits = 0; + +#define MAXCODE(n_bits) ( (1 << (n_bits)) - 1) +#define min(a,b) ((a>b) ? b : a) +#define XV_BITS 12 /* BITS was already defined on some systems */ +#define MSDOS 1 +#define HSIZE 5003 /* 80% occupancy */ + +typedef unsigned char char_type; +static int n_bits; /* number of bits/code */ +static int maxbits = XV_BITS; /* user settable max # bits/code */ +static int maxcode; /* maximum code, given n_bits */ +static int maxmaxcode = 1 << XV_BITS; /* NEVER generate this */ + +static count_int htab [HSIZE]; +static unsigned short codetab [HSIZE]; +#define HashTabOf(i) htab[i] +#define CodeTabOf(i) codetab[i] + +static int hsize = HSIZE; /* for dynamic table sizing */ + +/* + * To save much memory, we overlay the table used by compress() with those + * used by decompress(). The tab_prefix table is the same size and type + * as the codetab. The tab_suffix table needs 2**BITS characters. We + * get this from the beginning of htab. The output stack uses the rest + * of htab, and contains characters. There is plenty of room for any + * possible stack (stack used to be 8000 characters). + */ + +#define tab_prefixof(i) CodeTabOf(i) +#define tab_suffixof(i) ((char_type *)(htab))[i] +#define de_stack ((char_type *)&tab_suffixof(1<<XV_BITS)) + +static int free_ent = 0; /* first unused entry */ + +/* + * block compression parameters -- after all codes are used up, + * and compression rate changes, start over. + */ +static int clear_flg = 0; + +static long int in_count = 1; /* length of input */ +static long int out_count = 0; /* # of codes output (for debugging) */ + +/* + * compress stdin to stdout + * + * Algorithm: use open addressing double hashing (no chaining) on the + * prefix code / next character combination. We do a variant of Knuth's + * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime + * secondary probe. Here, the modular division first probe is gives way + * to a faster exclusive-or manipulation. Also do block compression with + * an adaptive reset, whereby the code table is cleared when the compression + * ratio decreases, but after the table fills. The variable-length output + * codes are re-sized at this point, and a special CLEAR code is generated + * for the decompressor. Late addition: construct the table according to + * file size for noticeable speed improvement on small files. Please direct + * questions about this implementation to ames!jaw. + */ + +static int g_init_bits; +static FILE *g_outfile; + +static int ClearCode; +static int EOFCode; + +/********************************************************/ +static void compress(init_bits, outfile, data, len) +int init_bits; +FILE *outfile; +byte *data; +int len; +{ + register long fcode; + register int i = 0; + register int c; + register int ent; + register int disp; + register int hsize_reg; + register int hshift; + + /* + * Set up the globals: g_init_bits - initial number of bits + * g_outfile - pointer to output file + */ + g_init_bits = init_bits; + g_outfile = outfile; + + /* initialize 'compress' globals */ + maxbits = XV_BITS; + maxmaxcode = 1<<XV_BITS; + xvbzero((char *) htab, sizeof(htab)); + xvbzero((char *) codetab, sizeof(codetab)); + hsize = HSIZE; + free_ent = 0; + clear_flg = 0; + in_count = 1; + out_count = 0; + cur_accum = 0; + cur_bits = 0; + + + /* + * Set up the necessary values + */ + out_count = 0; + clear_flg = 0; + in_count = 1; + maxcode = MAXCODE(n_bits = g_init_bits); + + ClearCode = (1 << (init_bits - 1)); + EOFCode = ClearCode + 1; + free_ent = ClearCode + 2; + + char_init(); + ent = pc2nc[*data++]; len--; + + hshift = 0; + for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L ) + hshift++; + hshift = 8 - hshift; /* set hash code range bound */ + + hsize_reg = hsize; + cl_hash( (count_int) hsize_reg); /* clear hash table */ + + output(ClearCode); + + while (len) { + c = pc2nc[*data++]; len--; + in_count++; + + fcode = (long) ( ( (long) c << maxbits) + ent); + i = (((int) c << hshift) ^ ent); /* xor hashing */ + + if ( HashTabOf (i) == fcode ) { + ent = CodeTabOf (i); + continue; + } + + else if ( (long)HashTabOf (i) < 0 ) /* empty slot */ + goto nomatch; + + disp = hsize_reg - i; /* secondary hash (after G. Knott) */ + if ( i == 0 ) + disp = 1; + +probe: + if ( (i -= disp) < 0 ) + i += hsize_reg; + + if ( HashTabOf (i) == fcode ) { + ent = CodeTabOf (i); + continue; + } + + if ( (long)HashTabOf (i) >= 0 ) + goto probe; + +nomatch: + output(ent); + out_count++; + ent = c; + + if ( free_ent < maxmaxcode ) { + CodeTabOf (i) = free_ent++; /* code -> hashtable */ + HashTabOf (i) = fcode; + } + else + cl_block(); + } + + /* Put out the final code */ + output(ent); + out_count++; + output(EOFCode); +} + + +/***************************************************************** + * TAG( output ) + * + * Output the given code. + * Inputs: + * code: A n_bits-bit integer. If == -1, then EOF. This assumes + * that n_bits =< (long)wordsize - 1. + * Outputs: + * Outputs code to the file. + * Assumptions: + * Chars are 8 bits long. + * Algorithm: + * Maintain a BITS character long buffer (so that 8 codes will + * fit in it exactly). Use the VAX insv instruction to insert each + * code in turn. When the buffer fills up empty it and start over. + */ + +static +unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, + 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, + 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +static void output(code) +int code; +{ + cur_accum &= masks[cur_bits]; + + if (cur_bits > 0) + cur_accum |= ((long)code << cur_bits); + else + cur_accum = code; + + cur_bits += n_bits; + + while( cur_bits >= 8 ) { + char_out( (unsigned int) (cur_accum & 0xff) ); + cur_accum >>= 8; + cur_bits -= 8; + } + + /* + * If the next entry is going to be too big for the code size, + * then increase it, if possible. + */ + + if (free_ent > maxcode || clear_flg) { + + if( clear_flg ) { + maxcode = MAXCODE (n_bits = g_init_bits); + clear_flg = 0; + } + else { + n_bits++; + if ( n_bits == maxbits ) + maxcode = maxmaxcode; + else + maxcode = MAXCODE(n_bits); + } + } + + if( code == EOFCode ) { + /* At EOF, write the rest of the buffer */ + while( cur_bits > 0 ) { + char_out( (unsigned int)(cur_accum & 0xff) ); + cur_accum >>= 8; + cur_bits -= 8; + } + + flush_char(); + + fflush( g_outfile ); + +#ifdef FOO + if( ferror( g_outfile ) ) + FatalError("unable to write GIF file"); +#endif + } +} + + +/********************************/ +static void cl_block () /* table clear for block compress */ +{ + /* Clear out the hash table */ + + cl_hash ( (count_int) hsize ); + free_ent = ClearCode + 2; + clear_flg = 1; + + output(ClearCode); +} + + +/********************************/ +static void cl_hash(hsize) /* reset code table */ +register count_int hsize; +{ + register count_int *htab_p = htab+hsize; + register long i; + register long m1 = -1; + + i = hsize - 16; + do { /* might use Sys V memset(3) here */ + *(htab_p-16) = m1; + *(htab_p-15) = m1; + *(htab_p-14) = m1; + *(htab_p-13) = m1; + *(htab_p-12) = m1; + *(htab_p-11) = m1; + *(htab_p-10) = m1; + *(htab_p-9) = m1; + *(htab_p-8) = m1; + *(htab_p-7) = m1; + *(htab_p-6) = m1; + *(htab_p-5) = m1; + *(htab_p-4) = m1; + *(htab_p-3) = m1; + *(htab_p-2) = m1; + *(htab_p-1) = m1; + htab_p -= 16; + } while ((i -= 16) >= 0); + + for ( i += 16; i > 0; i-- ) + *--htab_p = m1; +} + + +/****************************************************************************** + * + * GIF Specific routines + * + ******************************************************************************/ + +/* + * Number of characters so far in this 'packet' + */ +static int a_count; + +/* + * Set up the 'byte output' routine + */ +static void char_init() +{ + a_count = 0; +} + +/* + * Define the storage for the packet accumulator + */ +static char accum[ 256 ]; + +/* + * Add a character to the end of the current packet, and if it is 254 + * characters, flush the packet to disk. + */ +static void char_out(c) +int c; +{ + accum[ a_count++ ] = c; + if( a_count >= 254 ) + flush_char(); +} + +/* + * Flush the packet to disk, and reset the accumulator + */ +static void flush_char() +{ + if( a_count > 0 ) { + fputc( a_count, g_outfile ); + fwrite( accum, 1, a_count, g_outfile ); + a_count = 0; + } +} diff --git a/hl/tools/gif2h5/readhdf.c b/hl/tools/gif2h5/readhdf.c new file mode 100644 index 0000000..a7101c9 --- /dev/null +++ b/hl/tools/gif2h5/readhdf.c @@ -0,0 +1,177 @@ +#include "gif.h" + +/* just a small cleanup routine before we leave */ +void cleanup(BYTE *ptr) { + if (ptr) + free(ptr); +} + +/* Function : ReadHDF +** Return: 0 on completion without error, -1 on error +** Input: CHAR *h5_file - HDF file name +** CHAR *dset_name - Name of the HDF Image dataset +** CHAR *pal_name - Name of the HDF palette +** Output : BYTE** data - the HDF Image to be converted +** BYTE palette[256][3] - the corresponding palette +** hsize_t* image_size - the size of each dimension of the image +** +** Future Notes: +** The way readHDF works right now is that it expects the user +** to know the exact path to the HDF image. Thus it does not +** parse the HDF file looking for image datasets and corresponding +** palettes. Also it takes in the default palette for the image +** specified, if the palette is missing, it makes a default greyscale +** palette and throws it in. +** +*/ +int ReadHDF(BYTE** data , + BYTE palette[256][3] , + hsize_t *image_size , + CHAR *h5_file , + CHAR *dset_name , + CHAR *pal_name) +{ + hid_t fHfile; /* H5 file to open */ + herr_t status; /* status variable */ + hid_t dspace; /* dataspace identifier for the the dataset */ + hid_t dset; /* dataset identifier */ + + hid_t pal_set; /* dataset for palette */ + hid_t pal_space;/* dataspace for palette */ + hsize_t pal_size; /* size of the palette */ + + hsize_t datasize; /* size of the image */ + hsize_t maxdims; /* dummy */ + + int pal_exist = 0; /* do we have a palette? */ + + /* check stuff */ + if (!h5_file || !dset_name || !image_size) { + fprintf(stderr , "NULL is not an acceptable input for HDFread. Aborting.\n"); + return -1; + } + + /* do we have a palette ? */ + if (pal_name) { + pal_exist = 1; + } + + /* try opening the file */ + /* H5 file open calls */ + if ((fHfile = H5Fopen(h5_file , H5F_ACC_RDONLY , H5P_DEFAULT)) < 0) { + fprintf(stderr , "Unable to open HDF file for input. Aborting.\n"); + return -1; + } + + /* open the dataset for reading */ + if ((dset = H5Dopen(fHfile , dset_name)) < 0) { + fprintf(stderr , "Unable to open dataset\n"); + return -1; + } + + /* get the dataspace */ + if ((dspace = H5Dget_space(dset)) < 0) { + fprintf(stderr , "Unable to get dataspace\n"); + return -1; + } + + /* get the dimension size of the image */ + if (H5Sget_simple_extent_dims(dspace , image_size , &maxdims) !=2 ) { + fprintf(stderr , "Unable to get dimension info\n"); + return -1; + } + + /* size needed to store the image */ + datasize = image_size[0] * image_size[1]; + + /* allocate memory to store the image */ + if ((*data = (BYTE*) malloc(datasize)) == NULL) { + fprintf(stderr , "Out of memory, exiting"); + return -1; + } + + /* get the actual image */ + if ((status = H5Dread(dset , H5Dget_type(dset) , H5S_ALL , H5S_ALL , H5P_DEFAULT , *data)) < 0) { + fprintf(stderr , "Unable to read data \n"); + cleanup(*data); + return -1; + } + + if (pal_exist) { + hsize_t pal_size[2]; + hsize_t max_pal_dims[2]; + hsize_t pal_datasize; + CHAR *pal_path; + + BYTE *temp_buf; + hsize_t temp_size; + + /* get the palette dataset */ + if ((pal_set = H5Dopen(fHfile , pal_name)) < 0) { + fprintf(stderr , "Unable to open dataset\n"); + pal_exist = 0; + return -1; + } + + /* get the dataspace */ + if ((pal_space = H5Dget_space(pal_set)) < 0) { + fprintf(stderr , "Unable to get dataspace\n"); + pal_exist = 0; + return -1; + } + + /* get the dimension size of the palette. */ + if (H5Sget_simple_extent_dims(pal_space , pal_size , &max_pal_dims) !=2 ) { + fprintf(stderr , "Unable to get dimension info\n"); + pal_exist = 0; + return -1; + } + + /* size needed to store the image */ + pal_datasize = pal_size[0] * pal_size[1]; + + /* copy stuff into a temp buffer and then copy 256*3 elements to palette */ + temp_size = H5Dget_storage_size(pal_set); + + temp_buf = (BYTE*) malloc (temp_size * sizeof(BYTE)); + + /* make sure that the palette is actually 256 X 3 so that we don't create overflows */ + if (pal_datasize > 256 * 3) + { + fprintf(stderr , "Palette seems to be more than 256X3 bytes\n"); + fprintf(stderr , "Truncating palette to 256 colors. This might cause a problem with the final image\n"); + pal_datasize = 256 * 3; + } + + /* get the actual palette */ + if ((status = H5Dread(pal_set , H5Dget_type(pal_set) , H5S_ALL , H5S_ALL , H5P_DEFAULT , temp_buf)) < 0) { + fprintf(stderr , "Unable to read data \n"); + cleanup(*data); + cleanup(temp_buf); + return -1; + } + + /* copy stuff into the actual palette */ + memcpy(palette , temp_buf , pal_datasize); + + /* get rid of the temp memory */ + cleanup(temp_buf); + /* end of if (pal_exist) */ + + } else { + int i; + /* if palette does not exist we just go ahead and create a uniform greyscale palette */ + for (i = 0 ; i < 256 ; i++) { + palette[i][0] = 255 - i; + palette[i][1] = 255 - i; + palette[i][2] = 255 - i; + } + } + + /* close everything */ + status = H5Dclose(dset); + status = H5Sclose(dspace); + status = H5Fclose(fHfile); + + return 0; +} diff --git a/hl/tools/gif2h5/writehdf.c b/hl/tools/gif2h5/writehdf.c new file mode 100644 index 0000000..7afccdf --- /dev/null +++ b/hl/tools/gif2h5/writehdf.c @@ -0,0 +1,410 @@ +#include "gif.h" +#include <string.h> +#include <stdlib.h> +#include <string.h> + +/******************************************************************* +** Function: write_text_attribute +** Use: Just a small wrapper to write text attributes easily +********************************************************************/ +int write_text_attribute(hid_t dataset_id , char *attr_name , char *attr_value) { + + /* variables for the attributes */ + hsize_t attr_dims_size; /* dimensions for the attribute */ + hid_t attr_dataspace_id; /* dataspaces needed for the various attributes */ + hid_t attr_attr_id; /* attribute id */ + herr_t status; /* check return status */ + hid_t attr_type_id; + + + /* check strings */ + if (!attr_name || !attr_value) + return -1; + + /* figure out size of the data */ + attr_dims_size = strlen(attr_value) + 1; + + /* set the type to string */ + attr_type_id = H5Tcopy(H5T_C_S1); + H5Tset_size(attr_type_id , attr_dims_size); + + /* create the dataspace for the attribute */ + attr_dataspace_id = H5Screate_simple(1 , &attr_dims_size , NULL); + + /* create the attribute */ + attr_attr_id = H5Acreate(dataset_id , attr_name , attr_type_id , attr_dataspace_id , H5P_DEFAULT); + + /* write out the attribute data */ + if ((status = H5Awrite(attr_attr_id , attr_type_id , attr_value)) < 0) + return -1; + + /* close the attribute */ + if ((status = H5Aclose(attr_attr_id)) < 0) + return -1; + + /* close the dataspace */ + if ((status = H5Sclose(attr_dataspace_id)) < 0) { + fprintf(stderr , "Unable to close attribute dataspace. Aborting \n"); + return -1; + } + + return 0; + +} + +int +WriteHDF(GifMemoryStruct, HDFName , GIFFileName) +GIFTOMEM GifMemoryStruct; +char *HDFName; +char *GIFFileName; +{ + GIFHEAD gifHead; /* GIF Header structure */ + GIFIMAGEDESC* gifImageDesc; /* Logical Image Descriptor struct */ + + long ImageCount , /* number of images */ + CommentCount, /* number of comments */ + ApplicationCount , /* number of application extensions */ + PlainTextCount; /* number of plain text extensions */ + + char ImageName[256], /* Image name for the GR Image */ + CommentName[256], + ApplicationName[256], + PlainTextName[256]; + + char GroupName[VSNAMELENMAX]; /* so that we can name the subgroups appropriately */ + + /* H5 variables */ + hid_t file_id; /* H5 file id */ + hid_t image_id; /* H5 id for the whole image */ + hid_t pal_id; /* H5 id for the palette */ + herr_t status; /* status variable */ + hobj_ref_t pal_ref; /* Create a reference for the palette */ + + /* temp counter */ + int i; + + + + + + + /* get the GIFMem stuff */ + gifHead = *(GifMemoryStruct.GifHeader); + + /* get some data from gifHead */ + ImageCount = (WORD)gifHead.ImageCount; + CommentCount = (WORD)gifHead.CommentCount; + ApplicationCount = (WORD)gifHead.ApplicationCount; + PlainTextCount = (WORD)gifHead.PlainTextCount; + + /* get the main group name from GIFFileName */ + GroupName[0]= '/'; + if (strncpy(GroupName , GIFFileName , VSNAMELENMAX-2) == NULL) { + fprintf(stderr , "strncpy failed\n"); + exit(1); + } + GroupName[VSNAMELENMAX] = '\0'; + + + if ((file_id = H5Fcreate(HDFName , H5F_ACC_TRUNC , H5P_DEFAULT , H5P_DEFAULT)) < 0) { + /* error occured opening the HDF File for write */ + fprintf(stderr , "HDF file could not be opened for writing\n"); + fprintf(stderr , "NOTE: GIF file must be present in the same directory as the binary on UNIX systems.\n"); + exit(1); + } + + /* create a group within the root group to hold the gif image */ + /* might want to make a different naming style out here */ + image_id = H5Gcreate(file_id, GroupName , 0); + + /* first create the global palette if there is one */ + if (gifHead.PackedField & 0x80) { /* global palette exists */ + hid_t dataspace_id; /* identifier for dataspace */ + hsize_t dims[2]; /* specify the dimensions of the palette */ + + hsize_t dimsr[1] = {1}; /* needed to store reference */ + hid_t ref_dataspace_id; /* dataspace id for references */ + hid_t ref_dataset_id; /* dataset id for references */ + + /* size of the palette is tablesize (rows) X 3 (columns) */ + dims[0] = gifHead.TableSize; + dims[1] = 3; + + /* create the dataspace */ + if ((dataspace_id = H5Screate_simple(2 , dims , NULL)) < 0) { + fprintf(stderr , "Could not create dataspace for palette. Aborting...\n"); + return -1; + } + + /* create the palette dataset */ + if ((pal_id = H5Dcreate(image_id , "Global Palette" , H5T_NATIVE_UINT8 , dataspace_id , H5P_DEFAULT )) < 0) { + fprintf(stderr , "Could not create palette dataset. Aborting...\n"); + return -1; + } + + /* write the palette data out */ + /****** Ask Elena about VOIDP ******/ + if ((status = H5Dwrite(pal_id , H5T_NATIVE_UINT8 , H5S_ALL , H5S_ALL , H5P_DEFAULT , (void *)gifHead.HDFPalette)) < 0) { + fprintf(stderr , "Error writing dataset. Aborting...\n"); + return -1; + } + + /* set palette attributes */ + + /* attribute CLASS = PALETTE */ + if ((write_text_attribute(pal_id , "CLASS" , "PALETTE")) < 0) { + fprintf(stderr , "Unable to write palette attributes. Aborting\n"); + return -1; + } + + /* attribute PAL_COLORMODEL = RGB */ + if ((write_text_attribute(pal_id , "PAL_COLORMODEL" , "RGB")) < 0) { + fprintf(stderr , "Unable to write palette attributes. Aborting\n"); + return -1; + } + + /* attribute PAL_TYPE = STANDARD8 */ + if ((write_text_attribute(pal_id , "PAL_TYPE" , "STANDARD8")) < 0) { + fprintf(stderr , "Unable to write palette attributes. Aborting\n"); + return -1; + } + + /* attribute PAL_VERSION = 1.0 */ + if ((write_text_attribute(pal_id , "PAL_VERSION" , "1.0")) < 0) { + fprintf(stderr , "Unable to write palette attributes. Aborting\n"); + return -1; + } + + /* create dataspace for the dataset to store references */ + ref_dataspace_id = H5Screate_simple(1 , dimsr , NULL); + + /* create a dataset to store the references */ + ref_dataset_id = H5Dcreate(image_id , "Palette Reference" , H5T_STD_REF_OBJ , ref_dataspace_id , H5P_DEFAULT); + + /* create a reference to the palette */ + if ((status = H5Rcreate(&pal_ref , image_id , "Global Palette" , H5R_OBJECT , -1)) < 0) { + fprintf(stderr , "Unable to create palette reference\n"); + return -1; + } + + /* write the reference out */ + if ((status = H5Dwrite(ref_dataset_id , H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL , H5P_DEFAULT, &pal_ref)) < 0) { + fprintf(stderr , "Unable to write Palette Reference"); + return -1; + } + + /* close dataset */ + if ((status = H5Dclose(ref_dataset_id)) < 0) { + fprintf(stderr , "Unable to close palette dataset.\n"); + return -1; + } + + /* close dataspace */ + if ((status = H5Sclose(ref_dataspace_id)) < 0) { + fprintf(stderr , "Unable to close palette dataspace.\n"); + return -1; + } + + /* close everything */ + if ((status = H5Dclose(pal_id)) < 0) { + fprintf(stderr , "Unable to close palette dataset. Aborting.\n"); + return -1; + } + + if ((status = H5Sclose(dataspace_id)) < 0) { + fprintf(stderr , "Unable to close palette dataspace. Aborting.\n"); + return -1; + } + + } + + for(i=0 ; i < ImageCount ; i++) { + /* variables for the images */ + hsize_t dims[2]; /* dimensions for the dataset */ + hid_t dataspace_id; /* identifier for the dataspace */ + hid_t sub_image_id; /* wierd name to distinguish from the group_id */ + + /* variables for the attributes */ + hsize_t attr_dims[2]; /* dimensions for the attribute */ + hid_t attr_dataspace_id; /* dataspaces needed for the various attributes */ + hid_t attr_attr_id; /* attribute id */ + BYTE minmax[2]; /* lower and upper minmax values */ + + /* initialise minmax */ + minmax[0] = 0 ; minmax[1] = 255; + + /* get the gifImageDesc */ + gifImageDesc = GifMemoryStruct.GifImageDesc[i]; + + /* set the dimensions */ + dims[0] = gifImageDesc->ImageHeight; + dims[1] = gifImageDesc->ImageWidth; + + /* create the empty dataspace */ + if ((dataspace_id = H5Screate_simple(2 , dims , NULL)) < 0) { + fprintf(stderr , "Could not create image dataspace. Aborting\n"); + return -1; + } + + /* create the image name */ + sprintf(ImageName , "Image%d" , i); + + /* create the image data set */ + if ((sub_image_id = H5Dcreate(image_id , ImageName , H5T_NATIVE_UINT8 , dataspace_id , H5P_DEFAULT)) < 0) { + fprintf(stderr , "Could not create dataset for image. Aborting... \n"); + return -1; + } + + /* write out the image */ + /****** Ask Elena about VOIDP ******/ + if ((status = H5Dwrite(sub_image_id , H5T_NATIVE_UINT8 , H5S_ALL , H5S_ALL , H5P_DEFAULT , (void *)(gifImageDesc->Image))) < 0) { + fprintf(stderr , "Error writing image. Aborting... \n"); + return -1; + } + + /* set the attributes */ + /* This info is available at http://hdf.ncsa.uiuc.edu/HDF5/doc/ImageSpec.html */ + /* The following attributes must be set for each image: + ** --------------------------------------- + ** Attribute Name Value + ** CLASS IMAGE + ** IMAGE_VERSION 1.0 + ** IMAGE_SUBCLASS IMAGE_BITMAP + ** PALETTE ref. to palette datasets + ** IMAGE_MINMAXRANGE [0,255] + ** --------------------------------------- + */ + + /**************************************** + ** Attribute: CLASS + ** Value : IMAGE + *****************************************/ + + if (write_text_attribute(sub_image_id , "CLASS" , "IMAGE") < 0) { + fprintf(stderr , "Unable to write CLASS = IMAGE attribute\n"); + return -1; + } + + /**************************************** + ** Attribute: IMAGE_VERSION + ** Value : 1.0 + *****************************************/ + + if (write_text_attribute(sub_image_id , "IMAGE_VERSION" , "1.0") < 0) { + fprintf(stderr , "Unable to write IMAGE_VERSION attribute\n"); + return -1; + } + + /**************************************** + ** Attribute: IMAGE_SUBCLASS + ** Value : IMAGE_BITMAP + *****************************************/ + + if (write_text_attribute(sub_image_id , "IMAGE_SUBCLASS" , "IMAGE_BITMAP") < 0) { + fprintf(stderr , "Unable to write IMAGE_SUBCLASS attribute\n"); + return -1; + } + + /**************************************** + ** Attribute: IMAGE_COLORMODEL + ** Value : RGB + *****************************************/ + + if (write_text_attribute(sub_image_id , "IMAGE_COLORMODEL" , "RGB") < 0) { + fprintf(stderr , "Unable to write IMAGE_SUBCLASS attribute\n"); + return -1; + } + + /**************************************** + ** Attribute: PALETTE + ** Value : Reference to Palette + *****************************************/ + + /**** MAKE SURE PALETTE EXISTS!!! ****/ + if (gifHead.PackedField & 0x80) { /* global palette exists */ + + attr_dims[0] = 1; + + /* create the dataspace for the attribute */ + attr_dataspace_id = H5Screate_simple(1 , attr_dims , NULL); + + /* create the attribute */ + attr_attr_id = H5Acreate(sub_image_id , "PALETTE" , H5T_STD_REF_OBJ , attr_dataspace_id , H5P_DEFAULT); + + if ((status = H5Awrite(attr_attr_id , H5T_STD_REF_OBJ , &pal_ref)) < 0) { + fprintf(stderr , "Unable to write attribute. Aborting \n"); + return -1; + } + + /* close the attribute */ + if ((status = H5Aclose(attr_attr_id)) < 0) { + fprintf(stderr , "Unable to close CLASS IMAGE attribute. Aborting.\n"); + return -1; + } + + /* close the dataspace */ + if ((status = H5Sclose(attr_dataspace_id)) < 0) { + fprintf(stderr , "Unable to close attribute dataspace. Aborting \n"); + return -1; + } + + } + + /**************************************** + ** Attribute: IMAGE_MINMAXRANGE + ** Value : minmax + *****************************************/ + + attr_dims[0] = 2; + + /* create the dataspace for the attribute */ + attr_dataspace_id = H5Screate_simple(1 , attr_dims , NULL); + + /* create the attribute */ + attr_attr_id = H5Acreate(sub_image_id , "IMAGE_MINMAXRANGE" , H5T_NATIVE_UINT8 , attr_dataspace_id , H5P_DEFAULT); + + if ((status = H5Awrite(attr_attr_id , H5T_NATIVE_UINT8 , minmax)) < 0) { + fprintf(stderr , "Unable to write attribute. Aborting \n"); + return -1; + } + + /* close the attribute */ + if ((status = H5Aclose(attr_attr_id)) < 0) { + fprintf(stderr , "Unable to close CLASS IMAGE attribute. Aborting.\n"); + return -1; + } + + /* close the dataspace */ + if ((status = H5Sclose(attr_dataspace_id)) < 0) { + fprintf(stderr , "Unable to close attribute dataspace. Aborting \n"); + return -1; + } + + + /* close everything */ + if ((status = H5Dclose(sub_image_id)) < 0) { + fprintf(stderr , "Unable to close image dataset. Aborting \n"); + return -1; + } + + if ((status = H5Sclose(dataspace_id)) < 0) { + fprintf(stderr , "Unable to close image dataspace. Aborting \n"); + return -1; + } + + } + + /* close the main image group */ + if ((status = H5Gclose(image_id)) < 0) { + fprintf(stderr , "Could not close the image group. Aborting...\n"); + return -1; + } + + /* close the H5 file */ + if ((status = H5Fclose(file_id)) < 0) { + fprintf(stderr , "Could not close HDF5 file. Aborting...\n"); + return -1; + } + + return(0); +} diff --git a/tools/Makefile.in b/tools/Makefile.in index 5369e87..64653a6 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -9,7 +9,7 @@ srcdir=@srcdir@ ## All subdirectories except for the ``lib'' subdirectory. ## -SUBDIRS=h5dump h5ls misc @H5TOH4@ @H4TOH5@ +SUBDIRS=h5dump h5ls misc gifconv @H5TOH4@ @H4TOH5@ @COMMENCE@ diff --git a/tools/gifconv/Dependencies b/tools/gifconv/Dependencies new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tools/gifconv/Dependencies diff --git a/tools/gifconv/Makefile.in b/tools/gifconv/Makefile.in new file mode 100644 index 0000000..effeada --- /dev/null +++ b/tools/gifconv/Makefile.in @@ -0,0 +1,65 @@ +## HDF5 Library Makefile(.in) +## +## Copyright (C) 2001 National Center for Supercomputing Applications. +## All rights reserved. +## +## +top_srcdir=@top_srcdir@ +top_builddir=../.. +srcdir=@srcdir@ +SUBDIRS= +@COMMENCE@ + +## Add include directory to the C preprocessor flags, add -lh5tools and +## -lhdf5 to the list of libraries. +## +CPPFLAGS=-I. -I$(srcdir) -I$(top_builddir)/src -I$(top_srcdir)/src \ + -I$(top_srcdir)/tools/lib @CPPFLAGS@ + +## Test programs and scripts. +## +TEST_PROGS= +TEST_SCRIPTS= + +## These are our main targets: library and tools. +## +LIBTOOLS=../lib/libh5tools.la +LIBHDF5=$(top_builddir)/src/libhdf5.la + +PUB_PROGS= gif2h5 h52gif +PROGS=$(PUB_PROGS) $(TEST_PROGS) + +## Source and object files for the library; do not install +## +LIB_SRC= +LIB_OBJ=$(LIB_SRC:.c=.lo) +PUB_LIB= + +## Source and object files for programs... +## +PROG_SRC=decompress.c gif2hdf.c gif2mem.c gifread.c hdf2gif.c hdfgifwr.c readhdf.c writehdf.c +PROG_OBJ=$(PROG_SRC:.c=.lo) + +PRIVATE_HDR=gif.h + +## Source and object files for the tests +## +TEST_SRC= +TEST_OBJ=$(TEST_SRC:.c=.lo) + +## Programs have to be built before they can be tested! +## +check test _test: $(PROGS) + +## How to build the programs...They all depend on the hdf5 library and +## the tools library compiled in this directory. +## +$(PROGS): $(LIBTOOLS) $(LIBHDF5) + +gif2h5: gif2hdf.lo gif2mem.lo decompress.lo gifread.lo writehdf.lo + @$(LT_LINK_EXE) $(CFLAGS) -o $@ gif2hdf.lo gif2mem.lo decompress.lo gifread.lo writehdf.lo $(LIBTOOLS) $(LIBHDF5) $(LDFLAGS) $(LIBS) + +h52gif: hdf2gif.lo hdfgifwr.lo readhdf.lo + @$(LT_LINK_EXE) $(CFLAGS) -o $@ hdf2gif.lo hdfgifwr.lo readhdf.lo $(LIBTOOLS) $(LIBHDF5) $(LDFLAGS) $(LIBS) + +@CONCLUDE@ diff --git a/tools/gifconv/decompress.c b/tools/gifconv/decompress.c new file mode 100644 index 0000000..18dbb3e --- /dev/null +++ b/tools/gifconv/decompress.c @@ -0,0 +1,299 @@ +#include <stdio.h> +#include <stdlib.h> +#include "gif.h" + +#define NEXTBYTE (*ptr++) +#define IMAGESEP 0x2c +#define INTERLACEMASK 0x40 +#define COLORMAPMASK 0x80 +#define False 0 +#define True 1 + +WORD iWIDE,iHIGH,eWIDE,eHIGH,expand,numcols,strip,nostrip; +unsigned long cols[256]; +char *cmd; + +FILE *fp; + +static int BitOffset = 0, /* Bit Offset of next code */ +XC = 0, YC = 0, /* Output X and Y coords of current pixel */ +Pass = 0, /* Used by output routine if WORDerlaced pic */ +OutCount = 0, /* Decompressor output 'stack count' */ +RWidth, RHeight, /* screen dimensions */ +IWidth, IHeight, /* image dimensions */ +LeftOfs, TopOfs, /* image offset */ +BitsPerPixel, /* Bits per pixel, read from GIF header */ +BytesPerScanline, /* Bytes per scanline in output raster */ +ColorMapSize, /* number of colors */ +Background, /* background color */ +CodeSize, /* Code size, read from GIF header */ +InitCodeSize, /* Starting code size, used during Clear */ +Code, /* Value returned by ReadCode */ +MaxCode, /* limiting value for current code size */ +ClearCode, /* GIF clear code */ +EOFCode, /* GIF end-of-information code */ +CurCode, OldCode, InCode, /* Decompressor variables */ +FirstFree, /* First free code, generated per GIF spec */ +FreeCode, /* Decompressor, next free slot in hash table */ +FinChar, /* Decompressor variable */ +DataMask, /* AND mask for data size */ +ReadMask; /* Code AND mask for current code size */ + +/*MODIFICATIONS*/ +BYTE tempbyte[10]; +BYTE * tempBYTEptr[10]; +WORD tempint[10]; +WORD ImageCount = 0; +/*END MODIFICATION*/ + +boolean Interlace, HasColormap; + + +BYTE *Image; /* The result array */ +BYTE *RawGIF; /* The heap array to hold it, raw */ +BYTE *Raster; /* The raster data stream, unblocked */ + +/* The hash table used by the decompressor */ + +int Prefix[4096]; +int Suffix[4096]; + +/* An output array used by the decompressor */ + +int OutCode[1025]; + +/* The color map, read from the GIF header */ + +int numused; + +/* Fetch the next code from the raster data stream. The codes can be +* any length from 3 to 12 bits, packed WORDo 8-bit BYTEs, so we have to +* maWORDain our location in the Raster array as a BIT Offset. We compute +* the BYTE Offset WORDo the raster array by dividing this by 8, pick up +* three BYTEs, compute the bit Offset WORDo our 24-bit chunk, shift to +* bring the desired code to the bottom, then mask it off and return it. +*/ +ReadCode() +{ + int RawCode, ByteOffset; + + ByteOffset = BitOffset / 8; + RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]); + if (CodeSize >= 8) + RawCode += (0x10000 * Raster[ByteOffset + 2]); + RawCode >>= (BitOffset % 8); + BitOffset += CodeSize; + return(RawCode & ReadMask); +} + + +AddToPixel(Index) +BYTE Index; +{ + if (YC<IHeight) + *(Image + YC * BytesPerScanline + XC) = Index; + + + + /* Update the X-coordinate, and if it overflows, update the Y-coordinate */ + if (++XC == IWidth) { + + /* If a non-WORDerlaced picture, just increment YC to the next scan line. + * If it's WORDerlaced, deal with the WORDerlace as described in the GIF + * spec. Put the decoded scan line out to the screen if we haven't gone + * past the bottom of it. + */ + + XC = 0; + if (!Interlace) YC++; + else { + switch (Pass) { + case 0: + YC += 8; + if (YC >= IHeight) { + Pass++; + YC = 4; + } + break; + case 1: + YC += 8; + if (YC >= IHeight) { + Pass++; + YC = 2; + } + break; + + case 2: + YC += 4; + if (YC >= IHeight) { + Pass++; + YC = 1; + } + break; + case 3: + YC += 2; + break; + default: + break; + } + } + } +} + +/* Main routine. Convert a GIF image to an HDF image */ + +BYTE* Decompress(GifImageDesc , GifHead) +GIFIMAGEDESC *GifImageDesc; +GIFHEAD *GifHead; +{ + int i; + + XC = 0; + YC = 0; + Pass = 0; + OutCount = 0; + BitOffset = 0; + + DataMask = (WORD)((1L << ((GifHead->PackedField & 0x07) +1)) -1); + Raster = GifImageDesc->GIFImage; + + + /* Check for image seperator */ + + /* Now read in values from the image descriptor */ + IWidth = GifImageDesc->ImageWidth; + IHeight = GifImageDesc->ImageHeight; + Interlace = GifImageDesc->PackedField & 0x40; + + /* Note that I ignore the possible existence of a local color map. + * I'm told there aren't many files around that use them, and the spec + * says it's defined for future use. This could lead to an error + * reading some files. + */ + + /* Start reading the raster data. First we get the WORDial code size + * and compute decompressor constant values, based on this code size. + */ + + CodeSize = GifImageDesc->CodeSize; + ClearCode = (1 << CodeSize); + EOFCode = ClearCode + 1; + FreeCode = FirstFree = ClearCode + 2; + + /* The GIF spec has it that the code size is the code size used to + * compute the above values is the code size given in the file, but the + * code size used in compression/decompression is the code size given in + * the file plus one. (thus the ++). + */ + + CodeSize++; + InitCodeSize = CodeSize; + MaxCode = (1 << CodeSize); + ReadMask = MaxCode - 1; + + /* Read the raster data. Here we just transpose it from the GIF array + * to the Raster array, turning it from a series of blocks WORDo one long + * data stream, which makes life much easier for ReadCode(). + */ + + + + /* free(RawGIF); We're not done just yet - change made */ + + /* Allocate the Image */ + + if (!(Image = (BYTE *)malloc(IWidth*IHeight))) { + printf("Out of memory"); + exit(-1); + } + + BytesPerScanline = IWidth; + + /* Decompress the file, continuing until you see the GIF EOF code. + * One obvious enhancement is to add checking for corrupt files here. + */ + + Code = ReadCode(); + while (Code != EOFCode) { + + /* Clear code sets everything back to its initial value, then reads the + * immediately subsequent code as uncompressed data. + */ + + if (Code == ClearCode) { + CodeSize = InitCodeSize; + MaxCode = (1 << CodeSize); + ReadMask = MaxCode - 1; + FreeCode = FirstFree; + CurCode = OldCode = Code = ReadCode(); + FinChar = CurCode & DataMask; + AddToPixel(FinChar); + } + else { + + /* If not a clear code, then must be data: save same as CurCode and InCode */ + + CurCode = InCode = Code; + + /* If greater or equal to FreeCode, not in the hash table yet; + * repeat the last character decoded + */ + + if (CurCode >= FreeCode) { + CurCode = OldCode; + OutCode[OutCount++] = FinChar; + } + + /* Unless this code is raw data, pursue the chain poWORDed to by CurCode + * through the hash table to its end; each code in the chain puts its + * associated output code on the output queue. + */ + + while (CurCode > DataMask) { + if (OutCount > 1024) { + /*return error message*/ + } + OutCode[OutCount++] = Suffix[CurCode]; + CurCode = Prefix[CurCode]; + } + + /* The last code in the chain is treated as raw data. */ + + FinChar = CurCode & DataMask; + OutCode[OutCount++] = FinChar; + + /* Now we put the data out to the Output routine. + * It's been stacked LIFO, so deal with it that way... + */ + + for (i = OutCount - 1; i >= 0; i--) + AddToPixel(OutCode[i]); + OutCount = 0; + + /* Build the hash table on-the-fly. No table is stored in the file. */ + + Prefix[FreeCode] = OldCode; + Suffix[FreeCode] = FinChar; + OldCode = InCode; + + /* PoWORD to the next slot in the table. If we exceed the current + * MaxCode value, increment the code size unless it's already 12. If it + * is, do nothing: the next code decompressed better be CLEAR + */ + + FreeCode++; + if (FreeCode >= MaxCode) { + if (CodeSize < 12) { + CodeSize++; + MaxCode *= 2; + ReadMask = (1 << CodeSize) - 1; + } + } + } + Code = ReadCode(); + } + + return Image; +} + + diff --git a/tools/gifconv/gif.h b/tools/gifconv/gif.h new file mode 100644 index 0000000..f697881 --- /dev/null +++ b/tools/gifconv/gif.h @@ -0,0 +1,179 @@ +/****************************************************************************\ +** Title: GIF.H ** +** Purpose: GIF Header file ** +\****************************************************************************/ + +#ifndef GIF_H +#define GIF_H 1 + +#include <hdf5.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#define MAX_PAL 768 + +/*#include "datatype.h" Data type definitions */ + +/* set the name length restriction to 64 charachters */ +#define VSNAMELENMAX 64 /* this is a carryover from HDF4 */ + +/* typedef H5T_NATIVE_UINT8 BYTE; */ +typedef unsigned char BYTE; + +/* typedef H5T_NATIVE_UINT16 WORD; */ +typedef unsigned long WORD; + +typedef char CHAR; +typedef unsigned char boolean; + +#define false 0; +#define true 1; + +/* Set the EndianOrder. +** The GIF Reader file should do this. +** Set EndianOrder = 0 if machine is little endian +** EndianOrder = 1 if machine is big endian. +*/ +extern int EndianOrder; + +/* +** The GIF header format. +** +** This structure actually contains the header, logical screen +** descriptor, and the global color table for the GIF image. +*/ +typedef struct _GifHeader /* Offset Description */ +{ + BYTE PackedField; /* 0Ah Color Information */ + WORD TableSize; + BYTE ImageCount; /* Keep a count of the number of images */ + BYTE CommentCount; + BYTE ApplicationCount; + BYTE PlainTextCount; + BYTE HDFPalette[256][3]; + BYTE HeaderDump[6]; /* BYTE array to dump header contents */ + BYTE LSDDump[7]; /* Logical Screen Descriptor dump */ +} GIFHEAD; + + +/* +** The GIF Image Descriptor. +*/ +typedef struct _GifImageDescriptor +{ + WORD ImageWidth; /* Width of the image in pixels */ + WORD ImageHeight; /* Height of the image in pixels */ + BYTE PackedField; /* Image and Color Table Data Information */ + WORD TableSize; + WORD CodeSize; /* Minimum LZW CodeSize for image data */ + BYTE HDFPalette[256][3]; + BYTE GIDDump[9]; /* GifImageDescriptor dump */ + + BYTE *Image; /* Decompressed Raster Image */ + BYTE *GIFImage; +} GIFIMAGEDESC; + + +/* +** GIF 89a Graphic Control Extension Block +*/ +typedef struct _GifGraphicControlExtension +{ + BYTE GCEDump[5]; /* Graphic Control Extension Dump */ +} GIFGRAPHICCONTROL; + + +/* +** GIF 89a Plain Text Extension Block +*/ +typedef struct _GifPlainTextExtension +{ + BYTE PTEDump[15]; /* Plain Text Extension Dump */ + BYTE *PlainTextData; /* Plain Text data sub-blocks */ + WORD DataSize; +} GIFPLAINTEXT; + + +/* +** GIF 89a Application Extension Block +*/ +typedef struct _GifApplicationExtension +{ + BYTE AEDump[14]; /* Application Extension Dump */ + BYTE *ApplicationData; /* Application data sub-blocks */ + WORD DataSize; +} GIFAPPLICATION; + +/* +** GIF 89a Comment Extension Block +*/ +typedef struct _GifCommentExtension +{ + BYTE CEDump[2]; /* Comment Extension Dump */ + BYTE *CommentData; /* Comment data sub-blocks */ + WORD DataSize; + BYTE Terminator; /* Block Terminator (always 0) */ +} GIFCOMMENT; + +/* +** GIF to HDF Memory Struct +** Purpose : The gif to hdf structure is used to pass all the +** gif data to the memory, which gets caught by the hdf driver +** Its the drivers job to put the data in the appropriate places +** in the HDF file. +** I have assumed that the ImageDescriptors and GraphicControls follow +** one another, ie. I have not associated them with each other. The driver +** must assume a 1-1 correspondance. The same discussion with plain text +** extension. +*/ +typedef struct _GifToMem +{ + GIFHEAD *GifHeader; + GIFIMAGEDESC **GifImageDesc; + GIFGRAPHICCONTROL **GifGraphicControlExtension; + GIFPLAINTEXT **GifPlainTextExtension; + GIFAPPLICATION **GifApplicationExtension; + GIFCOMMENT **GifCommentExtension; +} GIFTOMEM; + + +/* +** Function Prototypes +*/ +/* GIF2MEM.C */ +GIFTOMEM Gif2Mem(BYTE *); + +/* GIFREAD.C */ +int ReadGifHeader(GIFHEAD *, BYTE **); +int ReadGifImageDesc(GIFIMAGEDESC *, BYTE **); +int ReadGifGraphicControl(GIFGRAPHICCONTROL *, BYTE **); +int ReadGifPlainText(GIFPLAINTEXT *, BYTE **); +int ReadGifApplication(GIFAPPLICATION *, BYTE **); +int ReadGifComment(GIFCOMMENT *, BYTE **); + +/* WRITEHDF.C */ +int WriteHDF(GIFTOMEM , CHAR * , CHAR *); + +/* Function : ReadHDF +** Return: 0 on completion without error, -1 on error +** Input: CHAR *h5_file - HDF file name +** CHAR *dset_name - Name of the HDF Image dataset +** CHAR *pal_name - Name of the HDF palette +** Output : BYTE* data - the HDF Image to be converted +** BYTE palette[256][3] - the corresponding palette +** hsize_t* image_size - the size of each dimension of the image +** +*/ +int ReadHDF(BYTE** data , BYTE palette[256][3] , hsize_t *image_size , CHAR *h5_file , CHAR *dset_name , CHAR *pal_name); + +BYTE *ReadDataSubBlocks(BYTE ** , WORD *); +BYTE *Decompress (GIFIMAGEDESC * , GIFHEAD *); +BYTE GetByte(BYTE *); +WORD GetWord(BYTE *); + +void cleanup(BYTE*); +#endif /* GIF_H */ + diff --git a/tools/gifconv/gif2hdf.c b/tools/gifconv/gif2hdf.c new file mode 100644 index 0000000..0211143 --- /dev/null +++ b/tools/gifconv/gif2hdf.c @@ -0,0 +1,114 @@ +/* #include <hdf.h> */ +#include "gif.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +int +main(argv , argc) +int argv; +char *argc[]; +{ + + GIFTOMEM GifMemoryStruct; + GIFIMAGEDESC gifImageDesc; + + FILE *fpGif; + + /* replacing int32 with long */ + long i,ImageCount; + long filesize; + + BYTE *MemGif; + BYTE *StartPos; + + /* VSNAMELENMAX is a carryover from HDF4 and is #defined to 256 in gif.h */ + char GIFFileName[VSNAMELENMAX]; + char HDFFileName[VSNAMELENMAX]; + + /* Initialize all GifMemoryStruct pointers to null + ** to prevent hassles later on + */ + GifMemoryStruct.GifHeader = NULL; + GifMemoryStruct.GifImageDesc = NULL; + GifMemoryStruct.GifGraphicControlExtension = NULL; + GifMemoryStruct.GifPlainTextExtension = NULL; + GifMemoryStruct.GifApplicationExtension = NULL; + GifMemoryStruct.GifCommentExtension = NULL; + + + if (argv<3) + { + printf("\n\nWrong Usage. Use:\ngif2hdf <GIFFILE> <HDFFILE>\n\n"); + return(-1); + } + + + + strncpy(GIFFileName , argc[1] , VSNAMELENMAX - 1); + strncpy(HDFFileName , argc[2] , VSNAMELENMAX - 1); + GIFFileName[VSNAMELENMAX - 1] = '\0'; + HDFFileName[VSNAMELENMAX - 1] = '\0'; + + if (!(fpGif = fopen(GIFFileName,"rb"))) { + printf("Unable to open GIF file for reading.\n"); + printf("Filename (including path) must be less than %d charachters in length\n",VSNAMELENMAX); + exit(-1); + } + + /* Get the whole file into memory. Mem's much faster than I/O */ + fseek(fpGif, 0L , 2); + filesize = ftell(fpGif); + fseek(fpGif, 0L , 0); + if (filesize == 0) printf("File Size Zero"); + if (!(MemGif = StartPos = (BYTE *)malloc(filesize))) { + printf("Out of memory"); + exit (-1); + } + if (fread(MemGif,filesize,1,fpGif) != 1) { + printf("Corrupted Input File"); + exit(-1); + } + + fseek(fpGif,0L,0); + + /* + ** Call Gif2Mem and break the whole file into parts. + ** Gif2Mem also calls decompresses the images so we don't + ** have to worry about that + */ + GifMemoryStruct = Gif2Mem(MemGif); + if (ferror(fpGif)) { + printf("File Stream Error\n\n"); + exit(-1); + } + fclose(fpGif); + + /* Call WriteHDF from here. Go ahead and change WriteHDF to write + ** whatever format you want + */ + if (WriteHDF(GifMemoryStruct , argc[2] , argc[1])) + printf("HDF Write Error\n\n"); + + /* Free all buffers */ + /* replacing int32 with long */ + ImageCount = (long)((GifMemoryStruct.GifHeader)->ImageCount); + + for(i = 0 ; i < ImageCount ; i++) + { + gifImageDesc = *(GifMemoryStruct.GifImageDesc[i]); + if (gifImageDesc.Image != NULL) + free(gifImageDesc.Image); + + if (GifMemoryStruct.GifGraphicControlExtension[i] != NULL) + free(GifMemoryStruct.GifGraphicControlExtension[i]); + + } + free(StartPos); + + free (GifMemoryStruct.GifHeader); + + if (GifMemoryStruct.GifApplicationExtension != NULL) + free (GifMemoryStruct.GifApplicationExtension); + + return (0); +} diff --git a/tools/gifconv/gif2mem.c b/tools/gifconv/gif2mem.c new file mode 100644 index 0000000..92ca8e5 --- /dev/null +++ b/tools/gifconv/gif2mem.c @@ -0,0 +1,344 @@ +/* +** This file contains snippets of code from James Murray's original file +** to display the GIF header information, but most of it has been modified to +** suit gif2hdf +*/ + + + +/****************************************************************************\ +** Title: GIFHEAD.C ** +** Purpose: Display the data in a GIF image file. ** +** Version: 1.0 ** +** Date: March 1992 ** +** Author: James D. Murray, Anaheim, CA, USA ** +** C Compilers: Borland C++ v2.0, Microsoft C v6.00a ** +** ** +** GIFHEAD displays all real information contained within a GIF image ** +** file, including all color tables and extension block information. ** +** GIFHEAD reads both GIF 87a abd 89a-format files. ** +** ** +** Copyright (C) 1991-92 by Graphics Software Labs. All rights reserved. ** +\****************************************************************************/ +#include <stdio.h> +#include "gif.h" +/* #include <hdf.h> */ + +#define VERSION "1.00" +extern int EndianOrder; + +GIFTOMEM +Gif2Mem(MemGif) +BYTE *MemGif; +{ + /* + ** The gif structure outline for passing data to memory + ** is given in gif.h + ** These pointers are redunant, should take them out in ver. 2 + */ + GIFHEAD *gifHead; /* GIF Header structure */ + GIFIMAGEDESC **gifImageDesc; /* Logical Image Descriptor struct */ + GIFPLAINTEXT **gifPlainText; /* Plain Text Extension structure */ + GIFAPPLICATION **gifApplication; /* Application Extension structure */ + GIFCOMMENT **gifComment; /* Comment Extension structure */ + GIFGRAPHICCONTROL **gifGraphicControl; /* Graphic Control Extension strct */ + + GIFTOMEM GifMemoryStruct; + + + + register WORD i; /* Loop counter */ + BYTE Identifier; /* Extension block identifier holder */ + BYTE Label; /* Extension block label holder */ + BYTE ImageCount; /* Count of the number of images in the file */ + BYTE ImageArray; /* Keep the size of the array to store Images */ + BYTE CommentCount; + BYTE CommentArray; + BYTE ApplicationCount; + BYTE ApplicationArray; + BYTE PlainTextCount; + BYTE PlainTextArray; + BYTE GCEflag; + BYTE aTemp; + BYTE j; + + BYTE w; /* Two more variables needed only while testing */ + BYTE *b; /* Endian Ordering */ + + /* Allocate memory for the GIF structures */ + /* Plug the structs into GifMemoryStruct at the end */ + /****************************************************/ + if (!(gifHead = (GIFHEAD *)malloc(sizeof(GIFHEAD)))) + { + printf("Could not allocate memory for gifHead\n"); + exit(-1); + } + + /* + ** The next three have to grow dynamically so we leave them + ** for now and let realloc handle it later on. + */ + gifImageDesc = NULL; + gifPlainText = NULL; + gifGraphicControl = NULL; + gifComment = NULL; + gifApplication = NULL; + + /******************************/ + /* Memory allocation complete */ + + + /* Carry out Endian Testing and set Endian Order */ + w = 0x0001; + b = (BYTE *) &w; + EndianOrder = (b[0] ? 1 : 0); + + /* Read the GIF image file header information */ + ReadGifHeader(gifHead, &MemGif); + + /* Check for FILE stream error */ + /* + if (ferror(fpGif)) + { + fputs("GIFHEAD: Error reading header information!\n", stderr); + exit(-3); + } + */ + + /* + ** Identify, read, and display block information. + */ + ImageCount = ImageArray = 0; + CommentCount = CommentArray = 0; + ApplicationCount = ApplicationArray = 0; + PlainTextCount = PlainTextArray = 0; + GCEflag = 0; + + for (;;) + { + Identifier = *MemGif++; + + switch (Identifier) + { + case 0x3B: /* Trailer */ + /* The counts are stored to make it easier while + ** putting stuff into the HDF file and then + ** deallocating space. + */ + gifHead->ImageCount = ImageCount; + gifHead->CommentCount = CommentCount; + gifHead->ApplicationCount = ApplicationCount; + gifHead->PlainTextCount = PlainTextCount; + + /* putting stuff into the gif2mem structure */ + GifMemoryStruct.GifHeader = gifHead; + GifMemoryStruct.GifImageDesc = gifImageDesc; + GifMemoryStruct.GifPlainTextExtension = gifPlainText; + GifMemoryStruct.GifApplicationExtension = gifApplication; + GifMemoryStruct.GifCommentExtension = gifComment; + GifMemoryStruct.GifGraphicControlExtension = gifGraphicControl; + + /* return the struct */ + return GifMemoryStruct; + + + + case 0x2C: /* Image Descriptor */ + /* If there was no image descriptor before this increase image count. + ** If an imagedescriptor was present, reset GCEflag + */ + if (GCEflag == 0) + ImageCount++; + else + GCEflag = 0; + + if (ImageCount > ImageArray) { + aTemp = ImageArray; + ImageArray = (ImageArray << 1) + 1; + if (!(gifImageDesc = (GIFIMAGEDESC **)realloc(gifImageDesc , sizeof(GIFIMAGEDESC *) * ImageArray))) + { + printf("Out of memory!"); + exit(-1); + } + if (!(gifGraphicControl = (GIFGRAPHICCONTROL **)realloc(gifGraphicControl , sizeof(GIFGRAPHICCONTROL *) * ImageArray))) + { + printf("Out of memory!"); + exit(-1); + } + + for (j = aTemp ; j < ImageArray ; j++) { + gifGraphicControl[j] = NULL; + gifImageDesc[j] = NULL; + } + } + + if(!(gifImageDesc[ImageCount-1] = (GIFIMAGEDESC*)malloc(sizeof(GIFIMAGEDESC)))) + { + printf("Out of memory!"); + exit(-1); + } + + + if (ReadGifImageDesc(gifImageDesc[ImageCount-1], &MemGif) == -1) + fputs("Error reading Image Descriptor information\n", stderr); + + /* + ** Decompress the Image + */ + gifImageDesc[ImageCount-1]->Image = Decompress(gifImageDesc[ImageCount-1] , gifHead); + free(gifImageDesc[ImageCount-1]->GIFImage); + + /* + ** Convert the local palette into an HDF compatible palette + ** In case the local color table is present, it is written out as the HDFPalette + ** If it is absent the global table is written as the HDFPalette. + */ + if (!((gifImageDesc[ImageCount-1]->PackedField) & 0x80)) + { + /* Check to see if the global color table exists.... */ + if (gifHead->PackedField & 0x80) { + for (i=0 ; i<gifHead->TableSize ; i++) + { + gifImageDesc[ImageCount-1]->HDFPalette[i][0] = gifHead->HDFPalette[i][0]; + gifImageDesc[ImageCount-1]->HDFPalette[i][1] = gifHead->HDFPalette[i][1]; + gifImageDesc[ImageCount-1]->HDFPalette[i][2] = gifHead->HDFPalette[i][2]; + } + } + gifImageDesc[ImageCount-1]->TableSize = gifHead->TableSize; + } + + break; + + case 0x21: /* Extension Block */ + Label = *MemGif++; + switch (Label) + { + case 0x01: /* Plain Text Extension */ + puts("Plain Text Extension\n"); + + PlainTextCount++; + if (PlainTextCount > PlainTextArray) + PlainTextArray = (PlainTextArray << 1) + 1; + + if (!(gifPlainText = (GIFPLAINTEXT **)realloc(gifPlainText , sizeof(GIFPLAINTEXT *) * PlainTextArray))) + { + printf("Out of memory!"); + exit(-1); + } + + if(!(gifPlainText[PlainTextCount - 1] = (GIFPLAINTEXT*)malloc(sizeof(GIFPLAINTEXT)))) + { + printf("Out of memory!"); + exit(-1); + } + + + + if (ReadGifPlainText(gifPlainText[PlainTextCount - 1], &MemGif)) + fprintf(stderr, + "Error reading Plain Text Extension information.\n"); + + break; + + case 0xFE: /* Comment Extension */ + CommentCount++; + if (CommentCount > CommentArray) + CommentArray = (CommentArray << 1) + 1; + + if (!(gifComment = (GIFCOMMENT **)realloc(gifComment , sizeof(GIFCOMMENT *) * CommentArray))) + { + printf("Out of memory!"); + exit(-1); + } + + if(!(gifComment[CommentCount - 1] = (GIFCOMMENT *)malloc(sizeof(GIFCOMMENT)))) + { + printf("Out of memory!"); + exit(-1); + } + + + if (ReadGifComment(gifComment[CommentCount - 1], &MemGif)) + fprintf(stderr, + "Error reading Comment Extension information\n"); + break; + + case 0xF9: /* Graphic Control Extension */ + if (GCEflag == 0 ) + ImageCount++; + + GCEflag = 1; + + if (ImageCount > ImageArray) { + aTemp = ImageArray; + ImageArray = (ImageArray << 1) + 1; + if (!(gifGraphicControl = (GIFGRAPHICCONTROL **)realloc(gifGraphicControl , sizeof(GIFGRAPHICCONTROL *) * ImageArray))) + { + printf("Out of memory!"); + exit(-1); + } + if (!(gifImageDesc = (GIFIMAGEDESC **)realloc(gifImageDesc , sizeof(GIFIMAGEDESC *) * ImageArray))) + { + printf("Out of memory!"); + exit(-1); + } + for (j = aTemp ; j < ImageArray ; j++) { + gifGraphicControl[j] = NULL; + gifImageDesc[j] = NULL; + } + } + + if(!(gifGraphicControl[ImageCount-1] = (GIFGRAPHICCONTROL*)malloc(sizeof(GIFGRAPHICCONTROL)))) + { + printf("Out of memory!"); + exit(-1); + } + + + if (ReadGifGraphicControl(gifGraphicControl[ImageCount-1], &MemGif)) + fprintf(stderr, + "Error reading Graphic Control Extension information\n"); + + if (!*MemGif++ == 0) + fprintf(stderr, + "Error reading Graphic Control Extension\n"); + + break; + + case 0xFF: /* Application Extension */ + ApplicationCount++; + if (ApplicationCount > ApplicationArray) + ApplicationArray = (ApplicationArray << 1) + 1; + + if (!(gifApplication = (GIFAPPLICATION **)realloc(gifApplication , sizeof(GIFAPPLICATION *) * ApplicationArray))) + { + printf("Out of memory!"); + exit(-1); + } + + if(!(gifApplication[ApplicationCount - 1] = (GIFAPPLICATION *)malloc(sizeof(GIFAPPLICATION)))) + { + printf("Out of memory!"); + exit(-1); + } + + + if (ReadGifApplication(gifApplication[ApplicationCount - 1], &MemGif)) + fprintf(stderr, + "Error reading Application Extension information\n"); + break; + + default: + + printf("Unknown Extension Label: 0x%02x\n", Label); + break; + } + break; + default: + fprintf(stderr, "Unknown Block Separator Character: 0x%02x\n", + Identifier); + } + } + + +} diff --git a/tools/gifconv/gifread.c b/tools/gifconv/gifread.c new file mode 100644 index 0000000..1196241 --- /dev/null +++ b/tools/gifconv/gifread.c @@ -0,0 +1,382 @@ +#include <stdio.h> +#include <stdlib.h> +#include "gif.h" + +int EndianOrder; +int i; + + +WORD +GetWord (MemGif) +BYTE *MemGif; +{ + register WORD w; + if (EndianOrder == 1) /* LittleEndian */ + { + w = (WORD) (*MemGif++ & 0xFF); + w |= (WORD) ((*MemGif++ & 0xFF) << 0x08); + } + else + { + w = (WORD) (*MemGif++ & 0xFF); + w = ((WORD) (*MemGif++ & 0xFF)) | (w << 0x08); + } + return w; +} + +BYTE +GetByte (MemGif) +BYTE *MemGif; +{ + return *MemGif; +} + +/* +** Read a GIF image BYTE Header. +** +** This function reads the Header, Logical Screen Descriptor, and +** Global Color Table (if any) from a GIF image file. The information +** is stored in a GIFHEAD structure. +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifHeader(GifHead, MemGif2) +GIFHEAD *GifHead; /* Pointer to GIF header structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + register WORD i; /* Loop counter */ + WORD tableSize; /* Number of entires in the Global Color Table */ + + GifHead->TableSize = 0; + for (i = 0 ; i < 6 ; i++) { + GifHead->HeaderDump[i] = *(*MemGif2)++; + } + if (strncmp(GifHead->HeaderDump , "GIF" , 3)) { + printf("The file does not appear to be a valid GIF file.\n"); + exit(-1); + } + + for (i = 0 ; i < 7 ; i++) { + GifHead->LSDDump[i] = *(*MemGif2)++; + } + + GifHead->PackedField = GifHead->LSDDump[4]; + /* Check if a Global Color Table is present */ + if (GifHead->PackedField & 0x80) + { + /* Read number of color table entries */ + tableSize = (WORD) (1L << ((GifHead->PackedField & 0x07) + 1)); + GifHead->TableSize = tableSize; + /* Read the Global Color Table */ + /* + ** There are some changes made here apart from just + ** reading in the global color table as would + ** seem intuitively obvious. + ** The colors are stored in the bottom part of the + ** palette as opposed to the top + */ + + for (i = 0; i < tableSize; i++) + { + GifHead->HDFPalette[i][0] = *(*MemGif2)++; + GifHead->HDFPalette[i][1] = *(*MemGif2)++; + GifHead->HDFPalette[i][2] = *(*MemGif2)++; + } + } + + /* Check for a FILE stream error */ + /* + if (ferror(FpGif)) + return(-1); + */ + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read a GIF Local Image Descriptor. +** +** This function reads the Local Image Descriptor, and Local Color +** Table (if any) from a GIF image file. The information is stored +** in a GIFIMAGEDESC structure. +** +** Note that the ImageSeparator field value in the GIFIMAGEDESC +** structure is assigned by the function calling ReadGifImageDesc(). +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifImageDesc(GifImageDesc, MemGif2) +GIFIMAGEDESC *GifImageDesc; /* Pointer to GIF image descriptor structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + register WORD i; /* Loop counter */ + WORD tableSize; /* Number of entries in the Local Color Table */ + BYTE Interlace; /* PackedField & 0x20 gives information on interlacing */ + BYTE *TempPtr; + int ch , ch1; + + GifImageDesc->TableSize = 0; + for (i = 0 ; i < 9 ; i++) { + GifImageDesc->GIDDump[i] = *(*MemGif2)++; + } + + /* + ** Get the relevant fields. I need ImageWidth and Height actively hence I have + ** taken information from those fields. I intend to keep the GifImageDesc data + ** structure as it is so that anyone needing the rest of the fields can do so + ** quickly. + */ + + if (EndianOrder == 1) /* LittleEndian */ + { + GifImageDesc->ImageWidth = (WORD) (GifImageDesc->GIDDump[4] & 0xFF); + GifImageDesc->ImageWidth |= (WORD) ((GifImageDesc->GIDDump[5] & 0xFF) << 0x08); + + GifImageDesc->ImageHeight = (WORD) (GifImageDesc->GIDDump[6] & 0xFF); + GifImageDesc->ImageHeight |= (WORD) ((GifImageDesc->GIDDump[7] & 0xFF) << 0x08); + + } + else + { + GifImageDesc->ImageWidth = (WORD) (GifImageDesc->GIDDump[4] & 0xFF); + GifImageDesc->ImageWidth = ((WORD) (GifImageDesc->GIDDump[5] & 0xFF)) | (GifImageDesc->ImageWidth << 0x08); + + GifImageDesc->ImageHeight = (WORD) (GifImageDesc->GIDDump[6] & 0xFF); + GifImageDesc->ImageHeight = ((WORD) (GifImageDesc->GIDDump[7] & 0xFF)) | (GifImageDesc->ImageWidth << 0x08); + + + } + + GifImageDesc->PackedField = GifImageDesc->GIDDump[8]; + + /* Interlace = GifImageDesc->PackedField & 0x20; */ + + /* Check if a Local Color Table is present */ + if (GifImageDesc->PackedField & 0x80) + { + /* Read number of color table entries */ + tableSize = (WORD) (1L << ((GifImageDesc->PackedField & 0x07) + 1)); + GifImageDesc->TableSize = tableSize; + /* Read the Local Color Table */ + for (i = 0; i < tableSize; i++) + { + GifImageDesc->HDFPalette[i][0] = *(*MemGif2)++; + GifImageDesc->HDFPalette[i][1] = *(*MemGif2)++; + GifImageDesc->HDFPalette[i][2] = *(*MemGif2)++; + } + } + + /* + ** Get LZW minimum Code Size + */ + GifImageDesc->CodeSize = (WORD)*(*MemGif2)++; + + /*GifImageDesc->GIFImage = ReadDataSubBlocks(FpGif);*/ + if (!(GifImageDesc->GIFImage = (BYTE *)malloc((GifImageDesc->ImageWidth) * (GifImageDesc->ImageHeight)))) { + printf("Out of memory"); + exit(-1); + } + + + TempPtr = GifImageDesc->GIFImage; + do + { + ch = ch1 = (int)*(*MemGif2)++; + while (ch--) *TempPtr++ = *(*MemGif2)++; + } + while (ch1); + + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read a GIF Graphic Control Extension block. +** +** Note that the Introducer and Label field values in the GIFGRAPHICCONTROL +** structure are assigned by the function calling ReadGifGraphicControl(). +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifGraphicControl(GifGraphicControl, MemGif2) +GIFGRAPHICCONTROL *GifGraphicControl; /* Pointer to GC Extension structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + + + for (i = 0 ; i < 5 ; i++) { + GifGraphicControl->GCEDump[i] = *(*MemGif2)++; + } + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read a GIF Plain Text Extension block. +** +** Note that the Introducer and Label field values in the GIFLPLAINTEXT +** structure are assigned by the function calling ReadGifPlainText(). +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifPlainText(GifPlainText, MemGif2) +GIFPLAINTEXT *GifPlainText; /* Pointer to Plain Text Extension structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + for (i = 0 ; i < 13 ; i++) { + GifPlainText->PTEDump[i] = *(*MemGif2)++; + } + + /* Read in the Plain Text data sub-blocks */ + if (!(GifPlainText->PlainTextData = ReadDataSubBlocks(MemGif2 , &(GifPlainText->DataSize)))) + return(1); + + /* + GifPlainText->Terminator = 0; + */ + + /* Check for a FILE stream error */ + /* + if (ferror(FpGif)) + return(-1); + */ + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read a GIF Application Extension block. +** +** Note that the Introducer and Label field values in the GIFAPPLICATION +** structure are assigned by the function calling ReadGifApplication(). +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifApplication(GifApplication, MemGif2) +GIFAPPLICATION *GifApplication; /* Pointer to Application Extension structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + for (i = 0 ; i < 12 ; i++) { + GifApplication->AEDump[i] = *(*MemGif2)++; + } + + /* Read in the Plain Text data sub-blocks */ + if (!(GifApplication->ApplicationData = ReadDataSubBlocks(MemGif2 , &(GifApplication->DataSize)))) + return(1); + /* + GifApplication->Terminator = 0; + */ + + /* Check for a FILE stream error */ + /* + if (ferror(FpGif)) + return(-1); + */ + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read a GIF Comment Extension block. +** +** Note that the Introducer and Label field values in the GIFCOMMENT +** structure are assigned by the function calling ReadGifComment(). +** +** Returns: -1 if a FILE stream error occured during the read, +** otherwise 0 if no error occured. +*/ +int +ReadGifComment(GifComment, MemGif2) +GIFCOMMENT *GifComment; /* Pointer to GIF Comment Extension structure */ +BYTE **MemGif2; /* GIF image file input FILE stream */ +{ + + /* Read in the Plain Text data sub-blocks */ + if (!(GifComment->CommentData = ReadDataSubBlocks(MemGif2 , &(GifComment->DataSize)))) + return(1); + + GifComment->Terminator = 0; + + return(0); /* No FILE stream error occured */ +} + + +/* +** Read one or more GIF data sub-blocks and write the information +** to a buffer. +** +** A GIF "sub-block" is a single count byte followed by 1 to 255 +** additional data bytes. +** +** Returns: A NULL pointer if a memory allocation error occured, +** otherwise a valid pointer if no error occured. +*/ +static BYTE * +ReadDataSubBlocks(MemGif2 , DSize) +BYTE **MemGif2; /* GIF image file input FILE stream */ +WORD *DSize; +{ + BYTE *ptr1; /* Pointer used to "walk the heap" */ + BYTE *ptr2; /* Pointer used to mark the top of the heap */ + BYTE dataSize; /* Size of the current data sub-block being read */ + WORD bufSize; /* Total size of the Plain Text data buffer */ + int tempcount = 0; + + bufSize = 0; /* The output buffer is empty */ + + dataSize = *(*MemGif2)++; /* Get the size of the first sub-block */ + + /* Allocate initial data buffer */ + if (!(ptr1 = ptr2 = (BYTE *) malloc(dataSize + 1))) { + printf("Out of memory. Allocation of memory for data sub-blocks for\neither Comment, Plain Text or Application Extensions failed"); + return((BYTE *) NULL); + } + for (;;) + { + tempcount++; + bufSize += (dataSize); /* Running total of the buffer size */ + *DSize = bufSize; + + /* *ptr1++ = dataSize; /* Write the data count */ + while (dataSize--) /* Read/write the Plain Text data */ + *ptr1++ = *(*MemGif2)++; + + /* Check if there is another data sub-block */ + if ((dataSize = *(*MemGif2)++) == 0) + break; /* Block Terminator encountered */ + + /* Increase the buffer size to accomodate the next sub-block */ + if (!(ptr1 = ptr2 = (BYTE *) realloc(ptr2, bufSize + dataSize + 1))) + return((BYTE *) NULL); + + + ptr1 += bufSize; /* Move pointer to the end of the data */ + + + } + + /**ptr1++ = (BYTE) NULL; /* Add NULL to simulate Terminator value */ + *ptr1++ = '\0'; + + return(ptr2); /* Return a pointer to the sub-block data */ +} + + + + + diff --git a/tools/gifconv/hdf2gif.c b/tools/gifconv/hdf2gif.c new file mode 100644 index 0000000..9c4133e --- /dev/null +++ b/tools/gifconv/hdf2gif.c @@ -0,0 +1,354 @@ +/* NOTES: +** 04/01 - 04/10: been working on it a lot. I think it does gif89 images just fine with +** palettes. So that's cool. Putting in multiple images and animation support right now +** 03/29: For some reason I can write .GIF files which IE will open and see but +** kodak imaging does not like. I'm sure its a problem with the GIF file, +** I can't figure out what. +** 03/17: Explicitely deallocate the GIFTOMEM* struct in the main loop. +** Check for both success and failure conditions +*/ + +#include "gif.h" +#include <stdio.h> + +#define MAX_FILE_LEN 256 +#define MAX_NUMBER_IMAGES 50 + +extern int hdfWriteGIF(FILE *fp, BYTE *pic, int ptype, int w, int h, BYTE *rmap, + BYTE *gmap, BYTE *bmap, BYTE *pc2ncmap, int numcols, int colorstyle, int BitsPerPixel); + +int EndianOrder; + +void PutByte(BYTE b , FILE *fpGif) +{ + if (fputc(b , fpGif) == EOF) { + printf("File Writing Error, cannot continue"); + exit(-1); + } +} + + +void putword(int w, FILE *fp) +{ + /* writes a 16-bit integer in GIF order (LSB first) */ + + fputc(w &0xff, fp); + + fputc((w>>8)&0xff,fp); +} + +void usage() { + printf("Usage: h52gif <h5_file> <gif_file> -i <h5_image> [-p <h5_palette>]\n"); + printf("h52gif expects *at least* one h5_image. You may repeat -i <h5_image> [-p <h5_palette>] at most 50 times (maximum of 50 images).\n"); +} + +int main(int argc , char **argv) { + + FILE *fpGif; + + hsize_t dim_sizes[2]; + + BYTE *Image; + /* compression structs */ + + CHAR *HDFName = NULL; + CHAR *GIFName = NULL; + CHAR *image_path = NULL; + CHAR *pal_path = NULL; + /* reference variables */ + + int has_local_palette; /* treated as a flag */ + int loop_times; /* number of times to loop, i'm going to treat it as a yes or no */ + + BYTE* b; + + BYTE GlobalPalette[256][3]; + BYTE Red[256]; + BYTE Green[256]; + BYTE Blue[256]; + + int RWidth, RHeight; + int LeftOfs, TopOfs; + int ColorMapSize, InitCodeSize, Background, BitsPerPixel; + int j,nc; + int w,h,i; + int numcols = 256; + int CountDown; + int curx , cury; + int time_out = 0; /* time between two images in the animation */ + int n_images , index; + + BYTE pc2nc[256] , r1[256] , g1[256] , b1[256]; + + /* initial stuff */ + int number_of_images = 0; + int arg_index = 2; + int bool_is_image = 0; /* 0 = false , 1 = true */ + int bool_is_palette = 0; + CHAR* image_name_arr[MAX_NUMBER_IMAGES]; + CHAR* pal_name_arr[MAX_NUMBER_IMAGES]; + + if (argc < 5) { + /* they didn't supply at least one image -- bail */ + usage(); + return 0; + } + + memset(image_name_arr , NULL , MAX_NUMBER_IMAGES); + memset(pal_name_arr , NULL , MAX_NUMBER_IMAGES); + + HDFName = (CHAR*) malloc (strlen(argv[1]) + 1); + GIFName = (CHAR*) malloc (strlen(argv[2]) + 1); + + if (strlen(argv[1] + 1) > MAX_FILE_LEN || strlen(argv[2] + 1) > MAX_FILE_LEN) { + /* supplied file names are too long. bail. */ + usage(); + printf("Supplied filenames exceed maximum length of 256 bytes\n"); + } + + strcpy(HDFName , argv[1]); + strcpy(GIFName , argv[2]); + + /* get the options */ + while (arg_index++ < argc - 1 && number_of_images < MAX_NUMBER_IMAGES) { + if (!strcmp(argv[arg_index] , "-i")) { + bool_is_image = 1; + continue; + } + if (!strcmp(argv[arg_index] , "-p")) { + bool_is_palette = 1; + continue; + } + if (!strcmp(argv[arg_index] , "-a")) { + time_out = 10; + continue; + } + if (bool_is_image) { + /* this is an image */ + /* allocate space to store the image name */ + image_name_arr[number_of_images] = (CHAR*) malloc(strlen(argv[arg_index] + 1)); + strcpy(image_name_arr[number_of_images] , argv[arg_index]); + /* make the palette array for this NULL */ + pal_name_arr[number_of_images] = NULL; + number_of_images++; + bool_is_image = 0; + continue; + } + if (bool_is_palette) { + /* this is a palette */ + /* allocate space to store the pal name */ + /* the palette was probably allocated for a previous image */ + pal_name_arr[number_of_images-1] = (CHAR*) malloc(strlen(argv[arg_index] + 1)); + strcpy(pal_name_arr[number_of_images - 1] , argv[arg_index]); + bool_is_palette = 0; + continue; + } + /* oops. This was not meant to happen */ + usage(); + /* + while (number_of_images--) { + cleanup(image_name_arr[number_of_images]); + cleanup(pal_name_arr[number_of_images]); + } + */ + return -1; + + } + + /* we shall always have a palette - read hdf will see to that */ + has_local_palette = true; + + /* Do Endian Order testing and set Endian Order */ + w = 0x0001; + b = (BYTE *) &w; + EndianOrder = (b[0] ? 1:0); + + if (!(fpGif = fopen(GIFName , "wb"))) { + printf("Error opening gif file for output. Aborting.\n"); + return -1; + } + + /* hardwire n_images to 1 for now. */ + n_images = number_of_images; + + Background = 0; + for (index = 0 ; index < n_images ; index++) { + + /* try to read the image and the palette */ + /* Lots of funky stuff to support multiple images has been taken off. + ** Just in case you're extending code, here's what you need to do in short: + ** figure out if there is a global palette or not, if there is one store that one + ** only. + ** If they are all local or a combination of local and global palettes, you will have + ** to write the global palette out and then independantly write the smaller local + ** palettes + */ + if (ReadHDF(&Image , GlobalPalette , dim_sizes , HDFName , image_name_arr[index] , pal_name_arr[index]) < 0) { + fprintf(stderr , "Unable to read HDF file\n"); + return -1; + } + + w = dim_sizes[1]; + h = dim_sizes[0]; + + RWidth = dim_sizes[1]; + RHeight = dim_sizes[0]; + LeftOfs = TopOfs = 0; + + + /* If the first image does not have a palette, I make my own global color table + ** Obviously this is not the best thing to do, better steps would be: + ** 1. Check for either a global palette or a global attribute called palette + ** 2. Check for palettes in any of the other images. + */ + if (!has_local_palette) { + for (i = 0 ; i < 256 ; i++) { + Red[i] = 255 - i; + Green[i] = 255 - i; + Blue[i] = 255 - i; + } + } + else { + for (i = 0 ; i < 256 ; i++){ + Red[i] = GlobalPalette[i][0]; + Green[i] = GlobalPalette[i][1]; + Blue[i] = GlobalPalette[i][2]; + } + } + + for (i=0; i<256; i++) { pc2nc[i] = r1[i] = g1[i] = b1[i] = 0; } + /* compute number of unique colors */ + nc = 0; + for (i=0; i<numcols; i++) { + /* see if color #i is already used */ + for (j=0; j<i; j++) { + if (Red[i] == Red[j] && Green[i] == Green[j] && + Blue[i] == Blue[j]) break; + } + if (j==i) { /* wasn't found */ + pc2nc[i] = nc; + r1[nc] = Red[i]; + g1[nc] = Green[i]; + b1[nc] = Blue[i]; + nc++; + } + else pc2nc[i] = pc2nc[j]; + } + /* figure out 'BitsPerPixel' */ + for (i=1; i<8; i++) { + if ( (1<<i) >= nc) break; + } + BitsPerPixel = i; + ColorMapSize = 1 << BitsPerPixel; + + + CountDown = w * h; /* # of pixels we'll be doing */ + + if (BitsPerPixel <= 1) InitCodeSize = 2; + else InitCodeSize = BitsPerPixel; + + curx = cury = 0; + + if (!fpGif) { + fprintf(stderr, "WriteGIF: file not open for writing\n" ); + return (1); + } + + /* If it is the first image we do all the header stuff that isn't required for the + ** rest of the images. + */ + if (index == 0) { + /* Write out the GIF header and logical screen descriptor */ + if (n_images > 1) { + fwrite("GIF89a", 1, 6, fpGif); /* the GIF magic number */ + loop_times = 0; + } + else { + fwrite("GIF87a", 1, 6, fpGif); /* the GIF magic number */ + loop_times = 1; + } + + putword(RWidth, fpGif); /* screen descriptor */ + putword(RHeight, fpGif); + + i = 0x00; /* No, there is no color map */ + i |= (8-1)<<4; /* OR in the color resolution (hardwired 8) */ + i |= (BitsPerPixel - 1); /* OR in the # of bits per pixel */ + fputc(i,fpGif); + + fputc(Background,fpGif); /* background color */ + + fputc(0, fpGif); /* future expansion byte */ + + + /* If loop_times is 0 , put in the application extension to make the gif anime loop + ** indefinitely + */ + if (time_out > 0) { + fputc(0x21 , fpGif); + fputc(0xFF , fpGif); + fputc(11 , fpGif); + fwrite("NETSCAPE2.0" , 1 , 11 , fpGif); + fputc(3 , fpGif); + fputc(1 , fpGif); + fputc(0 , fpGif); + fputc(0 , fpGif); + fputc(0 , fpGif); + + } + + + } + + if (n_images > 1) { + /* write a graphic control block */ + fputc(0x21 , fpGif); + fputc(0xF9 , fpGif); + fputc(4 , fpGif); + fputc(4 , fpGif); + putword(time_out , fpGif); + fputc(255, fpGif); + fputc(0 , fpGif); + } + + /* Put Image Descriptor + ** Hardwiring Left Offset and Top Offset to 0x00 + */ + + fputc (0x2c , fpGif); + putword (0x00 , fpGif); + putword (0x00 , fpGif); + putword (RWidth , fpGif); + putword (RHeight , fpGif); + + /* since we always have a local color palette ... */ + fputc ((0x80 | (BitsPerPixel - 1)) , fpGif); + for (i=0; i<ColorMapSize; i++) { /* write out Global colormap */ + fputc(r1[i], fpGif); + fputc(g1[i], fpGif); + fputc(b1[i], fpGif); + } + + fputc (InitCodeSize , fpGif); + + i = hdfWriteGIF(fpGif , Image , 0 , dim_sizes[0] , dim_sizes[1] , r1, g1 , b1 , pc2nc , 256 , 8 , BitsPerPixel); + fputc(0x00 , fpGif); + free (Image); + } + + if (fputc(';',fpGif) == EOF) { /* Write GIF file terminator */ + fprintf(stderr , "Error!"); + return -1; + } + + fclose (fpGif); + + while (number_of_images--) { + /*if (image_name_arr[number_of_images]) + free(image_name_arr[number_of_images]);*/ + /*if (pal_name_arr[number_of_images]) + free(pal_name_arr[number_of_images]);*/ + } + + return(0); +} diff --git a/tools/gifconv/hdfgifwr.c b/tools/gifconv/hdfgifwr.c new file mode 100644 index 0000000..28d556e --- /dev/null +++ b/tools/gifconv/hdfgifwr.c @@ -0,0 +1,516 @@ +/* + * hdfgifwr.c - handles writing of GIF files. + * + * Contains: + * hdfWriteGIF(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle, + * comment) + * + * Note: slightly brain-damaged, in that it'll only write non-interlaced + * GIF files (in the interests of speed, or something) + * + */ + + + +/***************************************************************** + * Portions of this code Copyright (C) 1989 by Michael Mauldin. + * Permission is granted to use this file in whole or in + * part for any purpose, educational, recreational or commercial, + * provided that this copyright notice is retained unchanged. + * This software is available to all free of charge by anonymous + * FTP and in the UUNET archives. + * + * + * Authors: Michael Mauldin (mlm@cs.cmu.edu) + * David Rowley (mgardi@watdcsu.waterloo.edu) + * + * Based on: compress.c - File compression ala IEEE Computer, June 1984. + * + * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) + * Jim McKie (decvax!mcvax!jim) + * Steve Davies (decvax!vax135!petsd!peora!srd) + * Ken Turkowski (decvax!decwrl!turtlevax!ken) + * James A. Woods (decvax!ihnp4!ames!jaw) + * Joe Orost (decvax!vax135!petsd!joe) + *****************************************************************/ + + +#include <stdio.h> +#include "gif.h" +#include <stdlib.h> +#include <string.h> + +typedef BYTE byte; +typedef long int count_int; + +/* indicies into conv24MB */ +#define CONV24_8BIT 0 +#define CONV24_24BIT 1 +#define CONV24_SEP1 2 +#define CONV24_LOCK 3 +#define CONV24_SEP2 4 +#define CONV24_FAST 5 +#define CONV24_SLOW 6 +#define CONV24_BEST 7 +#define CONV24_MAX 8 + +/* values 'picType' can take */ +#define PIC8 CONV24_8BIT +#define PIC24 CONV24_24BIT + +/* MONO returns total intensity of r,g,b components */ +#define MONO(rd,gn,bl) (((rd)*11 + (gn)*16 + (bl)*5) >> 5) /*.33R+ .5G+ .17B*/ + +static int Width, Height; +static int curx, cury; +static long CountDown; +static int Interlace; + +#ifdef __STDC__ +static void putword(int, FILE *); +static void compress(int, FILE *, byte *, int); +static void output(int); +static void cl_block(void); +static void cl_hash(count_int); +static void char_init(void); +static void char_out(int); +static void flush_char(void); +#else +static void putword(), compress(), output(), cl_block(), cl_hash(); +static void char_init(), char_out(), flush_char(); +#endif + +static byte pc2nc[256],r1[256],g1[256],b1[256]; + +void xvbzero(s, len) + char *s; + int len; +{ + for ( ; len>0; len--) *s++ = 0; +} + +/*************************************************************/ +int hdfWriteGIF(fp, pic, ptype, w, h, rmap, gmap, bmap, pc2ncmap, numcols, colorstyle, BitsPerPixel) + FILE *fp; + byte *pic; + int ptype, w,h; + byte *rmap, *gmap, *bmap , *pc2ncmap; + int numcols, colorstyle; + int BitsPerPixel; +{ + int RWidth, RHeight; + int LeftOfs, TopOfs; + int ColorMapSize, InitCodeSize, Background; + int i; + byte *pic8; + pic8 = pic; + + Interlace = 0; + Background = 0; + + for (i=0; i<256; i++) { + pc2nc[i] = pc2ncmap[i]; + r1[i] = rmap[i]; + g1[i] = gmap[i]; + b1[i] = bmap[i]; + } + + ColorMapSize = 1 << BitsPerPixel; + + RWidth = Width = w; + RHeight = Height = h; + LeftOfs = TopOfs = 0; + + CountDown = w * h; /* # of pixels we'll be doing */ + + if (BitsPerPixel <= 1) InitCodeSize = 2; + else InitCodeSize = BitsPerPixel; + + curx = cury = 0; + + if (!fp) { + fprintf(stderr, "WriteGIF: file not open for writing\n" ); + return (1); + } + + compress(InitCodeSize+1, fp, pic8, w*h); + + + if (ferror(fp)) return -1; + return (0); +} + + + + +/******************************/ +static void putword(w, fp) +int w; +FILE *fp; +{ + /* writes a 16-bit integer in GIF order (LSB first) */ + + fputc(w &0xff, fp); + + fputc((w>>8)&0xff,fp); +} + + + + +/***********************************************************************/ +static unsigned long cur_accum = 0; +static int cur_bits = 0; + +#define MAXCODE(n_bits) ( (1 << (n_bits)) - 1) +#define min(a,b) ((a>b) ? b : a) +#define XV_BITS 12 /* BITS was already defined on some systems */ +#define MSDOS 1 +#define HSIZE 5003 /* 80% occupancy */ + +typedef unsigned char char_type; +static int n_bits; /* number of bits/code */ +static int maxbits = XV_BITS; /* user settable max # bits/code */ +static int maxcode; /* maximum code, given n_bits */ +static int maxmaxcode = 1 << XV_BITS; /* NEVER generate this */ + +static count_int htab [HSIZE]; +static unsigned short codetab [HSIZE]; +#define HashTabOf(i) htab[i] +#define CodeTabOf(i) codetab[i] + +static int hsize = HSIZE; /* for dynamic table sizing */ + +/* + * To save much memory, we overlay the table used by compress() with those + * used by decompress(). The tab_prefix table is the same size and type + * as the codetab. The tab_suffix table needs 2**BITS characters. We + * get this from the beginning of htab. The output stack uses the rest + * of htab, and contains characters. There is plenty of room for any + * possible stack (stack used to be 8000 characters). + */ + +#define tab_prefixof(i) CodeTabOf(i) +#define tab_suffixof(i) ((char_type *)(htab))[i] +#define de_stack ((char_type *)&tab_suffixof(1<<XV_BITS)) + +static int free_ent = 0; /* first unused entry */ + +/* + * block compression parameters -- after all codes are used up, + * and compression rate changes, start over. + */ +static int clear_flg = 0; + +static long int in_count = 1; /* length of input */ +static long int out_count = 0; /* # of codes output (for debugging) */ + +/* + * compress stdin to stdout + * + * Algorithm: use open addressing double hashing (no chaining) on the + * prefix code / next character combination. We do a variant of Knuth's + * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime + * secondary probe. Here, the modular division first probe is gives way + * to a faster exclusive-or manipulation. Also do block compression with + * an adaptive reset, whereby the code table is cleared when the compression + * ratio decreases, but after the table fills. The variable-length output + * codes are re-sized at this point, and a special CLEAR code is generated + * for the decompressor. Late addition: construct the table according to + * file size for noticeable speed improvement on small files. Please direct + * questions about this implementation to ames!jaw. + */ + +static int g_init_bits; +static FILE *g_outfile; + +static int ClearCode; +static int EOFCode; + +/********************************************************/ +static void compress(init_bits, outfile, data, len) +int init_bits; +FILE *outfile; +byte *data; +int len; +{ + register long fcode; + register int i = 0; + register int c; + register int ent; + register int disp; + register int hsize_reg; + register int hshift; + + /* + * Set up the globals: g_init_bits - initial number of bits + * g_outfile - pointer to output file + */ + g_init_bits = init_bits; + g_outfile = outfile; + + /* initialize 'compress' globals */ + maxbits = XV_BITS; + maxmaxcode = 1<<XV_BITS; + xvbzero((char *) htab, sizeof(htab)); + xvbzero((char *) codetab, sizeof(codetab)); + hsize = HSIZE; + free_ent = 0; + clear_flg = 0; + in_count = 1; + out_count = 0; + cur_accum = 0; + cur_bits = 0; + + + /* + * Set up the necessary values + */ + out_count = 0; + clear_flg = 0; + in_count = 1; + maxcode = MAXCODE(n_bits = g_init_bits); + + ClearCode = (1 << (init_bits - 1)); + EOFCode = ClearCode + 1; + free_ent = ClearCode + 2; + + char_init(); + ent = pc2nc[*data++]; len--; + + hshift = 0; + for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L ) + hshift++; + hshift = 8 - hshift; /* set hash code range bound */ + + hsize_reg = hsize; + cl_hash( (count_int) hsize_reg); /* clear hash table */ + + output(ClearCode); + + while (len) { + c = pc2nc[*data++]; len--; + in_count++; + + fcode = (long) ( ( (long) c << maxbits) + ent); + i = (((int) c << hshift) ^ ent); /* xor hashing */ + + if ( HashTabOf (i) == fcode ) { + ent = CodeTabOf (i); + continue; + } + + else if ( (long)HashTabOf (i) < 0 ) /* empty slot */ + goto nomatch; + + disp = hsize_reg - i; /* secondary hash (after G. Knott) */ + if ( i == 0 ) + disp = 1; + +probe: + if ( (i -= disp) < 0 ) + i += hsize_reg; + + if ( HashTabOf (i) == fcode ) { + ent = CodeTabOf (i); + continue; + } + + if ( (long)HashTabOf (i) >= 0 ) + goto probe; + +nomatch: + output(ent); + out_count++; + ent = c; + + if ( free_ent < maxmaxcode ) { + CodeTabOf (i) = free_ent++; /* code -> hashtable */ + HashTabOf (i) = fcode; + } + else + cl_block(); + } + + /* Put out the final code */ + output(ent); + out_count++; + output(EOFCode); +} + + +/***************************************************************** + * TAG( output ) + * + * Output the given code. + * Inputs: + * code: A n_bits-bit integer. If == -1, then EOF. This assumes + * that n_bits =< (long)wordsize - 1. + * Outputs: + * Outputs code to the file. + * Assumptions: + * Chars are 8 bits long. + * Algorithm: + * Maintain a BITS character long buffer (so that 8 codes will + * fit in it exactly). Use the VAX insv instruction to insert each + * code in turn. When the buffer fills up empty it and start over. + */ + +static +unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, + 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, + 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +static void output(code) +int code; +{ + cur_accum &= masks[cur_bits]; + + if (cur_bits > 0) + cur_accum |= ((long)code << cur_bits); + else + cur_accum = code; + + cur_bits += n_bits; + + while( cur_bits >= 8 ) { + char_out( (unsigned int) (cur_accum & 0xff) ); + cur_accum >>= 8; + cur_bits -= 8; + } + + /* + * If the next entry is going to be too big for the code size, + * then increase it, if possible. + */ + + if (free_ent > maxcode || clear_flg) { + + if( clear_flg ) { + maxcode = MAXCODE (n_bits = g_init_bits); + clear_flg = 0; + } + else { + n_bits++; + if ( n_bits == maxbits ) + maxcode = maxmaxcode; + else + maxcode = MAXCODE(n_bits); + } + } + + if( code == EOFCode ) { + /* At EOF, write the rest of the buffer */ + while( cur_bits > 0 ) { + char_out( (unsigned int)(cur_accum & 0xff) ); + cur_accum >>= 8; + cur_bits -= 8; + } + + flush_char(); + + fflush( g_outfile ); + +#ifdef FOO + if( ferror( g_outfile ) ) + FatalError("unable to write GIF file"); +#endif + } +} + + +/********************************/ +static void cl_block () /* table clear for block compress */ +{ + /* Clear out the hash table */ + + cl_hash ( (count_int) hsize ); + free_ent = ClearCode + 2; + clear_flg = 1; + + output(ClearCode); +} + + +/********************************/ +static void cl_hash(hsize) /* reset code table */ +register count_int hsize; +{ + register count_int *htab_p = htab+hsize; + register long i; + register long m1 = -1; + + i = hsize - 16; + do { /* might use Sys V memset(3) here */ + *(htab_p-16) = m1; + *(htab_p-15) = m1; + *(htab_p-14) = m1; + *(htab_p-13) = m1; + *(htab_p-12) = m1; + *(htab_p-11) = m1; + *(htab_p-10) = m1; + *(htab_p-9) = m1; + *(htab_p-8) = m1; + *(htab_p-7) = m1; + *(htab_p-6) = m1; + *(htab_p-5) = m1; + *(htab_p-4) = m1; + *(htab_p-3) = m1; + *(htab_p-2) = m1; + *(htab_p-1) = m1; + htab_p -= 16; + } while ((i -= 16) >= 0); + + for ( i += 16; i > 0; i-- ) + *--htab_p = m1; +} + + +/****************************************************************************** + * + * GIF Specific routines + * + ******************************************************************************/ + +/* + * Number of characters so far in this 'packet' + */ +static int a_count; + +/* + * Set up the 'byte output' routine + */ +static void char_init() +{ + a_count = 0; +} + +/* + * Define the storage for the packet accumulator + */ +static char accum[ 256 ]; + +/* + * Add a character to the end of the current packet, and if it is 254 + * characters, flush the packet to disk. + */ +static void char_out(c) +int c; +{ + accum[ a_count++ ] = c; + if( a_count >= 254 ) + flush_char(); +} + +/* + * Flush the packet to disk, and reset the accumulator + */ +static void flush_char() +{ + if( a_count > 0 ) { + fputc( a_count, g_outfile ); + fwrite( accum, 1, a_count, g_outfile ); + a_count = 0; + } +} diff --git a/tools/gifconv/readhdf.c b/tools/gifconv/readhdf.c new file mode 100644 index 0000000..a7101c9 --- /dev/null +++ b/tools/gifconv/readhdf.c @@ -0,0 +1,177 @@ +#include "gif.h" + +/* just a small cleanup routine before we leave */ +void cleanup(BYTE *ptr) { + if (ptr) + free(ptr); +} + +/* Function : ReadHDF +** Return: 0 on completion without error, -1 on error +** Input: CHAR *h5_file - HDF file name +** CHAR *dset_name - Name of the HDF Image dataset +** CHAR *pal_name - Name of the HDF palette +** Output : BYTE** data - the HDF Image to be converted +** BYTE palette[256][3] - the corresponding palette +** hsize_t* image_size - the size of each dimension of the image +** +** Future Notes: +** The way readHDF works right now is that it expects the user +** to know the exact path to the HDF image. Thus it does not +** parse the HDF file looking for image datasets and corresponding +** palettes. Also it takes in the default palette for the image +** specified, if the palette is missing, it makes a default greyscale +** palette and throws it in. +** +*/ +int ReadHDF(BYTE** data , + BYTE palette[256][3] , + hsize_t *image_size , + CHAR *h5_file , + CHAR *dset_name , + CHAR *pal_name) +{ + hid_t fHfile; /* H5 file to open */ + herr_t status; /* status variable */ + hid_t dspace; /* dataspace identifier for the the dataset */ + hid_t dset; /* dataset identifier */ + + hid_t pal_set; /* dataset for palette */ + hid_t pal_space;/* dataspace for palette */ + hsize_t pal_size; /* size of the palette */ + + hsize_t datasize; /* size of the image */ + hsize_t maxdims; /* dummy */ + + int pal_exist = 0; /* do we have a palette? */ + + /* check stuff */ + if (!h5_file || !dset_name || !image_size) { + fprintf(stderr , "NULL is not an acceptable input for HDFread. Aborting.\n"); + return -1; + } + + /* do we have a palette ? */ + if (pal_name) { + pal_exist = 1; + } + + /* try opening the file */ + /* H5 file open calls */ + if ((fHfile = H5Fopen(h5_file , H5F_ACC_RDONLY , H5P_DEFAULT)) < 0) { + fprintf(stderr , "Unable to open HDF file for input. Aborting.\n"); + return -1; + } + + /* open the dataset for reading */ + if ((dset = H5Dopen(fHfile , dset_name)) < 0) { + fprintf(stderr , "Unable to open dataset\n"); + return -1; + } + + /* get the dataspace */ + if ((dspace = H5Dget_space(dset)) < 0) { + fprintf(stderr , "Unable to get dataspace\n"); + return -1; + } + + /* get the dimension size of the image */ + if (H5Sget_simple_extent_dims(dspace , image_size , &maxdims) !=2 ) { + fprintf(stderr , "Unable to get dimension info\n"); + return -1; + } + + /* size needed to store the image */ + datasize = image_size[0] * image_size[1]; + + /* allocate memory to store the image */ + if ((*data = (BYTE*) malloc(datasize)) == NULL) { + fprintf(stderr , "Out of memory, exiting"); + return -1; + } + + /* get the actual image */ + if ((status = H5Dread(dset , H5Dget_type(dset) , H5S_ALL , H5S_ALL , H5P_DEFAULT , *data)) < 0) { + fprintf(stderr , "Unable to read data \n"); + cleanup(*data); + return -1; + } + + if (pal_exist) { + hsize_t pal_size[2]; + hsize_t max_pal_dims[2]; + hsize_t pal_datasize; + CHAR *pal_path; + + BYTE *temp_buf; + hsize_t temp_size; + + /* get the palette dataset */ + if ((pal_set = H5Dopen(fHfile , pal_name)) < 0) { + fprintf(stderr , "Unable to open dataset\n"); + pal_exist = 0; + return -1; + } + + /* get the dataspace */ + if ((pal_space = H5Dget_space(pal_set)) < 0) { + fprintf(stderr , "Unable to get dataspace\n"); + pal_exist = 0; + return -1; + } + + /* get the dimension size of the palette. */ + if (H5Sget_simple_extent_dims(pal_space , pal_size , &max_pal_dims) !=2 ) { + fprintf(stderr , "Unable to get dimension info\n"); + pal_exist = 0; + return -1; + } + + /* size needed to store the image */ + pal_datasize = pal_size[0] * pal_size[1]; + + /* copy stuff into a temp buffer and then copy 256*3 elements to palette */ + temp_size = H5Dget_storage_size(pal_set); + + temp_buf = (BYTE*) malloc (temp_size * sizeof(BYTE)); + + /* make sure that the palette is actually 256 X 3 so that we don't create overflows */ + if (pal_datasize > 256 * 3) + { + fprintf(stderr , "Palette seems to be more than 256X3 bytes\n"); + fprintf(stderr , "Truncating palette to 256 colors. This might cause a problem with the final image\n"); + pal_datasize = 256 * 3; + } + + /* get the actual palette */ + if ((status = H5Dread(pal_set , H5Dget_type(pal_set) , H5S_ALL , H5S_ALL , H5P_DEFAULT , temp_buf)) < 0) { + fprintf(stderr , "Unable to read data \n"); + cleanup(*data); + cleanup(temp_buf); + return -1; + } + + /* copy stuff into the actual palette */ + memcpy(palette , temp_buf , pal_datasize); + + /* get rid of the temp memory */ + cleanup(temp_buf); + /* end of if (pal_exist) */ + + } else { + int i; + /* if palette does not exist we just go ahead and create a uniform greyscale palette */ + for (i = 0 ; i < 256 ; i++) { + palette[i][0] = 255 - i; + palette[i][1] = 255 - i; + palette[i][2] = 255 - i; + } + } + + /* close everything */ + status = H5Dclose(dset); + status = H5Sclose(dspace); + status = H5Fclose(fHfile); + + return 0; +} diff --git a/tools/gifconv/writehdf.c b/tools/gifconv/writehdf.c new file mode 100644 index 0000000..7afccdf --- /dev/null +++ b/tools/gifconv/writehdf.c @@ -0,0 +1,410 @@ +#include "gif.h" +#include <string.h> +#include <stdlib.h> +#include <string.h> + +/******************************************************************* +** Function: write_text_attribute +** Use: Just a small wrapper to write text attributes easily +********************************************************************/ +int write_text_attribute(hid_t dataset_id , char *attr_name , char *attr_value) { + + /* variables for the attributes */ + hsize_t attr_dims_size; /* dimensions for the attribute */ + hid_t attr_dataspace_id; /* dataspaces needed for the various attributes */ + hid_t attr_attr_id; /* attribute id */ + herr_t status; /* check return status */ + hid_t attr_type_id; + + + /* check strings */ + if (!attr_name || !attr_value) + return -1; + + /* figure out size of the data */ + attr_dims_size = strlen(attr_value) + 1; + + /* set the type to string */ + attr_type_id = H5Tcopy(H5T_C_S1); + H5Tset_size(attr_type_id , attr_dims_size); + + /* create the dataspace for the attribute */ + attr_dataspace_id = H5Screate_simple(1 , &attr_dims_size , NULL); + + /* create the attribute */ + attr_attr_id = H5Acreate(dataset_id , attr_name , attr_type_id , attr_dataspace_id , H5P_DEFAULT); + + /* write out the attribute data */ + if ((status = H5Awrite(attr_attr_id , attr_type_id , attr_value)) < 0) + return -1; + + /* close the attribute */ + if ((status = H5Aclose(attr_attr_id)) < 0) + return -1; + + /* close the dataspace */ + if ((status = H5Sclose(attr_dataspace_id)) < 0) { + fprintf(stderr , "Unable to close attribute dataspace. Aborting \n"); + return -1; + } + + return 0; + +} + +int +WriteHDF(GifMemoryStruct, HDFName , GIFFileName) +GIFTOMEM GifMemoryStruct; +char *HDFName; +char *GIFFileName; +{ + GIFHEAD gifHead; /* GIF Header structure */ + GIFIMAGEDESC* gifImageDesc; /* Logical Image Descriptor struct */ + + long ImageCount , /* number of images */ + CommentCount, /* number of comments */ + ApplicationCount , /* number of application extensions */ + PlainTextCount; /* number of plain text extensions */ + + char ImageName[256], /* Image name for the GR Image */ + CommentName[256], + ApplicationName[256], + PlainTextName[256]; + + char GroupName[VSNAMELENMAX]; /* so that we can name the subgroups appropriately */ + + /* H5 variables */ + hid_t file_id; /* H5 file id */ + hid_t image_id; /* H5 id for the whole image */ + hid_t pal_id; /* H5 id for the palette */ + herr_t status; /* status variable */ + hobj_ref_t pal_ref; /* Create a reference for the palette */ + + /* temp counter */ + int i; + + + + + + + /* get the GIFMem stuff */ + gifHead = *(GifMemoryStruct.GifHeader); + + /* get some data from gifHead */ + ImageCount = (WORD)gifHead.ImageCount; + CommentCount = (WORD)gifHead.CommentCount; + ApplicationCount = (WORD)gifHead.ApplicationCount; + PlainTextCount = (WORD)gifHead.PlainTextCount; + + /* get the main group name from GIFFileName */ + GroupName[0]= '/'; + if (strncpy(GroupName , GIFFileName , VSNAMELENMAX-2) == NULL) { + fprintf(stderr , "strncpy failed\n"); + exit(1); + } + GroupName[VSNAMELENMAX] = '\0'; + + + if ((file_id = H5Fcreate(HDFName , H5F_ACC_TRUNC , H5P_DEFAULT , H5P_DEFAULT)) < 0) { + /* error occured opening the HDF File for write */ + fprintf(stderr , "HDF file could not be opened for writing\n"); + fprintf(stderr , "NOTE: GIF file must be present in the same directory as the binary on UNIX systems.\n"); + exit(1); + } + + /* create a group within the root group to hold the gif image */ + /* might want to make a different naming style out here */ + image_id = H5Gcreate(file_id, GroupName , 0); + + /* first create the global palette if there is one */ + if (gifHead.PackedField & 0x80) { /* global palette exists */ + hid_t dataspace_id; /* identifier for dataspace */ + hsize_t dims[2]; /* specify the dimensions of the palette */ + + hsize_t dimsr[1] = {1}; /* needed to store reference */ + hid_t ref_dataspace_id; /* dataspace id for references */ + hid_t ref_dataset_id; /* dataset id for references */ + + /* size of the palette is tablesize (rows) X 3 (columns) */ + dims[0] = gifHead.TableSize; + dims[1] = 3; + + /* create the dataspace */ + if ((dataspace_id = H5Screate_simple(2 , dims , NULL)) < 0) { + fprintf(stderr , "Could not create dataspace for palette. Aborting...\n"); + return -1; + } + + /* create the palette dataset */ + if ((pal_id = H5Dcreate(image_id , "Global Palette" , H5T_NATIVE_UINT8 , dataspace_id , H5P_DEFAULT )) < 0) { + fprintf(stderr , "Could not create palette dataset. Aborting...\n"); + return -1; + } + + /* write the palette data out */ + /****** Ask Elena about VOIDP ******/ + if ((status = H5Dwrite(pal_id , H5T_NATIVE_UINT8 , H5S_ALL , H5S_ALL , H5P_DEFAULT , (void *)gifHead.HDFPalette)) < 0) { + fprintf(stderr , "Error writing dataset. Aborting...\n"); + return -1; + } + + /* set palette attributes */ + + /* attribute CLASS = PALETTE */ + if ((write_text_attribute(pal_id , "CLASS" , "PALETTE")) < 0) { + fprintf(stderr , "Unable to write palette attributes. Aborting\n"); + return -1; + } + + /* attribute PAL_COLORMODEL = RGB */ + if ((write_text_attribute(pal_id , "PAL_COLORMODEL" , "RGB")) < 0) { + fprintf(stderr , "Unable to write palette attributes. Aborting\n"); + return -1; + } + + /* attribute PAL_TYPE = STANDARD8 */ + if ((write_text_attribute(pal_id , "PAL_TYPE" , "STANDARD8")) < 0) { + fprintf(stderr , "Unable to write palette attributes. Aborting\n"); + return -1; + } + + /* attribute PAL_VERSION = 1.0 */ + if ((write_text_attribute(pal_id , "PAL_VERSION" , "1.0")) < 0) { + fprintf(stderr , "Unable to write palette attributes. Aborting\n"); + return -1; + } + + /* create dataspace for the dataset to store references */ + ref_dataspace_id = H5Screate_simple(1 , dimsr , NULL); + + /* create a dataset to store the references */ + ref_dataset_id = H5Dcreate(image_id , "Palette Reference" , H5T_STD_REF_OBJ , ref_dataspace_id , H5P_DEFAULT); + + /* create a reference to the palette */ + if ((status = H5Rcreate(&pal_ref , image_id , "Global Palette" , H5R_OBJECT , -1)) < 0) { + fprintf(stderr , "Unable to create palette reference\n"); + return -1; + } + + /* write the reference out */ + if ((status = H5Dwrite(ref_dataset_id , H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL , H5P_DEFAULT, &pal_ref)) < 0) { + fprintf(stderr , "Unable to write Palette Reference"); + return -1; + } + + /* close dataset */ + if ((status = H5Dclose(ref_dataset_id)) < 0) { + fprintf(stderr , "Unable to close palette dataset.\n"); + return -1; + } + + /* close dataspace */ + if ((status = H5Sclose(ref_dataspace_id)) < 0) { + fprintf(stderr , "Unable to close palette dataspace.\n"); + return -1; + } + + /* close everything */ + if ((status = H5Dclose(pal_id)) < 0) { + fprintf(stderr , "Unable to close palette dataset. Aborting.\n"); + return -1; + } + + if ((status = H5Sclose(dataspace_id)) < 0) { + fprintf(stderr , "Unable to close palette dataspace. Aborting.\n"); + return -1; + } + + } + + for(i=0 ; i < ImageCount ; i++) { + /* variables for the images */ + hsize_t dims[2]; /* dimensions for the dataset */ + hid_t dataspace_id; /* identifier for the dataspace */ + hid_t sub_image_id; /* wierd name to distinguish from the group_id */ + + /* variables for the attributes */ + hsize_t attr_dims[2]; /* dimensions for the attribute */ + hid_t attr_dataspace_id; /* dataspaces needed for the various attributes */ + hid_t attr_attr_id; /* attribute id */ + BYTE minmax[2]; /* lower and upper minmax values */ + + /* initialise minmax */ + minmax[0] = 0 ; minmax[1] = 255; + + /* get the gifImageDesc */ + gifImageDesc = GifMemoryStruct.GifImageDesc[i]; + + /* set the dimensions */ + dims[0] = gifImageDesc->ImageHeight; + dims[1] = gifImageDesc->ImageWidth; + + /* create the empty dataspace */ + if ((dataspace_id = H5Screate_simple(2 , dims , NULL)) < 0) { + fprintf(stderr , "Could not create image dataspace. Aborting\n"); + return -1; + } + + /* create the image name */ + sprintf(ImageName , "Image%d" , i); + + /* create the image data set */ + if ((sub_image_id = H5Dcreate(image_id , ImageName , H5T_NATIVE_UINT8 , dataspace_id , H5P_DEFAULT)) < 0) { + fprintf(stderr , "Could not create dataset for image. Aborting... \n"); + return -1; + } + + /* write out the image */ + /****** Ask Elena about VOIDP ******/ + if ((status = H5Dwrite(sub_image_id , H5T_NATIVE_UINT8 , H5S_ALL , H5S_ALL , H5P_DEFAULT , (void *)(gifImageDesc->Image))) < 0) { + fprintf(stderr , "Error writing image. Aborting... \n"); + return -1; + } + + /* set the attributes */ + /* This info is available at http://hdf.ncsa.uiuc.edu/HDF5/doc/ImageSpec.html */ + /* The following attributes must be set for each image: + ** --------------------------------------- + ** Attribute Name Value + ** CLASS IMAGE + ** IMAGE_VERSION 1.0 + ** IMAGE_SUBCLASS IMAGE_BITMAP + ** PALETTE ref. to palette datasets + ** IMAGE_MINMAXRANGE [0,255] + ** --------------------------------------- + */ + + /**************************************** + ** Attribute: CLASS + ** Value : IMAGE + *****************************************/ + + if (write_text_attribute(sub_image_id , "CLASS" , "IMAGE") < 0) { + fprintf(stderr , "Unable to write CLASS = IMAGE attribute\n"); + return -1; + } + + /**************************************** + ** Attribute: IMAGE_VERSION + ** Value : 1.0 + *****************************************/ + + if (write_text_attribute(sub_image_id , "IMAGE_VERSION" , "1.0") < 0) { + fprintf(stderr , "Unable to write IMAGE_VERSION attribute\n"); + return -1; + } + + /**************************************** + ** Attribute: IMAGE_SUBCLASS + ** Value : IMAGE_BITMAP + *****************************************/ + + if (write_text_attribute(sub_image_id , "IMAGE_SUBCLASS" , "IMAGE_BITMAP") < 0) { + fprintf(stderr , "Unable to write IMAGE_SUBCLASS attribute\n"); + return -1; + } + + /**************************************** + ** Attribute: IMAGE_COLORMODEL + ** Value : RGB + *****************************************/ + + if (write_text_attribute(sub_image_id , "IMAGE_COLORMODEL" , "RGB") < 0) { + fprintf(stderr , "Unable to write IMAGE_SUBCLASS attribute\n"); + return -1; + } + + /**************************************** + ** Attribute: PALETTE + ** Value : Reference to Palette + *****************************************/ + + /**** MAKE SURE PALETTE EXISTS!!! ****/ + if (gifHead.PackedField & 0x80) { /* global palette exists */ + + attr_dims[0] = 1; + + /* create the dataspace for the attribute */ + attr_dataspace_id = H5Screate_simple(1 , attr_dims , NULL); + + /* create the attribute */ + attr_attr_id = H5Acreate(sub_image_id , "PALETTE" , H5T_STD_REF_OBJ , attr_dataspace_id , H5P_DEFAULT); + + if ((status = H5Awrite(attr_attr_id , H5T_STD_REF_OBJ , &pal_ref)) < 0) { + fprintf(stderr , "Unable to write attribute. Aborting \n"); + return -1; + } + + /* close the attribute */ + if ((status = H5Aclose(attr_attr_id)) < 0) { + fprintf(stderr , "Unable to close CLASS IMAGE attribute. Aborting.\n"); + return -1; + } + + /* close the dataspace */ + if ((status = H5Sclose(attr_dataspace_id)) < 0) { + fprintf(stderr , "Unable to close attribute dataspace. Aborting \n"); + return -1; + } + + } + + /**************************************** + ** Attribute: IMAGE_MINMAXRANGE + ** Value : minmax + *****************************************/ + + attr_dims[0] = 2; + + /* create the dataspace for the attribute */ + attr_dataspace_id = H5Screate_simple(1 , attr_dims , NULL); + + /* create the attribute */ + attr_attr_id = H5Acreate(sub_image_id , "IMAGE_MINMAXRANGE" , H5T_NATIVE_UINT8 , attr_dataspace_id , H5P_DEFAULT); + + if ((status = H5Awrite(attr_attr_id , H5T_NATIVE_UINT8 , minmax)) < 0) { + fprintf(stderr , "Unable to write attribute. Aborting \n"); + return -1; + } + + /* close the attribute */ + if ((status = H5Aclose(attr_attr_id)) < 0) { + fprintf(stderr , "Unable to close CLASS IMAGE attribute. Aborting.\n"); + return -1; + } + + /* close the dataspace */ + if ((status = H5Sclose(attr_dataspace_id)) < 0) { + fprintf(stderr , "Unable to close attribute dataspace. Aborting \n"); + return -1; + } + + + /* close everything */ + if ((status = H5Dclose(sub_image_id)) < 0) { + fprintf(stderr , "Unable to close image dataset. Aborting \n"); + return -1; + } + + if ((status = H5Sclose(dataspace_id)) < 0) { + fprintf(stderr , "Unable to close image dataspace. Aborting \n"); + return -1; + } + + } + + /* close the main image group */ + if ((status = H5Gclose(image_id)) < 0) { + fprintf(stderr , "Could not close the image group. Aborting...\n"); + return -1; + } + + /* close the H5 file */ + if ((status = H5Fclose(file_id)) < 0) { + fprintf(stderr , "Could not close HDF5 file. Aborting...\n"); + return -1; + } + + return(0); +} |