/***************************************************************************** * "Gif-Lib" - Yet another gif library. * * * * Written by: Gershon Elber IBM PC Ver 1.1, Jun. 1989 * ****************************************************************************** * Module to dump graphic devices into a GIF file. Current supported devices: * * 1. EGA, VGA, SVGA (800x600), Hercules on the IBM PC (#define __MSDOS__). * * 2. SGI 4D Irix using gl library (#define __SGI_GL__). * * 3. X11 using libX.a (#define __X11__). * ****************************************************************************** * History: * * 22 Jun 89 - Version 1.0 by Gershon Elber. * * 12 Aug 90 - Version 1.1 by Gershon Elber (added devices). * *****************************************************************************/ #ifdef __MSDOS__ #include #include #include #endif /* __MSDOS__ */ #ifdef __SGI_GL__ #include #endif /* __SGI_GL__ */ #ifdef __X11__ #include #endif /* __X11__ */ #include #include "gif_lib.h" #define PROGRAM_NAME "GIF_LIBRARY" #define SVGA_SPECIAL 999 /* 800 by 600 Super VGA mode. */ static int GraphDriver = -1, /* Device parameters - reasonable values. */ GraphMode = -1, ScreenColorBits = 1; static long ScreenXMax = 100, ScreenYMax = 100; static unsigned int ScreenBase; #ifdef SYSV static char *VersionStr = "Gif library module,\t\tGershon Elber\n\ (C) Copyright 1989 Gershon Elber, Non commercial use only.\n"; #else static char *VersionStr = PROGRAM_NAME " IBMPC " GIF_LIB_VERSION " Gershon Elber, " __DATE__ ", " __TIME__ "\n" "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n"; #endif /* SYSV */ #if defined(__SGI_GL__) || defined(__X11__) GifByteType *GlblGifBuffer = NULL, *GlblGifBufferPtr = NULL; #endif /* __SGI_GL__ || __X11__ */ #ifdef __SGI_GL__ static int QuantizeRGBBuffer(int Width, int Height, long *RGBBuffer, GifColorType *ColorMap, GifByteType *GIFBuffer); #endif /* __SGI_GL__ */ static void GetScanLine(GifPixelType *ScanLine, int Y); static int HandleGifError(GifFileType *GifFile); /****************************************************************************** * Dump the given Device, into given File as GIF format: * * Return 0 on success, -1 if device not supported, or GIF-LIB error number. * * Device is selected via the ReqGraphDriver. Device mode is selected via * * ReqGraphMode1/2 as follows: * * 1. IBM PC Hercules card: HERCMONO (one mode only) in ReqGraphMode1, * * ReqGraphMode2/3 are ignored. * * 2. IBM PC EGA card: EGALO/EGAHI in ReqGraphMode1, * * ReqGraphMode2/3 are ignored. * * 3. IBM PC EGA64 card: EGA64LO/EGA64HI in ReqGraphMode1, * * ReqGraphMode2/3 are ignored. * * 4. IBM PC EGAMONO card: EGAMONOHI (one mode only) in ReqGraphMode1, * * ReqGraphMode2/3 are ignored. * * 5. IBM PC VGA card: VGALO/VGAMED/VGAHI in ReqGraphMode1, * * ReqGraphMode2/3 are ignored. * * 6. IBM PC SVGA card: ReqGraphMode1/2 are both ignored. Fixed mode (800x600 * * 16 colors) is assumed. * * 7. SGI 4D using GL: window id to dump (as returned by winget()) in * * ReqGraphMode1, ReqGraphMode2/3 are ignored. * * 8. X11: Window id in ReqGraphMode1, Display id in ReqGraphMode2, Color * * map id in ReqGraphMode3. * ******************************************************************************/ int DumpScreen2Gif(char *FileName, int ReqGraphDriver, int ReqGraphMode1, int ReqGraphMode2, int ReqGraphMode3) { int i, j, k; GifPixelType *ScanLine; GifFileType *GifFile; GifColorType *ColorMap = NULL; #ifdef __MSDOS__ static GifColorType MonoChromeColorMap[] = { { 0, 0, 0 }, { 255, 255, 255 } }; /* I have no idea what default EGA64 (4 colors) should be (I guessed...).*/ static GifColorType EGA64ColorMap[] = { { 0, 0, 0 }, /* 0. Black */ { 255, 0, 0 }, /* 1. Red */ { 0, 255, 0 }, /* 2. Green */ { 0, 0, 255 }, /* 3. Blue */ }; static GifColorType EGAColorMap[] = { { 0, 0, 0 }, /* 0. Black */ { 0, 0, 170 }, /* 1. Blue */ { 0, 170, 0 }, /* 2. Green */ { 0, 170, 170 }, /* 3. Cyan */ { 170, 0, 0 }, /* 4. Red */ { 170, 0, 170 }, /* 5. Magenta */ { 170, 170, 0 }, /* 6. Brown */ { 170, 170, 170 }, /* 7. LightGray */ { 85, 85, 85 }, /* 8. DarkGray */ { 85, 85, 255 }, /* 9. LightBlue */ { 85, 255, 85 }, /* 10. LightGreen */ { 85, 255, 255 }, /* 11. LightCyan */ { 255, 85, 85 }, /* 12. LightRed */ { 255, 85, 255 }, /* 13. LightMagenta */ { 255, 255, 85 }, /* 14. Yellow */ { 255, 255, 255 }, /* 15. White */ }; #endif /* __MSDOS__ */ #if defined(__SGI_GL__) || defined(__X11__) long *RGBBuffer; GifColorType ColorMap256[256]; #endif #ifdef __X11__ XImage *XImg; unsigned long XPixel; XColor XColorTable[256]; /* Up to 256 colors in X. */ XWindowAttributes WinAttr; #endif /* __X11__ */ switch (ReqGraphDriver) { /* Return on non supported screens. */ #ifdef __MSDOS__ case HERCMONO: ScreenXMax = 720; ScreenYMax = 350; ScreenColorBits = 1; ScreenBase = 0xb000; ColorMap = MonoChromeColorMap; break; case EGA: switch (ReqGraphMode1) { case EGALO: ScreenYMax = 200; break; case EGAHI: ScreenYMax = 350; break; default: return -1; } ScreenXMax = 640; ScreenColorBits = 4; ScreenBase = 0xa000; ColorMap = EGAColorMap; break; case EGA64: switch (ReqGraphMode1) { case EGA64LO: ScreenYMax = 200; break; case EGA64HI: ScreenYMax = 350; break; default: return -1; } ScreenXMax = 640; ScreenColorBits = 2; ScreenBase = 0xa000; ColorMap = EGA64ColorMap; break; case EGAMONO: switch (ReqGraphMode1) { case EGAMONOHI: ScreenYMax = 350; break; default: return -1; } ScreenXMax = 640; ScreenColorBits = 1; ScreenBase = 0xa000; ColorMap = MonoChromeColorMap; break; case VGA: switch (ReqGraphMode1) { case VGALO: ScreenYMax = 200; break; case VGAMED: ScreenYMax = 350; break; case VGAHI: ScreenYMax = 480; break; default: return -1; } ScreenXMax = 640; ScreenColorBits = 4; ScreenBase = 0xa000; ColorMap = EGAColorMap; break; case SVGA_SPECIAL: ScreenXMax = 800; ScreenYMax = 600; ScreenColorBits = 4; ScreenBase = 0xa000; ColorMap = EGAColorMap; break; #endif /* __MSDOS__ */ #ifdef __SGI_GL__ case GIF_DUMP_SGI_WINDOW: winset(ReqGraphMode1); /* Select window as active window. */ getsize(&ScreenXMax, &ScreenYMax); RGBBuffer = (long *) malloc(sizeof(long) * ScreenXMax * ScreenYMax); readsource(SRC_FRONT); if (lrectread((short) 0, (short) 0, (short) (ScreenXMax - 1), (short) (ScreenYMax - 1), RGBBuffer) != ScreenXMax * ScreenYMax) { /* Get data. */ free(RGBBuffer); return -1; } GlblGifBuffer = (GifByteType *) malloc(sizeof(GifByteType) * ScreenXMax * ScreenYMax); i = QuantizeRGBBuffer(ScreenXMax, ScreenYMax, RGBBuffer, ColorMap256, GlblGifBuffer); /* Find minimum color map size to hold all quantized colors. */ for (ScreenColorBits = 1; (1 << ScreenColorBits) < i && ScreenColorBits < 8; ScreenColorBits++); /* Start to dump with top line as GIF expects it. */ GlblGifBufferPtr = GlblGifBuffer + ScreenXMax * (ScreenYMax - 1); ColorMap = ColorMap256; free(RGBBuffer); break; #endif /* __SGI_GL__ */ #ifdef __X11__ case GIF_DUMP_X_WINDOW: XGetWindowAttributes((Display *) ReqGraphMode2, (Window) ReqGraphMode1, &WinAttr); ScreenXMax = WinAttr.width; ScreenYMax = WinAttr.height; XImg = XGetImage((Display *) ReqGraphMode2, (Window) ReqGraphMode1, 0, 0, ScreenXMax - 1, ScreenYMax - 1, AllPlanes, XYPixmap); GlblGifBuffer = (GifByteType *) malloc(sizeof(GifByteType) * ScreenXMax * ScreenYMax); /* Scan the image for all different colors exists. */ for (i = 0; i < 256; i++) XColorTable[i].pixel = 0; k = FALSE; for (i = 0; i < ScreenXMax; i++) for (j = 0; j < ScreenYMax; j++) { XPixel = XGetPixel(XImg, i, j); if (XPixel > 255) { if (!k) { /* Make sure we state it once only.*/ fprintf(stderr, "X Color table - truncated.\n"); k = TRUE; } XPixel = 255; } XColorTable[XPixel].pixel = XPixel; } /* Find the RGB representation of the colors. */ XQueryColors((Display *) ReqGraphMode2, (Colormap) ReqGraphMode3, XColorTable, 256); /* Count number of active colors (Note color 0 is always in) */ /* and create the Gif color map from it. */ ColorMap = ColorMap256; ColorMap[0].Red = ColorMap[0].Green = ColorMap[0].Blue = 0; for (i = j = 1; i < 256; i++) if (XColorTable[i].pixel) { ColorMap[j].Red = XColorTable[i].red / 256; ColorMap[j].Green = XColorTable[i].green / 256; ColorMap[j].Blue = XColorTable[i].blue / 256; /* Save the X color index into the Gif table: */ XColorTable[i].pixel = j++; } /* and set the number of colors in the Gif color map. */ for (ScreenColorBits = 1; (1 << ScreenColorBits) < j && ScreenColorBits < 8; ScreenColorBits++); /* Prepare the Gif image buffer as indices into the Gif color */ /* map from the X image. */ GlblGifBufferPtr = GlblGifBuffer; for (i = 0; i < ScreenXMax; i++) for (j = 0; j < ScreenYMax; j++) *GlblGifBufferPtr++ = XColorTable[XGetPixel(XImg, j, i) & 0xff].pixel; XDestroyImage(XImg); GlblGifBufferPtr = GlblGifBuffer; ColorMap = ColorMap256; break; #endif /* __X11__ */ default: return -1; } ScanLine = (GifPixelType *) malloc(sizeof(GifPixelType) * ScreenXMax); GraphDriver = ReqGraphDriver; GraphMode = ReqGraphMode1; if ((GifFile = EGifOpenFileName(FileName, FALSE)) == NULL || EGifPutScreenDesc(GifFile, ScreenXMax, ScreenYMax, ScreenColorBits, 0, ScreenColorBits, ColorMap) == GIF_ERROR || EGifPutImageDesc(GifFile, 0, 0, ScreenXMax, ScreenYMax, FALSE, 1, NULL) == GIF_ERROR) { free((char *) ScanLine); #if defined(__SGI_GL__) || defined(__X11__) free((char *) GlblGifBuffer); #endif return HandleGifError(GifFile); } for (i = 0; i < ScreenYMax; i++) { GetScanLine(ScanLine, i); if (EGifPutLine(GifFile, ScanLine, ScreenXMax) == GIF_ERROR) { free((char *) ScanLine); #if defined(__SGI_GL__) || defined(__X11__) free((char *) GlblGifBuffer); #endif return HandleGifError(GifFile); } } if (EGifCloseFile(GifFile) == GIF_ERROR) { free((char *) ScanLine); #if defined(__SGI_GL__) || defined(__X11__) free((char *) GlblGifBuffer); #endif return HandleGifError(GifFile); } free((char *) ScanLine); #if defined(__SGI_GL__) || defined(__X11__) free((char *) GlblGifBuffer); #endif return 0; } #ifdef __SGI_GL__ /****************************************************************************** * Quantize the given 24 bit (8 per RGB) into 256 colors. * ******************************************************************************/ static int QuantizeRGBBuffer(int Width, int Height, long *RGBBuffer, GifColorType *ColorMap, GifByteType *GIFBuffer) { int i; GifByteType *RedInput, *GreenInput, *BlueInput; /* Convert the RGB Buffer into 3 seperated buffers: */ RedInput = (GifByteType *) malloc(sizeof(GifByteType) * Width * Height); GreenInput = (GifByteType *) malloc(sizeof(GifByteType) * Width * Height); BlueInput = (GifByteType *) malloc(sizeof(GifByteType) * Width * Height); for (i = 0; i < Width * Height; i++) { RedInput[i] = RGBBuffer[i] & 0xff; GreenInput[i] = (RGBBuffer[i] >> 8) & 0xff; BlueInput[i] = (RGBBuffer[i] >> 16) & 0xff; } for (i = 0; i < 256; i++) ColorMap[i].Red = ColorMap[i].Green = ColorMap[i].Blue = 0; i = 256; QuantizeBuffer(Width, Height, &i, RedInput, GreenInput, BlueInput, GIFBuffer, ColorMap); free(RedInput); free(GreenInput); free(BlueInput); return i; /* Real number of colors in color table. */ } #endif /* __SGI_GL__ */ /****************************************************************************** * Update the given scan line buffer with the pixel levels of the Y line. * * This routine is device specific, so make sure you know was you are doing * ******************************************************************************/ static void GetScanLine(GifPixelType *ScanLine, int Y) { unsigned char ScreenByte; int i, j, k; unsigned int BufferOffset, Bit; #ifdef __MSDOS__ union REGS InRegs, OutRegs; #endif /* __MSDOS__ */ switch (GraphDriver) { #ifdef __MSDOS__ case HERCMONO: BufferOffset = 0x2000 * (Y % 4) + (Y / 4) * (ScreenXMax / 8); /* In one scan lines we have ScreenXMax / 8 bytes: */ for (i = 0, k = 0; i < ScreenXMax / 8; i++) { ScreenByte = (unsigned char) peekb(ScreenBase, BufferOffset++); for (j = 0, Bit = 0x80; j < 8; j++) { ScanLine[k++] = (ScreenByte & Bit ? 1 : 0); Bit >>= 1; } } break; case EGA: case EGA64: case EGAMONO: case VGA: case SVGA_SPECIAL: InRegs.x.dx = Y; InRegs.h.bh = 0; InRegs.h.ah = 0x0d; /* BIOS Read dot. */ for (i = 0; i < ScreenXMax; i++) { InRegs.x.cx = i; int86(0x10, &InRegs, &OutRegs); ScanLine[i] = OutRegs.h.al; } /* Makr this line as done by putting a xored dot on the left. */ InRegs.x.dx = Y; InRegs.h.bh = 0; InRegs.h.ah = 0x0c; /* BIOS Write dot (xor mode). */ InRegs.h.al = 0x81; /* Xor with color 1. */ InRegs.x.cx = 0; int86(0x10, &InRegs, &OutRegs); InRegs.x.dx = Y; InRegs.h.bh = 0; InRegs.h.ah = 0x0c; /* BIOS Write dot (xor mode). */ InRegs.h.al = 0x81; /* Xor with color 1. */ InRegs.x.cx = 1; int86(0x10, &InRegs, &OutRegs); if (Y == ScreenYMax - 1) {/* Last row - clear all marks we made. */ for (i = 0; i < ScreenYMax; i++) { InRegs.h.bh = 0; InRegs.h.ah = 0x0c; /* BIOS Write dot (xor mode). */ InRegs.h.al = 0x81; /* Xor back with color 1. */ InRegs.x.dx = i; InRegs.x.cx = 0; int86(0x10, &InRegs, &OutRegs); InRegs.h.bh = 0; InRegs.h.ah = 0x0c; /* BIOS Write dot (xor mode). */ InRegs.h.al = 0x81; /* Xor back with color 1. */ InRegs.x.dx = i; InRegs.x.cx = 1; int86(0x10, &InRegs, &OutRegs); } } break; #endif /* __MSDOS__ */ #ifdef __SGI_GL__ case GIF_DUMP_SGI_WINDOW: memcpy(ScanLine, GlblGifBufferPtr, ScreenXMax * sizeof(GifPixelType)); GlblGifBufferPtr -= ScreenXMax; break; #endif /* __SGI_GL__ */ #ifdef __X11__ case GIF_DUMP_X_WINDOW: memcpy(ScanLine, GlblGifBufferPtr, ScreenXMax * sizeof(GifPixelType)); GlblGifBufferPtr += ScreenXMax; break; #endif /* __X11__ */ default: break; } } /****************************************************************************** * Handle last GIF error. Try to close the file and free all allocated memory. * ******************************************************************************/ static int HandleGifError(GifFileType *GifFile) { int i = GifLastError(); if (EGifCloseFile(GifFile) == GIF_ERROR) { GifLastError(); } return i; }