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

  1. /*****************************************************************************
  2. *   "Gif-Lib" - Yet another gif library.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.1, Jul. 1989   *
  5. ******************************************************************************
  6. * Program to display GIF file under X11 window system.                 *
  7. * Options:                                     *
  8. * -p PosX PosY : defines the position where to put the image.             *
  9. * -d Display : what display should go to.                     *
  10. * -f : force attempt to allocate the exact colors. This usually look bad...  *
  11. * -h : on line help.                                 *
  12. ******************************************************************************
  13. * History:                                     *
  14. * 28 Dec 89 - Version 1.0 by Gershon Elber, color allocation is based on the *
  15. *        xgif program by John Bradley, bradley@cis.ipenn.edu.         *
  16. *****************************************************************************/
  17.  
  18. #ifdef __MSDOS__
  19. #include <graphics.h>
  20. #include <stdlib.h>
  21. #include <alloc.h>
  22. #include <io.h>
  23. #include <dos.h>
  24. #include <bios.h>
  25. #endif /* __MSDOS__ */
  26.  
  27. #include <X11/Xlib.h>
  28. #include <X11/Xutil.h>
  29. #include <X11/cursorfont.h>
  30.  
  31. #include <stdio.h>
  32. #include <ctype.h>
  33. #include <string.h>
  34. #include <fcntl.h>
  35. #include "gif_lib.h"
  36. #include "getarg.h"
  37.  
  38. #define PROGRAM_NAME    "Gif2X11"
  39.  
  40. #define ICON_SIZE    60
  41. #define ABS(x)        ((x) > 0 ? (x) : (-(x)))
  42.  
  43. #ifdef __MSDOS__
  44. extern unsigned int
  45.     _stklen = 16384;                 /* Increase default stack size. */
  46. #endif /* __MSDOS__ */
  47. #ifdef SYSV
  48. static char *VersionStr =
  49.         "Gif library module,\t\tGershon Elber\n\
  50.     (C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  51. static char
  52.     *CtrlStr = "Gif2X11 p%-PosX|PosY!d!d d%-Display!s f%- h%- GifFile!*s";
  53. #else
  54. static char
  55.     *VersionStr =
  56.     PROGRAM_NAME
  57.     GIF_LIB_VERSION
  58.     "    Gershon Elber,    "
  59.     __DATE__ ",   " __TIME__ "\n"
  60.     "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  61. static char
  62.     *CtrlStr =
  63.     PROGRAM_NAME
  64.     " p%-PosX|PosY!d!d d%-Display!s f%- h%- GifFile!*s";
  65. #endif /* SYSV */
  66.  
  67. /* Make some variables global, so we could access them faster: */
  68. static int
  69.     PosFlag = FALSE,
  70.     HelpFlag = FALSE,
  71.     DisplayFlag = FALSE,
  72.     ForceFlag = FALSE,
  73.     ColorMapSize = 0,
  74.     BackGround = 0,
  75.     XPosX = 0,
  76.     XPosY = 0,
  77.     InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
  78.     InterlacedJumps[] = { 8, 8, 4, 2 };    /* be read - offsets and jumps... */
  79. static char
  80.     *DisplayName = NULL;
  81. static GifColorType
  82.     *ColorMap;
  83.  
  84. /* X specific staff goes here. XColorTable will hold the GIF image colors,   */
  85. /* while XPixelTable will hold the pixel number so we can redirect through   */
  86. /* it when forming the image bitmap in X format.                 */
  87. /* Note the table has 256 entry which is the maximum allowed in GIF format.  */
  88. static XColor XColorTable[256];
  89. static unsigned long XPixelTable[256];
  90. static Display *XDisplay;
  91. static int XScreen;
  92. static Window Xroot, XImageWndw;
  93. static Colormap XColorMap;
  94. static GC XGraphContext;
  95. static Visual *XVisual;
  96. static XImage *XImageBuffer;
  97. static Pixmap XIcon;
  98. static Cursor XCursor;
  99.  
  100. static void Screen2X(int argc, char **argv, GifRowType *ScreenBuffer,
  101.              int ScreenWidth, int ScreenHeight);
  102. static void AllocateColors1(void);
  103. static void AllocateColors2(void);
  104.  
  105. /******************************************************************************
  106. * Interpret the command line and scan the given GIF file.              *
  107. ******************************************************************************/
  108. void main(int argc, char **argv)
  109. {
  110.     int    i, j, Error, NumFiles, ImageNum = 0, Size, Row, Col, Width, Height,
  111.         ExtCode, Count;
  112.     GifRecordType RecordType;
  113.     GifByteType *Extension;
  114.     char **FileName = NULL;
  115.     GifRowType *ScreenBuffer;
  116.     GifFileType *GifFile;
  117.  
  118.     if ((Error = GAGetArgs(argc, argv, CtrlStr,
  119.         &PosFlag, &XPosX, &XPosY,
  120.             &DisplayFlag, &DisplayName, &ForceFlag,
  121.         &HelpFlag, &NumFiles, &FileName)) != FALSE ||
  122.         (NumFiles > 1 && !HelpFlag)) {
  123.     if (Error)
  124.         GAPrintErrMsg(Error);
  125.     else if (NumFiles > 1)
  126.         GIF_MESSAGE("Error in command line parsing - one GIF file please.");
  127.     GAPrintHowTo(CtrlStr);
  128.     exit(1);
  129.     }
  130.  
  131.     if (HelpFlag) {
  132.     fprintf(stderr, VersionStr);
  133.     GAPrintHowTo(CtrlStr);
  134.     exit(0);
  135.     }
  136.  
  137.     if (NumFiles == 1) {
  138.     if ((GifFile = DGifOpenFileName(*FileName)) == NULL) {
  139.         PrintGifError();
  140.         exit(-1);
  141.     }
  142.     }
  143.     else {
  144.     /* Use the stdin instead: */
  145.  
  146. #ifdef __MSDOS__
  147.     setmode(0, O_BINARY);
  148. #endif /* __MSDOS__ */
  149.     if ((GifFile = DGifOpenFileHandle(0)) == NULL) {
  150.         PrintGifError();
  151.         exit(-1);
  152.     }
  153.     }
  154.  
  155.     /* Lets see if we can get access to the X server before we even start: */
  156.     if ((XDisplay = (Display *) XOpenDisplay(DisplayName)) == NULL)
  157.     GIF_EXIT("Failed to access X server, abored.");
  158.     XScreen = DefaultScreen(XDisplay);
  159.     Xroot = RootWindow(XDisplay, XScreen);
  160.     XColorMap = DefaultColormap(XDisplay, XScreen);
  161.     XGraphContext = DefaultGC(XDisplay, XScreen);
  162.     XVisual = DefaultVisual(XDisplay, XScreen);
  163.     XSetBackground(XDisplay, XGraphContext, BlackPixel(XDisplay, XScreen));
  164.     XSetForeground(XDisplay, XGraphContext, WhitePixel(XDisplay, XScreen));
  165.  
  166.     /* Allocate the screen as vector of column of rows. We cannt allocate    */
  167.     /* the all screen at once, as this broken minded CPU can allocate up to  */
  168.     /* 64k at a time and our image can be bigger than that:             */
  169.     /* Note this screen is device independent - its the screen as defined by */
  170.     /* the GIF file parameters itself.                         */
  171.     if ((ScreenBuffer = (GifRowType *)
  172.     malloc(GifFile -> SHeight * sizeof(GifRowType *))) == NULL)
  173.         GIF_EXIT("Failed to allocate memory required, aborted.");
  174.  
  175.     Size = GifFile -> SWidth * sizeof(GifPixelType);/* Size in bytes one row.*/
  176.     if ((ScreenBuffer[0] = (GifRowType) malloc(Size)) == NULL) /* First row. */
  177.     GIF_EXIT("Failed to allocate memory required, aborted.");
  178.  
  179.     for (i = 0; i < GifFile -> SWidth; i++)  /* Set its color to BackGround. */
  180.     ScreenBuffer[0][i] = GifFile -> SBackGroundColor;
  181.     for (i = 1; i < GifFile -> SHeight; i++) {
  182.     /* Allocate the other rows, and set their color to background too: */
  183.     if ((ScreenBuffer[i] = (GifRowType) malloc(Size)) == NULL)
  184.         GIF_EXIT("Failed to allocate memory required, aborted.");
  185.  
  186.     memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
  187.     }
  188.  
  189.     /* Scan the content of the GIF file and load the image(s) in: */
  190.     do {
  191.     if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
  192.         PrintGifError();
  193.         exit(-1);
  194.     }
  195.     switch (RecordType) {
  196.         case IMAGE_DESC_RECORD_TYPE:
  197.         if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
  198.             PrintGifError();
  199.             exit(-1);
  200.         }
  201.         Row = GifFile -> ITop; /* Image Position relative to Screen. */
  202.         Col = GifFile -> ILeft;
  203.         Width = GifFile -> IWidth;
  204.         Height = GifFile -> IHeight;
  205.         fprintf(stderr, "\n%s: Image %d at (%d, %d) [%dx%d]:     ",
  206.             PROGRAM_NAME, ++ImageNum, Col, Row, Width, Height);
  207.         if (GifFile -> ILeft + GifFile -> IWidth > GifFile -> SWidth ||
  208.            GifFile -> ITop + GifFile -> IHeight > GifFile -> SHeight) {
  209.             fprintf(stderr, "Image %d is not confined to screen dimension, aborted.\n");
  210.             exit(-2);
  211.         }
  212.         if (GifFile -> IInterlace) {
  213.             /* Need to perform 4 passes on the images: */
  214.             for (Count = i = 0; i < 4; i++)
  215.             for (j = Row + InterlacedOffset[i]; j<Row + Height;
  216.                          j += InterlacedJumps[i]) {
  217.                 fprintf(stderr, "\b\b\b\b%-4d", Count++);
  218.                 if (DGifGetLine(GifFile, &ScreenBuffer[j][Col],
  219.                 Width) == GIF_ERROR) {
  220.                 PrintGifError();
  221.                 exit(-1);
  222.                 }
  223.             }
  224.         }
  225.         else {
  226.             for (i = 0; i < Height; i++) {
  227.             fprintf(stderr, "\b\b\b\b%-4d", i);
  228.             if (DGifGetLine(GifFile, &ScreenBuffer[Row++][Col],
  229.                 Width) == GIF_ERROR) {
  230.                 PrintGifError();
  231.                 exit(-1);
  232.             }
  233.             }
  234.         }
  235.         break;
  236.         case EXTENSION_RECORD_TYPE:
  237.         /* Skip any extension blocks in file: */
  238.         if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
  239.             PrintGifError();
  240.             exit(-1);
  241.         }
  242.         while (Extension != NULL) {
  243.             if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
  244.             PrintGifError();
  245.             exit(-1);
  246.             }
  247.         }
  248.         break;
  249.         case TERMINATE_RECORD_TYPE:
  250.         break;
  251.         default:            /* Should be traps by DGifGetRecordType. */
  252.         break;
  253.     }
  254.     }
  255.     while (RecordType != TERMINATE_RECORD_TYPE);
  256.  
  257.     /* Lets display it - set the global variables required and do it: */
  258.     BackGround = GifFile -> SBackGroundColor;
  259.     ColorMap = (GifFile -> IColorMap ? GifFile -> IColorMap :
  260.                        GifFile -> SColorMap);
  261.     ColorMapSize = 1 << (GifFile -> IColorMap ? GifFile -> IBitsPerPixel :
  262.                                 GifFile -> SBitsPerPixel);
  263.     Screen2X(argc, argv, ScreenBuffer, GifFile -> SWidth, GifFile -> SHeight);
  264.  
  265.     if (DGifCloseFile(GifFile) == GIF_ERROR) {
  266.     PrintGifError();
  267.     exit(-1);
  268.     }
  269.     fprintf(stderr, "\n");
  270. }
  271.  
  272. /******************************************************************************
  273. * The real display routine.                              *
  274. ******************************************************************************/
  275. static void Screen2X(int argc, char **argv, GifRowType *ScreenBuffer,
  276.              int ScreenWidth, int ScreenHeight)
  277. {
  278.     int i, j, c, Size, x, y,
  279.         MinIntensity, MaxIntensity, AvgIntensity, IconSizeX, IconSizeY;
  280.     char *XImageData, *XIconData, KeyBuffer[81];
  281.     double Aspect;
  282.     GifByteType *OutLine, Data;
  283.     unsigned long ValueMask;
  284.     GifPixelType *Line;
  285.     GifRowType *DitherBuffer;
  286.     GifColorType *ColorMapEntry = ColorMap;
  287.     XSetWindowAttributes SetWinAttr;
  288.     XSizeHints Hints;
  289.     XEvent Event;
  290.     XExposeEvent *EEvent;
  291.     XComposeStatus Stat;
  292.     KeySym KS;
  293.  
  294.     /* Let find out what are the intensities in the color map: */
  295.     MaxIntensity = 0;
  296.     MinIntensity = 256 * 100;
  297.     for (i = 0; i < ColorMapSize; i++) {
  298.     c = ColorMapEntry[i].Red * 30 +
  299.         ColorMapEntry[i].Green * 59 +
  300.         ColorMapEntry[i].Blue * 11;
  301.     if (c > MaxIntensity) MaxIntensity = c;
  302.     if (c < MinIntensity) MinIntensity = c;
  303.     }
  304.     AvgIntensity = (MinIntensity + MaxIntensity) / 2;
  305.  
  306.     /* The big trick here is to select the colors so lets do this first: */
  307.     if (ForceFlag)
  308.     AllocateColors2();
  309.     else
  310.     AllocateColors1();
  311.  
  312.     SetWinAttr.background_pixel = BlackPixel( XDisplay, XScreen );
  313.     SetWinAttr.border_pixel = WhitePixel( XDisplay, XScreen );
  314.     ValueMask = CWBackPixel | CWBorderPixel;
  315.  
  316.     Hints.flags = PSize | PMinSize | PMaxSize;
  317.     Hints.x = Hints.y = 1;
  318.     Hints.width = Hints.min_width = Hints.max_width = ScreenWidth;
  319.     Hints.height = Hints.min_height = Hints.max_height = ScreenHeight;
  320.     if (PosFlag) {
  321.     Hints.flags |= USPosition;
  322.     Hints.x = XPosX;
  323.     Hints.y = XPosY;
  324.     }
  325.  
  326.     XImageWndw = XCreateWindow(XDisplay, Xroot, XPosX, XPosY,
  327.                    ScreenWidth, ScreenHeight,
  328.                    1, 0,
  329.                    CopyFromParent, CopyFromParent,
  330.                    ValueMask, &SetWinAttr);
  331.  
  332.     /* Set up the icon bit map to be a shrinked BW version of the image: */
  333.     if (ScreenWidth > ScreenHeight) {
  334.     IconSizeX = (ICON_SIZE / 8) * 8;
  335.     IconSizeY = (ScreenHeight * ICON_SIZE) / ScreenWidth;
  336.     }
  337.     else {
  338.     IconSizeY = ICON_SIZE;
  339.     IconSizeX = (((ScreenWidth * ICON_SIZE) / ScreenHeight) / 8) * 8;
  340.     }
  341.     XIconData = (char *) malloc(IconSizeX * IconSizeY / 8);
  342.     memset(XIconData, 0, IconSizeX * IconSizeY / 8);
  343.     for (i = 0; i < IconSizeY; i++) {
  344.     y = (i * ScreenHeight / IconSizeY);
  345.     Size = i * IconSizeX / 8;
  346.     for (j = 0; j < IconSizeX; j++) {
  347.         x = j * ScreenWidth / IconSizeX;
  348.         c = ScreenBuffer[y][x];
  349.         c = ColorMapEntry[c].Red * 30 +
  350.         ColorMapEntry[c].Green * 59 +
  351.         ColorMapEntry[c].Blue * 11 > AvgIntensity;
  352.         XIconData[Size + j / 8] |= c << (j % 8);
  353.     }
  354.     }
  355.  
  356.     XIcon = XCreateBitmapFromData(XDisplay, XImageWndw, XIconData,
  357.                   IconSizeX, IconSizeY);
  358.  
  359.     XSetStandardProperties(XDisplay, XImageWndw,
  360.                PROGRAM_NAME, PROGRAM_NAME, XIcon,
  361.                argv, argc,
  362.                &Hints);
  363.  
  364.     XSelectInput(XDisplay, XImageWndw, ExposureMask | KeyPressMask);
  365.  
  366.     /* Set out own cursor: */
  367.     XCursor = XCreateFontCursor(XDisplay, XC_diamond_cross);
  368.     XDefineCursor(XDisplay, XImageWndw, XCursor);
  369.     
  370.     XMapWindow(XDisplay, XImageWndw);
  371.  
  372.     /* Create the image in X format: */
  373.     if ((XImageData = (char *) malloc(ScreenWidth * ScreenHeight)) == NULL)
  374.     GIF_EXIT("Failed to allocate memory required, aborted.");
  375.  
  376.     for (i = 0; i < ScreenHeight; i++) {
  377.     y = i * ScreenWidth;
  378.     for (j = 0; j < ScreenWidth; j++)
  379.         XImageData[y + j] = XPixelTable[ScreenBuffer[i][j]];
  380.     }
  381.     XImageBuffer = XCreateImage(XDisplay, XVisual, 8, ZPixmap, 0,
  382.                 XImageData, ScreenWidth, ScreenHeight,
  383.                 8, ScreenWidth);
  384.  
  385.     while (TRUE) {
  386.     XNextEvent(XDisplay, &Event);
  387.     switch (Event.type) {
  388.         case Expose:
  389.             EEvent = (XExposeEvent *) &Event;
  390.         XPutImage(XDisplay, XImageWndw, XGraphContext, XImageBuffer,
  391.               EEvent -> x, EEvent -> y,
  392.               EEvent -> x, EEvent -> y,
  393.               EEvent -> width, EEvent -> height);
  394.         break;
  395.         case KeyPress:
  396.         XLookupString(&Event, KeyBuffer, 80, &KS, &Stat);
  397.         if (KeyBuffer[0] == 3) return;
  398.         break;
  399.     }
  400.     }
  401. }
  402.  
  403. /******************************************************************************
  404. * Routine to allocate the requested colors from the X server.              *
  405. * Colors are allocated until success by stripping off the least bits of the   *
  406. * colors.                                      *
  407. ******************************************************************************/
  408. static void AllocateColors1(void)
  409. {
  410.     int Strip, Msk, i, j;
  411.     char Msg[80];
  412.  
  413.     for (i = 0; i < 256; i++)
  414.     XPixelTable[i] = 0;       /* Put reasonable color for out of range. */
  415.  
  416.     for (Strip = 0, Msk = 0xff; Strip < 8; Strip++, Msk <<= 1) {
  417.     for (i = 0; i < ColorMapSize; i++) {
  418.         /* Prepere color entry in X format. */
  419.         XColorTable[i].red = (ColorMap[i].Red & Msk) << 8;
  420.         XColorTable[i].green = (ColorMap[i].Green & Msk) << 8;
  421.         XColorTable[i].blue = (ColorMap[i].Blue & Msk) << 8;
  422.         XColorTable[i].flags = DoRed | DoGreen | DoBlue;
  423.         if (XAllocColor(XDisplay, XColorMap, &XColorTable[i]))
  424.         XPixelTable[i] = XColorTable[i].pixel;
  425.         else
  426.         break;
  427.     }
  428.     if (i < ColorMapSize)
  429.         XFreeColors(XDisplay, XColorMap, XPixelTable, i, 0L);
  430.     else
  431.         break;
  432.     }
  433.  
  434.     if (Strip == 8)
  435.     GIF_EXIT("Can not display the image - not enough colors available.");
  436.  
  437.     if (Strip != 0) {
  438.     sprintf(Msg, "%d bits were stripped off the color map.", Strip);
  439.     GIF_MESSAGE(Msg);
  440.     }
  441. }
  442.  
  443. /******************************************************************************
  444. * Routine to allocate the requested colors from the X server.              *
  445. * Two stages are performed:                              *
  446. * 1. Colors are requested directly.                          *
  447. * 2. If not enough colors can be allocated, the closest current color          *
  448. *    in current table is selected instead.                      *
  449. * This allocation is not optimal as when fail to allocate all colors one      *
  450. * should pick the right colors to do allocate in order to minimize the        *
  451. * closest distance from the unallocated ones under some norm (what is a good  *
  452. * norm for the RGB space?). Improve it if you are bored.              *
  453. ******************************************************************************/
  454. static void AllocateColors2(void)
  455. {
  456.     int i, j, Index = 0, Count = 0, XNumOfColors;
  457.     char Msg[80];
  458.     unsigned long D, Distance, AvgDistance = 0, Red, Green, Blue;
  459.     GifBooleanType Failed = FALSE;
  460.     XColor *XOldColorTable;
  461.  
  462.     for (i = 0; i < 256; i++) {
  463.     if (i < ColorMapSize) {          /* Prepere color entry in X format. */
  464.         XColorTable[i].red = ColorMap[i].Red << 8;
  465.         XColorTable[i].green = ColorMap[i].Green << 8;
  466.         XColorTable[i].blue = ColorMap[i].Blue << 8;
  467.         XColorTable[i].flags = DoRed | DoGreen | DoBlue;
  468.         XPixelTable[i] = -1;               /* Not allocated yet. */
  469.     }
  470.     else
  471.         XPixelTable[i] = 0;    /* Put reasonable color for out of range. */
  472.     }
  473.  
  474.     for (i = 0; i < ColorMapSize; i++)          /* Allocate the colors from X: */
  475.     if (XAllocColor(XDisplay, XColorMap, &XColorTable[i]))
  476.         XPixelTable[i] = XColorTable[i].pixel;
  477.     else
  478.         Failed = TRUE;
  479.  
  480.     if (Failed) {
  481.     XNumOfColors = DisplayCells(XDisplay, XScreen);
  482.     XOldColorTable = (XColor *) malloc(sizeof(XColor) * XNumOfColors);
  483.     for (i = 0; i < XNumOfColors; i++) XOldColorTable[i].pixel = i;
  484.     XQueryColors(XDisplay, XColorMap, XOldColorTable, XNumOfColors);
  485.     
  486.     for (i = 0; i < ColorMapSize; i++) {
  487.         /* Allocate closest colors from X: */
  488.         if (XPixelTable[i] == -1) {      /* Failed to allocate this one. */
  489.         Distance = 0xffffffff;
  490.  
  491.         Red = XColorTable[i].red;
  492.         Green = XColorTable[i].green;
  493.         Blue = XColorTable[i].blue;
  494.  
  495.         for (j = 0; j < XNumOfColors; j++) {
  496.             /* Find the closest color in 3D RGB space using L1 norm. */
  497.             if ((D = ABS(Red - XOldColorTable[j].red) +
  498.                  ABS(Green - XOldColorTable[j].green) +
  499.                  ABS(Blue - XOldColorTable[j].blue)) < Distance) {
  500.             Distance = D;
  501.             Index = j;
  502.             }
  503.         }
  504.             XPixelTable[i] = Index;
  505.  
  506.         AvgDistance += Distance;
  507.         Count++;
  508.         }
  509.     }
  510.     free(XOldColorTable);
  511.  
  512.     sprintf(Msg, "Colors will be approximated (average error = %d).\n",
  513.         AvgDistance / Count);
  514.     GIF_MESSAGE(Msg);
  515.     }
  516. }
  517.