home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / graphics / gif-util.zip / GIFRSIZE.C < prev    next >
C/C++ Source or Header  |  1989-08-01  |  12KB  |  316 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 resize GIF by given factors horizontally and vertically.         *
  7. * Options:                                     *
  8. * -s n : resize both x & y direction by factor n.                 *
  9. * -x n : resize the x direction (horizontally) by factor n.             *
  10. * -y n : resize the y direction (vertically) by factor n.             *
  11. * -u : set up instead of down (default) by factor n.                 *
  12. * -d : scale down (default).                             *
  13. * -h : on line help.                                 *
  14. ******************************************************************************
  15. * History:                                     *
  16. * 4 Jul 89 - Version 1.0 by Gershon Elber.                     *
  17. *****************************************************************************/
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22. #include <alloc.h>
  23. #include <string.h>
  24. #include "gif_lib.h"
  25. #include "getarg.h"
  26.  
  27. #define PROGRAM_NAME    "GifRSize"
  28. #define VERSION        "ß Version 1.0, "
  29.  
  30. #define MAX_SCALE    16               /* Maximum scaling factor */
  31.  
  32. extern unsigned int
  33.     _stklen = 16384;                  /* Increase default stack size */
  34.  
  35. static char
  36.     *VersionStr =
  37.     PROGRAM_NAME
  38.     "    IBMPC "
  39.     VERSION
  40.     "    Gershon Elber,    "
  41.     __DATE__ ",   " __TIME__ "\n"
  42.     "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  43. static char
  44.     *CtrlStr =
  45.     PROGRAM_NAME
  46.     " s%-Scale!d x%-XScale!d y%-YScale!d u%- d%- h%- GifFile!*s";
  47. static char *ProgramName;
  48.  
  49. /* Make some variables global, so we could access them faster: */
  50. static PixelType
  51.     BackGroundColor = 0;
  52. static int
  53.     XScale = 2,
  54.     YScale = 2,
  55.     ScaleDown = TRUE;
  56.  
  57. static void Average(RowType LineIn[], RowType LineOut[], int OutLineLen);
  58. static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut);
  59.  
  60. /******************************************************************************
  61. * Interpret the command line and scan the given GIF file.              *
  62. ******************************************************************************/
  63. void main(int argc, char **argv)
  64. {
  65.     int    i, j, Error, NumFiles, ExtCode, ImageNum = 0, Scale, InCount,
  66.     ScaleFlag = FALSE, XScaleFlag = FALSE, YScaleFlag = FALSE,
  67.     UpFlag = FALSE, DownFlag = FALSE, HelpFlag = FALSE;
  68.     GifRecordType RecordType;
  69.     char s[80];
  70.     ByteType *Extension;
  71.     RowType LineIn[MAX_SCALE], LineOut[MAX_SCALE];
  72.     char **FileName = NULL;
  73.     GifFileType *GifFileIn = NULL, *GifFileOut = NULL;
  74.  
  75.     if (strlen(ProgramName = argv[0]) == 0)            /* DOS 3.x only! */
  76.     ProgramName = PROGRAM_NAME;      /* Do something reasonable for 2.x */
  77.  
  78.     if ((Error = GAGetArgs(argc, argv, CtrlStr, &ScaleFlag, &Scale,
  79.         &XScaleFlag, &XScale, &YScaleFlag, &YScale, &UpFlag, &DownFlag,
  80.         &HelpFlag, &NumFiles, &FileName)) != FALSE ||
  81.         (NumFiles > 1 && !HelpFlag)) {
  82.     if (Error) GAPrintErrMsg(Error);
  83.     else
  84.     if (NumFiles > 1)
  85.         MESSAGE("Error in command line parsing - one GIF file please\n");
  86.     GAPrintHowTo(CtrlStr);
  87.     exit(1);
  88.     }
  89.  
  90.     if (HelpFlag) {
  91.     fprintf(stderr, VersionStr);
  92.     GAPrintHowTo(CtrlStr);
  93.     exit(0);
  94.     }
  95.  
  96.     /* Decide if we scale up or down: */
  97.     if (UpFlag) ScaleDown = FALSE;
  98.     if (DownFlag) ScaleDown = TRUE;
  99.  
  100.     /* If specific direction was set, set other direction to 1: */
  101.     if (!XScaleFlag && YScaleFlag) XScale = 1;
  102.     if (!YScaleFlag && XScaleFlag) YScale = 1;
  103.  
  104.     /* If the specific direction was not set, but global one did use it: */
  105.     if (!XScaleFlag && ScaleFlag) XScale = Scale;
  106.     if (!YScaleFlag && ScaleFlag) YScale = Scale;
  107.     if (XScale > MAX_SCALE) {
  108.     sprintf(s, "XScale too big, maximum scale selected instead (%d)\n",
  109.                                 MAX_SCALE);
  110.     MESSAGE(s);
  111.     XScale = MAX_SCALE;
  112.     }
  113.     if (YScale > MAX_SCALE) {
  114.     sprintf(s, "YScale too big, maximum scale selected instead (%d)\n",
  115.                                 MAX_SCALE);
  116.     MESSAGE(s);
  117.     YScale = MAX_SCALE;
  118.     }
  119.  
  120.     if (NumFiles == 1) {
  121.     if ((GifFileIn = DGifOpenFileName(*FileName)) == NULL)
  122.         QuitGifError(GifFileIn, GifFileOut);
  123.     }
  124.     else {
  125.     /* Use the stdin instead: */
  126.     if ((GifFileIn = DGifOpenFileHandle(0)) == NULL)
  127.         QuitGifError(GifFileIn, GifFileOut);
  128.     }
  129.     BackGroundColor = GifFileIn -> SBackGroundColor;
  130.  
  131.     /* As at this time we know the Screen size of the input gif file, and as */
  132.     /* all image(s) in file must be less/equal to it, we can allocate the    */
  133.     /* scan lines for the input file, and output file. The number of lines   */
  134.     /* to allocate for each is set by ScaleDown & XScale & YScale:         */
  135.     if (ScaleDown) {
  136.     /* Output is smaller than input so we need only one output scanline: */
  137.     LineOut[0] = (RowType) malloc(GifFileIn -> SWidth / XScale *
  138.                             sizeof(PixelType));
  139.     for (i=0; i<YScale; i++) LineIn[i] =
  140.         (RowType) malloc(GifFileIn -> SWidth * sizeof(PixelType));
  141.     if (LineIn[YScale - 1] == NULL)
  142.         EXIT("Failed to allocate memory required, aborted\n");
  143.     }
  144.     else {
  145.     /* Input is smaller than output so we need only one input scanline:  */
  146.     LineIn[0] = (RowType) malloc(GifFileIn -> SWidth *
  147.                             sizeof(PixelType));
  148.     for (i=0; i<YScale; i++) LineOut[i] =
  149.         (RowType) malloc(GifFileIn -> SWidth * XScale * sizeof(PixelType));
  150.     if (LineOut[YScale - 1] == NULL)
  151.         EXIT("Failed to allocate memory required, aborted\n");
  152.     }
  153.  
  154.     /* Open stdout for the output file: */
  155.     if ((GifFileOut = EGifOpenFileHandle(1)) == NULL)
  156.     QuitGifError(GifFileIn, GifFileOut);
  157.  
  158.     /* And dump out its new scaled screen information: */
  159.     if (EGifPutScreenDesc(GifFileOut,
  160.     ScaleDown ? GifFileIn -> SWidth / XScale :
  161.             GifFileIn -> SWidth * XScale,
  162.     ScaleDown ? GifFileIn -> SHeight / YScale :
  163.             GifFileIn -> SHeight * YScale,
  164.     GifFileIn -> SColorResolution, GifFileIn -> SBackGroundColor,
  165.     GifFileIn -> SBitsPerPixel, GifFileIn -> SColorMap) == ERROR)
  166.     QuitGifError(GifFileIn, GifFileOut);
  167.  
  168.  
  169.     /* Scan the content of the GIF file and load the image(s) in: */
  170.     do {
  171.     if (DGifGetRecordType(GifFileIn, &RecordType) == ERROR)
  172.         QuitGifError(GifFileIn, GifFileOut);
  173.  
  174.     switch (RecordType) {
  175.         case IMAGE_DESC_RECORD_TYPE:
  176.         if (DGifGetImageDesc(GifFileIn) == ERROR)
  177.             QuitGifError(GifFileIn, GifFileOut);
  178.         /* Put the image descriptor to out file: */
  179.         if (EGifPutImageDesc(GifFileOut,
  180.             ScaleDown ? GifFileIn -> ILeft / XScale :
  181.                 GifFileIn -> ILeft * XScale,
  182.             ScaleDown ? GifFileIn -> ITop / YScale :
  183.                 GifFileIn -> ITop * YScale,
  184.             ScaleDown ? GifFileIn -> IWidth / XScale :
  185.                 GifFileIn -> IWidth * XScale,
  186.             ScaleDown ? GifFileIn -> IHeight / YScale :
  187.                 GifFileIn -> IHeight * YScale,
  188.             GifFileIn -> IInterlace, GifFileIn -> IBitsPerPixel,
  189.             GifFileIn -> IColorMap) == ERROR)
  190.             QuitGifError(GifFileIn, GifFileOut);
  191.  
  192.         if (GifFileIn -> IInterlace) {
  193.             EXIT("Cannt average4 interlaced images - use GifInter first\n");
  194.         }
  195.         else {
  196.             fprintf(stderr, "\n%s: Image %d at (%d, %d) [%dx%d]:     ",
  197.             ProgramName, ++ImageNum,
  198.             GifFileOut -> ILeft, GifFileOut -> ITop,
  199.             GifFileOut -> IWidth, GifFileOut -> IHeight);
  200.             InCount = 0;
  201.             if (ScaleDown) {
  202.             /* For each line of output, read YScale input lines, */
  203.             /* average them, and dump result out:             */
  204.             for (i=0; i<GifFileOut -> IHeight; i++) {
  205.                 fprintf(stderr, "\b\b\b\b%-4d", i);
  206.                 for (j=0; j<YScale; j++)
  207.                 if (DGifGetLine(GifFileIn, LineIn[j],
  208.                         GifFileIn -> IWidth) == ERROR)
  209.                     QuitGifError(GifFileIn, GifFileOut);
  210.                 InCount += YScale;
  211.                 Average(LineIn, LineOut, GifFileOut -> IWidth);
  212.                 if (EGifPutLine(GifFileOut, LineOut[0],
  213.                         GifFileOut -> IWidth) == ERROR)
  214.                 QuitGifError(GifFileIn, GifFileOut);
  215.             }
  216.             /* If scale is not dividable - discard last lines: */
  217.             for (i=InCount; i<GifFileIn -> IHeight; i++)
  218.                 DGifGetLine(GifFileIn, LineIn[i],
  219.                             GifFileIn -> IWidth);
  220.             }
  221.             else {
  222.             /* For each line of input, output YScale lines,         */
  223.             /* by averaging up this line to YScale lines:         */
  224.             for (i=0; i<GifFileIn -> IHeight; i++) {
  225.                 fprintf(stderr, "\b\b\b\b%-4d", i * YScale);
  226.                 if (DGifGetLine(GifFileIn, LineIn[0],
  227.                         GifFileIn -> IWidth) == ERROR)
  228.                 QuitGifError(GifFileIn, GifFileOut);
  229.                 Average(LineIn, LineOut, GifFileOut -> IWidth);
  230.                 for (j=0; j<YScale; j++)
  231.                 if (EGifPutLine(GifFileOut, LineOut[j],
  232.                         GifFileOut -> IWidth) == ERROR)
  233.                     QuitGifError(GifFileIn, GifFileOut);
  234.             }
  235.             }
  236.         }
  237.         break;
  238.         case EXTENSION_RECORD_TYPE:
  239.         /* Skip any extension blocks in file: */
  240.         if (DGifGetExtension(GifFileIn, &ExtCode, &Extension) == ERROR)
  241.             QuitGifError(GifFileIn, GifFileOut);
  242.         if (EGifPutExtension(GifFileOut, ExtCode, Extension[0],
  243.                             Extension) == ERROR)
  244.             QuitGifError(GifFileIn, GifFileOut);
  245.  
  246.         /* No support to more than one extension blocks, so discard: */
  247.         while (Extension != NULL) {
  248.             if (DGifGetExtensionNext(GifFileIn, &Extension) == ERROR)
  249.             QuitGifError(GifFileIn, GifFileOut);
  250.         }
  251.         break;
  252.         case TERMINATE_RECORD_TYPE:
  253.         break;
  254.         default:             /* Should be traps by DGifGetRecordType */
  255.         break;
  256.     }
  257.     }
  258.     while (RecordType != TERMINATE_RECORD_TYPE);
  259.  
  260.     if (DGifCloseFile(GifFileIn) == ERROR)
  261.     QuitGifError(GifFileIn, GifFileOut);
  262.     if (EGifCloseFile(GifFileOut) == ERROR)
  263.     QuitGifError(GifFileIn, GifFileOut);
  264. }
  265.  
  266. /******************************************************************************
  267. * Average routine - scale given lines as follows:                  *
  268. *   ScaleDown: for each YScale lines, for each box of size XScale by YScale   *
  269. * pick a pixel in it (usually upper left). If that pixel is equal to          *
  270. * background color, and there is in that square, none background pixel, pick  *
  271. * that instead. Use result pixel as output averaged pixel              *
  272. *   ScaleUp: each input pixel, is expanded both in X and in Y by the factors  *
  273. * XScale & YScale respectively.                              *
  274. ******************************************************************************/
  275. static void Average(RowType LineIn[], RowType LineOut[], int OutLineLen)
  276. {
  277.     int i, j, k, o;
  278.     PixelType Color;
  279.  
  280.  
  281.     if (ScaleDown) {
  282.     /* For each XScale by YScale pixels in a box, pick the top left one  */
  283.     /* if not background color, otherwise pick any non background from   */
  284.     /* other pixels in box if one exists.                     */
  285.     for (i=0, o=0; o<OutLineLen; i+=XScale, o++) {
  286.         if ((Color = LineIn[0][i]) == BackGroundColor) {
  287.         /* Scan all pixels to find non background color if exists: */
  288.         for (j=i; j<i+XScale && Color == BackGroundColor; j++)
  289.             for (k=0; k<YScale && Color == BackGroundColor; k++)
  290.             if (LineIn[k][j] != BackGroundColor)
  291.                 Color = LineIn[k][j];
  292.         }
  293.         LineOut[0][o] = Color;
  294.     }
  295.     }
  296.     else {
  297.     /* Make each input pixel a box of size XScale bu YScale: */
  298.     for (i=0, o=0; o<OutLineLen; i++, o+=XScale)   /* Prepare first line */
  299.         for (j=0; j<XScale; j++) LineOut[0][o+j] = LineIn[0][i];
  300.     /* And duplicate the other lines from first one: */
  301.     for (i=1; i<YScale; i++) memcpy(LineOut[i], LineOut[0],
  302.                     OutLineLen * sizeof(PixelType));
  303.     }
  304. }
  305.  
  306. /******************************************************************************
  307. * Close both input and output file (if open), and exit.                  *
  308. ******************************************************************************/
  309. static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut)
  310. {
  311.     PrintGifError();
  312.     if (GifFileIn != NULL) DGifCloseFile(GifFileIn);
  313.     if (GifFileOut != NULL) EGifCloseFile(GifFileOut);
  314.     exit(1);
  315. }
  316.