home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / graphics / gif-util.zip / GIFCOMB.C < prev    next >
C/C++ Source or Header  |  1989-08-01  |  12KB  |  314 lines

  1. /*****************************************************************************
  2. *   "Gif-Lib" - Yet another gif library.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber            IBM PC Ver 0.1,    Jul. 1989    *
  5. ******************************************************************************
  6. * Program to combine 2 GIF images into single one, using optional mask GIF   *
  7. * file. Result colormap will be the union of the two images colormaps.         *
  8. * Both images should have exactly the same size, although they may be mapped *
  9. * differently on screen. Only First GIF screen descriptor info. is used.     *
  10. * Options:                                     *
  11. * -m mask : optional boolean image, defines where second GIF should be used. *
  12. * -h : on line help.                                 *
  13. ******************************************************************************
  14. * History:                                     *
  15. * 12 Jul 89 - Version 1.0 by Gershon Elber.                     *
  16. *****************************************************************************/
  17.  
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <ctype.h>
  21. #include <alloc.h>
  22. #include <string.h>
  23. #include "gif_lib.h"
  24. #include "getarg.h"
  25.  
  26. #define PROGRAM_NAME    "GifComb"
  27. #define VERSION        "ß Version 1.0, "
  28.  
  29. extern unsigned int
  30.     _stklen = 16384;                  /* Increase default stack size */
  31.  
  32. static char
  33.     *VersionStr =
  34.     PROGRAM_NAME
  35.     "    IBMPC "
  36.     VERSION
  37.     "    Gershon Elber,    "
  38.     __DATE__ ",   " __TIME__ "\n"
  39.     "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  40. static char
  41.     *CtrlStr =
  42.     PROGRAM_NAME
  43.     " m%-MaskGIFFile!s h%- GifFile!*s";
  44. static char
  45.     *ProgramName;
  46.  
  47. static int ReadUntilImage(GifFileType *GifFile);
  48. static int UnionColorMap(GifColorType *ColorIn1, int ColorIn1Size,
  49.              GifColorType *ColorIn2, int ColorIn2Size,
  50.              GifColorType **ColorUnionPtr, int *ColorUnionSize,
  51.              PixelType ColorTransIn2[]);
  52. static void QuitGifError(GifFileType *GifFileIn1, GifFileType *GifFileIn2,
  53.              GifFileType *GifMaskFile, GifFileType *GifFileOut);
  54.  
  55. /******************************************************************************
  56. * Interpret the command line and scan the given GIF file.              *
  57. ******************************************************************************/
  58. void main(int argc, char **argv)
  59. {
  60.     int    i, j, Error, NumFiles, Size, ColorUnionSize,
  61.     ColorIn1Size, ColorIn2Size,
  62.     MaskFlag = FALSE, HelpFlag = FALSE;
  63.     char **FileName = NULL, *MaskFileName;
  64.     PixelType ColorTransIn2[256];
  65.     RowType LineIn1, LineIn2, LineMask, LineOut;
  66.     GifColorType *ColorIn1, *ColorIn2, *ColorUnion;
  67.     GifFileType *GifFileIn1 = NULL, *GifFileIn2 = NULL, *GifMaskFile = NULL,
  68.     *GifFileOut = NULL;
  69.  
  70.     if (strlen(ProgramName = argv[0]) == 0)            /* DOS 3.x only! */
  71.     ProgramName = PROGRAM_NAME;      /* Do something reasonable for 2.x */
  72.  
  73.     if ((Error = GAGetArgs(argc, argv, CtrlStr,
  74.         &MaskFlag, &MaskFileName,
  75.         &HelpFlag, &NumFiles, &FileName)) != FALSE ||
  76.         (NumFiles != 2 && !HelpFlag)) {
  77.     if (Error) GAPrintErrMsg(Error);
  78.     else
  79.     if (NumFiles != 2)
  80.         MESSAGE("Error in command line parsing - two GIF file please\n");
  81.     GAPrintHowTo(CtrlStr);
  82.     exit(1);
  83.     }
  84.  
  85.     if (HelpFlag) {
  86.     fprintf(stderr, VersionStr);
  87.     GAPrintHowTo(CtrlStr);
  88.     exit(0);
  89.     }
  90.  
  91.     /* Open all input files (two GIF to combine, and optional mask): */
  92.     if ((GifFileIn1 = DGifOpenFileName(FileName[0])) == NULL ||
  93.     (GifFileIn2 = DGifOpenFileName(FileName[1])) == NULL ||
  94.     (MaskFlag && (GifMaskFile = DGifOpenFileName(MaskFileName)) == NULL))
  95.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  96.  
  97.     if (ReadUntilImage(GifFileIn1) == ERROR ||
  98.     ReadUntilImage(GifFileIn2) == ERROR ||
  99.     (MaskFlag && ReadUntilImage(GifMaskFile) == ERROR))
  100.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  101.  
  102.     if (GifFileIn1 -> IWidth != GifFileIn2 -> IWidth ||
  103.     GifFileIn2 -> IHeight != GifFileIn2 -> IHeight ||
  104.     (MaskFlag && (GifFileIn1 -> IWidth != GifMaskFile -> IWidth ||
  105.               GifFileIn1 -> IHeight != GifMaskFile -> IHeight)))
  106.     EXIT("Given GIF files have different image dimensions\n");
  107.  
  108.     /* Open stdout for the output file: */
  109.     if ((GifFileOut = EGifOpenFileHandle(1)) == NULL)
  110.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  111.  
  112.     Size = sizeof(PixelType) * GifFileIn1 -> IWidth;
  113.     if ((LineIn1 = (RowType) malloc(Size)) == NULL ||
  114.     (LineIn2 = (RowType) malloc(Size)) == NULL ||
  115.     (MaskFlag && (LineMask = (RowType) malloc(Size)) == NULL) ||
  116.     (LineOut = (RowType) malloc(Size)) == NULL)
  117.     EXIT("Failed to allocate memory required, aborted");
  118.  
  119.     if (GifFileIn1 -> IColorMap) {
  120.     ColorIn1 = GifFileIn1 -> IColorMap;
  121.     ColorIn1Size = 1 << GifFileIn1 -> IBitsPerPixel;
  122.     }
  123.     else
  124.     if (GifFileIn1 -> SColorMap) {
  125.     ColorIn1 = GifFileIn1 -> SColorMap;
  126.     ColorIn1Size = 1 << GifFileIn1 -> SBitsPerPixel;
  127.     }
  128.     else EXIT("Neither Screen nor Image color map exists - GIF file 1\n");
  129.  
  130.     if (GifFileIn2 -> IColorMap) {
  131.     ColorIn2 = GifFileIn2 -> IColorMap;
  132.     ColorIn2Size = 1 << GifFileIn2 -> IBitsPerPixel;
  133.     }
  134.     else
  135.     if (GifFileIn2 -> SColorMap) {
  136.     ColorIn2 = GifFileIn2 -> SColorMap;
  137.     ColorIn2Size = 1 << GifFileIn2 -> SBitsPerPixel;
  138.     }
  139.     else EXIT("Neither Screen nor Image color map exists - GIF file 2\n");
  140.  
  141.     /* Create union of the two given color maps. ColorIn1 will be copied as  */
  142.     /* is while ColorIn2 will be mapped using ColorTransIn2 table.         */
  143.     /* ColorUnion is allocated by the procedure itself.                 */
  144.     if (UnionColorMap(ColorIn1, ColorIn1Size, ColorIn2, ColorIn2Size,
  145.             &ColorUnion, &ColorUnionSize, ColorTransIn2) == ERROR)
  146.     EXIT("Unioned color map is two big (>256 colors)");
  147.  
  148.     /* Dump out new image and screen descriptors: */
  149.     if (EGifPutScreenDesc(GifFileOut,
  150.     GifFileIn1 -> SWidth, GifFileIn1 -> SHeight,
  151.     ColorUnionSize, GifFileIn1 -> SBackGroundColor,
  152.     ColorUnionSize, ColorUnion) == ERROR)
  153.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  154.     free((char *) ColorUnion);            /* We dont need this any more... */
  155.  
  156.     if (EGifPutImageDesc(GifFileOut,
  157.     GifFileIn1 -> ILeft, GifFileIn1 -> ITop,
  158.     GifFileIn1 -> IWidth, GifFileIn1 -> IHeight,
  159.     GifFileIn1 -> IInterlace, GifFileIn1 -> IBitsPerPixel, NULL) == ERROR)
  160.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  161.  
  162.  
  163.     /* Time to do it: read 2 scan lines from 2 files (and optionally from    */
  164.     /* the mask file, merge them and them result out. Do it Height times:    */
  165.     fprintf(stderr, "\n%s: Image 1 at (%d, %d) [%dx%d]:     ",
  166.     ProgramName, GifFileOut -> ILeft, GifFileOut -> ITop,
  167.                 GifFileOut -> IWidth, GifFileOut -> IHeight);
  168.     for (i=0; i<GifFileIn1 -> IHeight; i++) {
  169.     if (DGifGetLine(GifFileIn1, LineIn1, GifFileIn1 -> IWidth) == ERROR ||
  170.         DGifGetLine(GifFileIn2, LineIn2, GifFileIn2 -> IWidth) == ERROR ||
  171.         (MaskFlag &&
  172.          DGifGetLine(GifMaskFile, LineMask, GifMaskFile -> IWidth)
  173.                                 == ERROR))
  174.         QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  175.     if (MaskFlag) {
  176.         /* Every time Mask has non background color, use LineIn1 pixel,  */
  177.         /* otherwise use LineIn2 pixel instead.                 */
  178.         for (j=0; j<GifFileIn1 -> IWidth; j++) {
  179.         if (LineMask[j] != GifMaskFile -> SBackGroundColor)
  180.              LineOut[j] = LineIn1[j];
  181.         else LineOut[j] = ColorTransIn2[LineIn2[j]];
  182.         }
  183.     }
  184.     else {
  185.         /* Every time Color of Image 1 is equal to background - take it  */
  186.         /* From Image 2 instead of the background.                 */
  187.         for (j=0; j<GifFileIn1 -> IWidth; j++) {
  188.         if (LineIn1[j] != GifFileIn1 -> SBackGroundColor)
  189.              LineOut[j] = LineIn1[j];
  190.         else LineOut[j] = ColorTransIn2[LineIn2[j]];
  191.         }
  192.     }
  193.     if (EGifPutLine(GifFileOut, LineOut, GifFileOut -> IWidth)
  194.                                 == ERROR)
  195.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  196.     fprintf(stderr, "\b\b\b\b%-4d", i);
  197.     }
  198.  
  199.     if (DGifCloseFile(GifFileIn1) == ERROR ||
  200.     DGifCloseFile(GifFileIn2) == ERROR ||
  201.     EGifCloseFile(GifFileOut) == ERROR ||
  202.     (MaskFlag && DGifCloseFile(GifMaskFile) == ERROR))
  203.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  204. }
  205.  
  206. /******************************************************************************
  207. * Read until first image in GIF file is detected and read its descriptor.     *
  208. ******************************************************************************/
  209. static int ReadUntilImage(GifFileType *GifFile)
  210. {
  211.     int ExtCode;
  212.     GifRecordType RecordType;
  213.     ByteType *Extension;
  214.  
  215.     /* Scan the content of the GIF file, until image descriptor is detected: */
  216.     do {
  217.     if (DGifGetRecordType(GifFile, &RecordType) == ERROR)
  218.         return ERROR;
  219.  
  220.     switch (RecordType) {
  221.         case IMAGE_DESC_RECORD_TYPE:
  222.         return DGifGetImageDesc(GifFile);
  223.         case EXTENSION_RECORD_TYPE:
  224.         /* Skip any extension blocks in file: */
  225.         if (DGifGetExtension(GifFile, &ExtCode, &Extension) == ERROR)
  226.             return ERROR;
  227.  
  228.         while (Extension != NULL)
  229.             if (DGifGetExtensionNext(GifFile, &Extension) == ERROR)
  230.             return ERROR;
  231.         break;
  232.         case TERMINATE_RECORD_TYPE:
  233.         break;
  234.         default:             /* Should be traps by DGifGetRecordType */
  235.         break;
  236.     }
  237.     }
  238.     while (RecordType != TERMINATE_RECORD_TYPE);
  239.  
  240.     return ERROR;          /* We should be here - no image was found! */
  241. }
  242.  
  243. /******************************************************************************
  244. * Create union of the two given color maps and return it. If result can not   *
  245. * fit into 256 colors, ERROR is returned, OK otherwise.                  *
  246. * ColorIn1 is copied as it to ColorUnion, while colors from ColorIn2 are      *
  247. * copied iff they dont exists before. ColorTransIn2 is used to map old          *
  248. * ColorIn2 into ColorUnion color map table.                      *
  249. ******************************************************************************/
  250. static int UnionColorMap(GifColorType *ColorIn1, int ColorIn1Size,
  251.              GifColorType *ColorIn2, int ColorIn2Size,
  252.              GifColorType **ColorUnionPtr, int *ColorUnionSize,
  253.              PixelType ColorTransIn2[])
  254. {
  255.     int i, j, CrntSlot;
  256.     GifColorType *ColorUnion;
  257.  
  258.     /* Allocate table which will hold result for sure: */
  259.     *ColorUnionPtr = ColorUnion = (GifColorType *) malloc(sizeof(GifColorType)
  260.     * (ColorIn1Size > ColorIn2Size ? ColorIn1Size : ColorIn2Size) * 2);
  261.  
  262.     /* Copy ColorIn1 to ColorUnionSize; */
  263.     for (i=0; i<ColorIn1Size; i++) ColorUnion[i] = ColorIn1[i];
  264.     CrntSlot = ColorIn1Size;                   /* Current Empty slot */
  265.  
  266.     /* Copy ColorIn2 to ColorUnionSize (use old colors if exists): */
  267.     for (i=0; i<ColorIn2Size && CrntSlot<=256; i++) {
  268.     /* Let see if this color already exists: */
  269.     for (j=0; j<ColorIn1Size; j++) {
  270.         /* If memcmp does not exists for you, use the following: */
  271.         /*
  272.         if (ColorIn1[j].Red   == ColorIn2[i].Red &&
  273.         ColorIn1[j].Green == ColorIn2[i].Green &&
  274.         ColorIn1[j].Blue  == ColorIn2[i].Blue) break;
  275.         */
  276.         if (memcmp(&ColorIn1[j], &ColorIn2[i], 3) == 0) break;
  277.     }
  278.     if (j < ColorIn1Size) {
  279.         /* We found this color aleardy exists in ColorIn1: */
  280.         ColorTransIn2[i] = j;
  281.     }
  282.     else {
  283.         /* Its new - copy it to a new slot: */
  284.         ColorUnion[CrntSlot] = ColorIn2[i];
  285.         ColorTransIn2[i] = CrntSlot++;
  286.     }
  287.     }
  288.  
  289.     if (CrntSlot > 256) return ERROR;
  290.  
  291.     /* Complete the color map to a power of two: */
  292.     for (i=1; i<=8; i++) if ((1 << i) >= CrntSlot) break;
  293.     for (j=CrntSlot; j<(1 << i); j++)
  294.     ColorUnion[j].Red = ColorUnion[j].Green = ColorUnion[j].Blue = 0;
  295.  
  296.     *ColorUnionSize = i;
  297.  
  298.     return OK;
  299. }
  300.  
  301. /******************************************************************************
  302. * Close both input and output file (if open), and exit.                  *
  303. ******************************************************************************/
  304. static void QuitGifError(GifFileType *GifFileIn1, GifFileType *GifFileIn2,
  305.              GifFileType *GifMaskFile, GifFileType *GifFileOut)
  306. {
  307.     PrintGifError();
  308.     if (GifFileIn1 != NULL) DGifCloseFile(GifFileIn1);
  309.     if (GifFileIn2 != NULL) DGifCloseFile(GifFileIn2);
  310.     if (GifMaskFile != NULL) DGifCloseFile(GifMaskFile);
  311.     if (GifFileOut != NULL) EGifCloseFile(GifFileOut);
  312.     exit(1);
  313. }
  314.