home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * "Gif-Lib" - Yet another gif library. *
- * *
- * Written by: Gershon Elber IBM PC 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: *
- * -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. *
- *****************************************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <alloc.h>
- #include <string.h>
- #include "gif_lib.h"
- #include "getarg.h"
-
- #define PROGRAM_NAME "GifComb"
- #define VERSION "ß Version 1.0, "
-
- extern unsigned int
- _stklen = 16384; /* Increase default stack size */
-
- static char
- *VersionStr =
- PROGRAM_NAME
- " IBMPC "
- VERSION
- " Gershon Elber, "
- __DATE__ ", " __TIME__ "\n"
- "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
- static char
- *CtrlStr =
- PROGRAM_NAME
- " m%-MaskGIFFile!s h%- GifFile!*s";
- static char
- *ProgramName;
-
- static int ReadUntilImage(GifFileType *GifFile);
- static int UnionColorMap(GifColorType *ColorIn1, int ColorIn1Size,
- GifColorType *ColorIn2, int ColorIn2Size,
- GifColorType **ColorUnionPtr, int *ColorUnionSize,
- PixelType 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, ColorIn2Size,
- MaskFlag = FALSE, HelpFlag = FALSE;
- char **FileName = NULL, *MaskFileName;
- PixelType ColorTransIn2[256];
- RowType LineIn1, LineIn2, LineMask, LineOut;
- GifColorType *ColorIn1, *ColorIn2, *ColorUnion;
- GifFileType *GifFileIn1 = NULL, *GifFileIn2 = NULL, *GifMaskFile = NULL,
- *GifFileOut = NULL;
-
- if (strlen(ProgramName = argv[0]) == 0) /* DOS 3.x only! */
- ProgramName = PROGRAM_NAME; /* Do something reasonable for 2.x */
-
- if ((Error = GAGetArgs(argc, argv, CtrlStr,
- &MaskFlag, &MaskFileName,
- &HelpFlag, &NumFiles, &FileName)) != FALSE ||
- (NumFiles != 2 && !HelpFlag)) {
- if (Error) GAPrintErrMsg(Error);
- else
- if (NumFiles != 2)
- MESSAGE("Error in command line parsing - two GIF file please\n");
- 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) == ERROR ||
- ReadUntilImage(GifFileIn2) == ERROR ||
- (MaskFlag && ReadUntilImage(GifMaskFile) == ERROR))
- QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
-
- if (GifFileIn1 -> IWidth != GifFileIn2 -> IWidth ||
- GifFileIn2 -> IHeight != GifFileIn2 -> IHeight ||
- (MaskFlag && (GifFileIn1 -> IWidth != GifMaskFile -> IWidth ||
- GifFileIn1 -> IHeight != GifMaskFile -> IHeight)))
- EXIT("Given GIF files have different image dimensions\n");
-
- /* Open stdout for the output file: */
- if ((GifFileOut = EGifOpenFileHandle(1)) == NULL)
- QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
-
- Size = sizeof(PixelType) * GifFileIn1 -> IWidth;
- if ((LineIn1 = (RowType) malloc(Size)) == NULL ||
- (LineIn2 = (RowType) malloc(Size)) == NULL ||
- (MaskFlag && (LineMask = (RowType) malloc(Size)) == NULL) ||
- (LineOut = (RowType) malloc(Size)) == NULL)
- 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 EXIT("Neither Screen nor Image color map exists - GIF file 1\n");
-
- if (GifFileIn2 -> IColorMap) {
- ColorIn2 = GifFileIn2 -> IColorMap;
- ColorIn2Size = 1 << GifFileIn2 -> IBitsPerPixel;
- }
- else
- if (GifFileIn2 -> SColorMap) {
- ColorIn2 = GifFileIn2 -> SColorMap;
- ColorIn2Size = 1 << GifFileIn2 -> SBitsPerPixel;
- }
- else EXIT("Neither Screen nor Image color map exists - GIF file 2\n");
-
- /* 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) == ERROR)
- 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) == 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) == 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: */
- fprintf(stderr, "\n%s: Image 1 at (%d, %d) [%dx%d]: ",
- ProgramName, GifFileOut -> ILeft, GifFileOut -> ITop,
- GifFileOut -> IWidth, GifFileOut -> IHeight);
- for (i=0; i<GifFileIn1 -> IHeight; i++) {
- if (DGifGetLine(GifFileIn1, LineIn1, GifFileIn1 -> IWidth) == ERROR ||
- DGifGetLine(GifFileIn2, LineIn2, GifFileIn2 -> IWidth) == ERROR ||
- (MaskFlag &&
- DGifGetLine(GifMaskFile, LineMask, GifMaskFile -> IWidth)
- == 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)
- == ERROR)
- QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
- fprintf(stderr, "\b\b\b\b%-4d", i);
- }
-
- if (DGifCloseFile(GifFileIn1) == ERROR ||
- DGifCloseFile(GifFileIn2) == ERROR ||
- EGifCloseFile(GifFileOut) == ERROR ||
- (MaskFlag && DGifCloseFile(GifMaskFile) == 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;
- ByteType *Extension;
-
- /* Scan the content of the GIF file, until image descriptor is detected: */
- do {
- if (DGifGetRecordType(GifFile, &RecordType) == ERROR)
- return 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) == ERROR)
- return ERROR;
-
- while (Extension != NULL)
- if (DGifGetExtensionNext(GifFile, &Extension) == ERROR)
- return ERROR;
- break;
- case TERMINATE_RECORD_TYPE:
- break;
- default: /* Should be traps by DGifGetRecordType */
- break;
- }
- }
- while (RecordType != TERMINATE_RECORD_TYPE);
-
- return 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, ERROR is returned, 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,
- PixelType 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 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 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);
- }
-