/* This file contains functions used to manipulate */ /* TIFF files and create multi-page TIFF files */ /* written by Peter vanVloten Feb 1999 */ /* Compiling instructions: bcc32 -c -w -a1 tifmerge.c OR cl /c /Zp1 /W4 tifmerge.c */ #include #include #include #include "TifMerge.h" typedef unsigned long DWORD; typedef unsigned short WORD; typedef int BOOL; #define TRUE 1 #define FALSE 0 /* TIFF 'version number' */ #define TIFF_VERSION 42 /* Tiff tags */ #define TTAG_TILEOFFSETS 324 #define TTAG_STRIPOFFSETS 273 #define TTAG_TILEBYTECOUNTS 325 #define TTAG_STRIPBYTECOUNTS 279 /* size of temporary copy buffer */ #define DATA_CHUNK 1024 /***** TIFF data structures *****/ /* TIFF file Header */ typedef struct { char szEndian[2]; /* Byte order II or MM */ WORD wMagicNumber; /* TIFF version ( always 42) */ DWORD dwIFD_Offset; /* Offset to first Image IFD */ } stTHeader; /* TIFF Tag Entry */ typedef struct { WORD wTagId; /* Tag identifier */ WORD wDataType; /* Tag Data type */ DWORD dwDataCount; /* Number of data items */ DWORD dwDataOffset; /* data or offset */ } stTiffTag; /* Image File Descriptor */ typedef struct { WORD wNumEntries; /* Number of tags in IFD */ stTiffTag* TagList; /* pointer to tag array */ DWORD dwNextIFD; /* next IFD, 0 if none */ DWORD dwFilePosNextIFD; /* position of next IFD */ } stTiffIFD; /***** end of TIFF data structures *****/ /***** private prototypes *****/ static DWORD TiffReadHeader( FILE* file, stTHeader* pTHeader); static void TiffFreeIFD( stTiffIFD* pIFD); static stTiffIFD* TiffReadIFD( FILE* file); static void TiffWriteIFD( FILE* file, stTiffIFD* pIFD); static BOOL TiffFixTag( stTiffTag* pTag, DWORD dwFileOffset); static BOOL TiffFixTagList( stTiffIFD* pIFD, DWORD dwFileOffset); static stTiffIFD* TiffReadLastIFD( FILE* file); static BOOL TiffFixIFDs( FILE* fil,DWORD pos,DWORD Ifd,DWORD ofst); static DWORD TiffAppendFile( FILE* OutFile, FILE* InFile); /***** end of private prototypes *****/ /* This functions reads in a given TIFF header */ /* and returns the offset to the first IFD */ DWORD TiffReadHeader( FILE* file, stTHeader* pTHeader) { fread( pTHeader, 1, sizeof( stTHeader), file); if( pTHeader->wMagicNumber != TIFF_VERSION) return 0; return pTHeader->dwIFD_Offset; } /* this function frees an IFD and all related tags*/ void TiffFreeIFD( stTiffIFD* pIFD) { if( pIFD->TagList) free( pIFD->TagList); free( pIFD); } /* this function allocates and reads from a file */ /* an IFD and its associated tags */ stTiffIFD* TiffReadIFD( FILE* file) { WORD wByteCount; stTiffIFD* pIFD = (stTiffIFD*)malloc( sizeof( stTiffIFD)); /* read the number of tags in the IFD */ fread( &pIFD->wNumEntries, 1,sizeof( pIFD->wNumEntries),file); /* allocate memory for an array of tags */ wByteCount = (WORD)(pIFD->wNumEntries * sizeof( stTiffTag)); pIFD->TagList = (stTiffTag*)malloc( wByteCount); /* read in the tags */ fread( pIFD->TagList, 1, wByteCount, file); /* store file position of next IFD pointer */ pIFD->dwFilePosNextIFD = ftell( file); /* read next IFD pointer */ fread( &(pIFD->dwNextIFD), 1, sizeof(pIFD->dwNextIFD), file); return pIFD; } /* This function writes the contents of an IFD */ void TiffWriteIFD( FILE* file, stTiffIFD* pIFD) { WORD wByteCount; /* write out the number of tags in the IFD */ fwrite( &pIFD->wNumEntries, 1,sizeof(pIFD->wNumEntries),file); /* write out the tags */ wByteCount = (WORD)(pIFD->wNumEntries * sizeof( stTiffTag)); fwrite( pIFD->TagList, 1, wByteCount, file); /* store file position of next IFD pointer */ pIFD->dwFilePosNextIFD = ftell( file); /* write next IFD pointer */ fwrite( &(pIFD->dwNextIFD), 1, sizeof(pIFD->dwNextIFD), file); } /* This function adds an offset to any tag that has */ /* absolute file offset data.This function should be */ /* modified for any private tags that contain file offsets */ BOOL TiffFixTag( stTiffTag* pTag, DWORD dwFileOffset) { switch( pTag->wTagId) { case TTAG_TILEOFFSETS: /* Tile offsets */ case TTAG_STRIPOFFSETS: /* Strip offsets */ pTag->dwDataOffset += dwFileOffset; break; case TTAG_TILEBYTECOUNTS: /* Tile byte counts */ case TTAG_STRIPBYTECOUNTS: /* Strip byte counts */ if( pTag->dwDataCount > 1) { pTag->dwDataOffset += dwFileOffset; } break; default: break; } return TRUE; } /* This function iterates through a Tag list */ /* and calls FixTag for each tag */ BOOL TiffFixTagList( stTiffIFD* pIFD, DWORD dwFileOffset) { int ii; for( ii=0; ii < pIFD->wNumEntries; ii++) { TiffFixTag( &(pIFD->TagList[ii]), dwFileOffset); } return TRUE; } /* This function steps through all the IFD in a TIFF */ /* file and returns the last IFD structure */ stTiffIFD* TiffReadLastIFD( FILE* file) { stTHeader THeader; stTiffIFD* pIFD; DWORD dwNextIFD; pIFD = NULL; /* Get TIFF File header */ dwNextIFD = TiffReadHeader( file, &THeader); while( dwNextIFD != 0) { fseek( file, dwNextIFD, SEEK_SET); pIFD = TiffReadIFD( file); dwNextIFD = pIFD->dwNextIFD; if( dwNextIFD != 0) TiffFreeIFD( pIFD); } return pIFD; } /* This function goes though all the IFDs and adds the */ /* new file offset to any address */ BOOL TiffFixIFDs(FILE* file,DWORD dwFPos,DWORD dwIFD,DWORD dwOffst) { stTiffIFD* pIFD; DWORD dwNextIFD; /* Initialize to first IFD */ dwNextIFD = dwIFD; while( dwNextIFD != 0) { dwNextIFD = dwNextIFD+dwOffst; /* Update the next IFD pointer */ fseek( file, dwFPos, SEEK_SET); fwrite( &dwNextIFD, 1, sizeof( dwNextIFD), file); /* goto the next IFD and read it */ fseek( file, dwNextIFD, SEEK_SET); pIFD = TiffReadIFD( file); TiffFixTagList( pIFD, dwOffst); /* save new IFD */ fseek( file, dwNextIFD, SEEK_SET); TiffWriteIFD( file, pIFD); dwNextIFD = pIFD->dwNextIFD; dwFPos = pIFD->dwFilePosNextIFD; TiffFreeIFD( pIFD); } return TRUE; } /* This function appends and inputfile to an outputfile */ /* it then returns an offset to the original IFD address */ DWORD TiffAppendFile( FILE* OutFile, FILE* InFile) { stTHeader THeader; DWORD dwFirstIFD; char szBuffer[DATA_CHUNK]; int nBytes; /* Get input TIFF File header */ dwFirstIFD = TiffReadHeader( InFile, &THeader); /* rewind to the begining of the input file */ fseek( InFile, 0, SEEK_SET); while((nBytes = fread( szBuffer, 1, DATA_CHUNK, InFile)) >0) { fwrite( szBuffer, 1, nBytes, OutFile); } return dwFirstIFD; } /* This is the main function called to append two TIFF files */ /* the first parameter is the output TIFF file, the second */ /* parameter is the TIFF file to be appended to the output */ /* returns 0 on success */ int TiffAppend( const char* lpOutFile, const char* lpInFile) { FILE *fInFile, *fOutFile; DWORD dwIFDPos, dwOff; DWORD dwFPosNextIFD; stTiffIFD* pLastIFD; /* Open target data file */ fOutFile = fopen( lpOutFile, "r+b"); if( fOutFile == NULL) return -1; /* save the offset to the last IFD */ pLastIFD = TiffReadLastIFD( fOutFile); /* Open source data file */ fInFile = fopen( lpInFile, "rb"); if( fInFile == NULL) return -1; /* seek to end of file */ fseek( fOutFile, 0, SEEK_END); /* save the end of file position */ dwOff = ftell( fOutFile); /* append data */ dwIFDPos = TiffAppendFile( fOutFile, fInFile); /* fix any file offsets */ dwFPosNextIFD = pLastIFD->dwFilePosNextIFD; TiffFixIFDs( fOutFile, dwFPosNextIFD, dwIFDPos, dwOff); fclose( fInFile); fclose( fOutFile); return 0; }