📄 gd.c
字号:
#include <stdio.h>#include <math.h>#include <string.h>#include <stdlib.h>#include "gd.h"#include "gdhelpers.h"#include "php.h"#ifdef _MSC_VER# if _MSC_VER >= 1300/* in MSVC.NET these are available but only for __cplusplus and not _MSC_EXTENSIONS */# if !defined(_MSC_EXTENSIONS) && defined(__cplusplus)# define HAVE_FABSF 1extern float fabsf(float x);# define HAVE_FLOORF 1extern float floorf(float x);# endif /*MSVC.NET */# endif /* MSC */#endif#ifndef HAVE_FABSF# define HAVE_FABSF 0#endif#ifndef HAVE_FLOORF# define HAVE_FLOORF 0#endif#if HAVE_FABSF == 0/* float fabsf(float x); */# define fabsf(x) ((float)(fabs(x)))#endif#if HAVE_FLOORF == 0/* float floorf(float x);*/#define floorf(x) ((float)(floor(x)))#endif#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 *//* 2.0.10: cast instead of floor() yields 35% performance improvement. Thanks to John Buckman. */#define floor_cast(exp) ((long) exp)extern int gdCosT[];extern int gdSinT[];static void gdImageBrushApply(gdImagePtr im, int x, int y);static void gdImageTileApply(gdImagePtr im, int x, int y);static void gdImageAntiAliasedApply(gdImagePtr im, int x, int y);static int gdLayerOverlay(int dst, int src);static int gdAlphaOverlayColor(int src, int dst, int max);int gdImageGetTrueColorPixel(gdImagePtr im, int x, int y);void php_gd_error_ex(int type, const char *format, ...){ va_list args; TSRMLS_FETCH(); va_start(args, format); php_verror(NULL, "", type, format, args TSRMLS_CC); va_end(args);}void php_gd_error(const char *format, ...){ va_list args; TSRMLS_FETCH(); va_start(args, format); php_verror(NULL, "", E_WARNING, format, args TSRMLS_CC); va_end(args);}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->AA_opacity = (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->AA_opacity[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; im->AA_polygon = 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;}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->AA_opacity = (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++) { im->tpixels[i] = (int *) gdCalloc(sx, sizeof(int)); im->AA_opacity[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char)); } 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->AA_polygon = 0; im->cx1 = 0; im->cy1 = 0; im->cx2 = im->sx - 1; im->cy2 = im->sy - 1; return im;}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->AA_opacity) { for (i = 0; i < im->sy; i++) { gdFree(im->AA_opacity[i]); } gdFree(im->AA_opacity); } if (im->polyInts) { gdFree(im->polyInts); } if (im->style) { gdFree(im->style); } gdFree(im);}int gdImageColorClosest (gdImagePtr im, int r, int g, int b){ return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);}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) */ 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.0f; s.G = g/255.0f; s.B = b/255.0f;}#ifndef MIN#define MIN(a,b) ((a)<(b)?(a):(b))#endif#define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))#ifndef MAX#define MAX(a,b) ((a)<(b)?(b):(a))#endif#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 float HWB_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.0f; /* Undefined hues always match... */ } else { diff = fabsf(HWB1.H - HWB2.H); if (diff > 3.0f) { diff = 6.0f - 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;}#endifint 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;}int gdImageColorExact (gdImagePtr im, int r, int g, int b){ return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);}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;}int gdImageColorAllocate (gdImagePtr im, int r, int g, int b){ return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);}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. */int gdImageColorResolve (gdImagePtr im, int r, int g, int b){ return gdImageColorResolveAlpha(im, r, g, b, gdAlphaOpaque);}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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -