- sync to 2.0.26
parent
c6d33ff048
commit
cfa7ee3b92
|
@ -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
|
|
@ -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
421
src/gd.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
19
src/gd.h
19
src/gd.h
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
278
src/gdft.c
278
src/gdft.c
|
@ -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. Å */
|
||||
/* or in hexadecimal form, e.g. 水 */
|
||||
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)
|
||||
|
|
|
@ -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 */
|
||||
}
|
Loading…
Reference in New Issue