📄 gd.c
字号:
#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdio.h>#include <math.h>#include <string.h>#include <stdlib.h>/* 2.03: don't include zlib here or we can't build without PNG */#include "gd.h"#include "gdhelpers.h"/* 2.0.12: this now checks the clipping rectangle */#define gdImageBoundsSafeMacro(im, x, y) (!((((y) < (im)->cy1) || ((y) > (im)->cy2)) || (((x) < (im)->cx1) || ((x) > (im)->cx2))))#ifdef _OSD_POSIX /* BS2000 uses the EBCDIC char set instead of ASCII */#define CHARSET_EBCDIC#define __attribute__(any) /*nothing */#endif/*_OSD_POSIX*/#ifndef CHARSET_EBCDIC#define ASC(ch) ch#else /*CHARSET_EBCDIC */#define ASC(ch) gd_toascii[(unsigned char)ch]static const unsigned char gd_toascii[256] = {/*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f, 0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /*................ *//*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97, 0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f, /*................ *//*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07, /*................ *//*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, 0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a, /*................ *//*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5, 0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, /* .........`.<(+| *//*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef, 0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f, /*&.........!$*);. *//*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5, 0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,/*-/........^,%_>?*//*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /*..........:#@'=" *//*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1, /*.abcdefghi...... *//*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4, /*.jklmnopqr...... *//*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae, /*..stuvwxyz...... *//*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc, 0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7, /*...........[\].. *//*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5, /*.ABCDEFGHI...... *//*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff, /*.JKLMNOPQR...... *//*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5, /*..STUVWXYZ...... *//*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e /*0123456789.{.}.~ */};#endif /*CHARSET_EBCDIC */extern int gdCosT[];extern int gdSinT[];static void gdImageBrushApply (gdImagePtr im, int x, int y);static void gdImageTileApply (gdImagePtr im, int x, int y);BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y);BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy){ int i; gdImagePtr im; im = (gdImage *) gdMalloc (sizeof (gdImage)); memset (im, 0, sizeof (gdImage)); /* Row-major ever since gd 1.3 */ im->pixels = (unsigned char **) gdMalloc (sizeof (unsigned char *) * sy); im->polyInts = 0; im->polyAllocated = 0; im->brush = 0; im->tile = 0; im->style = 0; for (i = 0; (i < sy); i++) { /* Row-major ever since gd 1.3 */ im->pixels[i] = (unsigned char *) gdCalloc (sx, sizeof (unsigned char)); } im->sx = sx; im->sy = sy; im->colorsTotal = 0; im->transparent = (-1); im->interlace = 0; im->thick = 1; im->AA = 0; for (i = 0; (i < gdMaxColors); i++) { im->open[i] = 1; im->red[i] = 0; im->green[i] = 0; im->blue[i] = 0; }; im->trueColor = 0; im->tpixels = 0; im->cx1 = 0; im->cy1 = 0; im->cx2 = im->sx - 1; im->cy2 = im->sy - 1; return im;}BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy){ int i; gdImagePtr im; im = (gdImage *) gdMalloc (sizeof (gdImage)); memset (im, 0, sizeof (gdImage)); im->tpixels = (int **) gdMalloc (sizeof (int *) * sy); im->polyInts = 0; im->polyAllocated = 0; im->brush = 0; im->tile = 0; im->style = 0; for (i = 0; (i < sy); i++) { im->tpixels[i] = (int *) gdCalloc (sx, sizeof (int)); } im->sx = sx; im->sy = sy; im->transparent = (-1); im->interlace = 0; im->trueColor = 1; /* 2.0.2: alpha blending is now on by default, and saving of alpha is off by default. This allows font antialiasing to work as expected on the first try in JPEGs -- quite important -- and also allows for smaller PNGs when saving of alpha channel is not really desired, which it usually isn't! */ im->saveAlphaFlag = 0; im->alphaBlendingFlag = 1; im->thick = 1; im->AA = 0; im->cx1 = 0; im->cy1 = 0; im->cx2 = im->sx - 1; im->cy2 = im->sy - 1; return im;}BGD_DECLARE(void) gdImageDestroy (gdImagePtr im){ int i; if (im->pixels) { for (i = 0; (i < im->sy); i++) { gdFree (im->pixels[i]); } gdFree (im->pixels); } if (im->tpixels) { for (i = 0; (i < im->sy); i++) { gdFree (im->tpixels[i]); } gdFree (im->tpixels); } if (im->polyInts) { gdFree (im->polyInts); } if (im->style) { gdFree (im->style); } gdFree (im);}BGD_DECLARE(int) gdImageColorClosest (gdImagePtr im, int r, int g, int b){ return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);}BGD_DECLARE(int) gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a){ int i; long rd, gd, bd, ad; int ct = (-1); int first = 1; long mindist = 0; if (im->trueColor) { return gdTrueColorAlpha (r, g, b, a); } for (i = 0; (i < (im->colorsTotal)); i++) { long dist; if (im->open[i]) { continue; } rd = (im->red[i] - r); gd = (im->green[i] - g); bd = (im->blue[i] - b); /* gd 2.02: whoops, was - b (thanks to David Marwood) */ /* gd 2.16: was blue rather than alpha! Geez! Thanks to Artur Jakub Jerzak */ ad = (im->alpha[i] - a); dist = rd * rd + gd * gd + bd * bd + ad * ad; if (first || (dist < mindist)) { mindist = dist; ct = i; first = 0; } } return ct;}/* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article * on colour conversion to/from RBG and HWB colour systems. * It has been modified to return the converted value as a * parameter. */#define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;}#define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;}#define HWB_UNDEFINED -1#define SETUP_RGB(s, r, g, b) {s.R = r/255.0; s.G = g/255.0; s.B = b/255.0;}#define MIN(a,b) ((a)<(b)?(a):(b))#define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))#define MAX(a,b) ((a)<(b)?(b):(a))#define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))/* * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure * red always maps to 6 in this implementation. Therefore UNDEFINED can be * defined as 0 in situations where only unsigned numbers are desired. */typedef struct{ float R, G, B;}RGBType;typedef struct{ float H, W, B;}HWBType;static HWBType *RGB_to_HWB (RGBType RGB, HWBType * HWB){ /* * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B. */ float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f; int i; w = MIN3 (R, G, B); v = MAX3 (R, G, B); b = 1 - v; if (v == w) RETURN_HWB (HWB_UNDEFINED, w, b); f = (R == w) ? G - B : ((G == w) ? B - R : R - G); i = (R == w) ? 3 : ((G == w) ? 5 : 1); RETURN_HWB (i - f / (v - w), w, b);}static floatHWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2){ RGBType RGB1, RGB2; HWBType HWB1, HWB2; float diff; SETUP_RGB (RGB1, r1, g1, b1); SETUP_RGB (RGB2, r2, g2, b2); RGB_to_HWB (RGB1, &HWB1); RGB_to_HWB (RGB2, &HWB2); /* * I made this bit up; it seems to produce OK results, and it is certainly * more visually correct than the current RGB metric. (PJW) */ if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED)) { diff = 0; /* Undefined hues always match... */ } else { diff = abs (HWB1.H - HWB2.H); if (diff > 3) { diff = 6 - diff; /* Remember, it's a colour circle */ } } diff = diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B - HWB2.B) * (HWB1.B - HWB2.B); return diff;}#if 0/* * This is not actually used, but is here for completeness, in case someone wants to * use the HWB stuff for anything else... */static RGBType *HWB_to_RGB (HWBType HWB, RGBType * RGB){ /* * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1]. * RGB are each returned on [0, 1]. */ float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f; int i; v = 1 - b; if (h == HWB_UNDEFINED) RETURN_RGB (v, v, v); i = floor (h); f = h - i; if (i & 1) f = 1 - f; /* if i is odd */ n = w + f * (v - w); /* linear interpolation between w and v */ switch (i) { case 6: case 0: RETURN_RGB (v, n, w); case 1: RETURN_RGB (n, v, w); case 2: RETURN_RGB (w, v, n); case 3: RETURN_RGB (w, n, v); case 4: RETURN_RGB (n, w, v); case 5: RETURN_RGB (v, w, n); } return RGB;}#endifBGD_DECLARE(int) gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b){ int i; /* long rd, gd, bd; */ int ct = (-1); int first = 1; float mindist = 0; if (im->trueColor) { return gdTrueColor (r, g, b); } for (i = 0; (i < (im->colorsTotal)); i++) { float dist; if (im->open[i]) { continue; } dist = HWB_Diff (im->red[i], im->green[i], im->blue[i], r, g, b); if (first || (dist < mindist)) { mindist = dist; ct = i; first = 0; } } return ct;}BGD_DECLARE(int) gdImageColorExact (gdImagePtr im, int r, int g, int b){ return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);}BGD_DECLARE(int) gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a){ int i; if (im->trueColor) { return gdTrueColorAlpha (r, g, b, a); } for (i = 0; (i < (im->colorsTotal)); i++) { if (im->open[i]) { continue; } if ((im->red[i] == r) && (im->green[i] == g) && (im->blue[i] == b) && (im->alpha[i] == a)) { return i; } } return -1;}BGD_DECLARE(int) gdImageColorAllocate (gdImagePtr im, int r, int g, int b){ return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);}BGD_DECLARE(int) gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a){ int i; int ct = (-1); if (im->trueColor) { return gdTrueColorAlpha (r, g, b, a); } for (i = 0; (i < (im->colorsTotal)); i++) { if (im->open[i]) { ct = i; break; } } if (ct == (-1)) { ct = im->colorsTotal; if (ct == gdMaxColors) { return -1; } im->colorsTotal++; } im->red[ct] = r; im->green[ct] = g; im->blue[ct] = b; im->alpha[ct] = a; im->open[ct] = 0; return ct;}/* * gdImageColorResolve is an alternative for the code fragment: * * if ((color=gdImageColorExact(im,R,G,B)) < 0) * if ((color=gdImageColorAllocate(im,R,G,B)) < 0) * color=gdImageColorClosest(im,R,G,B); * * in a single function. Its advantage is that it is guaranteed to * return a color index in one search over the color table. */BGD_DECLARE(int) gdImageColorResolve (gdImagePtr im, int r, int g, int b){ return gdImageColorResolveAlpha (im, r, g, b, gdAlphaOpaque);}BGD_DECLARE(int) gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a){ int c; int ct = -1; int op = -1; long rd, gd, bd, ad, dist; long mindist = 4 * 255 * 255; /* init to max poss dist */ if (im->trueColor) { return gdTrueColorAlpha (r, g, b, a); } for (c = 0; c < im->colorsTotal; c++) { if (im->open[c]) { op = c; /* Save open slot */ continue; /* Color not in use */ } if (c == im->transparent) { /* don't ever resolve to the color that has * been designated as the transparent color */ continue; } rd = (long) (im->red[c] - r); gd = (long) (im->green[c] - g); bd = (long) (im->blue[c] - b); ad = (long) (im->alpha[c] - a); dist = rd * rd + gd * gd + bd * bd + ad * ad; if (dist < mindist) { if (dist == 0) { return c; /* Return exact match color */ } mindist = dist; ct = c; } } /* no exact match. We now know closest, but first try to allocate exact */ if (op == -1) { op = im->colorsTotal; if (op == gdMaxColors) { /* No room for more colors */ return ct; /* Return closest available color */ } im->colorsTotal++; } im->red[op] = r; im->green[op] = g; im->blue[op] = b; im->alpha[op] = a; im->open[op] = 0; return op; /* Return newly allocated color */}BGD_DECLARE(void) gdImageColorDeallocate (gdImagePtr im, int color){ if (im->trueColor) { return; } /* Mark it open. */ im->open[color] = 1;}BGD_DECLARE(void) gdImageColorTransparent (gdImagePtr im, int color){ if (!im->trueColor) { if (im->transparent != -1) { im->alpha[im->transparent] = gdAlphaOpaque; } if (color != -1) { im->alpha[color] = gdAlphaTransparent; } } im->transparent = color;}BGD_DECLARE(void) gdImagePaletteCopy (gdImagePtr to, gdImagePtr from){ int i; int x, y, p; int xlate[256]; if (to->trueColor) { return; } if (from->trueColor) { return; } for (i = 0; i < 256; i++) { xlate[i] = -1; }; for (x = 0; x < (to->sx); x++) { for (y = 0; y < (to->sy); y++) { /* Optimization: no gdImageGetPixel */ p = to->pixels[y][x]; if (xlate[p] == -1) { /* This ought to use HWB, but we don't have an alpha-aware version of that yet. */ xlate[p] = gdImageColorClosestAlpha (from, to->red[p], to->green[p], to->blue[p], to->alpha[p]); /*printf("Mapping %d (%d, %d, %d, %d) to %d (%d, %d, %d, %d)\n", */ /* p, to->red[p], to->green[p], to->blue[p], to->alpha[p], */ /* xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]], from->alpha[xlate[p]]); */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -