- sync to 2.0.26

master
pierre 2006-04-05 15:53:17 +00:00
parent c6d33ff048
commit cfa7ee3b92
7 changed files with 503 additions and 355 deletions

42
src/entities.tcl Normal file
View File

@ -0,0 +1,42 @@
#!/usr/bin/tclsh
# get names for html-4.0 characters from:
# http://www.w3.org/TR/REC-html40/sgml/entities.html
set f [open entities.html r]
set entity_name_length_max 0
set nr_of_entities 0
while {! [eof $f]} {
set rec [gets $f]
if {[scan $rec {<!ENTITY %s CDATA "&#%d;"; --} name val] == 2} {
set entity($name) $val
set entity_name_length [string length $name]
if {$entity_name_length > $entity_name_length_max} {
set entity_name_length_max $entity_name_length
}
incr nr_of_entities
}
}
close $f
set f [open entities.h w]
puts $f "/*"
puts $f " * Generated file - do not edit directly."
puts $f " *"
puts $f " * This file was generated from:"
puts $f " * http://www.w3.org/TR/REC-html40/sgml/entities.html"
puts $f " * by means of the script:"
puts $f " * entities.tcl"
puts $f " */"
puts $f ""
puts $f "struct entities_s {"
puts $f " char *name;"
puts $f " int value;"
puts $f "} entities\[\] = {"
foreach name [lsort [array names entity]] {
puts $f " {\"$name\", $entity($name)},"
}
puts $f "};"
puts $f ""
puts $f "#define ENTITY_NAME_LENGTH_MAX $entity_name_length_max"
puts $f "#define NR_OF_ENTITIES $nr_of_entities"
close $f

View File

@ -18,12 +18,12 @@ doerr (FILE * err, const char *msg)
}
void
dowheel (gdImagePtr im, int color, char *fontfile,
int fontsize, double angle, int x, int y, char *string)
dowheel (gdImagePtr im, int color, char *fontfile, int fontsize,
double angle, int x, int y, int offset, char *string)
{
int brect[8];
FILE *err;
double curang;
double curangrads, curang, x0, y0;
char *cp;
err = fopen ("err.out", "a");
@ -34,23 +34,28 @@ dowheel (gdImagePtr im, int color, char *fontfile,
for (curang = 0.0; curang < 360.0; curang += angle)
{
curangrads = DEGTORAD(curang);
x0 = x + cos (curangrads) * offset;
y0 = y - sin (curangrads) * offset;
/* The case of newlines is taken care of in the gdImageStringTTF call */
#if defined(OLDER_GD)
cp =
gdImageStringTTF (im, brect, color, fontfile, fontsize,
DEGTORAD (curang), x, y, string);
cp = gdImageStringTTF (im, brect, color, fontfile, fontsize,
curangrads, x0, y0, string);
#else
cp =
gdImageStringFT (im, brect, color, fontfile, fontsize,
DEGTORAD (curang), x, y, string);
cp = gdImageStringFT (im, brect, color, fontfile, fontsize,
curangrads, x0, y0, string);
#endif
if (cp)
doerr (err, cp);
gdImagePolygon (im, (gdPointPtr)brect, 4, color);
}
fclose (err);
}
#if 0
void
dolines (gdImagePtr im, int color, double incr, int x, int y, int offset,
int length)
@ -68,6 +73,7 @@ dolines (gdImagePtr im, int color, double incr, int x, int y, int offset,
gdImageLine (im, x0, y0, x1, y1, color);
}
}
#endif
void
dotest (char *font, int size, double incr,
@ -91,8 +97,10 @@ dotest (char *font, int size, double incr,
out = fopen (filename, "wb");
dowheel (im, fc, font, size, incr, xc, yc, string);
dowheel (im, fc, font, size, incr, xc, yc, 20, string);
#if 0
dolines (im, lc, incr, xc, yc, 20, 120);
#endif
#if defined(HAVE_LIBPNG)
gdImagePng (im, out);
@ -108,22 +116,22 @@ main (int argc, char **argv)
{
#if defined(HAVE_LIBPNG)
dotest ("times", 16, 20.0, 400, 400, ".....Hello, there!",
dotest ("times", 16, 20.0, 400, 400, "Hello, there!",
"fontwheeltest1.png");
dotest ("times", 16, 30.0, 400, 400, ".....Hello, there!",
dotest ("times", 16, 30.0, 400, 400, "Hello, there!",
"fontwheeltest2.png");
dotest ("arial", 16, 45.0, 400, 400, ".....Hello, there!",
dotest ("arial", 16, 45.0, 400, 400, "Hello, there!",
"fontwheeltest3.png");
dotest ("arial", 16, 90.0, 400, 400, ".....Hello, there!",
dotest ("arial", 16, 90.0, 400, 400, "Hello\nthere!",
"fontwheeltest4.png");
#elif defined(HAVE_LIBJPEG)
dotest ("times", 16, 20.0, 400, 400, ".....Hello, there!",
dotest ("times", 16, 20.0, 400, 400, "Hello, there!",
"fontwheeltest1.jpeg");
dotest ("times", 16, 30.0, 400, 400, ".....Hello, there!",
dotest ("times", 16, 30.0, 400, 400, "Hello, there!",
"fontwheeltest2.jpeg");
dotest ("arial", 16, 45.0, 400, 400, ".....Hello, there!",
dotest ("arial", 16, 45.0, 400, 400, "Hello, there!",
"fontwheeltest3.jpeg");
dotest ("arial", 16, 90.0, 400, 400, ".....Hello, there!",
dotest ("arial", 16, 90.0, 400, 400, "Hello\nthere!",
"fontwheeltest4.jpeg");
#else
fprintf (stderr, "no PNG or JPEG support\n");

421
src/gd.c
View File

@ -1,5 +1,3 @@
/* TODO: make sure you didn't break resampling */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@ -67,7 +65,6 @@ 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);
int gdImageGetTrueColorPixel (gdImagePtr im, int x, int y);
BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy)
@ -78,8 +75,6 @@ BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy)
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;
@ -89,8 +84,6 @@ BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy)
{
/* 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;
@ -99,7 +92,6 @@ BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy)
im->interlace = 0;
im->thick = 1;
im->AA = 0;
im->AA_polygon = 0;
for (i = 0; (i < gdMaxColors); i++)
{
im->open[i] = 1;
@ -123,8 +115,6 @@ BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy)
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;
@ -133,8 +123,6 @@ BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy)
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;
@ -150,7 +138,6 @@ BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy)
im->alphaBlendingFlag = 1;
im->thick = 1;
im->AA = 0;
im->AA_polygon = 0;
im->cx1 = 0;
im->cy1 = 0;
im->cx2 = im->sx - 1;
@ -177,14 +164,6 @@ BGD_DECLARE(void) gdImageDestroy (gdImagePtr im)
}
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);
@ -650,18 +629,21 @@ BGD_DECLARE(void) gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
the second call!) The code is simplified from that in the article,
as we know that gd images always start at (0,0) */
/* 2.0.26, TBB: we now have to respect a clipping rectangle, it won't
necessarily start at 0. */
static int
clip_1d (int *x0, int *y0, int *x1, int *y1, int maxdim)
clip_1d (int *x0, int *y0, int *x1, int *y1, int mindim, int maxdim)
{
double m; /* gradient of line */
if (*x0 < 0)
if (*x0 < mindim)
{ /* start of line is left of window */
if (*x1 < 0) /* as is the end, so the line never cuts the window */
if (*x1 < mindim) /* as is the end, so the line never cuts the window */
return 0;
m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */
/* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */
*y0 -= m * *x0;
*x0 = 0;
*y0 -= m * (*x0 - mindim);
*x0 = mindim;
/* now, perhaps, adjust the far end of the line as well */
if (*x1 > maxdim)
{
@ -680,10 +662,10 @@ clip_1d (int *x0, int *y0, int *x1, int *y1, int maxdim)
boundary */
*x0 = maxdim;
/* now, perhaps, adjust the end of the line */
if (*x1 < 0)
if (*x1 < mindim)
{
*y1 -= m * *x1;
*x1 = 0;
*y1 -= m * (*x1 - mindim);
*x1 = mindim;
}
return 1;
}
@ -695,11 +677,11 @@ clip_1d (int *x0, int *y0, int *x1, int *y1, int maxdim)
*x1 = maxdim;
return 1;
}
if (*x1 < 0)
if (*x1 < mindim)
{ /* other end is outside to the left */
m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */
*y1 -= m * *x1;
*x1 = 0;
*y1 -= m * (*x1 - mindim);
*x1 = mindim;
return 1;
}
/* only get here if both points are inside the window */
@ -749,7 +731,9 @@ BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color)
gdImageTileApply (im, x, y);
break;
case gdAntiAliased:
gdImageAntiAliasedApply (im, x, y);
/* This shouldn't happen (2.0.26) because we just call
gdImageAALine now, but do something sane. */
gdImageSetPixel(im, x, y, im->AA_color);
break;
default:
if (gdImageBoundsSafeMacro (im, x, y))
@ -921,70 +905,6 @@ gdImageTileApply (gdImagePtr im, int x, int y)
}
}
static void
gdImageAntiAliasedApply (gdImagePtr im, int px, int py)
{
float p_dist, p_alpha;
unsigned char opacity;
/*
* Find the perpendicular distance from point C (px, py) to the line
* segment AB that is being drawn. (Adapted from an algorithm from the
* comp.graphics.algorithms FAQ.)
*/
int LAC_2, LBC_2;
int Ax_Cx = im->AAL_x1 - px;
int Ay_Cy = im->AAL_y1 - py;
int Bx_Cx = im->AAL_x2 - px;
int By_Cy = im->AAL_y2 - py;
/* 2.0.13: bounds check! AA_opacity is just as capable of
overflowing as the main pixel array. Arne Jorgensen.
2.0.14: typo fixed. 2.0.15: moved down below declarations
to satisfy non-C++ compilers. */
if (!gdImageBoundsSafeMacro (im, px, py))
{
return;
}
/* Get the squares of the lengths of the segemnts AC and BC. */
LAC_2 = (Ax_Cx * Ax_Cx) + (Ay_Cy * Ay_Cy);
LBC_2 = (Bx_Cx * Bx_Cx) + (By_Cy * By_Cy);
if (((im->AAL_LAB_2 + LAC_2) >= LBC_2) &&
((im->AAL_LAB_2 + LBC_2) >= LAC_2))
{
/* The two angles are acute. The point lies inside the portion of the
* plane spanned by the line segment. */
p_dist = fabs ((float) ((Ay_Cy * im->AAL_Bx_Ax) -
(Ax_Cx * im->AAL_By_Ay)) / im->AAL_LAB);
}
else
{
/* The point is past an end of the line segment. It's length from the
* segment is the shorter of the lengths from the endpoints, but call
* the distance -1, so as not to compute the alpha nor draw the pixel.
*/
p_dist = -1;
}
if ((p_dist >= 0) && (p_dist <= (float) (im->thick)))
{
p_alpha = pow (1.0 - (p_dist / 1.5), 2);
if (p_alpha > 0)
{
if (p_alpha >= 1)
opacity = 255;
else
opacity = (unsigned char) (p_alpha * 255.0);
if (!(im->AA_polygon) || (im->AA_opacity[py][px] < opacity))
im->AA_opacity[py][px] = opacity;
}
}
}
BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y)
{
if (gdImageBoundsSafeMacro (im, x, y))
@ -1022,95 +942,39 @@ gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
BGD_DECLARE(void) gdImageAABlend (gdImagePtr im)
{
float p_alpha, old_alpha;
int color = im->AA_color, color_red, color_green, color_blue;
int old_color, old_red, old_green, old_blue;
int p_color, p_red, p_green, p_blue;
int px, py;
color_red = gdImageRed (im, color);
color_green = gdImageGreen (im, color);
color_blue = gdImageBlue (im, color);
/* Impose the anti-aliased drawing on the image. */
for (py = 0; py < im->sy; py++)
{
for (px = 0; px < im->sx; px++)
{
if (im->AA_opacity[py][px] != 0)
{
old_color = gdImageGetPixel (im, px, py);
if ((old_color != color)
&& ((old_color != im->AA_dont_blend)
|| (im->AA_opacity[py][px] == 255)))
{
/* Only blend with different colors that aren't the
* dont_blend color. */
p_alpha = (float) (im->AA_opacity[py][px]) / 255.0;
old_alpha = 1.0 - p_alpha;
if (p_alpha >= 1.0)
p_color = color;
else
{
old_red = gdImageRed (im, old_color);
old_green = gdImageGreen (im, old_color);
old_blue = gdImageBlue (im, old_color);
p_red = (int) (((float) color_red * p_alpha) +
((float) old_red * old_alpha));
p_green = (int) (((float) color_green * p_alpha) +
((float) old_green * old_alpha));
p_blue = (int) (((float) color_blue * p_alpha) +
((float) old_blue * old_alpha));
p_color =
gdImageColorResolve (im, p_red, p_green, p_blue);
}
gdImageSetPixel (im, px, py, p_color);
}
}
}
/* Clear the AA_opacity array behind us. */
memset (im->AA_opacity[py], 0, im->sx);
}
/* NO-OP, kept for library compatibility. */
}
static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col);
/* Bresenham as presented in Foley & Van Dam */
BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
{
int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
int wid;
int w, wstart;
int thick = im->thick;
/* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no
points need to be drawn */
if (clip_1d (&x1, &y1, &x2, &y2, gdImageSX (im)) == 0)
return;
if (clip_1d (&y1, &x1, &y2, &x2, gdImageSY (im)) == 0)
return;
/* gdAntiAliased passed as color: set anti-aliased line (AAL) global vars. */
int thick;
if (color == gdAntiAliased)
{
im->AAL_x1 = x1;
im->AAL_y1 = y1;
im->AAL_x2 = x2;
im->AAL_y2 = y2;
/* Compute what we can for point-to-line distance calculation later. */
im->AAL_Bx_Ax = x2 - x1;
im->AAL_By_Ay = y2 - y1;
im->AAL_LAB_2 =
(im->AAL_Bx_Ax * im->AAL_Bx_Ax) + (im->AAL_By_Ay * im->AAL_By_Ay);
im->AAL_LAB = sqrt (im->AAL_LAB_2);
/* For AA, we must draw pixels outside the width of the line. Keep in
* mind that this will be curtailed by cos/sin of theta later. */
thick += 4;
/*
gdAntiAliased passed as color: use the much faster, much cheaper
and equally attractive gdImageAALine implementation. That
clips too, so don't clip twice.
*/
gdImageAALine(im, x1, y1, x2, y2, im->AA_color);
return;
}
/* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no
points need to be drawn. 2.0.26, TBB: clip to edges of clipping
rectangle. We were getting away with this because gdImageSetPixel
is used for actual drawing, but this is still more efficient and opens
the way to skip per-pixel bounds checking in the future. */
if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0)
return;
if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0)
return;
thick = im->thick;
dx = abs (x2 - x1);
dy = abs (y2 - y1);
@ -1282,9 +1146,6 @@ BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, in
}
}
/* If this is the only line we are drawing, go ahead and blend. */
if ((color == gdAntiAliased) && !(im->AA_polygon))
gdImageAABlend (im);
}
static void dashedSet (gdImagePtr im, int x, int y, int color,
int *onP, int *dashStepP, int wid, int vert);
@ -2665,10 +2526,6 @@ BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
return;
}
/* Let it be known that we are drawing a polygon so that the opacity
* mask doesn't get cleared after each line. */
if (c == gdAntiAliased)
im->AA_polygon = 1;
lx = p->x;
ly = p->y;
@ -2681,15 +2538,8 @@ BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
ly = p->y;
}
if (c == gdAntiAliased)
{
im->AA_polygon = 0;
gdImageAABlend (im);
}
}
int gdCompareInt (const void *a, const void *b);
/* THANKS to Kirsten Schulz for the polygon fixes! */
/* The intersection finding technique of this code could be improved */
@ -2697,9 +2547,14 @@ int gdCompareInt (const void *a, const void *b);
/* That could help to adjust intersections to produce a nice */
/* interior_extrema. */
static void horizontalLine(gdImagePtr im, int minx, int maxx, int y,
int fill_color);
BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
{
int i;
int j;
int index;
int y;
int miny, maxy;
int x1, y1;
@ -2712,10 +2567,6 @@ BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int
return;
}
if (c == gdAntiAliased)
fill_color = im->AA_color;
else
fill_color = c;
if (!im->polyAllocated)
{
@ -2745,13 +2596,14 @@ BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int
}
}
/* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
if (miny < 0)
/* 2.0.26: clipping rectangle is even better */
if (miny < im->cy1)
{
miny = 0;
miny = im->cy1;
}
if (maxy >= gdImageSY (im))
if (maxy > im->cy2)
{
maxy = gdImageSY (im) - 1;
maxy = im->cy2;
}
/* Fix in 1.3: count a vertex only once */
for (y = miny; (y <= maxy); y++)
@ -2759,6 +2611,12 @@ BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int
/*1.4 int interLast = 0; */
/* int dirLast = 0; */
/* int interFirst = 1; */
int yshift = 0;
if (c == gdAntiAliased) {
fill_color = im->AA_color;
} else {
fill_color = c;
}
ints = 0;
for (i = 0; (i < n); i++)
{
@ -2794,37 +2652,80 @@ BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int
/* Do the following math as float intermediately, and round to ensure
* that Polygon and FilledPolygon for the same set of points have the
* same footprint. */
if ((y >= y1) && (y < y2))
{
im->polyInts[ints++] = (float) ((y - y1) * (x2 - x1)) /
(float) (y2 - y1) + 0.5 + x1;
im->polyInts[ints++] = (int) ((float) ((y - y1) * (x2 - x1)) /
(float) (y2 - y1) + 0.5 + x1);
}
else if ((y == maxy) && (y > y1) && (y <= y2))
{
im->polyInts[ints++] = (float) ((y - y1) * (x2 - x1)) /
(float) (y2 - y1) + 0.5 + x1;
im->polyInts[ints++] = (int) ((float) ((y - y1) * (x2 - x1)) /
(float) (y2 - y1) + 0.5 + x1);
}
}
qsort (im->polyInts, ints, sizeof (int), gdCompareInt);
/*
2.0.26: polygons pretty much always have less than 100 points,
and most of the time they have considerably less. For such trivial
cases, insertion sort is a good choice. Also a good choice for
future implementations that may wish to indirect through a table.
*/
for (i = 1; (i < ints); i++) {
index = im->polyInts[i];
j = i;
while ((j > 0) && (im->polyInts[j - 1] > index)) {
im->polyInts[j] = im->polyInts[j - 1];
j--;
}
im->polyInts[j] = index;
}
for (i = 0; (i < (ints)); i += 2)
{
gdImageLine (im, im->polyInts[i], y, im->polyInts[i + 1], y,
fill_color);
int minx = im->polyInts[i];
int maxx = im->polyInts[i + 1];
horizontalLine(im, minx, maxx, y, fill_color);
}
}
/* If we are drawing this AA, then redraw the border with AA lines. */
if (c == gdAntiAliased)
/* This doesn't work as well as I'd like, but it doesn't clash either. */
if (c == gdAntiAliased) {
gdImagePolygon (im, p, n, c);
}
}
int
gdCompareInt (const void *a, const void *b)
static void horizontalLine(gdImagePtr im, int minx, int maxx, int y,
int fill_color)
{
return (*(const int *) a) - (*(const int *) b);
if (minx < im->cx1) {
minx = im->cx1;
}
if (maxx > im->cx2) {
maxx = im->cx2;
}
if (y < im->cy1) {
y = im->cy1;
}
if (y > im->cy2) {
y = im->cy2;
}
if (minx > maxx) {
int t = maxx;
maxx = minx;
minx = t;
}
if (im->trueColor) {
while (minx <= maxx) {
im->tpixels[y][minx++] = fill_color;
}
} else {
while (minx <= maxx) {
im->pixels[y][minx++] = fill_color;
}
}
}
inline static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t);
BGD_DECLARE(void) gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
{
if (im->style)
@ -3069,3 +2970,103 @@ BGD_DECLARE(void) gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, i
*x2P = im->cx2;
*y2P = im->cy2;
}
/*
* Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
* */
#define BLEND_COLOR(a, nc, c, cc) \
nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
inline static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
{
int dr,dg,db,p,r,g,b;
p = gdImageGetPixel(im,x,y);
/* TBB: we have to implement the dont_blend stuff to provide
the full feature set of the old implementation */
if ((p == color)
|| ((p == im->AA_dont_blend)
&& (t != 0x00)))
{
return;
}
dr = gdTrueColorGetRed(color);
dg = gdTrueColorGetGreen(color);
db = gdTrueColorGetBlue(color);
r = gdTrueColorGetRed(p);
g = gdTrueColorGetGreen(p);
b = gdTrueColorGetBlue(p);
BLEND_COLOR(t, dr, r, dr);
BLEND_COLOR(t, dg, g, dg);
BLEND_COLOR(t, db, b, db);
im->tpixels[y][x]=gdTrueColorAlpha(dr, dg, db, gdAlphaOpaque);
}
static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col)
{
/* keep them as 32bits */
long x, y, inc;
long dx, dy,tmp;
if (!im->trueColor) {
/* TBB: don't crash when the image is of the wrong type */
gdImageLine(im, x1, y1, x2, y2, col);
return;
}
/* TBB: use the clipping rectangle */
if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0)
return;
if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0)
return;
dx = x2 - x1;
dy = y2 - y1;
if (dx == 0 && dy == 0) {
/* TBB: allow setting points */
gdImageSetAAPixelColor(im, x1, y1, col, 0xFF);
return;
}
if (abs(dx) > abs(dy)) {
if (dx < 0) {
tmp = x1;
x1 = x2;
x2 = tmp;
tmp = y1;
y1 = y2;
y2 = tmp;
dx = x2 - x1;
dy = y2 - y1;
}
x = x1 << 16;
y = y1 << 16;
inc = (dy * 65536) / dx;
/* TBB: set the last pixel for consistency (<=) */
while ((x >> 16) <= x2) {
gdImageSetAAPixelColor(im, x >> 16, y >> 16, col, (y >> 8) & 0xFF);
gdImageSetAAPixelColor(im, x >> 16, (y >> 16) + 1,col, (~y >> 8) & 0xFF);
x += (1 << 16);
y += inc;
}
} else {
if (dy < 0) {
tmp = x1;
x1 = x2;
x2 = tmp;
tmp = y1;
y1 = y2;
y2 = tmp;
dx = x2 - x1;
dy = y2 - y1;
}
x = x1 << 16;
y = y1 << 16;
inc = (dx * 65536) / dy;
/* TBB: set the last pixel for consistency (<=) */
while ((y>>16) <= y2) {
gdImageSetAAPixelColor(im, x >> 16, y >> 16, col, (x >> 8) & 0xFF);
gdImageSetAAPixelColor(im, (x >> 16) + 1, (y >> 16),col, (~x >> 8) & 0xFF);
x += inc;
y += (1<<16);
}
}
}

View File

@ -176,22 +176,14 @@ extern "C"
have that capability. JPEG doesn't. */
int saveAlphaFlag;
/* 2.0.12: anti-aliased globals */
/* There should NEVER BE ACCESSOR MACROS FOR ITEMS BELOW HERE, so this
part of the structure can be safely changed in new releases. */
/* 2.0.12: anti-aliased globals. 2.0.26: just a few vestiges after
switching to the fast, memory-cheap implementation from PHP-gd. */
int AA;
int AA_color;
int AA_dont_blend;
unsigned char **AA_opacity;
int AA_polygon;
/* Stored and pre-computed variables for determining the perpendicular
distance from a point to the anti-aliased line being drawn: */
int AAL_x1;
int AAL_y1;
int AAL_x2;
int AAL_y2;
int AAL_Bx_Ax;
int AAL_By_Ay;
int AAL_LAB_2;
float AAL_LAB;
/* 2.0.12: simple clipping rectangle. These values
must be checked for safety when set; please use
@ -316,6 +308,7 @@ BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color);
BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y);
/* Now a No-Op, but kept for binary compatibility. */
BGD_DECLARE(void) gdImageAABlend (gdImagePtr im);
BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color);

View File

@ -168,8 +168,8 @@ main (void)
int y1 = rand () % gdImageSY (im_out);
int x2 = rand () % gdImageSX (im_out);
int y2 = rand () % gdImageSY (im_out);
gdImageSetAntiAliased (im_out, white);
gdImageLine (im_out, x1, y1, x2, y2, gdAntiAliased);
gdImageSetAntiAliased (im_out, white);
gdImageLine (im_out, x1, y1, x2, y2, gdAntiAliased);
}
/* Make output image interlaced (progressive, in the case of JPEG) */
gdImageInterlace (im_out, 1);

View File

@ -15,6 +15,7 @@
#include <math.h>
#include "gd.h"
#include "gdhelpers.h"
#include "entities.h"
/* 2.0.10: WIN32, not MSWIN32 */
#ifndef WIN32
@ -185,6 +186,12 @@ tweencolorkey_t;
#include "jisx0208.h"
#endif
static int comp_entities(const void *e1, const void *e2) {
struct entities_s *en1 = (struct entities_s *) e1;
struct entities_s *en2 = (struct entities_s *) e2;
return strcmp(en1->name, en2->name);
}
#define Tcl_UniChar int
#define TCL_UTF_MAX 3
static int
@ -193,8 +200,12 @@ gdTcl_UtfToUniChar (char *str, Tcl_UniChar * chPtr)
/* chPtr is the int for the result */
{
int byte;
char entity_name_buf[ENTITY_NAME_LENGTH_MAX+1];
char *p;
struct entities_s key, *res;
/* HTML4.0 entities in decimal form, e.g. &#197; */
/* or in hexadecimal form, e.g. &#x6C34; */
byte = *((unsigned char *) str);
if (byte == '&')
{
@ -203,15 +214,33 @@ gdTcl_UtfToUniChar (char *str, Tcl_UniChar * chPtr)
byte = *((unsigned char *) (str + 1));
if (byte == '#')
{
for (i = 2; i < 8; i++)
{
byte = *((unsigned char *) (str + i));
if (byte >= '0' && byte <= '9')
{
n = (n * 10) + (byte - '0');
byte = *((unsigned char *) (str + 2));
if (byte == 'x' || byte == 'X')
{
for (i = 3; i < 8; i++)
{
byte = *((unsigned char *) (str + i));
if (byte >= 'A' && byte <= 'F')
byte = byte - 'A' + 10;
else if (byte >= 'a' && byte <= 'f')
byte = byte - 'a' + 10;
else if (byte >= '0' && byte <= '9')
byte = byte - '0';
else
break;
n = (n * 16) + byte;
}
}
else
{
for (i = 2; i < 8; i++)
{
byte = *((unsigned char *) (str + i));
if (byte >= '0' && byte <= '9')
n = (n * 10) + (byte - '0');
else
break;
}
else
break;
}
if (byte == ';')
{
@ -219,6 +248,29 @@ gdTcl_UtfToUniChar (char *str, Tcl_UniChar * chPtr)
return ++i;
}
}
else
{
key.name = p = entity_name_buf;
for (i = 1; i < 1 + ENTITY_NAME_LENGTH_MAX; i++)
{
byte = *((unsigned char *) (str + i));
if (byte == '\0')
break;
if (byte == ';')
{
*p++ = '\0';
res = bsearch(&key, entities, NR_OF_ENTITIES,
sizeof(entities[0]), *comp_entities);
if (res)
{
*chPtr = (Tcl_UniChar) res->value;
return ++i;
}
break;
}
*p++ = byte;
}
}
}
/*
@ -403,6 +455,19 @@ fontFetch (char **error, void *key)
for (dir = strtok (path, PATHSEPARATOR); dir;
dir = strtok (0, PATHSEPARATOR))
{
if (strchr (name, '.'))
{
sprintf (fullname, "%s/%s", dir, name);
if (access (fullname, R_OK) == 0)
{
font_found++;
break;
}
else
{
continue;
}
}
sprintf (fullname, "%s/%s.ttf", dir, name);
if (access (fullname, R_OK) == 0)
{
@ -634,6 +699,7 @@ gdft_draw_bitmap (gdCache_head_t * tc_cache, gdImage * im, int fg,
{
unsigned char *pixel = NULL;
int *tpixel = NULL;
int opixel;
int x, y, row, col, pc, pcr;
tweencolor_t *tc_elem;
@ -679,6 +745,9 @@ gdft_draw_bitmap (gdCache_head_t * tc_cache, gdImage * im, int fg,
{
return "Unsupported ft_pixel_mode";
}
if (level == 0) /* if background */
continue;
if ((fg >= 0) && (im->trueColor))
{
/* Consider alpha in the foreground color itself to be an
@ -689,7 +758,7 @@ gdft_draw_bitmap (gdCache_head_t * tc_cache, gdImage * im, int fg,
level * (gdAlphaMax -
gdTrueColorGetAlpha (fg)) / gdAlphaMax;
}
level = gdAlphaMax - level;
level = gdAlphaMax - level; /* inverting to get alpha */
x = pen_x + col;
/* clip if out of bounds */
/* 2.0.16: clip to clipping rectangle, Matt McNabb */
@ -708,9 +777,16 @@ gdft_draw_bitmap (gdCache_head_t * tc_cache, gdImage * im, int fg,
{
if (im->alphaBlendingFlag)
{
*tpixel =
gdAlphaBlend (*tpixel,
opixel = *tpixel;
if (gdTrueColorGetAlpha(opixel) != gdAlphaTransparent)
{
*tpixel = gdAlphaBlend (opixel,
(level << 24) + (fg & 0xFFFFFF));
}
else
{
*tpixel = (level << 24) + (fg & 0xFFFFFF);
}
}
else
{
@ -763,43 +839,35 @@ gdft_draw_bitmap (gdCache_head_t * tc_cache, gdImage * im, int fg,
{
return "Unsupported ft_pixel_mode";
}
if (tc_key.pixel > 0) /* if not background */
if (tc_key.pixel == 0) /* if background */
continue;
x = pen_x + col;
/* clip if out of bounds */
if (x >= im->sx || x < 0)
continue;
/* get pixel location in gd buffer */
pixel = &im->pixels[y][x];
if (tc_key.pixel == NUMCOLORS)
{
x = pen_x + col;
/* use fg color directly. gd 2.0.2: watch out for
negative indexes (thanks to David Marwood). */
*pixel = (fg < 0) ? -fg : fg;
}
else
{
/* find antialised color */
/* clip if out of bounds */
if (x >= im->sx || x < 0)
continue;
/* get pixel location in gd buffer */
pixel = &im->pixels[y][x];
if (tc_key.pixel == NUMCOLORS)
{
/* use fg color directly. gd 2.0.2: watch out for
negative indexes (thanks to David Marwood). */
*pixel = (fg < 0) ? -fg : fg;
}
else
{
/* find antialised color */
tc_key.bgcolor = *pixel;
tc_elem = (tweencolor_t *) gdCacheGet (tc_cache, &tc_key);
*pixel = tc_elem->tweencolor;
}
tc_key.bgcolor = *pixel;
tc_elem = (tweencolor_t *) gdCacheGet (tc_cache, &tc_key);
*pixel = tc_elem->tweencolor;
}
}
}
return (char *) NULL;
}
static int
gdroundupdown (FT_F26Dot6 v1, int updown)
{
return (!updown)
? (v1 < 0 ? ((v1 - 63) >> 6) : v1 >> 6)
: (v1 > 0 ? ((v1 + 63) >> 6) : v1 >> 6);
}
extern int any2eucjp (char *, char *, unsigned int);
/* Persistent font cache until explicitly cleared */
@ -859,9 +927,8 @@ BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *f
double ptsize, double angle, int x, int y, char *string,
gdFTStringExtraPtr strex)
{
FT_BBox bbox, glyph_bbox;
FT_Matrix matrix;
FT_Vector pen, delta, penf;
FT_Vector penf, delta, total_min, total_max, glyph_min, glyph_max;
FT_Face face;
FT_Glyph image;
FT_GlyphSlot slot;
@ -870,8 +937,7 @@ BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *f
FT_UInt glyph_index, previous;
double sin_a = sin (angle);
double cos_a = cos (angle);
int len, i = 0, ch;
int x1 = 0, y1 = 0;
int len, i, ch;
font_t *font;
fontkey_t fontkey;
char *next;
@ -955,10 +1021,6 @@ BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *f
matrix.xy = -matrix.yx;
matrix.yy = matrix.xx;
penf.x = penf.y = 0; /* running position of non-rotated string */
pen.x = pen.y = 0; /* running position of rotated string */
bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0;
use_kerning = FT_HAS_KERNING (face);
previous = 0;
if (fg < 0)
@ -1031,17 +1093,18 @@ BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *f
next = string;
}
#endif
while (*next)
penf.x = penf.y = 0; /* running position of non-rotated glyphs */
for (i=0; *next; i++)
{
ch = *next;
/* carriage returns */
if (ch == '\r')
{
penf.x = 0;
x1 = (penf.x * cos_a - penf.y * sin_a + 32) / 64;
y1 = (penf.x * sin_a + penf.y * cos_a + 32) / 64;
pen.x = pen.y = 0;
previous = 0; /* clear kerning flag */
next++;
continue;
@ -1051,11 +1114,8 @@ BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *f
{
/* 2.0.13: reset penf.x. Christopher J. Grayce */
penf.x = 0;
penf.y -= face->size->metrics.height * linespace;
penf.y = (penf.y - 32) & -64; /* round to next pixel row */
x1 = (penf.x * cos_a - penf.y * sin_a + 32) / 64;
y1 = (penf.x * sin_a + penf.y * cos_a + 32) / 64;
pen.x = pen.y = 0;
penf.y += face->size->metrics.height * linespace;
penf.y = (penf.y + 32) & -64; /* round to next pixel row */
previous = 0; /* clear kerning flag */
next++;
continue;
@ -1152,7 +1212,6 @@ BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *f
{
FT_Get_Kerning (face, previous, glyph_index,
ft_kerning_default, &delta);
pen.x += delta.x;
/* 2.0.12: indispensable for an accurate bounding box. */
penf.x += delta.x;
}
@ -1166,40 +1225,45 @@ BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *f
return "Problem loading glyph";
}
/* transform glyph image */
FT_Get_Glyph (slot, &image);
if (brect)
{ /* only if need brect */
FT_Glyph_Get_CBox (image, ft_glyph_bbox_gridfit, &glyph_bbox);
glyph_bbox.xMin += penf.x;
glyph_bbox.yMin += penf.y;
glyph_bbox.xMax += penf.x;
glyph_bbox.yMax += penf.y;
if (ch == ' ') /* special case for trailing space */
glyph_bbox.xMax += slot->metrics.horiAdvance;
if (!i)
{ /* if first character, init BB corner values */
bbox.xMin = glyph_bbox.xMin;
bbox.yMin = glyph_bbox.yMin;
bbox.xMax = glyph_bbox.xMax;
bbox.yMax = glyph_bbox.yMax;
glyph_min.x = penf.x + slot->metrics.horiBearingX;
glyph_min.y = penf.y - slot->metrics.horiBearingY;
if (ch == ' ') /* special case for trailing space */
{
glyph_max.x = penf.x + slot->metrics.horiAdvance;
}
else
{
glyph_max.x = glyph_min.x + slot->metrics.width;
}
glyph_max.y = glyph_min.y + slot->metrics.height;
if (i==0)
{
total_min = glyph_min;
total_max = glyph_max;
}
else
{
if (bbox.xMin > glyph_bbox.xMin)
bbox.xMin = glyph_bbox.xMin;
if (bbox.yMin > glyph_bbox.yMin)
bbox.yMin = glyph_bbox.yMin;
if (bbox.xMax < glyph_bbox.xMax)
bbox.xMax = glyph_bbox.xMax;
if (bbox.yMax < glyph_bbox.yMax)
bbox.yMax = glyph_bbox.yMax;
if (glyph_min.x < total_min.x)
total_min.x = glyph_min.x;
if (glyph_min.y < total_min.y)
total_min.y = glyph_min.y;
if (glyph_max.x > total_max.x)
total_max.x = glyph_max.x;
if (glyph_max.y > total_max.y)
total_max.y = glyph_max.y;
}
i++;
}
if (render)
{
/* transform glyph image */
FT_Get_Glyph (slot, &image);
if (image->format != ft_glyph_format_bitmap)
{
err = FT_Glyph_To_Bitmap (&image, ft_render_mode_normal, 0, 1);
@ -1214,47 +1278,37 @@ BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *f
/* now, draw to our target surface */
bm = (FT_BitmapGlyph) image;
gdft_draw_bitmap (tc_cache, im, fg, bm->bitmap,
x + x1 + ((pen.x + 31) >> 6) + bm->left,
y - y1 + ((pen.y + 31) >> 6) - bm->top);
x + (penf.x * cos_a + penf.y * sin_a + 32)/64 + bm->left,
y - (penf.x * sin_a - penf.y * cos_a - 32)/64 - bm->top);
FT_Done_Glyph (image);
}
/* record current glyph index for kerning */
previous = glyph_index;
/* increment pen position */
pen.x += image->advance.x >> 10;
pen.y -= image->advance.y >> 10;
/* advance character position */
penf.x += slot->metrics.horiAdvance;
FT_Done_Glyph (image);
}
if (brect)
{ /* only if need brect */
/* For perfect rounding, must get sin(a + pi/4) and sin(a - pi/4). */
double d1 = sin (angle + 0.78539816339744830962);
double d2 = sin (angle - 0.78539816339744830962);
/* rotate bounding rectangle */
brect[0] = (int) (bbox.xMin * cos_a - bbox.yMin * sin_a);
brect[1] = (int) (bbox.xMin * sin_a + bbox.yMin * cos_a);
brect[2] = (int) (bbox.xMax * cos_a - bbox.yMin * sin_a);
brect[3] = (int) (bbox.xMax * sin_a + bbox.yMin * cos_a);
brect[4] = (int) (bbox.xMax * cos_a - bbox.yMax * sin_a);
brect[5] = (int) (bbox.xMax * sin_a + bbox.yMax * cos_a);
brect[6] = (int) (bbox.xMin * cos_a - bbox.yMax * sin_a);
brect[7] = (int) (bbox.xMin * sin_a + bbox.yMax * cos_a);
/* scale, round and offset brect */
brect[0] = x + gdroundupdown (brect[0], d2 > 0);
brect[1] = y - gdroundupdown (brect[1], d1 < 0);
brect[2] = x + gdroundupdown (brect[2], d1 > 0);
brect[3] = y - gdroundupdown (brect[3], d2 > 0);
brect[4] = x + gdroundupdown (brect[4], d2 < 0);
brect[5] = y - gdroundupdown (brect[5], d1 > 0);
brect[6] = x + gdroundupdown (brect[6], d1 < 0);
brect[7] = y - gdroundupdown (brect[7], d2 < 0);
/* increase by 1 pixel to allow for rounding */
total_min.x -= 64;
total_min.y -= 64;
total_max.x += 64;
total_max.y += 64;
/* rotate bounding rectangle, scale and round to int pixels, and translate */
brect[0] = x + (total_min.x * cos_a + total_min.y * sin_a + 32)/64;
brect[1] = y - (total_min.x * sin_a - total_min.y * cos_a + 32)/64;
brect[2] = x + (total_max.x * cos_a + total_min.y * sin_a + 32)/64;
brect[3] = y - (total_max.x * sin_a - total_min.y * cos_a + 32)/64;
brect[4] = x + (total_max.x * cos_a + total_max.y * sin_a + 32)/64;
brect[5] = y - (total_max.x * sin_a - total_max.y * cos_a + 32)/64;
brect[6] = x + (total_min.x * cos_a + total_max.y * sin_a + 32)/64;
brect[7] = y - (total_min.x * sin_a - total_max.y * cos_a + 32)/64;
}
if (tmpstr)

50
src/testtr.c Normal file
View File

@ -0,0 +1,50 @@
#ifdef HAVE_CONFIG_H #include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include "gd.h"
#define FALSE 0
#define TRUE (!FALSE)
int
main (int argc, char *argv[])
{
#ifdef HAVE_LIBFREETYPE
FILE *out;
int transparent, green, black;
gdImagePtr im;
im = gdImageCreateTrueColor(100,100);
black = gdImageColorResolveAlpha(im, 0, 0, 0, gdAlphaOpaque);
green = gdImageColorResolveAlpha(im, 0, gdGreenMax, 0, gdAlphaOpaque);
transparent = gdImageColorResolveAlpha(im,
gdRedMax-1, gdGreenMax, gdBlueMax, gdAlphaTransparent);
gdImageColorTransparent(im, transparent);
/* Blending must be off to lay a transparent basecolor.
Nothing to blend with anyway. */
gdImageAlphaBlending(im, FALSE);
gdImageFill (im, im->sx/2, im->sy/2, transparent);
/* Blend everything else together,
especially fonts over non-transparent backgrounds */
gdImageAlphaBlending(im, TRUE);
gdImageFilledRectangle (im, 30, 30, 70, 70, green);
gdImageStringFT (im, NULL, black, "times", 18, 0, 50, 50, "Hello");
gdImageSaveAlpha (im, TRUE);
out = fopen ("testtr.png", "wb");
gdImagePng (im, out);
fclose (out);
gdImageDestroy (im);
return 0;
#else
fprintf(stderr, "Compiled without freetype support\n");
return 0;
#endif /* HAVE_LIBFREETYPE */
}