home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / grafik / giflib11 / util / gifcomb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-09-03  |  12.3 KB  |  322 lines

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