diff options
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); +} |