www.pudn.com > giflib12.zip > GIFCOMB.C


/***************************************************************************** 
*   "Gif-Lib" - Yet another gif library.				     * 
*									     * 
* Written by:  Gershon Elber				Ver 0.1, Jul. 1989   * 
****************************************************************************** 
* Program to combine 2 GIF images into single one, using optional mask GIF   * 
* file. Result colormap will be the union of the two images colormaps.	     * 
* Both images should have exactly the same size, although they may be mapped * 
* differently on screen. Only First GIF screen descriptor info. is used.     * 
* Options:								     * 
* -q : quite printing mode.						     * 
* -m mask : optional boolean image, defines where second GIF should be used. * 
* -h : on line help.							     * 
****************************************************************************** 
* History:								     * 
* 12 Jul 89 - Version 1.0 by Gershon Elber.				     * 
*****************************************************************************/ 
 
#ifdef __MSDOS__ 
#include  
#include  
#endif /* _MSDOS__ */ 
 
#include  
#include  
#include  
#include "gif_lib.h" 
#include "getarg.h" 
 
#define PROGRAM_NAME	"GifComb" 
 
#ifdef __MSDOS__ 
extern unsigned int 
    _stklen = 16384;			     /* Increase default stack size. */ 
#endif /* __MSDOS__ */ 
 
#ifdef SYSV 
static char *VersionStr = 
        "Gif library module,\t\tGershon Elber\n\ 
	(C) Copyright 1989 Gershon Elber, Non commercial use only.\n"; 
static char 
    *CtrlStr = "GifComb q%- m%-MaskGIFFile!s h%- GifFile!*s"; 
#else 
static char 
    *VersionStr = 
	PROGRAM_NAME 
	GIF_LIB_VERSION 
	"	Gershon Elber,	" 
	__DATE__ ",   " __TIME__ "\n" 
	"(C) Copyright 1989 Gershon Elber, Non commercial use only.\n"; 
static char 
    *CtrlStr = 
	PROGRAM_NAME 
	" q%- m%-MaskGIFFile!s h%- GifFile!*s"; 
#endif /* SYSV */ 
 
static int ReadUntilImage(GifFileType *GifFile); 
static int UnionColorMap(GifColorType *ColorIn1, int ColorIn1Size, 
			 GifColorType *ColorIn2, int ColorIn2Size, 
			 GifColorType **ColorUnionPtr, int *ColorUnionSize, 
			 GifPixelType ColorTransIn2[]); 
static void QuitGifError(GifFileType *GifFileIn1, GifFileType *GifFileIn2, 
			 GifFileType *GifMaskFile, GifFileType *GifFileOut); 
 
/****************************************************************************** 
* Interpret the command line and scan the given GIF file.		      * 
******************************************************************************/ 
void main(int argc, char **argv) 
{ 
    int	i, j, Error, NumFiles, Size, ColorUnionSize, 
	ColorIn1Size = 0, ColorIn2Size = 0, 
	MaskFlag = FALSE, HelpFlag = FALSE; 
    char **FileName = NULL, *MaskFileName; 
    GifPixelType ColorTransIn2[256]; 
    GifRowType LineIn1 = NULL, LineIn2 = NULL, LineMask = NULL, LineOut = NULL; 
    GifColorType *ColorIn1 = NULL, *ColorIn2 = NULL, *ColorUnion; 
    GifFileType *GifFileIn1 = NULL, *GifFileIn2 = NULL, *GifMaskFile = NULL, 
	*GifFileOut = NULL; 
 
    if ((Error = GAGetArgs(argc, argv, CtrlStr, 
		&GifQuitePrint, &MaskFlag, &MaskFileName, 
		&HelpFlag, &NumFiles, &FileName)) != FALSE || 
		(NumFiles != 2 && !HelpFlag)) { 
	if (Error) 
	    GAPrintErrMsg(Error); 
	else if (NumFiles != 2) 
	    GIF_MESSAGE("Error in command line parsing - two GIF file please."); 
	GAPrintHowTo(CtrlStr); 
	exit(1); 
    } 
 
    if (HelpFlag) { 
	fprintf(stderr, VersionStr); 
	GAPrintHowTo(CtrlStr); 
	exit(0); 
    } 
 
    /* Open all input files (two GIF to combine, and optional mask): */ 
    if ((GifFileIn1 = DGifOpenFileName(FileName[0])) == NULL || 
	(GifFileIn2 = DGifOpenFileName(FileName[1])) == NULL || 
	(MaskFlag && (GifMaskFile = DGifOpenFileName(MaskFileName)) == NULL)) 
	QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut); 
 
    if (ReadUntilImage(GifFileIn1) == GIF_ERROR || 
	ReadUntilImage(GifFileIn2) == GIF_ERROR || 
	(MaskFlag && ReadUntilImage(GifMaskFile) == GIF_ERROR)) 
	QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut); 
 
    if (GifFileIn1 -> IWidth != GifFileIn2 -> IWidth || 
	GifFileIn2 -> IHeight != GifFileIn2 -> IHeight || 
	(MaskFlag && (GifFileIn1 -> IWidth != GifMaskFile -> IWidth || 
		      GifFileIn1 -> IHeight != GifMaskFile -> IHeight))) 
	GIF_EXIT("Given GIF files have different image dimensions."); 
 
    /* Open stdout for the output file: */ 
    if ((GifFileOut = EGifOpenFileHandle(1)) == NULL) 
	QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut); 
 
    Size = sizeof(GifPixelType) * GifFileIn1 -> IWidth; 
    if ((LineIn1 = (GifRowType) malloc(Size)) == NULL || 
	(LineIn2 = (GifRowType) malloc(Size)) == NULL || 
	(MaskFlag && (LineMask = (GifRowType) malloc(Size)) == NULL) || 
	(LineOut = (GifRowType) malloc(Size)) == NULL) 
	GIF_EXIT("Failed to allocate memory required, aborted."); 
 
    if (GifFileIn1 -> IColorMap) { 
	ColorIn1 = GifFileIn1 -> IColorMap; 
	ColorIn1Size = 1 << GifFileIn1 -> IBitsPerPixel; 
    } 
    else if (GifFileIn1 -> SColorMap) { 
	ColorIn1 = GifFileIn1 -> SColorMap; 
	ColorIn1Size = 1 << GifFileIn1 -> SBitsPerPixel; 
    } 
    else 
	GIF_EXIT("Neither Screen nor Image color map exists - GIF file 1."); 
 
    if (GifFileIn2 -> IColorMap) { 
	ColorIn2 = GifFileIn2 -> IColorMap; 
	ColorIn2Size = 1 << GifFileIn2 -> IBitsPerPixel; 
    } 
    else if (GifFileIn2 -> SColorMap) { 
	ColorIn2 = GifFileIn2 -> SColorMap; 
	ColorIn2Size = 1 << GifFileIn2 -> SBitsPerPixel; 
    } 
    else 
	GIF_EXIT("Neither Screen nor Image color map exists - GIF file 2."); 
 
    /* Create union of the two given color maps. ColorIn1 will be copied as  */ 
    /* is while ColorIn2 will be mapped using ColorTransIn2 table.	     */ 
    /* ColorUnion is allocated by the procedure itself.			     */ 
    if (UnionColorMap(ColorIn1, ColorIn1Size, ColorIn2, ColorIn2Size, 
		&ColorUnion, &ColorUnionSize, ColorTransIn2) == GIF_ERROR) 
	GIF_EXIT("Unioned color map is two big (>256 colors)."); 
 
    /* Dump out new image and screen descriptors: */ 
    if (EGifPutScreenDesc(GifFileOut, 
	GifFileIn1 -> SWidth, GifFileIn1 -> SHeight, 
	ColorUnionSize, GifFileIn1 -> SBackGroundColor, 
	ColorUnionSize, ColorUnion) == GIF_ERROR) 
	QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut); 
    free((char *) ColorUnion);		    /* We dont need this any more... */ 
 
    if (EGifPutImageDesc(GifFileOut, 
	GifFileIn1 -> ILeft, GifFileIn1 -> ITop, 
	GifFileIn1 -> IWidth, GifFileIn1 -> IHeight, 
	GifFileIn1 -> IInterlace, GifFileIn1 -> IBitsPerPixel, NULL) == GIF_ERROR) 
	QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut); 
 
 
    /* Time to do it: read 2 scan lines from 2 files (and optionally from    */ 
    /* the mask file, merge them and them result out. Do it Height times:    */ 
    GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]:     ", 
	PROGRAM_NAME, GifFileOut -> ILeft, GifFileOut -> ITop, 
				GifFileOut -> IWidth, GifFileOut -> IHeight); 
    for (i = 0; i < GifFileIn1 -> IHeight; i++) { 
	if (DGifGetLine(GifFileIn1, LineIn1, GifFileIn1 -> IWidth) == GIF_ERROR || 
	    DGifGetLine(GifFileIn2, LineIn2, GifFileIn2 -> IWidth) == GIF_ERROR || 
	    (MaskFlag && 
	     DGifGetLine(GifMaskFile, LineMask, GifMaskFile -> IWidth) 
								== GIF_ERROR)) 
	    QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut); 
	if (MaskFlag) { 
	    /* Every time Mask has non background color, use LineIn1 pixel,  */ 
	    /* otherwise use LineIn2 pixel instead.			     */ 
	    for (j = 0; j < GifFileIn1 -> IWidth; j++) { 
		if (LineMask[j] != GifMaskFile -> SBackGroundColor) 
		    LineOut[j] = LineIn1[j]; 
		else 
		    LineOut[j] = ColorTransIn2[LineIn2[j]]; 
	    } 
	} 
	else { 
	    /* Every time Color of Image 1 is equal to background - take it  */ 
	    /* From Image 2 instead of the background.			     */ 
	    for (j = 0; j < GifFileIn1 -> IWidth; j++) { 
		if (LineIn1[j] != GifFileIn1 -> SBackGroundColor) 
		    LineOut[j] = LineIn1[j]; 
		else 
		    LineOut[j] = ColorTransIn2[LineIn2[j]]; 
	    } 
	} 
	if (EGifPutLine(GifFileOut, LineOut, GifFileOut -> IWidth) 
								== GIF_ERROR) 
	QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut); 
	GifQprintf("\b\b\b\b%-4d", i); 
    } 
 
    if (DGifCloseFile(GifFileIn1) == GIF_ERROR || 
	DGifCloseFile(GifFileIn2) == GIF_ERROR || 
	EGifCloseFile(GifFileOut) == GIF_ERROR || 
	(MaskFlag && DGifCloseFile(GifMaskFile) == GIF_ERROR)) 
	QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut); 
} 
 
/****************************************************************************** 
* Read until first image in GIF file is detected and read its descriptor.     * 
******************************************************************************/ 
static int ReadUntilImage(GifFileType *GifFile) 
{ 
    int ExtCode; 
    GifRecordType RecordType; 
    GifByteType *Extension; 
 
    /* Scan the content of the GIF file, until image descriptor is detected: */ 
    do { 
	if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) 
	    return GIF_ERROR; 
 
	switch (RecordType) { 
	    case IMAGE_DESC_RECORD_TYPE: 
		return DGifGetImageDesc(GifFile); 
	    case EXTENSION_RECORD_TYPE: 
		/* Skip any extension blocks in file: */ 
		if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) 
		    return GIF_ERROR; 
 
		while (Extension != NULL) 
		    if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) 
			return GIF_ERROR; 
		break; 
	    case TERMINATE_RECORD_TYPE: 
		break; 
	    default:		    /* Should be traps by DGifGetRecordType. */ 
		break; 
	} 
    } 
    while (RecordType != TERMINATE_RECORD_TYPE); 
 
    return GIF_ERROR;		  /* We should be here - no image was found! */ 
} 
 
/****************************************************************************** 
* Create union of the two given color maps and return it. If result can not   * 
* fit into 256 colors, GIF_ERROR is returned, GIF_OK otherwise.		      * 
* ColorIn1 is copied as it to ColorUnion, while colors from ColorIn2 are      * 
* copied iff they dont exists before. ColorTransIn2 is used to map old	      * 
* ColorIn2 into ColorUnion color map table.				      * 
******************************************************************************/ 
static int UnionColorMap(GifColorType *ColorIn1, int ColorIn1Size, 
			 GifColorType *ColorIn2, int ColorIn2Size, 
			 GifColorType **ColorUnionPtr, int *ColorUnionSize, 
			 GifPixelType ColorTransIn2[]) 
{ 
    int i, j, CrntSlot; 
    GifColorType *ColorUnion; 
 
    /* Allocate table which will hold result for sure: */ 
    *ColorUnionPtr = ColorUnion = (GifColorType *) malloc(sizeof(GifColorType) 
	* (ColorIn1Size > ColorIn2Size ? ColorIn1Size : ColorIn2Size) * 2); 
 
    /* Copy ColorIn1 to ColorUnionSize; */ 
    for (i = 0; i < ColorIn1Size; i++) ColorUnion[i] = ColorIn1[i]; 
    CrntSlot = ColorIn1Size;			      /* Current Empty slot. */ 
 
    /* Copy ColorIn2 to ColorUnionSize (use old colors if exists): */ 
    for (i = 0; i < ColorIn2Size && CrntSlot<=256; i++) { 
	/* Let see if this color already exists: */ 
	for (j = 0; j < ColorIn1Size; j++) { 
	    /* If memcmp does not exists for you, use the following: */ 
	    /* 
	    if (ColorIn1[j].Red   == ColorIn2[i].Red && 
		ColorIn1[j].Green == ColorIn2[i].Green && 
		ColorIn1[j].Blue  == ColorIn2[i].Blue) break; 
	    */ 
	    if (memcmp(&ColorIn1[j], &ColorIn2[i], 3) == 0) break; 
	} 
	if (j < ColorIn1Size) { 
	    /* We found this color aleardy exists in ColorIn1: */ 
	    ColorTransIn2[i] = j; 
	} 
	else { 
	    /* Its new - copy it to a new slot: */ 
	    ColorUnion[CrntSlot] = ColorIn2[i]; 
	    ColorTransIn2[i] = CrntSlot++; 
	} 
    } 
 
    if (CrntSlot > 256) return GIF_ERROR; 
 
    /* Complete the color map to a power of two: */ 
    for (i = 1; i <= 8; i++) if ((1 << i) >= CrntSlot) break; 
    for (j = CrntSlot; j < (1 << i); j++) 
	ColorUnion[j].Red = ColorUnion[j].Green = ColorUnion[j].Blue = 0; 
 
    *ColorUnionSize = i; 
 
    return GIF_OK; 
} 
 
/****************************************************************************** 
* Close both input and output file (if open), and exit.			      * 
******************************************************************************/ 
static void QuitGifError(GifFileType *GifFileIn1, GifFileType *GifFileIn2, 
			 GifFileType *GifMaskFile, GifFileType *GifFileOut) 
{ 
    PrintGifError(); 
    if (GifFileIn1 != NULL) DGifCloseFile(GifFileIn1); 
    if (GifFileIn2 != NULL) DGifCloseFile(GifFileIn2); 
    if (GifMaskFile != NULL) DGifCloseFile(GifMaskFile); 
    if (GifFileOut != NULL) EGifCloseFile(GifFileOut); 
    exit(1); 
}