/*****************************************************************************/ /* Gift.c */ /*****************************************************************************/ /* standard C header files */ #include #include #include #include /* VMS header files */ #include #include #include #include /* application header files */ #include "gift.h" #include "alpha_08pt.h" #include "alpha_09pt.h" #include "alpha_10pt.h" #include "alpha_11pt.h" #include "alpha_12pt.h" #include "alpha_14pt.h" #include "alpha_16pt.h" #include "alpha_18pt.h" #include "alpha_20pt.h" #include "alpha_24pt.h" #include "alpha_28pt.h" #include "alpha_36pt.h" #include "alpha_48pt.h" #define VMSok(x) ((x) & STS$M_SUCCESS) #define VMSnok(x) !(((x) & STS$M_SUCCESS)) #define boolean int #define true 1 #define false 0 /* macro provides NULL pointer if CGI variable does not exist */ #define GetCgiVarIfExists(CharPointer,CgiVariableName) \ CharPointer = getenv(CgiVariableName) /* macro provides pointer to empty string even if CGI variable does not exist */ #define GetCgiVar(CharPointer,CgiVariableName) \ if ((CharPointer = getenv(CgiVariableName)) == NULL) \ CharPointer = ""; \ if (Debug) fprintf (stdout, "%s |%s|\n", CgiVariableName, CharPointer); extern boolean Debug, HttpHasBeenOutput; extern char *SoftwareID; extern FILE *HttpOut; boolean GraphicFontsInitialized, GraphicNoCacheGif = false; int GraphicBackground = 0, GraphicBitsPerPixel = 4, GraphicByteCount, GraphicColourBorder, GraphicColourBg, GraphicColourCount = 16, GraphicColourFg, GraphicHeight, GraphicHttpOutFd, GraphicFontPoints, GraphicPixelCount, GraphicTransparencyColour = -1, GraphicWidth, GraphicWidthBorder, GraphicWidthFg; unsigned char *GraphicPtr; #define MaxFonts 48 struct GraphicFontStruct Font [MaxFonts+1]; unsigned char GraphicRgbRed [] = { 000, 255, 000, 000, 255, 255, 000, 255, 192, 128, 000, 000, 128, 128, 128, 250 }; unsigned char GraphicRgbGreen [] = { 000, 000, 255, 000, 255, 000, 255, 255, 192, 000, 128, 000, 128, 000, 128, 240 }; unsigned char GraphicRgbBlue [] = { 000, 000, 000, 255, 000, 255, 255, 255, 192, 000, 000, 128, 000, 128, 128, 230 }; int GraphicColourBlack = 0, GraphicColourRed = 1, GraphicColourGreen = 2, GraphicColourBlue = 3, GraphicColourYellow = 4, GraphicColourMagenta = 5, GraphicColourCyan = 6, GraphicColourWhite = 7, GraphicColourGrey = 8, GraphicColourDRed = 9, GraphicColourDGreen = 10, GraphicColourDBlue = 11, GraphicColourDYellow = 12, GraphicColourDMagenta = 13, GraphicColourDCyan = 14, GraphicColourDWhite = 15; char *GraphicRgbName [] = { "black", "red", "green", "blue", "yellow", "magenta", "cyan", "white", "grey", "dred", "dgreen", "dblue", "dyellow", "dmagenta", "dcyan", "dwhite", "" }; /*****************************************************************************/ /* Create and send an image of example/test colours. */ GiftTestColours () { register int x, y; int Colour, ColourCount, Width; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftTestColours()\n"); for (ColourCount = 0; GraphicRgbName[ColourCount][0]; ColourCount++); GraphicHeight = y = (ColourCount * 35) + 100 + 50; GraphicWidth = 800; GiftNewGraphic (GraphicWidth, GraphicHeight, GraphicColourBlack); y -= 100; Font[36].Colour = GraphicColourYellow; GiftDrawString (150, y+30, "GIFT Colour Test", &Font[36]); GiftDrawString (150, y+20, "________________", &Font[36]); GiftDrawBorder (GraphicColourYellow, 1); for (Colour = 0; GraphicRgbName[Colour][0]; Colour++) { y -= 35; GiftDrawBlock (50, y, 140, y+30, GraphicColourWhite); GiftDrawString (60, y+(30-Font[10].CharHeight)/2, GraphicRgbName[Colour], &Font[10]); GiftDrawBlock (145, y, 750, y+30, Colour); } /* send the graphic to the client */ GiftImage (); } /*****************************************************************************/ /* Create and send an image of example/test graphics. */ GiftTestGraphics () { register int x, y; int Colour, Width; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftTestGraphics()\n"); GiftNewGraphic (800, 800, GraphicColourBlack); Font[36].Colour = GraphicColourYellow; GiftDrawString (150, 730, "GIFT Graphics Test", &Font[36]); GiftDrawString (150, 720, "__________________", &Font[36]); Colour = GraphicColourRed; Font[8].Colour = GraphicColourGreen; Font[12].Colour = GraphicColourGreen; y = 610; GiftDrawString (10, y+50, "Lines done with GiftDrawLine()", &Font[12]); GiftDrawString (10, y+35, "widths 1, 2, 4 & 8", &Font[8]); GiftDrawLine (250, y+40, 550, y+40, Colour, 1); GiftDrawLine (250, y+30, 550, y+30, Colour, 2); GiftDrawLine (250, y+17, 550, y+17, Colour, 4); GiftDrawLine (250, y, 550, y, Colour, 8); y = 360; GiftDrawString (10, y+215, "Shape done with GiftDrawLine()", &Font[12]); GiftDrawString (10, y+200, "Colour = GiftColour (\"blue\");\n\ y = 360;\n\ GiftDrawLine (100, y, 700, y, Colour, 1);\n\ GiftDrawLine (100, y+100, 700, y+100, Colour, 1);\n\ GiftDrawLine (100, y, 100, y+100, Colour, 1);\n\ GiftDrawLine (700, y, 700, y+100, Colour, 1);\n\ GiftDrawLine (100, y, 700, y+100, Colour, 1);\n\ GiftDrawLine (100, y+100, 700, y, Colour, 1);", &Font[8]); Colour = GraphicColourBlue; GiftDrawLine (100, y, 700, y, Colour, 1); GiftDrawLine (100,y+100, 700, y+100, Colour, 1); GiftDrawLine (100, y, 100, y+100, Colour, 1); GiftDrawLine (700, y, 700, y+100, Colour, 1); GiftDrawLine (100, y, 700, y+100, Colour, 1); GiftDrawLine (100, y+100, 700, y, Colour, 1); y = 180; GiftDrawString (10, y+145, "Blocks done with GiftDrawBlock()", &Font[12]); Font[10].Colour = GraphicColourBlack; Font[10].Italic = true; Colour = GraphicColourCyan; GiftDrawBlock (100, y+40, 700, y+130, Colour); GiftDrawString (110, y+43, "cyan", &Font[10]); Colour = GraphicColourMagenta; GiftDrawBlock (200, y+60, 600, y+110, Colour); GiftDrawString (210, y+63, "magenta", &Font[10]); Colour = GraphicColourYellow; GiftDrawBlock (300, y+70, 500, y+100, Colour); GiftDrawString (310, y+73, "yellow", &Font[10]); Font[10].Italic = false; Font[8].Colour = Colour = GraphicColourRed; GiftDrawLine (240, y+65, 340, y+30, Colour, 1); GiftDrawString (340, y+20, "(black against magenta doesn't\n stand out very well at all!)", &Font[8]); GiftDrawBorder (GraphicColourYellow, 1); /* send the graphic to the client */ GiftImage (); } /*****************************************************************************/ /* Create and send an image of all available fonts in various colours. */ GiftTestFonts () { static char *Colours [] = { "blue", "green", "red", "" }; register int idx; int Count, CountColour, CountFont, x, y; char FontSize [32], FwdString [96], RevString [96]; char *StringPtr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftTestFonts()\n"); if (!GraphicWidth) GraphicWidth = 800; if (!GraphicHeight) GraphicHeight = 1150; GiftNewGraphic (GraphicWidth, GraphicHeight, GraphicColourBlack); idx = 0; for (Count = 0x20; Count < 0x7f; Count++) FwdString[idx++] = Count; FwdString[idx] = '\0'; idx = 0; for (Count = 0x7e; Count >= 0x20; Count--) RevString[idx++] = Count; RevString[idx] = '\0'; y = 3; for (CountColour = 0; Colours[CountColour][0]; CountColour++) { for (CountFont = MaxFonts; CountFont; CountFont--) { if (!Font[CountFont].PointSize) continue; Font[CountFont].Colour = GiftColour (Colours[CountColour]); x = 3; sprintf (FontSize, "%dpts:", Font[CountFont].PointSize); x = GiftDrawString (x, y, FontSize, &Font[CountFont]); x = GiftDrawString (x, y, FwdString, &Font[CountFont]); y += Font[CountFont].CharHeight; } } Font[36].Colour = GraphicColourYellow; GiftDrawString (190, 1095, "GIFT Font Test", &Font[36]); GiftDrawString (190, 1085, "______________", &Font[36]); GiftDrawBorder (GraphicColourYellow, 1); /* send the graphic to the client */ GiftImage (); } /*****************************************************************************/ /* Allocate memory for a graphic of the specified size, then set all the pixels to the specifiied colour. */ GiftNewGraphic ( int Width, int Height, int Colour ) { /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftNewGraphic() %d,%d %d\n", Width, Height, Colour); if (!(GraphicWidth = Width)) GraphicWidth = DefaultGraphicWidth; if (!(GraphicHeight = Height)) GraphicHeight = DefaultGraphicHeight; GraphicPixelCount = GraphicWidth * GraphicHeight; if ((GraphicPtr = malloc (GraphicPixelCount)) == NULL) exit (ErrorGeneral ("Memory allocation failed.", __FILE__, __LINE__)); /* set all the pixels to background colour */ memset (GraphicPtr, Colour, GraphicPixelCount); } /*****************************************************************************/ /* Set all the pixels in the graphic to the specified colour. */ GiftBackground (int Colour) { /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftBackground() %d\n", Colour); memset (GraphicPtr, Colour, GraphicPixelCount); } /*****************************************************************************/ /* Initialize any defaults then create a new graphic. */ GiftInitGraphic () { /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftInitGraphic()\n"); if (GraphicPtr != NULL) exit (GiftGraphicErrorReport ("Graphic already initialized.")); if (!GraphicWidth) GraphicWidth = DefaultGraphicWidth; if (!GraphicHeight) GraphicHeight = DefaultGraphicHeight; if (!GraphicColourBorder) GraphicColourBorder = GiftColour (DefaultBorderColour); if (!GraphicWidthBorder) GraphicWidthBorder = DefaultBorderWidth; if (!GraphicColourBg) GraphicColourBg = GiftColour (DefaultGraphicColourBg); if (!GraphicColourFg) GraphicColourFg = GiftColour (DefaultGraphicColourFg); if (!GraphicWidthFg) GraphicWidthFg = DefaultGraphicWidthFg; GiftNewGraphic (GraphicWidth, GraphicHeight, GraphicColourBg); } /*****************************************************************************/ /* Returns the index number for the colour represented by the supplied name. If no colour matching the supplied string a graphic error message is generated. */ int GiftColour (char *ColourString) { register int idx; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftColour() |%s|\n", ColourString); if (isdigit(*ColourString)) { idx = atol(ColourString); if (idx >= 0 || idx < (1 << GraphicBitsPerPixel)) return (idx); } else { for (idx = 0; GraphicRgbName[idx][0]; idx++) { if (Debug) fprintf (stdout, "GraphicRgbName[%d] |%s|\n", idx, GraphicRgbName[idx]); if (strsame (GraphicRgbName[idx], ColourString, -1)) break; } if (GraphicRgbName[idx][0]) return (idx); } { /* local storage */ char String [256]; sprintf (String, "Colour \"%s\" unknown.", ColourString); exit (GiftGraphicErrorReport (String)); } } /*****************************************************************************/ /* Generate a graphic error message. This is designed to allow errors to be reported even though the browser is retrieving and displaying an image. The error message can contain multiple lines, and adjusts its height accordingly, but lines should be limited to 80 characters. */ int GiftGraphicErrorReport (char *ErrorMessage) { register char *cptr; int y, LineCount; char String [256]; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftGraphicErrorReport() |%s|\n", ErrorMessage); LineCount = 1; for (cptr = ErrorMessage; *cptr; cptr++) if (*cptr == '\n') LineCount++; sprintf (String, "Report generated by server (%s)", SoftwareID); GraphicWidth = (Font[10].CharWidth * 80) + 25; GraphicHeight = 100 + LineCount * 15; y = GraphicHeight - 100; GiftNewGraphic (GraphicWidth, GraphicHeight, GraphicColourBlack); Font[28].Colour = GraphicColourRed; Font[12].Colour = Font[10].Colour = GraphicColourYellow; GiftDrawString (10, y+50, "ERROR!", &Font[28]); GiftDrawString (13, y+30, String, &Font[12]); GiftDrawString (13, y, ErrorMessage, &Font[10]); GiftDrawBorder (GraphicColourYellow, 2); /* send the graphic to the client */ GiftImage (); return (SS$_NORMAL); } /*****************************************************************************/ /* Only returns if the font size is supported, if not generates a graphic error message. */ GiftCheckFont (int GraphicFontPoints) { char String [64]; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftCheckFont() %d\n", GraphicFontPoints); if (GraphicFontPoints >= 8 && GraphicFontPoints <= MaxFonts && Font[GraphicFontPoints].PointSize) return; sprintf (String, "Font size %d not supported.", GraphicFontPoints); exit (GiftGraphicErrorReport (String)); } /*****************************************************************************/ /* Initialize the font structures with "define"d information from the included X-bitmap files. An array of font structures is used, where each element corresponding to a supported font point size has font data in it. This function may be called at any time to re-initialize all fonts. The fonts sizes supported are indicated by indicies being initialized. */ GiftInitFonts () { register int idx; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftInitFonts()\n"); for (idx = 0; idx <= MaxFonts; idx++) memset (&Font[idx], 0, sizeof(Font[idx])); Font[8].XbmHeight = alpha_08pt_height; Font[8].XbmWidth = alpha_08pt_width; Font[8].Bits = alpha_08pt_bits; Font[8].NumberOfChar = alpha_08pt_font_number_of_char; Font[8].FirstChar = alpha_08pt_font_first_char; Font[8].CharHeight = alpha_08pt_font_height; Font[8].CharWidth = alpha_08pt_font_width; Font[8].PointSize = 08; Font[8].Colour = GraphicColourBlack; Font[9].XbmHeight = alpha_09pt_height; Font[9].XbmWidth = alpha_09pt_width; Font[9].Bits = alpha_09pt_bits; Font[9].NumberOfChar = alpha_09pt_font_number_of_char; Font[9].FirstChar = alpha_09pt_font_first_char; Font[9].CharHeight = alpha_09pt_font_height; Font[9].CharWidth = alpha_09pt_font_width; Font[9].PointSize = 09; Font[9].Colour = GraphicColourBlack; Font[10].XbmHeight = alpha_10pt_height; Font[10].XbmWidth = alpha_10pt_width; Font[10].Bits = alpha_10pt_bits; Font[10].NumberOfChar = alpha_10pt_font_number_of_char; Font[10].FirstChar = alpha_10pt_font_first_char; Font[10].CharHeight = alpha_10pt_font_height; Font[10].CharWidth = alpha_10pt_font_width; Font[10].PointSize = 10; Font[10].Colour = GraphicColourBlack; Font[11].XbmHeight = alpha_11pt_height; Font[11].XbmWidth = alpha_11pt_width; Font[11].Bits = alpha_11pt_bits; Font[11].NumberOfChar = alpha_11pt_font_number_of_char; Font[11].FirstChar = alpha_11pt_font_first_char; Font[11].CharHeight = alpha_11pt_font_height; Font[11].CharWidth = alpha_11pt_font_width; Font[11].PointSize = 11; Font[11].Colour = GraphicColourBlack; Font[12].XbmHeight = alpha_12pt_height; Font[12].XbmWidth = alpha_12pt_width; Font[12].Bits = alpha_12pt_bits; Font[12].NumberOfChar = alpha_12pt_font_number_of_char; Font[12].FirstChar = alpha_12pt_font_first_char; Font[12].CharHeight = alpha_12pt_font_height; Font[12].CharWidth = alpha_12pt_font_width; Font[12].PointSize = 12; Font[12].Colour = GraphicColourBlack; Font[14].XbmHeight = alpha_14pt_height; Font[14].XbmWidth = alpha_14pt_width; Font[14].Bits = alpha_14pt_bits; Font[14].NumberOfChar = alpha_14pt_font_number_of_char; Font[14].FirstChar = alpha_14pt_font_first_char; Font[14].CharHeight = alpha_14pt_font_height; Font[14].CharWidth = alpha_14pt_font_width; Font[14].PointSize = 14; Font[14].Colour = GraphicColourBlack; Font[16].XbmHeight = alpha_16pt_height; Font[16].XbmWidth = alpha_16pt_width; Font[16].Bits = alpha_16pt_bits; Font[16].NumberOfChar = alpha_16pt_font_number_of_char; Font[16].FirstChar = alpha_16pt_font_first_char; Font[16].CharHeight = alpha_16pt_font_height; Font[16].CharWidth = alpha_16pt_font_width; Font[16].PointSize = 16; Font[16].Colour = GraphicColourBlack; Font[18].XbmHeight = alpha_18pt_height; Font[18].XbmWidth = alpha_18pt_width; Font[18].Bits = alpha_18pt_bits; Font[18].NumberOfChar = alpha_18pt_font_number_of_char; Font[18].FirstChar = alpha_18pt_font_first_char; Font[18].CharHeight = alpha_18pt_font_height; Font[18].CharWidth = alpha_18pt_font_width; Font[18].PointSize = 18; Font[18].Colour = GraphicColourBlack; Font[20].XbmHeight = alpha_20pt_height; Font[20].XbmWidth = alpha_20pt_width; Font[20].Bits = alpha_20pt_bits; Font[20].NumberOfChar = alpha_20pt_font_number_of_char; Font[20].FirstChar = alpha_20pt_font_first_char; Font[20].CharHeight = alpha_20pt_font_height; Font[20].CharWidth = alpha_20pt_font_width; Font[20].PointSize = 20; Font[20].Colour = GraphicColourBlack; Font[24].XbmHeight = alpha_24pt_height; Font[24].XbmWidth = alpha_24pt_width; Font[24].Bits = alpha_24pt_bits; Font[24].NumberOfChar = alpha_24pt_font_number_of_char; Font[24].FirstChar = alpha_24pt_font_first_char; Font[24].CharHeight = alpha_24pt_font_height; Font[24].CharWidth = alpha_24pt_font_width; Font[24].PointSize = 24; Font[24].Colour = GraphicColourBlack; Font[28].XbmHeight = alpha_28pt_height; Font[28].XbmWidth = alpha_28pt_width; Font[28].Bits = alpha_28pt_bits; Font[28].NumberOfChar = alpha_28pt_font_number_of_char; Font[28].FirstChar = alpha_28pt_font_first_char; Font[28].CharHeight = alpha_28pt_font_height; Font[28].CharWidth = alpha_28pt_font_width; Font[28].PointSize = 28; Font[28].Colour = GraphicColourBlack; Font[36].XbmHeight = alpha_36pt_height; Font[36].XbmWidth = alpha_36pt_width; Font[36].Bits = alpha_36pt_bits; Font[36].NumberOfChar = alpha_36pt_font_number_of_char; Font[36].FirstChar = alpha_36pt_font_first_char; Font[36].CharHeight = alpha_36pt_font_height; Font[36].CharWidth = alpha_36pt_font_width; Font[36].PointSize = 36; Font[36].Colour = GraphicColourBlack; Font[48].XbmHeight = alpha_48pt_height; Font[48].XbmWidth = alpha_48pt_width; Font[48].Bits = alpha_48pt_bits; Font[48].NumberOfChar = alpha_48pt_font_number_of_char; Font[48].FirstChar = alpha_48pt_font_first_char; Font[48].CharHeight = alpha_48pt_font_height; Font[48].CharWidth = alpha_48pt_font_width; Font[48].PointSize = 48; Font[48].Colour = GraphicColourBlack; GraphicFontsInitialized = true; } /*****************************************************************************/ /* Draws a string of characters using the supplied font. A new-line character moves the line down the graphic by the height of the font. */ int GiftDrawString ( int atx, int aty, char *String, struct GraphicFontStruct *FontPtr ) { register char *cptr; int x, y; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftDrawString() %d,%d |%s|\n", atx, aty, String); if (!GraphicFontsInitialized) GiftInitFonts (); x = atx; y = aty; for (cptr = String; *cptr; cptr++) { switch (*cptr) { case '\r' : x = atx; break; case '\n' : x = atx; y -= FontPtr->CharHeight; break; default : x = GiftDrawChar (x, y, *cptr, FontPtr); } } return (x); } /*****************************************************************************/ /* Draws ASCII character in parameter 'c' at (x,y) from the font pointed to by 'FontPtr'. The fonts used are X-bitmap representations of fixed-fonts of various point sizes. Each character has a fixed width and height, and so is relatively easy to render. Characters can be italicised, bolded, underlined, doubled in height, reverse-videoed, by setting the appropriate boolean in the font structure. */ GiftDrawChar ( int atx, int aty, int c, struct GraphicFontStruct *FontPtr ) { register unsigned char fb; register int x, y, tox, toy, fbit, flip, pixcnt; int PixelSize; int BytesPerRow, FontByte, PixelWidth, OriginalAtX, RowCount, UnderLineRow, XWidth; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftDrawChar() %d %d,%d\n", c, atx, aty); if (c < 0x20 || c > 0x7e) return; if (!FontPtr->PointSize) return; OriginalAtX = atx; if (FontPtr->Double) PixelWidth = PixelSize = 2; else PixelWidth = PixelSize = 1; if (FontPtr->Bold) PixelSize = 2; else if (!FontPtr->Double) PixelSize = 1; if (FontPtr->UnderLine) UnderLineRow = FontPtr->XbmHeight - 1; else UnderLineRow = -1; XWidth = (FontPtr->CharWidth * PixelWidth); /* zero equals one pixel, one equals 2 pixels, etc. */ PixelSize--; /* X bitmap rows always end in a whole byte */ if (FontPtr->XbmWidth % 8) BytesPerRow = (FontPtr->XbmWidth / 8) + 1; else BytesPerRow = FontPtr->XbmWidth / 8; for (RowCount = FontPtr->CharHeight - 1; RowCount >= 0; RowCount--) { if (Debug) fprintf (stdout, "RowCount: %d x,y: %d,%d\n", RowCount, atx, aty); if (RowCount == UnderLineRow) { if (FontPtr->Inverse) flip = 0x00; else flip = 0xff; } else { if (FontPtr->Inverse) flip = 0xff; else flip = 0x00; } FontByte = (RowCount * BytesPerRow) + (((c - FontPtr->FirstChar) * FontPtr->CharWidth) / 8); fbit = ((c - FontPtr->FirstChar) * FontPtr->CharWidth) % 8; if (fbit) fbit = 0x01 << fbit; else fbit = 0x01; pixcnt = FontPtr->CharWidth; fb = (*(FontPtr->Bits + FontByte)) ^ flip; if (Debug) fprintf (stdout, "FontByte: %d fbit: %d pixcnt: %d\n", FontByte, fbit, pixcnt); while (pixcnt--) { if (fb & fbit) { if (atx >= 0 && atx < GraphicWidth && aty >= 0 && aty < GraphicHeight) { if ((tox = atx + PixelSize) >= GraphicWidth) tox = GraphicWidth - 1; if ((toy = aty + PixelSize) >= GraphicHeight) tox = GraphicHeight - 1; if (PixelSize) { for (x = atx; x <= tox; x++) for (y = aty; y <= toy; y++) *(GraphicPtr + (y * GraphicWidth) + x) = FontPtr->Colour; } else *(GraphicPtr + (aty * GraphicWidth) + atx) = FontPtr->Colour; } } atx += PixelWidth; if (!pixcnt) break; if (fbit & 0x80) { fbit = 0x01; fb = (*(FontPtr->Bits + ++FontByte)) ^ flip; } else fbit = fbit << 1; } if (!FontPtr->Italic || RowCount % 3) atx -= XWidth; else atx -= XWidth - 1; aty += PixelWidth; } return (OriginalAtX + XWidth); } /*****************************************************************************/ /* The basic point drawing/plotting function. Draws a point at (x,y) in the specified colour. Width specifies the size of the point, 1 being one pixel, 2 being 2x2 pixels, 3 being 3x3 pixels, etc. Points with widths greater than 1 begin at the specified (x,y) and grow in the x and y directions. Generates a graphic error message if coordinates are out-of-range. */ GiftDrawPoint ( int atx, int aty, int Colour, int Width ) { /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftDrawPoint() %d,%d\n", atx, aty); if (!Width) return; if (atx >= 0 && atx < GraphicWidth && aty >= 0 && aty <= GraphicHeight) { if (Width == 1) { *(GraphicPtr + (aty * GraphicWidth) + atx) = Colour; return; } else if (Width > 1) { /* local storage */ register int x, y, tox, toy; if (Width > MaxPointWidth) Width = MaxPointWidth; if ((tox = atx + Width) >= GraphicWidth) tox = GraphicWidth - 1; if ((toy = aty + Width) >= GraphicHeight) tox = GraphicHeight - 1; for (x = atx; x <= tox; x++) for (y = aty; y <= toy; y++) *(GraphicPtr + (y * GraphicWidth) + x) = Colour; return; } } { /* local storage */ char String [256]; sprintf (String, "Point (%d,%d) out-of-range within %dx%d.", atx, aty, GraphicWidth, GraphicHeight); exit (GiftGraphicErrorReport (String)); } } /*****************************************************************************/ /* Draws a straight line from (x1,y1) to (x2,y2) of the specified colour and width. Generates a graphic error message if coordinates out-of-range. For efficiency plots its own points without calling GiftDrawPoint(). */ GiftDrawLine ( int x1, int y1, int x2, int y2, int Colour, int Width ) { register int i, x, xinc, y, ygrad, yinc; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftDrawLine() %d,%d %d,%d %d %d\n", x1, y1, x2, y2, Colour, Width); if (!Width) return; if (x1 < 0 || x1 >= GraphicWidth || x2 < 0 || x2 >= GraphicWidth || y1 < 0 || y1 >= GraphicHeight || y2 < 0 || y2 >= GraphicHeight) { /* local storage */ char String [256]; sprintf (String, "Line (%d,%d)(%d,%d) out-of-range within %dx%d.", x1, y1, x2, y2, GraphicWidth, GraphicHeight); exit (GiftGraphicErrorReport (String)); } if (x1 > x2) { x = x1; x1 = x2; x2 = x; y = y1; y1 = y2; y2 = y; } if (x1 == x2) xinc = 0; else xinc = 1; if (y2 - y1 == 0) i = ygrad = 0; else if ((i = ygrad = (x2 - x1) / (y2 - y1)) == 0) i = ygrad = 1; if (ygrad < 0) yinc = -1; else yinc = 1; if (Debug) fprintf (stdout, "%d,%d %d,%d yinc: %d ygrad: %d\n", x1, y1, x2, y2, yinc, ygrad); y = y1; x = x1; while (x <= x2 && ((yinc > 0 && y <= y2) || (yinc < 0 && y >= y2))) { /* plot the point */ if (Width == 1) *(GraphicPtr + (y * GraphicWidth) + x) = Colour; else { /* local storage */ register int xx, yy, tox, toy; if (Width > MaxPointWidth) Width = MaxPointWidth; if ((tox = x + Width) >= GraphicWidth) tox = GraphicWidth - 1; if ((toy = y + Width) >= GraphicHeight) tox = GraphicHeight - 1; for (xx = x; xx <= tox; xx++) for (yy = y; yy <= toy; yy++) *(GraphicPtr + (yy * GraphicWidth) + xx) = Colour; } x += xinc; i -= yinc; if (!i && ygrad) { if (y2 - y == 0) i = ygrad = 0; else if ((i = ygrad = (x2 - x) / (y2 - y)) == 0) i = ygrad = 1; y += yinc; } } } /*****************************************************************************/ /* Draw a rectangle with opposite corners defined by (x1,y1) and (x2,y2) of the specified colour and width. */ GiftDrawRect ( int x1, int y1, int x2, int y2, int Colour, int Width ) { register int x, y; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftDrawRect() %d,%d %d,%d %d\n", x1, y1, x2, y2, Colour); if (x1 < 0 || x1 >= GraphicWidth || x2 < 0 || x2 >= GraphicWidth || y1 < 0 || y1 >= GraphicHeight || y2 < 0 || y2 >= GraphicHeight) { /* local storage */ char String [256]; sprintf (String, "Rectangle (%d,%d %d,%d) out-of-range within %dx%d.", x1, y1, x2, y2, GraphicWidth, GraphicHeight); exit (GiftGraphicErrorReport (String)); } GiftDrawLine (x1, y1, x1, y2, Colour, Width); GiftDrawLine (x1, y2, x2, y2, Colour, Width); GiftDrawLine (x2, y2, x2, y1, Colour, Width); GiftDrawLine (x2, y1, x1, y1, Colour, Width); } /*****************************************************************************/ /* Draw a rectangle with opposite corners defined by (x1,y1) and (x2,y2) filled with the specified colour. */ GiftDrawBlock ( int x1, int y1, int x2, int y2, int Colour ) { register int x, y; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftDrawBlock() %d,%d %d,%d %d\n", x1, y1, x2, y2, Colour); if (x1 < 0 || x1 >= GraphicWidth || x2 < 0 || x2 >= GraphicWidth || y1 < 0 || y1 >= GraphicHeight || y2 < 0 || y2 >= GraphicHeight) { /* local storage */ char String [256]; sprintf (String, "Block (%d,%d %d,%d) out-of-range within %dx%d.", x1, y1, x2, y2, GraphicWidth, GraphicHeight); exit (GiftGraphicErrorReport (String)); } if (x1 > x2) { x = x1; x1 = x2; x2 = x; } if (y1 > y2) { y = y1; y1 = y2; y2 = y; } for (x = x1; x <= x2; x++) GiftDrawLine (x, y1, x, y2, Colour, 1); } /*****************************************************************************/ /* Place a border of the specified colour and width around the entire graphic. */ GiftDrawBorder ( int Colour, int Width ) { register int x, y, cnt; register unsigned char *gptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftDrawBorder() %d %d\n", Colour, Width); if (Width <= 0) Width = 1; else if (Width >= GraphicWidth) Width = GraphicWidth - 1; else if (Width >= GraphicHeight) Width = GraphicHeight - 1; if (Width > MaxPointWidth) Width = MaxPointWidth; for (cnt = 0; cnt < Width; cnt++) { gptr = GraphicPtr + (cnt * GraphicWidth); for (x = 0; x < GraphicWidth; x++) *gptr++ = Colour; } for (cnt = Width; cnt; cnt--) { gptr = GraphicPtr + (GraphicHeight - cnt) * GraphicWidth; for (x = 0; x < GraphicWidth; x++) *gptr++ = Colour; } for (cnt = 0; cnt < Width; cnt++) { gptr = GraphicPtr + cnt; for (y = 0; y < GraphicHeight; y++) *(gptr + (y * GraphicWidth)) = Colour; } for (cnt = Width; cnt; cnt--) { gptr = GraphicPtr + GraphicWidth - cnt; for (y = 0; y < GraphicHeight; y++) *(gptr + (y * GraphicWidth)) = Colour; } } /*****************************************************************************/ /* Create and send a graphic percentage-used bar. */ GiftUsageBar ( int Percentage, int AlertPercentage, char *Text ) { int UsageColour, y; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftUsageBar()\n"); if (!GraphicWidth) GraphicWidth = 500; if (!GraphicHeight) GraphicHeight = 30; GiftNewGraphic (GraphicWidth, GraphicHeight, GraphicColourWhite); if (AlertPercentage && Percentage >= AlertPercentage) UsageColour = GraphicColourRed; else UsageColour = GraphicColourGreen; /* draw a "dirty-white" progress bar to overlay the white background */ GiftDrawBar (GraphicColourDWhite, 100); /* draw the appropriate colour progress bar to indicate usage */ GiftDrawBar (UsageColour, Percentage); /* put a black border around the graphic */ GiftDrawBorder (GraphicColourBlack, 1); if (Text[0]) { y = GraphicHeight / 4; if (AlertPercentage && Percentage >= AlertPercentage) { Font[10].Bold = true; Font[10].Colour = GraphicColourWhite; GiftDrawString (11, y-1, Text, &Font[10]); } Font[10].Colour = GraphicColourBlack; GiftDrawString (10, y, Text, &Font[10]); Font[10].Bold = false; } /* send the graphic to the client */ GiftImage (); } /*****************************************************************************/ /* Draws a percentage bar from left to right. The bar is solid colour, but graduated by leaving 2 pixels blank at 10% points, one pixel at 5% points. */ GiftDrawBar ( int Colour, int Percentage ) { register int x, y, cnt; register unsigned char *pptr; int SolidPixels, Width; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftDrawBar() %d %d\n", Colour, Percentage); /* convert from a percentage to an actual number of pixels */ if ((Width = (Percentage * GraphicWidth) / 100) >= GraphicWidth) Width = GraphicWidth - 1; SolidPixels = GraphicWidth / 20; for (y = 0; y < GraphicHeight; y++) { pptr = GraphicPtr + (y * GraphicWidth); x = 0; while (x < Width) { if (x % 2) cnt = SolidPixels - 1; else { if (x+1 < Width) { x++; pptr++; } cnt = SolidPixels - 2; } while (cnt-- && x++ < Width) *pptr++ = Colour; if (x+1 < Width) { x++; pptr++; } } } } /*****************************************************************************/ /* */ GiftButton ( char *ColourName, char *Text, int FontPoints ) { int ButtonColour; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftButton() |%s|%s| %d\n", ColourName, Text, FontPoints); GraphicWidth = GraphicHeight = 0; if (ColourName == NULL) ColourName = ""; if (Text == NULL) Text = ""; if (ColourName[0]) ButtonColour = GiftColour (ColourName); else ButtonColour = GiftColour (DefaultButtonColour); if (!FontPoints) FontPoints = DefaultButtonFontPoints; GiftDrawButton (ButtonColour, Text, &Font[FontPoints]); } /*****************************************************************************/ /* */ GiftDrawButton ( int ButtonColour, char *Text, struct GraphicFontStruct *FontPtr ) { register char *cptr, *sptr; int x, y, TextHeight, LongestLine, LineCount, TextWidth; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftDrawButton() %d |%s|\n", ButtonColour, Text); if (!GraphicFontsInitialized) GiftInitFonts (); LongestLine = 0; LineCount = 1; for (cptr = sptr = Text; *cptr; cptr++) { if (*cptr == '\n') { LineCount++; if (cptr - sptr > LongestLine) LongestLine = cptr - sptr; sptr = ++cptr; } } if (cptr - sptr > LongestLine) LongestLine = cptr - sptr; TextWidth = (FontPtr->CharWidth * LongestLine); TextHeight = (FontPtr->CharHeight * LineCount); if (!GraphicWidth) GraphicWidth = TextWidth + (FontPtr->CharWidth * 2); if (!GraphicHeight) GraphicHeight = TextHeight + (FontPtr->CharHeight / 2); GiftNewGraphic (GraphicWidth, GraphicHeight, GraphicColourGrey); x = (GraphicWidth - TextWidth) / 2; y = GraphicHeight - ((GraphicHeight - TextHeight) / 2) - FontPtr->CharHeight - 1; /** if (FontPtr->PointSize > 10) FontPtr->Bold = true; **/ FontPtr->Colour = GraphicColourWhite; GiftDrawString (x+1, y-1, Text, FontPtr); FontPtr->Colour = GraphicColourBlack; GiftDrawString (x, y, Text, FontPtr); /** if (FontPtr->PointSize > 10) FontPtr->Bold = false; **/ GiftDrawBorder (GraphicColourBlack, 2); GiftDrawLine (0, 1, 0, GraphicHeight-2, ButtonColour, 1); GiftDrawLine (1, GraphicHeight-1, GraphicWidth-2, GraphicHeight-1, ButtonColour, 1); /* send the graphic to the client */ GiftImage (); } /*****************************************************************************/ /* Parses the supplied string for directives. */ GiftParseParameters ( char *String, int LineNumber ) { register char *cptr, *sptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftParseParameters() |%s|\n", String); cptr = String; while (*cptr) { if (Debug) fprintf (stdout, "cptr |%s|\n", cptr); if (toupper(cptr[0]) == 'P' && toupper(cptr[1]) == 'N' && toupper(cptr[2]) == 'T' && (cptr[3] == '=' || cptr[3] == ':')) { /**************/ /* draw point */ /**************/ int x, y; if (Debug) fprintf (stdout, "draw point\n"); sptr = (cptr += 4); while (isdigit(*cptr)) cptr++; if (*cptr != ',') exit (GiftParseError ("Syntax", sptr-String, LineNumber)); *cptr++ = '\0'; if (!isdigit(*sptr)) exit (GiftParseError ("Syntax", sptr-String, LineNumber)); x = atol(sptr); sptr = cptr; while (isdigit(*cptr)) cptr++; if (*cptr && (*cptr != '&' || *cptr != ';')) exit (GiftParseError ("Syntax", sptr-String, LineNumber)); if (*cptr) *cptr++ = '\0'; if (!isdigit(*sptr)) exit (GiftParseError ("Syntax", sptr-String, LineNumber)); y = atol(sptr); if (GraphicPtr == NULL) GiftInitGraphic (); GiftDrawPoint (x, y, GraphicColourFg, GraphicWidthFg); continue; } if (toupper(cptr[0]) == 'P' && toupper(cptr[1]) == 'R' && toupper(cptr[2]) == 'O' && (cptr[3] == '=' || cptr[3] == ':')) { /***********************/ /* draw a progress bar */ /***********************/ int Percentage, ProgressBarAlertPercentage; if (Debug) fprintf (stdout, "draw progress-bar\n"); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';' && *cptr != ',') cptr++; if (*cptr == ',') ProgressBarAlertPercentage = 0; else ProgressBarAlertPercentage = 101; if (*cptr) *cptr++ = '\0'; Percentage = atol(sptr); if (!isdigit(*sptr) || Percentage < 0 || Percentage > 100) exit (GiftParseError ("Syntax", sptr-String, LineNumber)); if (!ProgressBarAlertPercentage) { sptr = cptr; while (*cptr && *cptr != '&' && *cptr != ';') cptr++; if (*cptr) *cptr++ = '\0'; ProgressBarAlertPercentage = atol(sptr); if (!isdigit(*sptr) || ProgressBarAlertPercentage < 0 || ProgressBarAlertPercentage > 100) exit (GiftParseError ("Syntax", sptr-String, LineNumber)); } if (!GraphicWidth) GraphicWidth = DefaultProgressBarWidth; if (!GraphicHeight) GraphicHeight = DefaultProgressBarHeight; if (!GraphicColourFg) GraphicColourFg = GiftColour (DefaultProgressBarColour); if (Percentage >= ProgressBarAlertPercentage) GraphicColourFg = GiftColour (DefaultProgressBarAlertColour); if (GraphicPtr == NULL) GiftInitGraphic (); GiftBackground (GraphicColourWhite); GiftDrawBar (GraphicColourDWhite, 100); GiftDrawBar (GraphicColourFg, Percentage); GiftDrawBorder (GraphicColourBorder, GraphicWidthBorder); continue; } if (toupper(cptr[0]) == 'B' && toupper(cptr[1]) == 'U' && toupper(cptr[2]) == 'T' && (cptr[3] == '=' || cptr[3] == ':')) { /*****************/ /* draw a button */ /*****************/ char Text [256]; if (Debug) fprintf (stdout, "draw button\n"); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';' && *cptr != ',') cptr++; if (*cptr) *cptr++ = '\0'; GiftCopyTextFromUrl (sptr, Text, sizeof(Text)); if (!GraphicColourFg) GraphicColourFg = GiftColour (DefaultButtonColour); if (!GraphicFontPoints) GraphicFontPoints = DefaultButtonFontPoints; GiftDrawButton (GraphicColourFg, Text, &Font[GraphicFontPoints]); continue; } if (toupper(cptr[0]) == 'F' && toupper(cptr[1]) == 'G' && toupper(cptr[2]) == 'C' && (cptr[3] == '=' || cptr[3] == ':')) { /*********************/ /* foreground colour */ /*********************/ if (Debug) fprintf (stdout, "foreground colour\n"); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';') cptr++; if (*cptr) *cptr++ = '\0'; GraphicColourFg = GiftColour (sptr); continue; } if (toupper(cptr[0]) == 'F' && toupper(cptr[1]) == 'G' && toupper(cptr[2]) == 'W' && (cptr[3] == '=' || cptr[3] == ':')) { /********************/ /* foreground width */ /********************/ if (Debug) fprintf (stdout, "foreground width\n"); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';') cptr++; if (*cptr) *cptr++ = '\0'; GraphicWidthFg = atol(sptr); if (GraphicWidthFg < 0 || GraphicWidthFg >= GraphicWidth || GraphicWidthFg >= GraphicHeight) exit (GiftParseError ("Foreground width", sptr-String, LineNumber)); continue; } if (toupper(cptr[0]) == 'B' && toupper(cptr[1]) == 'G' && toupper(cptr[2]) == 'C' && (cptr[3] == '=' || cptr[3] == ':')) { /*********************/ /* background colour */ /*********************/ if (Debug) fprintf (stdout, "background colour\n"); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';') cptr++; if (*cptr) *cptr++ = '\0'; GraphicColourBg = GiftColour (sptr); continue; } if (toupper(cptr[0]) == 'T' && toupper(cptr[1]) == 'R' && toupper(cptr[2]) == 'C' && (cptr[3] == '=' || cptr[3] == ':')) { /***********************/ /* transparency colour */ /***********************/ if (Debug) fprintf (stdout, "transparency colour\n"); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';') cptr++; if (*cptr) *cptr++ = '\0'; GraphicTransparencyColour = GiftColour (sptr); continue; } if (toupper(cptr[0]) == 'B' && toupper(cptr[1]) == 'D' && toupper(cptr[2]) == 'C' && (cptr[3] == '=' || cptr[3] == ':')) { /*****************/ /* border colour */ /*****************/ if (Debug) fprintf (stdout, "border colour\n"); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';') cptr++; if (*cptr) *cptr++ = '\0'; GraphicColourBorder = GiftColour (sptr); continue; } if (toupper(cptr[0]) == 'B' && toupper(cptr[1]) == 'D' && toupper(cptr[2]) == 'W' && (cptr[3] == '=' || cptr[3] == ':')) { /****************/ /* border width */ /****************/ if (Debug) fprintf (stdout, "border width\n"); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';') cptr++; if (*cptr) *cptr++ = '\0'; GraphicWidthBorder = atol(sptr); /* possibly need to initialize the GIF to set height and width */ if (GraphicPtr == NULL) GiftInitGraphic (); if (GraphicWidthBorder < 0 || GraphicWidthBorder >= GraphicWidth || GraphicWidthBorder >= GraphicHeight) exit (GiftParseError ("Border width", sptr-String, LineNumber)); GiftDrawBorder (GraphicColourBorder, GraphicWidthBorder); continue; } if (toupper(cptr[0]) == 'G' && toupper(cptr[1]) == 'R' && toupper(cptr[2]) == 'W' && (cptr[3] == '=' || cptr[3] == ':')) { /*****************/ /* graphic width */ /*****************/ if (Debug) fprintf (stdout, "graphic width\n"); if (GraphicPtr != NULL) exit (GiftParseError ("Multiple graphic width", sptr-String, LineNumber)); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';') cptr++; if (*cptr) *cptr++ = '\0'; GraphicWidth = atol(sptr); if (GraphicWidth <= 0 || GraphicWidth >= MaxGraphicWidth) exit (GiftParseError ("Graphic width", sptr-String, LineNumber)); continue; } if (toupper(cptr[0]) == 'G' && toupper(cptr[1]) == 'R' && toupper(cptr[2]) == 'H' && (cptr[3] == '=' || cptr[3] == ':')) { /******************/ /* graphic height */ /******************/ if (Debug) fprintf (stdout, "graphic height\n"); if (GraphicPtr != NULL) exit (GiftParseError ("Multiple graphic height", sptr-String, LineNumber)); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';') cptr++; if (*cptr) *cptr++ = '\0'; GraphicHeight = atol(sptr); if (GraphicHeight <= 0 || GraphicHeight >= MaxGraphicHeight) exit (GiftParseError ("Graphic height", sptr-String, LineNumber)); continue; } if (toupper(cptr[0]) == 'C' && toupper(cptr[1]) == 'O' && toupper(cptr[2]) == 'L' && (cptr[3] == '=' || cptr[3] == ':')) { /*******************/ /* redefine colour */ /*******************/ static char ErrorRedefine [] = "Redefine colour error."; int Index, Red, Green, Blue; if (Debug) fprintf (stdout, "redefine colour\n"); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';' && *cptr != ',') cptr++; if (*cptr != ',') exit (GiftParseError ("Syntax", sptr-String, LineNumber)); *cptr++ = '\0'; Index = GiftColour (sptr); Red = Green = Blue = -1; sptr = cptr; while (*cptr && *cptr != '&' && *cptr != ';' && *cptr != ',') cptr++; if (*cptr != ',') exit (GiftParseError ("Syntax", sptr-String, LineNumber)); *cptr++ = '\0'; if (!isdigit(*sptr)) exit (GiftParseError ("Syntax", sptr-String, LineNumber)); Red = atol(sptr); sptr = cptr; while (*cptr && *cptr != '&' && *cptr != ';' && *cptr != ',') cptr++; if (*cptr != ',') exit (GiftParseError ("Syntax", sptr-String, LineNumber)); *cptr++ = '\0'; if (!isdigit(*sptr)) exit (GiftParseError ("Syntax", sptr-String, LineNumber)); Green = atol(sptr); sptr = cptr; while (*cptr && *cptr != '&' && *cptr != ';' && *cptr != ',') cptr++; if (*cptr && *cptr == ',') exit (GiftParseError ("Syntax", sptr-String, LineNumber)); if (*cptr) *cptr++ = '\0'; if (!isdigit(*sptr)) exit (GiftParseError ("Syntax", sptr-String, LineNumber)); Blue = atol(sptr); if (Red < 0 || Red > 255 || Green < 0 || Green > 255 || Blue < 0 || Blue > 255) exit (GiftParseError ("Colour specification", sptr-String, LineNumber)); GraphicRgbRed[Index] = Red; GraphicRgbGreen[Index] = Green; GraphicRgbBlue[Index] = Blue; continue; } if (toupper(cptr[0]) == 'F' && toupper(cptr[1]) == 'N' && toupper(cptr[2]) == 'T' && (cptr[3] == '=' || cptr[3] == ':')) { /***************/ /* font points */ /***************/ if (Debug) fprintf (stdout, "font points\n"); sptr = (cptr += 4); while (*cptr && *cptr != '&' && *cptr != ';') cptr++; if (*cptr) *cptr++ = '\0'; if (!isdigit(*sptr)) exit (GiftParseError ("Syntax", sptr-String, LineNumber)); GraphicFontPoints = atol(sptr); GiftCheckFont (GraphicFontPoints); continue; } /*********************/ /* unknown parameter */ /*********************/ sptr = cptr; while (*cptr && *cptr != '&' && *cptr != ';') cptr++; *cptr = '\0'; exit (GiftParseError ("Unknown parameter", sptr-String, LineNumber)); } } /*****************************************************************************/ /* Copy text from one string to another, converting characters forbidden to appear as plain-text in an HTTP URL back into plain-text. For example the '?', '+', '&', etc., are converted from "%nn" hexadecimal escaped characters. */ int GiftCopyTextFromUrl ( register char *sptr, register char *DestPtr, register int SizeOfDest ) { register char c; register char *dptr, *zptr; if (!SizeOfDest) return (0); zptr = (dptr = DestPtr) + SizeOfDest; while (*sptr && dptr < zptr) { if (*sptr == '%') { /* an escaped character ("%xx" where xx is a hexadecimal number) */ sptr++; if (*sptr) sptr++; if (*sptr) sptr++; c = *sptr; *sptr = '\0'; *dptr++ = (unsigned char) strtol (sptr-2, NULL, 16); *sptr = c; } else *dptr++ = *sptr++; } if (sptr >= zptr) dptr = DestPtr; *dptr = '\0'; return (dptr - DestPtr); } /*****************************************************************************/ /* */ GiftParseError ( char *Text, int CharacterNumber, int LineNumber ) { char String [256]; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftParseError() |%s| %d %d\n", Text, CharacterNumber, LineNumber); if (LineNumber) sprintf (String, "%s problem at character %d of line %d.", Text, CharacterNumber, LineNumber); else sprintf (String, "%s problem at character %d.", Text, CharacterNumber); exit (GiftGraphicErrorReport (String)); } /*****************************************************************************/ /* Return a bitmap image to the client as a GIF image. The code in these functions is implemented in accordance with Compuserve's Graphic Interchange Format Programming Reference specification, version 89a, 31st July 1990. The LZW compression employed by the GIF algorithm is implemented using code derived from the PBM suite. Two functions, virtually unmodified, are employed, GiftCompress() ... formally called 'compgif()', and GiftPackBits() ... formally called 'pack_bits()'. The original commentary and copyright notice remains as per the code author's request. */ GiftImage () { static char Http200NoCacheGifHeader [] = "HTTP/1.0 200 Success\r\n\ Content-Type: image/gif\r\n\ Expires: Fri, 13 Jan 1978 15:00:00 GMT\r\n\ Pragma: no-cache\r\n\ \r\n"; static char Http200GifHeader [] = "HTTP/1.0 200 Success\r\n\ Content-Type: image/gif\r\n\ Expires: Fri, 13 Jan 1978 15:00:00 GMT\r\n\ \r\n"; register unsigned char *bptr; register int idx, Byte; int LeftOffset, TopOffset, Resolution, ColorMapSize, InitCodeSize; unsigned char Buffer [256]; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GiftImage()\n"); /* get the descriptor associated with this file (used for GIF output) */ GraphicHttpOutFd = fileno (HttpOut); ColorMapSize = 1 << GraphicBitsPerPixel; LeftOffset = TopOffset = 0; Resolution = GraphicBitsPerPixel; /* the initial code size */ if (GraphicBitsPerPixel <= 1) InitCodeSize = 2; else InitCodeSize = GraphicBitsPerPixel; /* for convenience accumulate bytes into this buffer before output */ bptr = Buffer; /***************/ /* HTTP header */ /***************/ if (GraphicNoCacheGif) { memcpy (bptr, Http200NoCacheGifHeader, sizeof(Http200NoCacheGifHeader)-1); bptr += sizeof(Http200NoCacheGifHeader)-1; } else { memcpy (bptr, Http200GifHeader, sizeof(Http200GifHeader)-1); bptr += sizeof(Http200GifHeader)-1; } /**************************/ /* GIF Data Stream header */ /**************************/ strcpy (bptr, "GIF89a"); bptr += 6; /*****************************/ /* Logical Screen Descriptor */ /*****************************/ /* width and height of logical screen */ *bptr++ = GraphicWidth & 0xff; *bptr++ = (GraphicWidth >> 8) & 0xff; *bptr++ = GraphicHeight & 0xff; *bptr++ = (GraphicHeight >> 8) & 0xff; /* indicate that there is a global colour map */ Byte = 0x80; /* OR in the resolution */ Byte |= (Resolution - 1) << 5; /* OR in the Bits per Pixel */ Byte |= (GraphicBitsPerPixel - 1); /* write it out */ *bptr++ = Byte; /* background colour */ *bptr++ = GraphicBackground; /* pixel aspect ratio */ *bptr++ = 0; /***********************/ /* Global Colour Table */ /***********************/ for (idx = 0; idx < ColorMapSize; idx++) { *bptr++ = GraphicRgbRed[idx]; *bptr++ = GraphicRgbGreen[idx]; *bptr++ = GraphicRgbBlue[idx]; } /****************************************/ /* Graphic Control Extension descriptor */ /****************************************/ if (GraphicTransparencyColour >= 0) { /* extension introducer and graphic control label */ *bptr++ = 0x21; *bptr++ = 0xf9; /* fixed size of the following data block */ *bptr++ = 0x04; /* Transparency Index is provided */ *bptr++ = 0x01; /* no data in these */ *bptr++ = 0x00; *bptr++ = 0x00; /* Transparent Color Index value, background SHOULD BE TRANSPARENT */ *bptr++ = GraphicTransparencyColour; /* block terminator */ *bptr++ = 0x00; } /********************/ /* Image descriptor */ /********************/ /* write an Image separator */ *bptr++ = 0x2c; /* location of image within logical screen */ *bptr++ = LeftOffset & 0xff; *bptr++ = (LeftOffset >> 8) & 0xff; *bptr++ = TopOffset & 0xff; *bptr++ = (TopOffset >> 8) & 0xff; /* width and height of image within logical screen */ *bptr++ = GraphicWidth & 0xff; *bptr++ = (GraphicWidth >> 8) & 0xff; *bptr++ = GraphicHeight & 0xff; *bptr++ = (GraphicHeight >> 8) & 0xff; /* no local color table, image is not interlaced, not ordered, etc. */ *bptr++ = 0x00; /**************************/ /* table-based image data */ /**************************/ /* write out the initial code size */ *bptr++ = InitCodeSize; /* transfer what we've accumlated in the local buffer */ write (GraphicHttpOutFd, Buffer, bptr-Buffer); /* LZW compress the data using PBM-derived algorithm and code */ GiftCompress (InitCodeSize + 1); /****************************************/ /* end of image data and GIF terminator */ /****************************************/ /* write out a zero-length packet (to end the series), and terminator */ write (GraphicHttpOutFd, "\0;", 2); } /*****************************************************************************/ /* Get a series of pixels from the bitmap. It is done in such a way that the origin (0,0) is in the bottom, left hand corner, although the memory origin is at byte zero. */ int GiftNextPixel () { static int CountX = 0, CountY = -1; static unsigned char *PixelPtr; /*********/ /* begin */ /*********/ if (!CountX--) { if (CountY < 0) CountY = GraphicHeight; if (!CountY--) return (EOF); CountX = GraphicWidth - 1; PixelPtr = GraphicPtr + (CountY * GraphicWidth); } return (*PixelPtr++); } /****************************************************************************/ /* * This software is copyrighted as noted below. It may be freely copied, * modified, and redistributed, provided that the copyright notice is * preserved on all copies. * * There is no warranty or other guarantee of fitness for this software, * it is provided solely "as is". Bug reports or fixes may be sent * to the author, who may or may not act on them as he desires. * * You may not include this software in a program or other software product * without supplying the source, or without informing the end-user that the * source is available for no extra charge. * * If you modify this software, you should include a notice giving the * name of the person performing the modification, the date of modification, * and the reason for such modification. */ /* compgif.c */ /* * * GIF Image compression - LZW algorithm implemented with Trie type * structure. * Written by Bailey Brown, Jr. * last change May 24, 1990 * file: compgif.c * * You may use or modify this code as you wish, as long as you mention * my name in your documentation. * * - Bailey Brown, Jr. * */ #define MAXIMUMCODE 4095 /* 2**maximum_code_size */ #define BLOCKSIZE 256 /* max block byte count + 1 */ #define NULLPREFIX -1 typedef struct str_table_entry { int code; int prefix; int suffix; } strTableEntry; typedef struct str_table_node { strTableEntry entry; struct str_table_node *left; struct str_table_node *right; struct str_table_node *children; } strTableNode, *strTableNodePtr, **strTable; /* ******************************************************************** * compgif() recieves pointers to an input function and an output * * stream, and the code size as parameters and outputs successive * * blocks of LZW compressed gif data. The calling routine should * * have aready written the GIF file header out to the output file. * * It assumes that there will be no more than 8 bits/pixel and that * * each data item comes from successive bytes returned by infun. * ******************************************************************** */ int GiftCompress (int code_size) { strTable heap; /* our very own memory manager */ int heap_index; int clear_code, end_code, cur_code; int i, found, num_colors, prefix, compress_size; int cur_char, end_of_data, bits_per_pix; strTableNodePtr cur_node; strTable root; /* root of string table for LZW compression is */ /* an array of 2**bits_per_pix pointers to atomic nodes */ heap_index = 0; heap = (strTable)malloc(sizeof(strTableNodePtr)*MAXIMUMCODE); if (heap == NULL) printf("can't allocate heap"); for (i=0; i < MAXIMUMCODE; i++) { heap[i] = (strTableNodePtr)malloc(sizeof(strTableNode)); if (heap[i] == NULL) { printf("can't allocate heap"); exit (1); } } bits_per_pix = code_size - 1; compress_size = code_size; num_colors = 1<<(bits_per_pix); clear_code = num_colors; end_code = clear_code + 1; cur_code = end_code + 1; prefix = NULLPREFIX; root = (strTable)malloc(sizeof(strTableNodePtr)*num_colors); if (!root) { printf("memory allocation failure (root)"); exit (1); } for(i=0; ientry.code = i; root[i]->entry.prefix = NULLPREFIX; root[i]->entry.suffix = i; root[i]->left = NULL; root[i]->right = NULL; root[i]->children = NULL; } /* initialize output block */ GiftPackBits(compress_size, -1); GiftPackBits(compress_size, clear_code); end_of_data = 0; if ((cur_char = GiftNextPixel()) == EOF) printf("premature end of data"); while (!end_of_data) { prefix = cur_char; cur_node = root[prefix]; found = 1; if((cur_char = GiftNextPixel()) == EOF) { end_of_data = 1; break; } while(cur_node->children && found) { cur_node = cur_node->children; while(cur_node->entry.suffix != cur_char) { if (cur_char < cur_node->entry.suffix) { if (cur_node->left) cur_node = cur_node->left; else { cur_node->left = heap[heap_index++]; cur_node = cur_node->left; found = 0; break; } } else { if (cur_node->right) cur_node = cur_node->right; else { cur_node->right = heap[heap_index++]; cur_node = cur_node->right; found = 0; break; } } } if (found) { prefix = cur_node->entry.code; if((cur_char = GiftNextPixel()) == EOF) { end_of_data = 1; break; } } } if (end_of_data) break; if (found) { cur_node->children = heap[heap_index++]; cur_node = cur_node->children; } cur_node->children = NULL; cur_node->left = NULL; cur_node->right = NULL; cur_node->entry.code = cur_code; cur_node->entry.prefix = prefix; cur_node->entry.suffix = cur_char; GiftPackBits(compress_size, prefix); if (cur_code > ((1<<(compress_size))-1)) compress_size++; if (cur_code < MAXIMUMCODE) { cur_code++; } else { heap_index = num_colors; /* reinitialize string table */ for (i=0; i < num_colors; i++ ) root[i]->children = NULL; GiftPackBits(compress_size, clear_code); compress_size = bits_per_pix + 1; cur_code = end_code + 1; } } GiftPackBits(compress_size, prefix); GiftPackBits(compress_size, end_code); GiftPackBits(compress_size, -1); for (i=0; i < MAXIMUMCODE; i++) free(heap[i]); free(heap); free(root); return (1); } /* ************************************************************************ * GiftPackBits() packs the bits of the codes generated by gifenc() into * * a 1..256 byte output block. The first byte of the block is the * * number 0..255 of data bytes in the block. To flush or initialize * * the block, pass a negative argument. * ************************************************************************ */ int GiftPackBits (int compress_size, int prefix) { static int cur_bit = 8; static unsigned char block[BLOCKSIZE] = { 0 }; int i, left_over_bits; /* if we are about to excede the bounds of block or if the flush code (code_bis < 0) we output the block */ if((cur_bit + compress_size > (BLOCKSIZE-1)*8) || (prefix < 0)) { /* handle case of data overlapping blocks */ if ((left_over_bits = (((cur_bit>>3) + ((cur_bit & 7) != 0))<<3) - cur_bit) != 0) { for (i=0; i < left_over_bits; i++) { if (prefix & (1<>3] |= (char)(1<<(cur_bit & 7)); /* note n>>3 == n/8 and n & 7 == n % 8 */ cur_bit++; } } compress_size -= left_over_bits; prefix = prefix>>left_over_bits; block[0] = (unsigned char)((cur_bit>>3) - 1); if (block[0]) write (GraphicHttpOutFd, block, block[0]+1); for(i=0; i < BLOCKSIZE; i++) block[i] = 0; cur_bit = 8; } if (prefix >= 0) { for (i=0; i < compress_size; i++) { if (prefix & (1<>3] |= (unsigned char)(1<<(cur_bit & 7)); /* note n>>3 == n/8 and n & 7 == n % 8 */ cur_bit++; } } return (1); } /*****************************************************************************/