- sync to 2.0.0

master
pierre 2006-04-05 15:42:22 +00:00
parent c9af8e769b
commit fceb93d2b9
22 changed files with 5485 additions and 1662 deletions

45
src/alphachanneltest.html Normal file
View File

@ -0,0 +1,45 @@
<head>
<title>gd Alpha Channel Test</title>
<head>
<body bgcolor="#c0c0FF">
<h1>gd Alpha Channel Test</h1>
If your browser fully supports PNG alpha channels, the
"blended" and "alpha channel" images should appear identical
to the naked eye. Miniscule mathematical differences may
exist due to the 7-bit alpha channel resolution of gd.
<p>
Palette and truecolor images will look slightly different,
as the palette versions are limited to 256 palette entries,
which are used as well as possible to approach the effect
of the original truecolor version.
<table>
<tr>
<th colspan=2>Truecolor Images</th>
<tr>
<th>Blending against light blue, Half Size<td><img src="blending-halfsize-truecolor.png">
<tr>
<th>Alpha channel, Half Size<td><img src="noblending-halfsize-truecolor.png">
<tr>
<th>Blending against light blue, Full Size<td><img src="blending-fullsize-truecolor.png">
<tr>
<th>Alpha channel, Full Size<td><img src="noblending-fullsize-truecolor.png">
<tr>
<th>Blending against light blue, Double Size<td><img src="blending-doublesize-truecolor.png">
<tr>
<th>Alpha channel, Double Size<td><img src="noblending-doublesize-truecolor.png">
<tr>
<th colspan=2>Palette Images</th>
<tr>
<th>Blending against light blue, Half Size<td><img src="blending-halfsize-palette.png">
<tr>
<th>Alpha channel, Half Size<td><img src="noblending-halfsize-palette.png">
<tr>
<th>Blending against light blue, Full Size<td><img src="blending-fullsize-palette.png">
<tr>
<th>Alpha channel, Full Size<td><img src="noblending-fullsize-palette.png">
<tr>
<th>Blending against light blue, Double Size<td><img src="blending-doublesize-palette.png">
<tr>
<th>Alpha channel, Double Size<td><img src="noblending-doublesize-palette.png"></table>
</body>

BIN
src/antialiased.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

1
src/errs Normal file
View File

@ -0,0 +1 @@
gcc -I. -I/usr/include/freetype2 -I/usr/include/X11 -I/usr/X11R6/include/X11 -I/usr/local/include -O -DHAVE_LIBXPM -DHAVE_LIBPNG -DHAVE_LIBJPEG -DHAVE_LIBFREETYPE -c gd_gd2.c -o gd_gd2.o

1151
src/gd.c

File diff suppressed because it is too large Load Diff

229
src/gd.h
View File

@ -24,7 +24,9 @@ extern "C" {
#include <stdio.h>
#include "gd_io.h"
/* This can't be changed in the current palette-only version of gd. */
/* The maximum number of palette entries in palette-based images.
In the wonderful new world of gd 2.0, you can of course have
many more colors when using truecolor mode. */
#define gdMaxColors 256
@ -33,15 +35,63 @@ extern "C" {
access sx, sy, the color table, and colorsTotal for
read-only purposes. */
/* If 'truecolor' is set true, the image is truecolor;
pixels are represented by integers, which
must be 32 bits wide or more.
True colors are repsented as follows:
ARGB
Where 'A' (alpha channel) occupies only the
LOWER 7 BITS of the MSB. This very small
loss of alpha channel resolution allows gd 2.x
to keep backwards compatibility by allowing
signed integers to be used to represent colors,
and negative numbers to represent special cases,
just as in gd 1.x. */
#define gdAlphaMax 127
#define gdAlphaOpaque 0
#define gdAlphaTransparent 127
#define gdRedMax 255
#define gdGreenMax 255
#define gdBlueMax 255
#define gdTrueColorGetAlpha(c) (((c) & 0x7F000000) >> 24)
#define gdTrueColorGetRed(c) (((c) & 0xFF0000) >> 16)
#define gdTrueColorGetGreen(c) (((c) & 0x00FF00) >> 8)
#define gdTrueColorGetBlue(c) ((c) & 0x0000FF)
/* This function accepts truecolor pixel values only. The
source color is composited with the destination color
based on the alpha channel value of the source color.
The resulting color is opaque. */
int gdAlphaBlend(int dest, int src);
typedef struct gdImageStruct {
/* Palette-based image pixels */
unsigned char ** pixels;
int sx;
int sy;
/* These are valid in palette images only. See also
/* 'alpha', which appears later in the structure to
preserve binary backwards compatibility */
int colorsTotal;
int red[gdMaxColors];
int green[gdMaxColors];
int blue[gdMaxColors];
int open[gdMaxColors];
/* For backwards compatibility, this is set to the
first palette entry with 100% transparency,
and is also set and reset by the
gdImageColorTransparent function. Newer
applications can allocate palette entries
with any desired level of transparency; however,
bear in mind that many viewers, notably
many web browsers, fail to implement
full alpha channel for PNG and provide
support for full opacity or transparency only. */
int transparent;
int *polyInts;
int polyAllocated;
@ -53,6 +103,32 @@ typedef struct gdImageStruct {
int stylePos;
int *style;
int interlace;
/* New in 2.0: thickness of line. Initialized to 1. */
int thick;
/* New in 2.0: alpha channel for palettes. Note that only
Macintosh Internet Explorer and (possibly) Netscape 6
really support multiple levels of transparency in
palettes, to my knowledge, as of 2/15/01. Most
common browsers will display 100% opaque and
100% transparent correctly, and do something
unpredictable and/or undesirable for levels
in between. TBB */
int alpha[gdMaxColors];
/* Truecolor flag and pixels. New 2.0 fields appear here at the
end to minimize breakage of existing object code. */
int trueColor;
int ** tpixels;
/* Should alpha channel be copied, or applied, each time a
pixel is drawn? This applies to truecolor images only.
No attempt is made to alpha-blend in palette images,
even if semitransparent palette entries exist.
To do that, build your image as a truecolor image,
then quantize down to 8 bits. */
int alphaBlendingFlag;
/* Should the alpha channel of the image be saved? This affects
PNG at the moment; other future formats may also
have that capability. JPEG doesn't. */
int saveAlphaFlag;
} gdImage;
typedef gdImage * gdImagePtr;
@ -92,7 +168,20 @@ typedef gdFont *gdFontPtr;
/* Functions to manipulate images. */
/* Creates a palette-based image (up to 256 colors). */
gdImagePtr gdImageCreate(int sx, int sy);
/* An alternate name for the above (2.0). */
#define gdImageCreatePalette gdImageCreate
/* Creates a truecolor image (millions of colors). */
gdImagePtr gdImageCreateTrueColor(int sx, int sy);
/* Creates an image from various file types. These functions
return a palette or truecolor image based on the
nature of the file being loaded. Truecolor PNG
stays truecolor; palette PNG stays palette-based;
JPEG is always truecolor. */
gdImagePtr gdImageCreateFromPng(FILE *fd);
gdImagePtr gdImageCreateFromPngCtx(gdIOCtxPtr in);
gdImagePtr gdImageCreateFromWBMP(FILE *inFile);
@ -124,9 +213,20 @@ gdImagePtr gdImageCreateFromGd2PartCtx(gdIOCtxPtr in, int srcx, int srcy, int w,
gdImagePtr gdImageCreateFromXbm(FILE *fd);
void gdImageDestroy(gdImagePtr im);
/* Replaces or blends with the background depending on the
most recent call to gdImageAlphaBlending and the
alpha channel value of 'color'; default is to overwrite.
Tiling and line styling are also implemented
here. All other gd drawing functions pass through this call,
allowing for many useful effects. */
void gdImageSetPixel(gdImagePtr im, int x, int y, int color);
int gdImageGetPixel(gdImagePtr im, int x, int y);
void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
/* For backwards compatibility only. Use gdImageSetStyle()
for much more flexible line drawing. */
void gdImageDashedLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
@ -143,11 +243,11 @@ void gdImageStringUp(gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s,
void gdImageString16(gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color);
void gdImageStringUp16(gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color);
/* FreeType 1.x text output (DEPRECATED) */
/* Calls gdImageStringFT. Provided for backwards compatibility only. */
char *gdImageStringTTF(gdImage *im, int *brect, int fg, char *fontlist,
double ptsize, double angle, int x, int y, char *string);
/* FreeType 2 text output (NIFTY) */
/* FreeType 2 text output */
char *gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
double ptsize, double angle, int x, int y, char *string);
@ -159,12 +259,74 @@ typedef struct {
void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c);
void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c);
/* These functions still work with truecolor images,
for which they never return error. */
int gdImageColorAllocate(gdImagePtr im, int r, int g, int b);
/* gd 2.0: palette entries with non-opaque transparency are permitted. */
int gdImageColorAllocateAlpha(gdImagePtr im, int r, int g, int b, int a);
/* Assumes opaque is the preferred alpha channel value */
int gdImageColorClosest(gdImagePtr im, int r, int g, int b);
/* Closest match taking all four parameters into account.
A slightly different color with the same transparency
beats the exact same color with radically different
transparency */
int gdImageColorClosestAlpha(gdImagePtr im, int r, int g, int b, int a);
/* Returns exact, 100% opaque matches only */
int gdImageColorExact(gdImagePtr im, int r, int g, int b);
/* Returns an exact match only, including alpha */
int gdImageColorExactAlpha(gdImagePtr im, int r, int g, int b, int a);
/* Opaque only */
int gdImageColorResolve(gdImagePtr im, int r, int g, int b);
/* Based on gdImageColorExactAlpha and gdImageColorClosestAlpha */
int gdImageColorResolveAlpha(gdImagePtr im, int r, int g, int b, int a);
/* A simpler way to obtain an opaque truecolor value for drawing on a
truecolor image. Not for use with palette images! */
#define gdTrueColor(r, g, b) (((r) << 16) + \
((g) << 8) + \
(b))
/* Returns a truecolor value with an alpha channel component.
gdAlphaMax (127, **NOT 255**) is transparent, 0 is completely
opaque. */
#define gdTrueColorAlpha(r, g, b, a) (((a) << 24) + \
((r) << 16) + \
((g) << 8) + \
(b))
void gdImageColorDeallocate(gdImagePtr im, int color);
/* Converts a truecolor image to a palette-based image,
using a high-quality two-pass quantization routine
which attempts to preserve alpha channel information
as well as R/G/B color information when creating
a palette. If ditherFlag is set, the image will be
dithered to approximate colors better, at the expense
of some obvious "speckling." colorsWanted can be
anything up to 256. If the original source image
includes photographic information or anything that
came out of a JPEG, 256 is strongly recommended.
Better yet, don't use this function -- write real
truecolor PNGs and JPEGs. The disk space gain of
conversion to palette is not great (for small images
it can be negative) and the quality loss is ugly. */
void gdImageTrueColorToPalette(gdImagePtr im, int ditherFlag, int colorsWanted);
/* Specifies a color index (if a palette image) or an
RGB color (if a truecolor image) which should be
considered 100% transparent. FOR TRUECOLOR IMAGES,
THIS IS IGNORED IF AN ALPHA CHANNEL IS BEING
SAVED. Use gdImageSaveAlpha(im, 0); to
turn off the saving of a full alpha channel in
a truecolor image. Note that gdImageColorTransparent
is usually compatible with older browsers that
do not understand full alpha channels well. TBB */
void gdImageColorTransparent(gdImagePtr im, int color);
void gdImagePaletteCopy(gdImagePtr dst, gdImagePtr src);
void gdImagePng(gdImagePtr im, FILE *out);
void gdImagePngCtx(gdImagePtr im, gdIOCtx *out);
@ -209,7 +371,14 @@ void* gdImageGdPtr(gdImagePtr im, int *size);
/* Best to free this memory with gdFree(), not free() */
void* gdImageGd2Ptr(gdImagePtr im, int cs, int fmt, int *size);
void gdImageEllipse(gdImagePtr im, int cx, int cy, int w, int h, int color);
void gdImageArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color);
#define gdPie 0
#define gdChord 1
void gdImageFilledEllipse(gdImagePtr im, int cx, int cy, int w, int h, int color, int style);
void gdImageFilledArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style);
void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color);
void gdImageFill(gdImagePtr im, int x, int y, int color);
void gdImageCopy(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h);
@ -218,25 +387,62 @@ void gdImageCopyMerge(gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
void gdImageCopyMergeGray(gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
int srcX, int srcY, int w, int h, int pct);
/* Stretches or shrinks to fit, as needed */
/* Stretches or shrinks to fit, as needed. Does NOT attempt
to average the entire set of source pixels that scale down onto the
destination pixel. */
void gdImageCopyResized(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH);
/* gd 2.0: stretches or shrinks to fit, as needed. When called with a
truecolor destination image, this function averages the
entire set of source pixels that scale down onto the
destination pixel, taking into account what portion of the
destination pixel each source pixel represents. This is a
floating point operation, but this is not a performance issue
on modern hardware, except for some embedded devices. If the
destination is a palette image, gdImageCopyResized is
substituted automatically. */
void gdImageCopyResampled(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH);
void gdImageSetBrush(gdImagePtr im, gdImagePtr brush);
void gdImageSetTile(gdImagePtr im, gdImagePtr tile);
void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels);
/* On or off (1 or 0) */
/* Line thickness (defaults to 1). Affects lines, ellipses,
rectangles, polygons and so forth. */
void gdImageSetThickness(gdImagePtr im, int thickness);
/* On or off (1 or 0) for all three of these. */
void gdImageInterlace(gdImagePtr im, int interlaceArg);
void gdImageAlphaBlending(gdImagePtr im, int alphaBlendingArg);
void gdImageSaveAlpha(gdImagePtr im, int saveAlphaArg);
/* Macros to access information about images. */
/* Returns nonzero if the image is a truecolor image,
zero for a palette image. */
#define gdImageTrueColor(im) ((im)->trueColor)
/* Macros to access information about images. READ ONLY. Changing
these values will NOT have the desired result. */
#define gdImageSX(im) ((im)->sx)
#define gdImageSY(im) ((im)->sy)
#define gdImageColorsTotal(im) ((im)->colorsTotal)
#define gdImageRed(im, c) ((im)->red[(c)])
#define gdImageGreen(im, c) ((im)->green[(c)])
#define gdImageBlue(im, c) ((im)->blue[(c)])
#define gdImageRed(im, c) ((im)->trueColor ? gdTrueColorGetRed(c) : \
(im)->red[(c)])
#define gdImageGreen(im, c) ((im)->trueColor ? gdTrueColorGetGreen(c) : \
(im)->green[(c)])
#define gdImageBlue(im, c) ((im)->trueColor ? gdTrueColorGetBlue(c) : \
(im)->blue[(c)])
#define gdImageAlpha(im, c) ((im)->trueColor ? gdTrueColorGetAlpha(c) : \
(im)->alpha[(c)])
#define gdImageGetTransparent(im) ((im)->transparent)
#define gdImageGetInterlaced(im) ((im)->interlace)
/* These macros provide direct access to pixels in
palette-based and truecolor images, respectively.
If you use these macros, you must perform your own
bounds checking. Use of the macro for the correct type
of image is also your responsibility. */
#define gdImagePalettePixel(im, x, y) (im)->pixels[(y)][(x)]
#define gdImageTrueColorPixel(im, x, y) (im)->tpixels[(y)][(x)]
/* I/O Support routines. */
gdIOCtx* gdNewFileCtx(FILE*);
@ -248,7 +454,7 @@ void* gdDPExtractData(struct gdIOCtx* ctx, int *size);
#define GD2_CHUNKSIZE_MIN 64
#define GD2_CHUNKSIZE_MAX 4096
#define GD2_VERS 1
#define GD2_VERS 2
#define GD2_ID "gd2"
#define GD2_FMT_RAW 1
#define GD2_FMT_COMPRESSED 2
@ -264,6 +470,7 @@ int gdImageCompare(gdImagePtr im1, gdImagePtr im2);
#define GD_CMP_TRANSPARENT 32 /* Transparent colour */
#define GD_CMP_BACKGROUND 64 /* Background colour */
#define GD_CMP_INTERLACE 128 /* Interlaced setting */
#define GD_CMP_TRUECOLOR 256 /* Truecolor vs palette differs */
/* resolution affects ttf font rendering, particularly hinting */
#define GD_RESOLUTION 96 /* pixels per inch */

600
src/gd_arc_f.c Normal file
View File

@ -0,0 +1,600 @@
#include "gd.h"
#include <math.h>
/* Courtesy of F J Franklin. */
static gdPoint gdArcClosest (int width,int height,int angle);
void gdImageFilledEllipse(gdImagePtr im, int cx, int cy, int width, int height, int color, int style)
{
gdImageFilledArc(im, cx, cy, width, height, 0, 360, color, style);
}
void gdImageFilledArc(gdImagePtr im, int cx, int cy, int width, int height, int s, int e, int color, int style)
{ gdPoint pt[7];
gdPoint axis_pt[4];
int angle;
int have_s = 0;
int have_e = 0;
int flip_x = 0;
int flip_y = 0;
int conquer = 0;
int i;
int a;
int b;
int x;
int y;
long s_sin = 0;
long s_cos = 0;
long e_sin = 0;
long e_cos = 0;
long w; /* a * 2 */
long h; /* b * 2 */
long x2; /* x * 2 */
long y2; /* y * 2 */
long lx2; /* x * 2 (line) */
long ly2; /* y * 2 (line) */
long ws; /* (a * 2)^2 */
long hs; /* (b * 2)^2 */
long whs; /* (a * 2)^2 * (b * 2)^2 */
long g; /* decision variable */
long lg; /* decision variable (line) */
width = (width & 1) ? (width + 1) : (width );
height = (height & 1) ? (height + 1) : (height);
a = width / 2;
b = height / 2;
axis_pt[0].x = a;
axis_pt[0].y = 0;
axis_pt[1].x = 0;
axis_pt[1].y = b;
axis_pt[2].x = -a;
axis_pt[2].y = 0;
axis_pt[3].x = 0;
axis_pt[3].y = -b;
if (s == e) return;
if ((e - s) >= 360)
{ s = 0;
e = 0;
}
while (s < 0) s += 360;
while (s >= 360) s -= 360;
while (e < 0) e += 360;
while (e >= 360) e -= 360;
if (e <= s) e += 360;
/* I'm assuming a chord-rule at the moment. Need to add origin to get a
* pie-rule, but will need to set chord-rule before recursion...
*/
for (i = 0; i < 4; i++)
{ if ((s < (i+1)*90) && (e > (i+1)*90))
{ gdImageFilledArc (im,cx,cy,width,height,s,(i+1)*90,color,gdChord);
pt[0] = gdArcClosest (width,height,s);
pt[0].x += cx;
pt[0].y += cy;
pt[1].x = cx + axis_pt[(i+1)&3].x;
pt[1].y = cy + axis_pt[(i+1)&3].y;
if (e <= (i+2)*90)
{ gdImageFilledArc (im,cx,cy,width,height,(i+1)*90,e,color,gdChord);
pt[2] = gdArcClosest (width,height,e);
pt[2].x += cx;
pt[2].y += cy;
if (style == gdChord)
{ gdImageFilledPolygon (im,pt,3,color);
gdImagePolygon (im,pt,3,color);
}
else if (style == gdPie)
{ pt[3].x = cx;
pt[3].y = cy;
gdImageFilledPolygon (im,pt,4,color);
gdImagePolygon (im,pt,4,color);
}
}
else
{ gdImageFilledArc (im,cx,cy,width,height,(i+1)*90,(i+2)*90,color,gdChord);
pt[2].x = cx + axis_pt[(i+2)&3].x;
pt[2].y = cy + axis_pt[(i+2)&3].y;
if (e <= (i+3)*90)
{ gdImageFilledArc (im,cx,cy,width,height,(i+2)*90,e,color,gdChord);
pt[3] = gdArcClosest (width,height,e);
pt[3].x += cx;
pt[3].y += cy;
if (style == gdChord)
{ gdImageFilledPolygon (im,pt,4,color);
gdImagePolygon (im,pt,4,color);
}
else if (style == gdPie)
{ pt[4].x = cx;
pt[4].y = cy;
gdImageFilledPolygon (im,pt,5,color);
gdImagePolygon (im,pt,5,color);
}
}
else
{ gdImageFilledArc (im,cx,cy,width,height,(i+2)*90,(i+3)*90,color,gdChord);
pt[3].x = cx + axis_pt[(i+3)&3].x;
pt[3].y = cy + axis_pt[(i+3)&3].y;
if (e <= (i+4)*90)
{ gdImageFilledArc (im,cx,cy,width,height,(i+3)*90,e,color,gdChord);
pt[4] = gdArcClosest (width,height,e);
pt[4].x += cx;
pt[4].y += cy;
if (style == gdChord)
{ gdImageFilledPolygon (im,pt,5,color);
gdImagePolygon (im,pt,5,color);
}
else if (style == gdPie)
{ pt[5].x = cx;
pt[5].y = cy;
gdImageFilledPolygon (im,pt,6,color);
gdImagePolygon (im,pt,6,color);
}
}
else
{ gdImageFilledArc (im,cx,cy,width,height,(i+3)*90,(i+4)*90,color,gdChord);
pt[4].x = cx + axis_pt[(i+4)&3].x;
pt[4].y = cy + axis_pt[(i+4)&3].y;
gdImageFilledArc (im,cx,cy,width,height,(i+4)*90,e,color,gdChord);
pt[5] = gdArcClosest (width,height,e);
pt[5].x += cx;
pt[5].y += cy;
if (style == gdChord)
{ gdImageFilledPolygon (im,pt,6,color);
gdImagePolygon (im,pt,6,color);
}
else if (style == gdPie)
{ pt[6].x = cx;
pt[6].y = cy;
gdImageFilledPolygon (im,pt,7,color);
gdImagePolygon (im,pt,7,color);
}
}
}
}
return;
}
}
/* At this point we have only arcs that lies within a quadrant -
* map this to first quadrant...
*/
if ((s >= 90) && (e <= 180))
{ angle = s;
s = 180 - e;
e = 180 - angle;
flip_x = 1;
}
if ((s >= 180) && (e <= 270))
{ s = s - 180;
e = e - 180;
flip_x = 1;
flip_y = 1;
}
if ((s >= 270) && (e <= 360))
{ angle = s;
s = 360 - e;
e = 360 - angle;
flip_y = 1;
}
if (s == 0)
{ s_sin = 0;
s_cos = (long) ((double) 32768);
}
else
{ s_sin = (long) ((double) 32768 * sin ((double) s * M_PI / (double) 180));
s_cos = (long) ((double) 32768 * cos ((double) s * M_PI / (double) 180));
}
if (e == 0)
{ e_sin = (long) ((double) 32768);
e_cos = 0;
}
else
{ e_sin = (long) ((double) 32768 * sin ((double) e * M_PI / (double) 180));
e_cos = (long) ((double) 32768 * cos ((double) e * M_PI / (double) 180));
}
w = (long) width;
h = (long) height;
ws = w * w;
hs = h * h;
whs = 1;
while ((ws > 32768) || (hs > 32768))
{ ws = (ws + 1) / 2; /* Unfortunate limitations on integers makes */
hs = (hs + 1) / 2; /* drawing large ellipses problematic... */
whs *= 2;
}
while ((ws * hs) > (0x04000000L / whs))
{ ws = (ws + 1) / 2;
hs = (hs + 1) / 2;
whs *= 2;
}
whs *= ws * hs;
pt[0].x = w / 2;
pt[0].y = 0;
pt[2].x = 0;
pt[2].y = h / 2;
have_s = 0;
have_e = 0;
if (s == 0) have_s = 1;
if (e == 90) have_e = 1;
x2 = w;
y2 = 0; /* Starting point is exactly on ellipse */
g = x2 - 1;
g = g * g * hs + 4 * ws - whs;
while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */
{ y2 += 2;
g += ws * 4 * (y2 + 1);
if (g > 0) /* Need to drop */
{ x2 -= 2;
g -= hs * 4 * x2;
}
if ((have_s == 0) && ((s_sin * x2) <= (y2 * s_cos)))
{ pt[0].x = (int) (x2 / 2);
pt[0].y = (int) (y2 / 2);
have_s = 1;
}
if ((have_e == 0) && ((e_sin * x2) <= (y2 * e_cos)))
{ pt[2].x = (int) (x2 / 2);
pt[2].y = (int) (y2 / 2);
have_e = 1;
}
}
pt[1].x = (int) (x2 / 2);
pt[1].y = (int) (y2 / 2);
x2 = 0;
y2 = h; /* Starting point is exactly on ellipse */
g = y2 - 1;
g = g * g * ws + 4 * hs - whs;
while ((x2 * hs) < (y2 * ws))
{ x2 += 2;
g += hs * 4 * (x2 + 1);
if (g > 0) /* Need to drop */
{ y2 -= 2;
g -= ws * 4 * y2;
}
if ((have_s == 0) && ((s_sin * x2) >= (y2 * s_cos)))
{ pt[0].x = (int) (x2 / 2);
pt[0].y = (int) (y2 / 2);
have_s = 1;
}
if ((have_e == 0) && ((e_sin * x2) >= (y2 * e_cos)))
{ pt[2].x = (int) (x2 / 2);
pt[2].y = (int) (y2 / 2);
have_e = 1;
}
}
if ((have_s == 0) || (have_e == 0)) return; /* Bizarre case */
if (style == gdPie)
{ pt[3] = pt[0];
pt[4] = pt[1];
pt[5] = pt[2];
pt[0].x = cx + (flip_x ? (-pt[0].x) : pt[0].x);
pt[0].y = cy + (flip_y ? (-pt[0].y) : pt[0].y);
pt[1].x = cx;
pt[1].y = cy;
pt[2].x = cx + (flip_x ? (-pt[2].x) : pt[2].x);
pt[2].y = cy + (flip_y ? (-pt[2].y) : pt[2].y);
gdImageFilledPolygon (im,pt,3,color);
gdImagePolygon (im,pt,3,color);
pt[0] = pt[3];
pt[1] = pt[4];
pt[2] = pt[5];
}
if (((s_cos * hs) > (s_sin * ws)) && ((e_cos * hs) < (e_sin * ws)))
{ /* the points are on different parts of the curve...
* this is too tricky to try to handle, so divide and conquer:
*/
pt[3] = pt[0];
pt[4] = pt[1];
pt[5] = pt[2];
pt[0].x = cx + (flip_x ? (-pt[0].x) : pt[0].x);
pt[0].y = cy + (flip_y ? (-pt[0].y) : pt[0].y);
pt[1].x = cx + (flip_x ? (-pt[1].x) : pt[1].x);
pt[1].y = cy + (flip_y ? (-pt[1].y) : pt[1].y);
pt[2].x = cx + (flip_x ? (-pt[2].x) : pt[2].x);
pt[2].y = cy + (flip_y ? (-pt[2].y) : pt[2].y);
gdImageFilledPolygon (im,pt,3,color);
gdImagePolygon (im,pt,3,color);
pt[0] = pt[3];
pt[2] = pt[4];
conquer = 1;
}
if (conquer || (((s_cos * hs) > (s_sin * ws)) && ((e_cos * hs) > (e_sin * ws))))
{ /* This is the best bit... */
/* steep line + ellipse */
/* go up & left from pt[0] to pt[2] */
x2 = w;
y2 = 0; /* Starting point is exactly on ellipse */
g = x2 - 1;
g = g * g * hs + 4 * ws - whs;
while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */
{ if ((s_sin * x2) <= (y2 * s_cos)) break;
y2 += 2;
g += ws * 4 * (y2 + 1);
if (g > 0) /* Need to drop */
{ x2 -= 2;
g -= hs * 4 * x2;
}
}
lx2 = x2;
ly2 = y2;
lg = lx2 * (pt[0].y - pt[2].y) - ly2 * (pt[0].x - pt[2].x);
lg = (lx2 - 1) * (pt[0].y - pt[2].y) - (ly2 + 2) * (pt[0].x - pt[2].x) - lg;
while (y2 < (2 * pt[2].y))
{ y2 += 2;
g += ws * 4 * (y2 + 1);
if (g > 0) /* Need to drop */
{ x2 -= 2;
g -= hs * 4 * x2;
}
ly2 += 2;
lg -= 2 * (pt[0].x - pt[2].x);
if (lg < 0) /* Need to drop */
{ lx2 -= 2;
lg -= 2 * (pt[0].y - pt[2].y);
}
y = (int) (y2 / 2);
for (x = (int) (lx2 / 2); x <= (int) (x2 / 2); x++)
{ gdImageSetPixel (im,((flip_x)?(cx-x):(cx+x)),
((flip_y)?(cy-y):(cy+y)),color);
}
}
}
if (conquer)
{ pt[0] = pt[4];
pt[2] = pt[5];
}
if (conquer || (((s_cos * hs) < (s_sin * ws)) && ((e_cos * hs) < (e_sin * ws))))
{ /* This is the best bit... */
/* gradual line + ellipse */
/* go down & right from pt[2] to pt[0] */
x2 = 0;
y2 = h; /* Starting point is exactly on ellipse */
g = y2 - 1;
g = g * g * ws + 4 * hs - whs;
while ((x2 * hs) < (y2 * ws))
{ x2 += 2;
g += hs * 4 * (x2 + 1);
if (g > 0) /* Need to drop */
{ y2 -= 2;
g -= ws * 4 * y2;
}
if ((e_sin * x2) >= (y2 * e_cos)) break;
}
lx2 = x2;
ly2 = y2;
lg = lx2 * (pt[0].y - pt[2].y) - ly2 * (pt[0].x - pt[2].x);
lg = (lx2 + 2) * (pt[0].y - pt[2].y) - (ly2 - 1) * (pt[0].x - pt[2].x) - lg;
while (x2 < (2 * pt[0].x))
{ x2 += 2;
g += hs * 4 * (x2 + 1);
if (g > 0) /* Need to drop */
{ y2 -= 2;
g -= ws * 4 * y2;
}
lx2 += 2;
lg += 2 * (pt[0].y - pt[2].y);
if (lg < 0) /* Need to drop */
{ ly2 -= 2;
lg += 2 * (pt[0].x - pt[2].x);
}
x = (int) (x2 / 2);
for (y = (int) (ly2 / 2); y <= (int) (y2 / 2); y++)
{ gdImageSetPixel (im,((flip_x)?(cx-x):(cx+x)),
((flip_y)?(cy-y):(cy+y)),color);
}
}
}
}
static gdPoint gdArcClosest (int width,int height,int angle)
{ gdPoint pt;
int flip_x = 0;
int flip_y = 0;
long a_sin = 0;
long a_cos = 0;
long w; /* a * 2 */
long h; /* b * 2 */
long x2; /* x * 2 */
long y2; /* y * 2 */
long ws; /* (a * 2)^2 */
long hs; /* (b * 2)^2 */
long whs; /* (a * 2)^2 * (b * 2)^2 */
long g; /* decision variable */
w = (long) ((width & 1) ? (width + 1) : (width ));
h = (long) ((height & 1) ? (height + 1) : (height));
while (angle < 0) angle += 360;
while (angle >= 360) angle -= 360;
if (angle == 0)
{ pt.x = w / 2;
pt.y = 0;
return (pt);
}
if (angle == 90)
{ pt.x = 0;
pt.y = h / 2;
return (pt);
}
if (angle == 180)
{ pt.x = - w / 2;
pt.y = 0;
return (pt);
}
if (angle == 270)
{ pt.x = 0;
pt.y = - h / 2;
return (pt);
}
pt.x = 0;
pt.y = 0;
if ((angle > 90) && (angle < 180))
{ angle = 180 - angle;
flip_x = 1;
}
if ((angle > 180) && (angle < 270))
{ angle = angle - 180;
flip_x = 1;
flip_y = 1;
}
if ((angle > 270) && (angle < 360))
{ angle = 360 - angle;
flip_y = 1;
}
a_sin = (long) ((double) 32768 * sin ((double) angle * M_PI / (double) 180));
a_cos = (long) ((double) 32768 * cos ((double) angle * M_PI / (double) 180));
ws = w * w;
hs = h * h;
whs = 1;
while ((ws > 32768) || (hs > 32768))
{ ws = (ws + 1) / 2; /* Unfortunate limitations on integers makes */
hs = (hs + 1) / 2; /* drawing large ellipses problematic... */
whs *= 2;
}
while ((ws * hs) > (0x04000000L / whs))
{ ws = (ws + 1) / 2;
hs = (hs + 1) / 2;
whs *= 2;
}
whs *= ws * hs;
if ((a_cos * hs) > (a_sin * ws))
{ x2 = w;
y2 = 0; /* Starting point is exactly on ellipse */
g = x2 - 1;
g = g * g * hs + 4 * ws - whs;
while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */
{ y2 += 2;
g += ws * 4 * (y2 + 1);
if (g > 0) /* Need to drop */
{ x2 -= 2;
g -= hs * 4 * x2;
}
if ((a_sin * x2) <= (y2 * a_cos))
{ pt.x = (int) (x2 / 2);
pt.y = (int) (y2 / 2);
break;
}
}
}
else
{ x2 = 0;
y2 = h; /* Starting point is exactly on ellipse */
g = y2 - 1;
g = g * g * ws + 4 * hs - whs;
while ((x2 * hs) < (y2 * ws))
{ x2 += 2;
g += hs * 4 * (x2 + 1);
if (g > 0) /* Need to drop */
{ y2 -= 2;
g -= ws * 4 * y2;
}
if ((a_sin * x2) >= (y2 * a_cos))
{ pt.x = (int) (x2 / 2);
pt.y = (int) (y2 / 2);
break;
}
}
}
if (flip_x) pt.x = - pt.x;
if (flip_y) pt.y = - pt.y;
return (pt);
}

View File

@ -19,20 +19,34 @@ extern void gdImageGd(gdImagePtr im, FILE *out);
/* */
/* Shared code to read color tables from gd file. */
/* */
int _gdGetColors(gdIOCtx *in, gdImagePtr im)
int _gdGetColors(gdIOCtx *in, gdImagePtr im, int gd2xFlag)
{
int i;
if (!gdGetByte(&im->colorsTotal, in)) {
goto fail1;
}
if (!gdGetWord(&im->transparent, in)) {
goto fail1;
}
if (im->transparent == 257) {
im->transparent = (-1);
}
if (gd2xFlag) {
if (!gdGetByte(&im->trueColor, in)) {
goto fail1;
}
/* This should have been a word all along */
if (!im->trueColor) {
if (!gdGetWord(&im->colorsTotal, in)) {
goto fail1;
}
}
/* Int to accommodate truecolor single-color transparency */
if (!gdGetInt(&im->transparent, in)) {
goto fail1;
}
} else {
if (!gdGetByte(&im->colorsTotal, in)) {
goto fail1;
}
if (!gdGetWord(&im->transparent, in)) {
goto fail1;
}
if (im->transparent == 257) {
im->transparent = (-1);
}
}
GD2_DBG(printf("Pallette had %d colours (T=%d)\n",im->colorsTotal, im->transparent));
for (i=0; (i<gdMaxColors); i++) {
@ -45,6 +59,11 @@ int _gdGetColors(gdIOCtx *in, gdImagePtr im)
if (!gdGetByte(&im->blue[i], in)) {
goto fail1;
}
if (gd2xFlag) {
if (!gdGetByte(&im->alpha[i], in)) {
goto fail1;
}
}
}
for (i=0; (i < im->colorsTotal); i++) {
@ -64,10 +83,17 @@ static
gdImagePtr _gdCreateFromFile(gdIOCtx *in, int *sx, int *sy)
{
gdImagePtr im;
int gd2xFlag = 0;
if (!gdGetWord(sx, in)) {
goto fail1;
}
if (*sx == 65535) {
/* This is a gd 2.0 .gd file */
gd2xFlag = 1;
if (!gdGetWord(sx, in)) {
goto fail1;
}
}
if (!gdGetWord(sy, in)) {
goto fail1;
}
@ -76,7 +102,7 @@ gdImagePtr _gdCreateFromFile(gdIOCtx *in, int *sx, int *sy)
im = gdImageCreate(*sx, *sy);
if (!_gdGetColors(in, im)) {
if (!_gdGetColors(in, im, gd2xFlag)) {
goto fail2;
}
@ -139,22 +165,26 @@ void _gdPutColors(gdImagePtr im, gdIOCtx *out)
int i;
int trans;
gdPutC((unsigned char)im->colorsTotal, out);
trans = im->transparent;
if (trans == (-1)) {
trans = 257;
}
gdPutWord(trans, out);
for (i=0; (i<gdMaxColors); i++) {
gdPutC((unsigned char)im->red[i], out);
gdPutC((unsigned char)im->green[i], out);
gdPutC((unsigned char)im->blue[i], out);
}
gdPutC(im->trueColor, out);
if (!im->trueColor) {
gdPutWord(im->colorsTotal, out);
}
gdPutInt(im->transparent, out);
if (!im->trueColor) {
for (i=0; (i<gdMaxColors); i++) {
gdPutC((unsigned char)im->red[i], out);
gdPutC((unsigned char)im->green[i], out);
gdPutC((unsigned char)im->blue[i], out);
gdPutC((unsigned char)im->alpha[i], out);
}
}
}
static
void _gdPutHeader(gdImagePtr im, gdIOCtx *out)
{
/* 65535 indicates this is a gd 2.x .gd file. */
gdPutWord(65535, out);
gdPutWord(im->sx, out);
gdPutWord(im->sy, out);
@ -171,7 +201,11 @@ static void _gdImageGd(gdImagePtr im, gdIOCtx *out)
for (y=0; (y < im->sy); y++) {
for (x=0; (x < im->sx); x++) {
/* ROW-MAJOR IN GD 1.3 */
gdPutC((unsigned char)im->pixels[y][x], out);
if (im->trueColor) {
gdPutInt(im->tpixels[y][x], out);
} else {
gdPutC((unsigned char)im->pixels[y][x], out);
}
}
}
}

View File

@ -30,9 +30,9 @@
typedef struct {
int offset;
int size;
} t_chunk_info;
} t_chunk_info;
extern int _gdGetColors(gdIOCtx *in, gdImagePtr im);
extern int _gdGetColors(gdIOCtx *in, gdImagePtr im, int gd2xFlag);
extern void _gdPutColors(gdImagePtr im, gdIOCtx *out);
/* */
@ -74,11 +74,11 @@ int _gd2GetHeader(gdIOCtxPtr in, int *sx, int *sy,
};
GD2_DBG(printf("Version: %d\n", *vers));
if (*vers != 1) {
if ((*vers != 1) && (*vers != 2)) {
GD2_DBG(printf("Bad version: %d\n", *vers));
goto fail1;
};
/* Image Size */
if (!gdGetWord(sx, in)) {
GD2_DBG(printf("Could not get x-size\n"));
@ -90,7 +90,7 @@ int _gd2GetHeader(gdIOCtxPtr in, int *sx, int *sy,
}
GD2_DBG(printf("Image is %dx%d\n", *sx, *sy));
/* Chunk Size */
/* Chunk Size (pixels, not bytes!) */
if (gdGetWord(cs, in) != 1) {
goto fail1;
};
@ -167,7 +167,7 @@ gdImagePtr _gd2CreateFromFile(gdIOCtxPtr in, int *sx, int *sy,
goto fail1;
};
if (!_gdGetColors(in, im)) {
if (!_gdGetColors(in, im, (*vers) == 2)) {
GD2_DBG(printf("Could not read color palette\n"));
goto fail2;
}
@ -238,6 +238,7 @@ gdImagePtr gdImageCreateFromGd2Ctx(gdIOCtxPtr in)
uLongf chunkLen;
int chunkPos;
int compMax;
int bytesPerPixel;
char *compBuf = NULL; /* So we can gdFree it with impunity. */
gdImagePtr im;
@ -248,7 +249,7 @@ gdImagePtr gdImageCreateFromGd2Ctx(gdIOCtxPtr in)
if (im == NULL) {
return 0;
};
bytesPerPixel = im->trueColor ? 4 : 1;
nc = ncx * ncy;
if (fmt == GD2_FMT_COMPRESSED) {
@ -262,7 +263,7 @@ gdImagePtr gdImageCreateFromGd2Ctx(gdIOCtxPtr in)
compMax++;
/* Allocate buffers */
chunkMax = cs * cs;
chunkMax = cs * bytesPerPixel * cs;
chunkBuf = gdCalloc(chunkMax,1);
compBuf = gdCalloc(compMax,1);
GD2_DBG(printf("Largest compressed chunk is %d bytes\n",compMax));
@ -311,19 +312,35 @@ gdImagePtr gdImageCreateFromGd2Ctx(gdIOCtxPtr in)
if (fmt == GD2_FMT_RAW) {
for (x= xlo ; x < xhi; x++) {
ch = gdGetC(in);
if (ch == EOF) {
ch = 0;
/*printf("EOF while reading\n"); */
/*gdImageDestroy(im); */
/*return 0; */
if (im->trueColor) {
if (!gdGetInt(&im->tpixels[y][x], in)) {
/*printf("EOF while reading\n"); */
/*gdImageDestroy(im); */
/*return 0; */
im->tpixels[y][x] = 0;
}
} else {
int ch;
if (!gdGetByte(&ch, in)) {
/*printf("EOF while reading\n"); */
/*gdImageDestroy(im); */
/*return 0; */
ch = 0;
}
im->pixels[y][x] = ch;
}
/*GD2_DBG(printf(" (%d, %d)", x, y)); */
im->pixels[y][x] = ch;
}
} else {
for (x= xlo ; x < xhi; x++) {
im->pixels[y][x] = chunkBuf[chunkPos++];
if (im->trueColor) {
im->pixels[y][x] =
(chunkBuf[chunkPos++] << 24) +
(chunkBuf[chunkPos++] << 16) +
(chunkBuf[chunkPos++] << 8) +
chunkBuf[chunkPos++];
} else {
im->pixels[y][x] = chunkBuf[chunkPos++];
}
};
};
/*GD2_DBG(printf("\n")); */
@ -399,7 +416,7 @@ gdImagePtr gdImageCreateFromGd2PartCtx(gdIOCtx *in, int srcx, int srcy, int w, i
goto fail1;
};
if (!_gdGetColors(in, im)) {
if (!_gdGetColors(in, im, vers == 2)) {
goto fail2;
}
GD2_DBG(printf("Image palette completed: %d colours\n", im->colorsTotal));
@ -417,7 +434,11 @@ gdImagePtr gdImageCreateFromGd2PartCtx(gdIOCtx *in, int srcx, int srcy, int w, i
};
compMax++;
chunkMax = cs * cs;
if (im->trueColor) {
chunkMax = cs * cs * 4;
} else {
chunkMax = cs * cs;
}
chunkBuf = gdCalloc(chunkMax,1);
compBuf = gdCalloc(compMax,1);
};
@ -464,7 +485,11 @@ gdImagePtr gdImageCreateFromGd2PartCtx(gdIOCtx *in, int srcx, int srcy, int w, i
if (fmt == GD2_FMT_RAW) {
GD2_DBG(printf("Using raw format data\n"));
dpos = cy * (cs * fsx) + cx * cs * (yhi-ylo) + dstart;
if (im->trueColor) {
dpos = (cy * (cs * fsx) + cx * cs * (yhi-ylo) * 4) + dstart;
} else {
dpos = cy * (cs * fsx) + cx * cs * (yhi-ylo) + dstart;
}
if (gdSeek(in, dpos) != 0) {
printf("Error from seek: %d\n",errno);
@ -491,17 +516,30 @@ gdImagePtr gdImageCreateFromGd2PartCtx(gdIOCtx *in, int srcx, int srcy, int w, i
for (y=ylo ; (y < yhi); y++) {
for (x= xlo ; x < xhi; x++) {
if (fmt == GD2_FMT_RAW) {
ch = gdGetC(in);
if (ch == EOF) {
ch = 0;
/*printf("EOF while reading file\n"); */
/*goto fail2; */
};
if (im->trueColor) {
if (!gdGetInt(&ch, in)) {
ch = 0;
/*printf("EOF while reading file\n"); */
/*goto fail2; */
}
} else {
ch = gdGetC(in);
if (ch == EOF) {
ch = 0;
/*printf("EOF while reading file\n"); */
/*goto fail2; */
}
}
} else {
ch = chunkBuf[chunkPos++];
if (im->trueColor) {
ch = chunkBuf[chunkPos++] << 24 +
chunkBuf[chunkPos++] << 16 +
chunkBuf[chunkPos++] << 8 +
chunkBuf[chunkPos++];
} else {
ch = chunkBuf[chunkPos++];
}
};
/* Only use a point that is in the image. */
@ -569,6 +607,7 @@ static void _gdImageGd2(gdImagePtr im, gdIOCtx *out, int cs, int fmt)
int idxSize;
t_chunk_info *chunkIdx = NULL;
int posSave;
int bytesPerPixel = im->trueColor ? 4 : 1;
int compMax;
/*printf("Trying to write GD2 file\n"); */
@ -609,12 +648,12 @@ static void _gdImageGd2(gdImagePtr im, gdIOCtx *out, int cs, int fmt)
/* The zlib notes say output buffer size should be (input size) * 1.01 * 12 */
/* - we'll use 1.02 to be paranoid. */
/* */
compMax = cs * cs * 1.02 + 12;
compMax = cs * bytesPerPixel * cs * 1.02 + 12;
/* */
/* Allocate the buffers. */
/* */
chunkData = gdCalloc(cs*cs,1);
chunkData = gdCalloc(cs*bytesPerPixel*cs,1);
compData = gdCalloc(compMax,1);
/* */
@ -657,13 +696,26 @@ static void _gdImageGd2(gdImagePtr im, gdIOCtx *out, int cs, int fmt)
if (fmt == GD2_FMT_COMPRESSED) {
for (x= xlo ; x < xhi; x++) {
int p = im->pixels[y][x];
/*GD2_DBG(printf("%d...",x)); */
chunkData[chunkLen++] = im->pixels[y][x];
if (im->trueColor) {
chunkData[chunkLen++] = gdTrueColorGetAlpha(p);
chunkData[chunkLen++] = gdTrueColorGetRed(p);
chunkData[chunkLen++] = gdTrueColorGetGreen(p);
chunkData[chunkLen++] = gdTrueColorGetBlue(p);
} else {
chunkData[chunkLen++] = p;
}
};
} else {
for (x= xlo ; x < xhi; x++) {
/*GD2_DBG(printf("%d, ",x)); */
gdPutC((unsigned char)im->pixels[y][x], out);
if (im->trueColor) {
gdPutInt(im->tpixels[y][x], out);
} else {
gdPutC((unsigned char)im->pixels[y][x], out);
}
};
};
/*GD2_DBG(printf("y=%d done.\n",y)); */

View File

@ -6,9 +6,10 @@
* Group. For more information on the IJG JPEG software (and JPEG
* documentation, etc.), see ftp://ftp.uu.net/graphics/jpeg/.
*
* NOTE: IJG 12-bit JSAMPLE (BITS_IN_JSAMPLE == 12) mode, although
* theoretically supported in this code, has not really been tested.
* Caveat emptor.
* NOTE: IJG 12-bit JSAMPLE (BITS_IN_JSAMPLE == 12) mode is not
* supported at all on read in gd 2.0, and is not supported on write
* except for palette images, which is sort of pointless (TBB). Even that
* has never been tested according to DB.
*
* Copyright 2000 Doug Becker, mailto:thebeckers@home.com
*
@ -17,20 +18,22 @@
* major CGI brain damage
*/
/* TBB: move this up so include files are not brought in */
#ifdef HAVE_LIBJPEG
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <limits.h>
#include <string.h>
/* 1.8.1: remove dependency on jinclude.h */
#include "jpeglib.h"
#include "jerror.h"
#include "gd.h"
#include "gdhelpers.h"
#ifdef HAVE_LIBJPEG
static const char * const GD_JPEG_VERSION = "2.0";
static const char * const GD_JPEG_VERSION = "1.0";
typedef struct _jmpbuf_wrapper {
jmp_buf jmpbuf;
@ -106,11 +109,12 @@ gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
printf("gd-jpeg: gd JPEG version %s\n", GD_JPEG_VERSION);
printf("gd-jpeg: JPEG library version %d, %d-bit sample values\n",
JPEG_LIB_VERSION, BITS_IN_JSAMPLE);
for (i = 0; i < im->colorsTotal; i++) {
if (!im->open[i])
printf("gd-jpeg: gd colormap index %d: (%d, %d, %d)\n", i,
im->red[i], im->green[i], im->blue[i]);
if (!im->trueColor) {
for (i = 0; i < im->colorsTotal; i++) {
if (!im->open[i])
printf("gd-jpeg: gd colormap index %d: (%d, %d, %d)\n", i,
im->red[i], im->green[i], im->blue[i]);
}
}
#endif /* JPEG_DEBUG */
@ -171,36 +175,60 @@ gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
strcat(comment + strlen(comment), " default quality\n");
jpeg_write_marker(&cinfo, JPEG_COM, (unsigned char *)comment,
(unsigned int)strlen(comment));
if (im->trueColor) {
#if BITS_IN_JSAMPLE == 12
fprintf(stderr, "gd-jpeg: error: jpeg library was compiled for 12-bit\n"
"precision. This is mostly useless, because JPEGs on the web are\n"
"8-bit and such versions of the jpeg library won't read or write\n"
"them. GD doesn't support these unusual images. Edit your\n"
"jmorecfg.h file to specify the correct precision and completely\n"
"'make clean' and 'make install' libjpeg again. Sorry.\n");
goto error;
#endif /* BITS_IN_JSAMPLE == 12 */
for (i = 0; i < im->sy; i++) {
for (jidx = 0, j = 0; j < im->sx; j++) {
int val = im->tpixels[i][j];
row[jidx++] = gdTrueColorGetRed(val);
row[jidx++] = gdTrueColorGetGreen(val);
row[jidx++] = gdTrueColorGetBlue(val);
}
for (i = 0; i < im->sy; i++) {
for (jidx = 0, j = 0; j < im->sx; j++) {
int idx = im->pixels[i][j];
nlines = jpeg_write_scanlines(&cinfo, rowptr, 1);
if (nlines != 1)
fprintf(stderr, "gd_jpeg: warning: jpeg_write_scanlines"
" returns %u -- expected 1\n", nlines);
}
} else {
for (i = 0; i < im->sy; i++) {
for (jidx = 0, j = 0; j < im->sx; j++) {
int idx = im->pixels[i][j];
/*
* NB: Although gd RGB values are ints, their max value is
* 255 (see the documentation for gdImageColorAllocate())
* -- perfect for 8-bit JPEG encoding (which is the norm)
*/
#if BITS_IN_JSAMPLE == 8
row[jidx++] = im->red[idx];
row[jidx++] = im->green[idx];
row[jidx++] = im->blue[idx];
#elif BITS_IN_JSAMPLE == 12
row[jidx++] = im->red[idx] << 4;
row[jidx++] = im->green[idx] << 4;
row[jidx++] = im->blue[idx] << 4;
#else
#error IJG JPEG library BITS_IN_JSAMPLE value must be 8 or 12
#endif
}
/*
* NB: Although gd RGB values are ints, their max value is
* 255 (see the documentation for gdImageColorAllocate())
* -- perfect for 8-bit JPEG encoding (which is the norm)
*/
#if BITS_IN_JSAMPLE == 8
row[jidx++] = im->red[idx];
row[jidx++] = im->green[idx];
row[jidx++] = im->blue[idx];
#elif BITS_IN_JSAMPLE == 12
row[jidx++] = im->red[idx] << 4;
row[jidx++] = im->green[idx] << 4;
row[jidx++] = im->blue[idx] << 4;
#else
#error IJG JPEG library BITS_IN_JSAMPLE value must be 8 or 12
#endif
}
nlines = jpeg_write_scanlines(&cinfo, rowptr, 1);
if (nlines != 1)
fprintf(stderr, "gd_jpeg: warning: jpeg_write_scanlines"
" returns %u -- expected 1\n", nlines);
nlines = jpeg_write_scanlines(&cinfo, rowptr, 1);
if (nlines != 1)
fprintf(stderr, "gd_jpeg: warning: jpeg_write_scanlines"
" returns %u -- expected 1\n", nlines);
}
}
jpeg_finish_compress(&cinfo);
error:
jpeg_destroy_compress(&cinfo);
gdFree(row);
}
@ -277,21 +305,19 @@ gdImageCreateFromJpegCtx(gdIOCtx *infile)
" greater than INT_MAX (%d) (and thus greater than"
" gd can handle)\n", cinfo.image_width, INT_MAX);
im = gdImageCreate((int)cinfo.image_width,
im = gdImageCreateTrueColor((int)cinfo.image_width,
(int)cinfo.image_height);
if (im == 0) {
fprintf(stderr, "gd-jpeg error: cannot allocate gdImage"
" struct\n");
goto error;
goto error;
}
/*
* Have the JPEG library quantize the number of image colors to
* 256 maximum; force into RGB colorspace
* Force the image into RGB colorspace, but don't
* reduce the number of colors anymore (GD 2.0)
*/
cinfo.out_color_space = JCS_RGB;
cinfo.quantize_colors = TRUE;
cinfo.desired_number_of_colors = gdMaxColors;
if (jpeg_start_decompress(&cinfo) != TRUE)
fprintf(stderr, "gd-jpeg: warning: jpeg_start_decompress"
@ -345,36 +371,35 @@ gdImageCreateFromJpegCtx(gdIOCtx *infile)
fflush(stdout);
#endif /* JPEG_DEBUG */
/* REMOVED by TBB 2/12/01. This field of the structure is
documented as private, and sure enough it's gone in the
latest libjpeg, replaced by something else. Unfortunately
there is still no right way to find out if the file was
progressive or not; just declare your intent before you
write one by calling gdImageInterlace(im, 1) yourself.
After all, we're not really supposed to rework JPEGs and
write them out again anyway. Lossy compression, remember? */
#if 0
gdImageInterlace(im, cinfo.progressive_mode != 0);
im->colorsTotal = cinfo.actual_number_of_colors;
if (cinfo.output_components != 1) {
#endif
if (cinfo.output_components != 3) {
fprintf(stderr, "gd-jpeg: error: JPEG color quantization"
" request resulted in output_components == %d"
" (expected 1)\n", cinfo.output_components);
" (expected 3)\n", cinfo.output_components);
goto error;
}
for (i = 0; i < im->colorsTotal; i++) {
#if BITS_IN_JSAMPLE == 8
im->red[i] = cinfo.colormap[0][i];
im->green[i] = cinfo.colormap[1][i];
im->blue[i] = cinfo.colormap[2][i];
#elif BITS_IN_JSAMPLE == 12
im->red[i] = (cinfo.colormap[0][i] >> 4) & 0xff;
im->green[i] = (cinfo.colormap[1][i] >> 4) & 0xff;
im->blue[i] = (cinfo.colormap[2][i] >> 4) & 0xff;
#else
#error IJG JPEG library BITS_IN_JSAMPLE value must be 8 or 12
#endif
im->open[i] = 0;
#ifdef JPEG_DEBUG
printf("gd-jpeg: gd colormap index %d set to (%d, %d, %d)\n", i,
im->red[i], im->green[i], im->blue[i]);
#endif
}
#if BITS_IN_JSAMPLE == 12
fprintf(stderr, "gd-jpeg: error: jpeg library was compiled for 12-bit\n"
"precision. This is mostly useless, because JPEGs on the web are\n"
"8-bit and such versions of the jpeg library won't read or write\n"
"them. GD doesn't support these unusual images. Edit your\n"
"jmorecfg.h file to specify the correct precision and completely\n"
"'make clean' and 'make install' libjpeg again. Sorry.\n");
goto error;
#endif /* BITS_IN_JSAMPLE == 12 */
row = gdCalloc(cinfo.output_width, sizeof(JSAMPLE));
row = gdCalloc(cinfo.output_width * 3, sizeof(JSAMPLE));
if (row == 0) {
fprintf(stderr, "gd-jpeg: error: unable to allocate row for"
" JPEG scanline: gdCalloc returns NULL\n");
@ -391,7 +416,8 @@ gdImageCreateFromJpegCtx(gdIOCtx *infile)
}
for (j = 0; j < cinfo.output_width; j++)
im->pixels[i][j] = row[j];
im->tpixels[i][j] = gdTrueColor(row[j * 3], row[j * 3 + 1],
row[j * 3 + 2]);
}
if (jpeg_finish_decompress(&cinfo) != TRUE)

View File

@ -1,3 +1,5 @@
#ifdef HAVE_LIBPNG
#include <stdio.h>
#include <math.h>
#include <string.h>
@ -9,8 +11,6 @@
#define TRUE 1
#define FALSE 0
#ifdef HAVE_LIBPNG
/*---------------------------------------------------------------------------
gd_png.c Copyright 1999 Greg Roelofs and Thomas Boutell
@ -20,14 +20,17 @@
except that these functions are noisier in the case of errors (comment
out all fprintf() statements to disable that).
Only GIF-like PNG features are currently supported; that is, images must
either be indexed-color to begin with or they will be converted to it,
and they can have, at most, a single, fully transparent palette entry or
color. (Alpha channels are ignored.) Since gd images are artificially
generated, gamma is also ignored, and there is currently no support for
embedded text annotations (a la GIF comments) in gd.
GD 2.0 supports RGBA truecolor and will read and write truecolor PNGs.
GD 2.0 supports 8 bits of color resolution per channel and
7 bits of alpha channel resolution. Images with more than 8 bits
per channel are reduced to 8 bits. Images with an alpha channel are
only able to resolve down to '1/128th opaque' instead of '1/256th',
and this conversion is also automatic. I very much doubt you can see it.
Both tRNS and true alpha are supported.
Last updated: 19 July 1999
Gamma is ignored, and there is no support for text annotations.
Last updated: 9 February 2001
---------------------------------------------------------------------------*/
@ -107,6 +110,7 @@ gdImagePtr gdImageCreateFromPngCtx(gdIOCtx *infile)
int num_palette, num_trans;
png_colorp palette;
png_color_16p trans_gray_rgb;
png_color_16p trans_color_rgb;
png_bytep trans;
png_bytep image_data = NULL;
png_bytepp row_pointers = NULL;
@ -164,17 +168,25 @@ gdImagePtr gdImageCreateFromPngCtx(gdIOCtx *infile)
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, NULL, NULL);
if ((color_type == PNG_COLOR_TYPE_RGB) ||
(color_type == PNG_COLOR_TYPE_RGB_ALPHA))
{
im = gdImageCreateTrueColor((int)width, (int)height);
} else {
im = gdImageCreate((int)width, (int)height);
}
if (im == NULL) {
fprintf(stderr, "gd-png error: cannot allocate gdImage struct\n");
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
gdFree(image_data);
gdFree(row_pointers);
return NULL;
}
if (bit_depth == 16)
png_set_strip_16(png_ptr);
else if (bit_depth < 8)
png_set_packing(png_ptr); /* expand to 1 byte per pixel */
if (color_type & PNG_COLOR_MASK_ALPHA) {
fprintf(stderr, "gd-png warning: alpha channel not supported\n");
png_set_strip_alpha(png_ptr);
}
switch (color_type) {
case PNG_COLOR_TYPE_PALETTE:
png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
@ -183,29 +195,19 @@ gdImagePtr gdImageCreateFromPngCtx(gdIOCtx *infile)
num_palette);
#endif /* DEBUG */
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
int real_num_trans = 0, idx_first_trans = -1;
int min_trans = 256, idx_min_trans = -1;
/* gd 2.0: we support this rather thoroughly now. Grab the
first fully transparent entry, if any, as the value of
the simple-transparency index, mostly for backwards
binary compatibility. The alpha channel is where it's
really at these days. */
int firstZero = 1;
png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
for (i = 0; i < num_trans; ++i) {
if (trans[i] < 255) {
++real_num_trans;
if (idx_first_trans < 0)
idx_first_trans = i;
if (trans[i] < min_trans) {
min_trans = trans[i];
idx_min_trans = i;
}
}
}
if (real_num_trans > 0) {
if (real_num_trans > 1 || trans[idx_first_trans] != 0) {
fprintf(stderr, "gd-png warning: only single-color, "
"100%% transparency supported\n");
transparent = idx_min_trans;
} else {
transparent = idx_first_trans;
}
im->alpha[i] = gdAlphaMax - (trans[i] >> 1);
if ((trans[i] == 0) && (firstZero)) {
im->transparent = i;
firstZero = 0;
}
}
}
break;
@ -257,83 +259,19 @@ gdImagePtr gdImageCreateFromPngCtx(gdIOCtx *infile)
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGB_ALPHA:
/* allocate a palette and check for single-shade transparency */
if ((palette = (png_colorp)gdMalloc(256*sizeof(png_color))) == NULL) {
fprintf(stderr, "gd-png error: cannot allocate RGB palette\n");
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
palette_allocated = TRUE;
num_palette = 256;
/* gd 2.0: we now support truecolor. See the comment above
for a rare situation in which the transparent pixel may not
work properly with 16-bit channels. */
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb);
if (bit_depth == 16) { /* png_set_strip_16() not yet active */
palette[0].red = trans_gray_rgb->red >> 8;
palette[0].green = trans_gray_rgb->green >> 8;
palette[0].blue = trans_gray_rgb->blue >> 8;
} else {
palette[0].red = trans_gray_rgb->red;
palette[0].green = trans_gray_rgb->green;
palette[0].blue = trans_gray_rgb->blue;
}
transparent = 0;
/* Note that the same error exists in the 16-bit RGB case as in
* the grayscale case, except that the degeneracy is now 16.8
* million to 1 (at a minimum--actually more than that due to
* quantization). Again, this is an extremely rare problem.
* Unfortunately, it also affects 8-bit-per-sample RGB images
* (quantization), unless libpng is doing something sneaky... */
} else {
palette[0].red = palette[0].green = palette[0].blue = 224;
}
#if 0 /* libpng.txt demo code looks broken--need to check both PLTE and hIST */
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) {
png_color_16p histogram;
png_get_hIST(png_ptr, info_ptr, &histogram);
png_set_dither(png_ptr, palette, num_palette,
max_screen_colors, histogram, 1);
} else
#endif
{
int idx, red, green, blue;
#ifdef PALETTE_6x7x6
/* allocate a 6x7x6 color cube, starting at index 4 */
idx = 4;
for (red = 0; red < 256; red += 51) {
for (i = 0; i < 7; ++i) {
green = (i * 425) / 10; /* i.e., 42.5 */
for (blue = 0; blue < 256; blue += 51) {
palette[idx].red = red;
palette[idx].green = green;
palette[idx].blue = blue;
++idx;
}
}
}
/* fill in remaining entries (1-3) with common gray values */
palette[1].red = palette[1].green = palette[1].blue = 192;
palette[2].red = palette[2].green = palette[2].blue = 128;
palette[3].red = palette[3].green = palette[3].blue = 64;
/* final argument (full_dither) *must* be 1: */
png_set_dither(png_ptr, palette, 256, 256, NULL, 1);
#else
/* allocate a 6x6x6 color cube, starting at index 0 or 1 */
idx = (transparent < 0)? 0 : 1;
for (red = 0; red < 256; red += 51) {
for (green = 0; green < 256; green += 51) {
for (blue = 0; blue < 256; blue += 51) {
palette[idx].red = red;
palette[idx].green = green;
palette[idx].blue = blue;
++idx;
}
}
}
png_set_dither(png_ptr, palette, idx, idx, NULL, 1);
#endif
png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_color_rgb);
if (bit_depth == 16) /* png_set_strip_16() not yet in effect */
transparent = gdTrueColor(trans_color_rgb->red >> 8,
trans_color_rgb->green >> 8,
trans_color_rgb->blue >> 8);
else
transparent = gdTrueColor(trans_color_rgb->red,
trans_color_rgb->green,
trans_color_rgb->blue);
}
break;
}
@ -362,48 +300,70 @@ gdImagePtr gdImageCreateFromPngCtx(gdIOCtx *infile)
png_read_image(png_ptr, row_pointers); /* read whole image... */
png_read_end(png_ptr, NULL); /* ...done! */
if ((im = gdImageCreate((int)width, (int)height)) == NULL) {
fprintf(stderr, "gd-png error: cannot allocate gdImage struct\n");
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
gdFree(image_data);
gdFree(row_pointers);
return NULL;
if (!im->trueColor) {
im->colorsTotal = num_palette;
im->transparent = transparent;
/* load the palette and mark all entries "open" (unused) for now */
open = im->open;
for (i = 0; i < num_palette; ++i) {
im->red[i] = palette[i].red;
im->green[i] = palette[i].green;
im->blue[i] = palette[i].blue;
open[i] = 1;
}
for (i = num_palette; i < gdMaxColors; ++i) {
open[i] = 1;
}
}
im->colorsTotal = num_palette;
im->transparent = transparent;
im->interlace = (interlace_type == PNG_INTERLACE_ADAM7);
/* load the palette and mark all entries "open" (unused) for now */
open = im->open;
for (i = 0; i < num_palette; ++i) {
im->red[i] = palette[i].red;
im->green[i] = palette[i].green;
im->blue[i] = palette[i].blue;
open[i] = 1;
}
for (i = num_palette; i < gdMaxColors; ++i) {
open[i] = 1;
}
/* can't nuke structs until done with palette */
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
/* could copy data with memcpy(), but also want to check colormap entries */
for (j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
register png_byte idx = row_pointers[j][i];
im->pixels[j][i] = idx;
open[idx] = 0;
switch (color_type) {
case PNG_COLOR_TYPE_RGB:
for (j = 0; j < height; j++) {
int boffset = 0;
for (i = 0; i < width; i++) {
register png_byte r = row_pointers[j][boffset++];
register png_byte g = row_pointers[j][boffset++];
register png_byte b = row_pointers[j][boffset++];
im->tpixels[j][i] = gdTrueColor(r, g, b);
}
}
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
for (j = 0; j < height; j++) {
int boffset = 0;
for (i = 0; i < width; i++) {
register png_byte r = row_pointers[j][boffset++];
register png_byte g = row_pointers[j][boffset++];
register png_byte b = row_pointers[j][boffset++];
/* gd has only 7 bits of alpha channel resolution, and
127 is transparent, 0 opaque. A moment of convenience,
a lifetime of compatibility. */
register png_byte a = gdAlphaMax -
(row_pointers[j][boffset++] >> 1);
im->tpixels[j][i] = gdTrueColorAlpha(r, g, b, a);
}
}
break;
default:
/* Palette image, or something coerced to be one */
for (j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
register png_byte idx = row_pointers[j][i];
im->pixels[j][i] = idx;
open[idx] = 0;
}
}
}
#ifdef DEBUG
for (i = num_palette; i < gdMaxColors; ++i) {
if (!open[i]) {
fprintf(stderr, "gd-png warning: image data references out-of-range"
" color index (%d)\n", i);
if (!im->trueColor) {
for (i = num_palette; i < gdMaxColors; ++i) {
if (!open[i]) {
fprintf(stderr, "gd-png warning: image data references out-of-range"
" color index (%d)\n", i);
}
}
}
#endif
@ -445,8 +405,9 @@ void gdImagePngCtx(gdImagePtr im, gdIOCtx *outfile)
int height = im->sy;
int colors = im->colorsTotal;
int *open = im->open;
int mapping[gdMaxColors]; /* mapping[gif_index] == png_index */
png_byte trans_value = 0;
int mapping[gdMaxColors]; /* mapping[gd_index] == png_index */
png_byte trans_values[256];
png_color_16 trans_rgb_value;
png_color palette[gdMaxColors];
png_structp png_ptr;
png_infop info_ptr;
@ -482,9 +443,11 @@ void gdImagePngCtx(gdImagePtr im, gdIOCtx *outfile)
png_set_write_fn(png_ptr, (void *)outfile, gdPngWriteData, gdPngFlushData);
/* For now gd only supports palette images, for which filter type NONE is
* almost guaranteed to be the best. But that's what libpng defaults to
* for palette images anyway, so no need to set this explicitly. */
/* This is best for palette images, and libpng defaults to it for
palette images anyway, so we don't need to do it explicitly.
What to ideally do for truecolor images depends, alas, on the image.
gd is intentionally imperfect and doesn't spend a lot of time
fussing with such things. */
/* png_set_filter(png_ptr, 0, PNG_FILTER_NONE); */
/* may want to force maximum compression, but time penalty is large */
@ -494,74 +457,128 @@ void gdImagePngCtx(gdImagePtr im, gdIOCtx *outfile)
* image data is 16K or less; will save some decoder memory [min == 8] */
/* png_set_compression_window_bits(png_ptr, 15); */
if (transparent >= im->colorsTotal ||
(transparent >= 0 && open[transparent]))
transparent = -1;
for (i = 0; i < gdMaxColors; ++i)
mapping[i] = -1;
/* count actual number of colors used (colorsTotal == high-water mark) */
colors = 0;
for (i = 0; i < im->colorsTotal; ++i) {
if (!open[i]) {
mapping[i] = colors;
++colors;
}
if (!im->trueColor) {
if (transparent >= im->colorsTotal ||
(transparent >= 0 && open[transparent]))
transparent = -1;
}
if (colors < im->colorsTotal) {
remap = TRUE;
if (transparent >= 0)
transparent = mapping[transparent];
if (!im->trueColor) {
for (i = 0; i < gdMaxColors; ++i)
mapping[i] = -1;
}
if (!im->trueColor) {
/* count actual number of colors used (colorsTotal == high-water mark) */
colors = 0;
for (i = 0; i < im->colorsTotal; ++i) {
if (!open[i]) {
mapping[i] = colors;
++colors;
}
}
if (colors < im->colorsTotal) {
remap = TRUE;
}
if (colors <= 2)
bit_depth = 1;
else if (colors <= 4)
bit_depth = 2;
else if (colors <= 16)
bit_depth = 4;
else
bit_depth = 8;
}
if (colors <= 2)
bit_depth = 1;
else if (colors <= 4)
bit_depth = 2;
else if (colors <= 16)
bit_depth = 4;
else
bit_depth = 8;
interlace_type = im->interlace? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
PNG_COLOR_TYPE_PALETTE, interlace_type,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
if (transparent >= 0) {
/* always write PNG files with the transparent palette entry first to
* minimize size of the tRNS chunk; swap if necessary */
if (transparent != 0) {
if (!remap) { /* so colors == im->colorsTotal */
remap = TRUE;
for (i = 0; i < colors; ++i)
mapping[i] = i;
}
mapping[transparent] = 0;
mapping[0] = transparent;
}
png_set_tRNS(png_ptr, info_ptr, &trans_value, 1, NULL);
if (im->trueColor) {
if (im->saveAlphaFlag) {
png_set_IHDR(png_ptr, info_ptr, width, height, 8,
PNG_COLOR_TYPE_RGB_ALPHA, interlace_type,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
} else {
png_set_IHDR(png_ptr, info_ptr, width, height, 8,
PNG_COLOR_TYPE_RGB, interlace_type,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
}
} else {
png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
PNG_COLOR_TYPE_PALETTE, interlace_type,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
}
if (im->trueColor && (!im->saveAlphaFlag) && (transparent >= 0)) {
trans_rgb_value.red = gdTrueColorGetRed(im->trueColor);
trans_rgb_value.green = gdTrueColorGetGreen(im->trueColor);
trans_rgb_value.blue = gdTrueColorGetBlue(im->trueColor);
png_set_tRNS(png_ptr, info_ptr, 0, 0, &trans_rgb_value);
}
if (!im->trueColor) {
/* Oy veh. Remap the PNG palette to put the
entries with interesting alpha channel
values first. This minimizes the size
of the tRNS chunk and thus the size
of the PNG file as a whole. */
int tc = 0;
int i;
int j;
int k;
int highTrans = -1;
for (i = 0; (i < im->colorsTotal); i++) {
if ((!im->open[i]) &&
(im->alpha[i] != gdAlphaOpaque))
{
tc++;
}
}
if (tc) {
#if 0
for (i = 0; (i < im->colorsTotal); i++) {
trans_values[i] = 255 -
((im->alpha[i] << 1) +
(im->alpha[i] >> 7));
}
png_set_tRNS(png_ptr, info_ptr, trans_values, 256, NULL);
#endif
if (!remap) {
remap = TRUE;
}
/* (Semi-)transparent indexes come up from the bottom
of the list of real colors; opaque
indexes come down from the top */
j = 0;
k = colors - 1;
for (i = 0; (i < im->colorsTotal); i++) {
if (!im->open[i]) {
if (im->alpha[i] != gdAlphaOpaque) {
trans_values[j] = 255 -
((im->alpha[i] << 1) +
(im->alpha[i] >> 7));
mapping[i] = j++;
} else {
mapping[i] = k--;
}
}
}
png_set_tRNS(png_ptr, info_ptr, trans_values, tc, NULL);
}
}
/* convert GIF palette to libpng layout */
if (remap)
for (i = 0; i < im->colorsTotal; ++i) {
if (mapping[i] < 0)
continue;
palette[mapping[i]].red = im->red[i];
palette[mapping[i]].green = im->green[i];
palette[mapping[i]].blue = im->blue[i];
}
else
for (i = 0; i < colors; ++i) {
palette[i].red = im->red[i];
palette[i].green = im->green[i];
palette[i].blue = im->blue[i];
}
png_set_PLTE(png_ptr, info_ptr, palette, colors);
/* convert palette to libpng layout */
if (!im->trueColor) {
if (remap)
for (i = 0; i < im->colorsTotal; ++i) {
if (mapping[i] < 0)
continue;
palette[mapping[i]].red = im->red[i];
palette[mapping[i]].green = im->green[i];
palette[mapping[i]].blue = im->blue[i];
}
else
for (i = 0; i < colors; ++i) {
palette[i].red = im->red[i];
palette[i].green = im->green[i];
palette[i].blue = im->blue[i];
}
png_set_PLTE(png_ptr, info_ptr, palette, colors);
}
/* write out the PNG header info (everything up to first IDAT) */
png_write_info(png_ptr, info_ptr);
@ -575,21 +592,37 @@ void gdImagePngCtx(gdImagePtr im, gdIOCtx *outfile)
* pointers and can be passed to png_write_image() function directly.
* The remapping case could be accomplished with less memory for non-
* interlaced images, but interlacing causes some serious complications. */
if (remap) {
if (im->trueColor) {
int channels = im->saveAlphaFlag ? 4 : 3;
/* Our little 7-bit alpha channel trick costs us a bit here. */
png_bytep *row_pointers;
row_pointers = gdMalloc(sizeof(png_bytep) * height);
if (row_pointers == NULL) {
fprintf(stderr, "gd-png error: unable to allocate row_pointers\n");
}
for (j = 0; j < height; ++j) {
if ((row_pointers[j] = (png_bytep)gdMalloc(width)) == NULL) {
int bo = 0;
if ((row_pointers[j] = (png_bytep)gdMalloc(width * channels)) == NULL) {
fprintf(stderr, "gd-png error: unable to allocate rows\n");
for (i = 0; i < j; ++i)
gdFree(row_pointers[i]);
return;
}
for (i = 0; i < width; ++i)
row_pointers[j][i] = mapping[im->pixels[j][i]];
for (i = 0; i < width; ++i) {
unsigned char a;
row_pointers[j][bo++] = gdTrueColorGetRed(im->tpixels[j][i]);
row_pointers[j][bo++] = gdTrueColorGetGreen(im->tpixels[j][i]);
row_pointers[j][bo++] = gdTrueColorGetBlue(im->tpixels[j][i]);
if (im->saveAlphaFlag) {
/* convert the 7-bit alpha channel to an 8-bit alpha channel.
We do a little bit-flipping magic, repeating the MSB
as the LSB, to ensure that 0 maps to 0 and
127 maps to 255. We also have to invert to match
PNG's convention in which 255 is opaque. */
a = gdTrueColorGetAlpha(im->tpixels[j][i]);
row_pointers[j][bo++] = 255 - ((a << 1) + (a >> 7));
}
}
}
png_write_image(png_ptr, row_pointers);
@ -597,13 +630,38 @@ void gdImagePngCtx(gdImagePtr im, gdIOCtx *outfile)
for (j = 0; j < height; ++j)
gdFree(row_pointers[j]);
gdFree(row_pointers);
} else {
png_write_image(png_ptr, im->pixels);
png_write_end(png_ptr, info_ptr);
gdFree(row_pointers);
} else {
if (remap) {
png_bytep *row_pointers;
row_pointers = gdMalloc(sizeof(png_bytep) * height);
if (row_pointers == NULL) {
fprintf(stderr, "gd-png error: unable to allocate row_pointers\n");
}
for (j = 0; j < height; ++j) {
if ((row_pointers[j] = (png_bytep)gdMalloc(width)) == NULL) {
fprintf(stderr, "gd-png error: unable to allocate rows\n");
for (i = 0; i < j; ++i)
gdFree(row_pointers[i]);
return;
}
for (i = 0; i < width; ++i)
row_pointers[j][i] = mapping[im->pixels[j][i]];
}
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);
for (j = 0; j < height; ++j)
gdFree(row_pointers[j]);
gdFree(row_pointers);
} else {
png_write_image(png_ptr, im->pixels);
png_write_end(png_ptr, info_ptr);
}
}
/* 1.6.3: maybe we should give that memory BACK! TBB */
png_destroy_write_struct(&png_ptr, &info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
}

1508
src/gd_topal.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@ int main(void)
FILE *out;
/* Input and output images */
gdImagePtr im_in, im_out;
gdImagePtr im_in = 0, im_out = 0;
/* Brush image */
gdImagePtr brush;
@ -24,9 +24,8 @@ int main(void)
/* Points for polygon */
gdPoint points[3];
/* Create output image, 128 by 128 pixels. */
im_out = gdImageCreate(128, 128);
/* Create output image, 256 by 256 pixels, true color. */
im_out = gdImageCreateTrueColor(256, 256);
/* First color allocated is background. */
white = gdImageColorAllocate(im_out, 255, 255, 255);
@ -35,7 +34,6 @@ int main(void)
/* Try to load demoin.png and paste part of it into the
output image. */
in = fopen("demoin.png", "rb");
if (!in) {
fprintf(stderr, "Can't load source image; this demo\n");
@ -47,34 +45,35 @@ int main(void)
fclose(in);
/* Now copy, and magnify as we do so */
gdImageCopyResized(im_out, im_in,
16, 16, 0, 0, 96, 96, 127, 127);
32, 32, 0, 0, 192, 192, 255, 255);
}
red = gdImageColorAllocate(im_out, 255, 0, 0);
green = gdImageColorAllocate(im_out, 0, 255, 0);
blue = gdImageColorAllocate(im_out, 0, 0, 255);
/* Rectangle */
gdImageLine(im_out, 8, 8, 120, 8, green);
gdImageLine(im_out, 120, 8, 120, 120, green);
gdImageLine(im_out, 120, 120, 8, 120, green);
gdImageLine(im_out, 8, 120, 8, 8, green);
gdImageLine(im_out, 16, 16, 240, 16, green);
gdImageLine(im_out, 240, 16, 240, 240, green);
gdImageLine(im_out, 240, 240, 16, 240, green);
gdImageLine(im_out, 16, 240, 16, 16, green);
/* Circle */
gdImageArc(im_out, 64, 64, 30, 10, 0, 360, blue);
gdImageArc(im_out, 128, 128, 60, 20, 0, 720, blue);
/* Arc */
gdImageArc(im_out, 64, 64, 20, 20, 45, 135, blue);
/* Flood fill */
gdImageFill(im_out, 4, 4, blue);
gdImageArc(im_out, 128, 128, 40, 40, 90, 270, blue);
/* Flood fill: doesn't do much on a continuously
variable tone jpeg original. */
gdImageFill(im_out, 8, 8, blue);
/* Polygon */
points[0].x = 32;
points[0].x = 64;
points[0].y = 0;
points[1].x = 0;
points[1].y = 64;
points[2].x = 64;
points[2].y = 64;
points[1].y = 128;
points[2].x = 128;
points[2].y = 128;
gdImageFilledPolygon(im_out, points, 3, green);
/* Brush. A fairly wild example also involving a line style! */
if (im_in) {
int style[8];
brush = gdImageCreate(8, 8);
brush = gdImageCreateTrueColor(16, 16);
gdImageCopyResized(brush, im_in,
0, 0, 0, 0,
gdImageSX(brush), gdImageSY(brush),
@ -92,15 +91,14 @@ int main(void)
style[7] = 1;
gdImageSetStyle(im_out, style, 8);
/* Draw the styled, brushed line */
gdImageLine(im_out, 0, 127, 127, 0, gdStyledBrushed);
gdImageLine(im_out, 0, 255, 255, 0, gdStyledBrushed);
}
/* Text */
gdImageString(im_out, gdFontGiant, 16, 16,
gdImageString(im_out, gdFontGiant, 32, 32,
(unsigned char *) "hi", red);
gdImageStringUp(im_out, gdFontSmall, 32, 32,
gdImageStringUp(im_out, gdFontSmall, 64, 64,
(unsigned char *) "hi", red);
/* Make output image interlaced (allows "fade in" in some viewers,
and in the latest web browsers) */
/* Make output image interlaced (progressive, in the case of JPEG) */
gdImageInterlace(im_out, 1);
out = fopen("demoout.png", "wb");
/* Write PNG */

View File

@ -20,15 +20,18 @@
/* number of antialised colors for indexed bitmaps */
#define NUMCOLORS 8
char * gdImageStringTTF(gdImage *im, int *brect, int fg, char *fontlist,
double ptsize, double angle, int x, int y, char *string)
{
gdImageStringFT(im, brect, fg, fontlist, ptsize,
angle, x, y, string);
}
#ifndef HAVE_LIBFREETYPE
char * gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
double ptsize, double angle, int x, int y, char *string)
{
#ifdef HAVE_LIBTTF
return gdImageStringTTF(im,brect,fg,fontlist,ptsize,angle,x,y,string);
#else
return "libgd was not built with FreeType font support\n";
#endif
}
#else
@ -93,16 +96,16 @@ typedef struct {
} fontkey_t;
typedef struct {
unsigned char pixel; /* key */
unsigned char bgcolor; /* key */
int pixel; /* key */
int bgcolor; /* key */
int fgcolor; /* key */ /* -ve means no antialias */
gdImagePtr im; /* key */
unsigned char tweencolor;
int tweencolor;
} tweencolor_t;
typedef struct {
unsigned char pixel; /* key */
unsigned char bgcolor; /* key */
int pixel; /* key */
int bgcolor; /* key */
int fgcolor; /* key */ /* -ve means no antialias */
gdImagePtr im; /* key */
} tweencolorkey_t;
@ -447,10 +450,18 @@ tweenColorFetch (char **error, void *key)
a->tweencolor = -fg;
} else {
npixel = NUMCOLORS - pixel;
a->tweencolor = gdImageColorResolve(im,
(pixel * im->red[fg] + npixel * im->red[bg]) / NUMCOLORS,
(pixel * im->green[fg] + npixel * im->green[bg]) / NUMCOLORS,
(pixel * im->blue[fg] + npixel * im->blue[bg]) / NUMCOLORS);
if (im->trueColor) {
a->tweencolor = gdTrueColorAlpha(
(pixel * gdTrueColorGetRed(fg) + npixel * gdTrueColorGetRed(bg)) / NUMCOLORS,
(pixel * gdTrueColorGetGreen(fg) + npixel * gdTrueColorGetGreen(bg)) / NUMCOLORS,
(pixel * gdTrueColorGetBlue(fg) + npixel * gdTrueColorGetBlue(bg)) / NUMCOLORS,
gdTrueColorGetAlpha(fg));
} else {
a->tweencolor = gdImageColorResolve(im,
(pixel * im->red[fg] + npixel * im->red[bg]) / NUMCOLORS,
(pixel * im->green[fg] + npixel * im->green[bg]) / NUMCOLORS,
(pixel * im->blue[fg] + npixel * im->blue[bg]) / NUMCOLORS);
}
}
return (void *)a;
}
@ -464,7 +475,8 @@ tweenColorRelease(void *element)
/* draw_bitmap - transfers glyph bitmap to GD image */
static char *
gdft_draw_bitmap(gdImage *im, int fg, FT_Bitmap bitmap, int pen_x, int pen_y) {
char *pixel;
unsigned char *pixel;
int *tpixel;
int x, y, row, col, pc;
tweencolor_t *tc_elem;
@ -478,7 +490,7 @@ gdft_draw_bitmap(gdImage *im, int fg, FT_Bitmap bitmap, int pen_x, int pen_y) {
tweenColorTest, tweenColorFetch, tweenColorRelease);
}
/* copy to gif, mapping colors */
/* copy to image, mapping colors */
tc_key.fgcolor = fg;
tc_key.im = im;
for (row = 0; row < bitmap.rows; row++) {
@ -511,18 +523,33 @@ gdft_draw_bitmap(gdImage *im, int fg, FT_Bitmap bitmap, int pen_x, int pen_y) {
/* clip if out of bounds */
if (x >= im->sx || x < 0) continue;
/* get pixel location in gd buffer */
pixel = &im->pixels[y][x];
if (im->trueColor) {
tpixel = &im->tpixels[y][x];
} else {
pixel = &im->pixels[y][x];
}
if (tc_key.pixel == NUMCOLORS) {
/* use fg color directly */
*pixel = fg;
if (im->trueColor) {
*tpixel = fg;
} else {
*pixel = fg;
}
} else {
/* find antialised color */
tc_key.bgcolor = *pixel;
if (im->trueColor) {
tc_key.bgcolor = *tpixel;
} else {
tc_key.bgcolor = *pixel;
}
tc_elem = (tweencolor_t *)gdCacheGet(
tc_cache, &tc_key);
*pixel = tc_elem->tweencolor;
if (im->trueColor) {
*tpixel = tc_elem->tweencolor;
} else {
*pixel = tc_elem->tweencolor;
}
}
}
}
@ -538,11 +565,9 @@ extern int any2eucjp(char *, char *, unsigned int);
char * gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
double ptsize, double angle, int x, int y, char *string)
{
FT_F26Dot6 ur_x=0, ur_y=0, ll_x=0, ll_y=0;
FT_F26Dot6 advance_x, advance_y;
FT_BBox bbox;
FT_BBox bbox, glyph_bbox;
FT_Matrix matrix;
FT_Vector pen, delta;
FT_Vector pen, delta, penf;
FT_Face face;
FT_Glyph image;
FT_GlyphSlot slot;
@ -557,6 +582,8 @@ char * gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
fontkey_t fontkey;
char *next;
char *tmpstr = 0;
int render = (im && fg <=255 && fg >= -255);
FT_BitmapGlyph bm;
/***** initialize font library and font cache on first call ******/
static gdCache_head_t *fontCache;
@ -591,13 +618,13 @@ char * gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
matrix.xy = - matrix.yx;
matrix.yy = matrix.xx;
pen.x = pen.y = 0; /* running position of rotated string */
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;
advance_x = advance_y = 0; /* running position (26.6) of right string */
#ifndef JISX0208
if (font->have_char_map_sjis) {
#endif
@ -617,9 +644,9 @@ char * gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
/* carriage returns */
if (ch == '\r') {
advance_x = 0;
x1 = (advance_x * cos_a - advance_y * sin_a + 32) / 64;
y1 = (advance_x * sin_a + advance_y * cos_a + 32) / 64;
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++;
@ -627,10 +654,10 @@ char * gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
}
/* newlines */
if (ch == '\n') {
advance_y -= face->size->metrics.height * LINESPACE;
advance_y = (advance_y-32) & -64; /* round to next pixel row */
x1 = (advance_x * cos_a - advance_y * sin_a + 32) / 64;
y1 = (advance_x * sin_a + advance_y * cos_a + 32) / 64;
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;
previous = 0; /* clear kerning flag */
next++;
@ -681,82 +708,99 @@ char * gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
}
}
FT_Set_Transform(face, &matrix, &pen);
/* Convert character code to glyph index */
glyph_index = FT_Get_Char_Index( face, ch );
/* retieve kerning distance and move pen position */
/* retrieve kerning distance and move pen position */
if ( use_kerning && previous && glyph_index ) {
FT_Get_Kerning( face, previous, glyph_index,
ft_kerning_default, &delta );
pen.x += delta.x >> 6;
pen.x += delta.x;
}
/* load glyph image into the slot (erase previous one) */
err = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER);
if (err) {
return "Problem loading glyph";
err = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
if (err) 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);
if (!i) { /* if first character, init BB corner values */
bbox.xMin = bbox.yMin = (1 << 30) - 1;
bbox.xMax = bbox.yMax = -bbox.xMin;
}
glyph_bbox.xMin += penf.x; glyph_bbox.yMin += penf.y;
glyph_bbox.xMax += penf.x; glyph_bbox.yMax += penf.y;
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;
i++;
}
/* if null *im, or invalid color,
then assume user just wants brect */
if (im && fg <= 255 && fg >= -255) {
/* transform glyph image */
FT_Glyph_Transform(image, &matrix, 0);
/* now, draw to our target surface */
gdft_draw_bitmap(im, fg, slot->bitmap,
x + x1 + pen.x + slot->bitmap_left,
y - y1 + pen.y - slot->bitmap_top);
if (render) {
if (image->format != ft_glyph_format_bitmap) {
err = FT_Glyph_To_Bitmap(&image, ft_render_mode_normal, 0, 1);
if (err) return "Problem rendering glyph";
}
/* now, draw to our target surface */
bm = (FT_BitmapGlyph)image;
gdft_draw_bitmap(im, fg, bm->bitmap,
x + x1 + ((pen.x + 31) >> 6) + bm->left,
y - y1 + ((pen.y + 31) >> 6) - bm->top);
}
/* increment pen position */
pen.x += slot->advance.x >> 6;
pen.y -= slot->advance.y >> 6;
/* record current glyph index for kerning */
previous = glyph_index;
if (brect) { /* only if need brect */
if (! i++) { /* if first character, init BB corner values */
ll_x = slot->metrics.horiBearingX;
ll_y = slot->metrics.horiBearingY - slot->metrics.height;
ur_x = slot->metrics.horiBearingX + slot->metrics.width;
ur_y = slot->metrics.horiBearingY;
}
else {
if (! advance_x) ll_x = MIN(slot->metrics.horiBearingX, ll_x);
ll_y = MIN(advance_y + slot->metrics.horiBearingY - slot->metrics.height, ll_y);
ur_x = MAX(advance_x + slot->metrics.horiBearingX + slot->metrics.width, ur_x);
if (! advance_y) ur_y = MAX(slot->metrics.horiBearingY, ur_y);
}
}
/* increment pen position */
pen.x += image->advance.x >> 10;
pen.y -= image->advance.y >> 10;
advance_x += slot->metrics.horiAdvance;
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)(ll_x * cos_a - ll_y * sin_a);
brect[1] = (int)(ll_x * sin_a + ll_y * cos_a);
brect[2] = (int)(ur_x * cos_a - ll_y * sin_a);
brect[3] = (int)(ur_x * sin_a + ll_y * cos_a);
brect[4] = (int)(ur_x * cos_a - ur_y * sin_a);
brect[5] = (int)(ur_x * sin_a + ur_y * cos_a);
brect[6] = (int)(ll_x * cos_a - ur_y * sin_a);
brect[7] = (int)(ll_x * sin_a + ur_y * cos_a);
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 */
i = 0;
while (i<8) {
brect[i] = x + (brect[i] + 32) / 64;
i++;
brect[i] = y - (brect[i] + 32) / 64;
i++;
}
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);
}
if ( tmpstr ) gdFree(tmpstr);
return (char *)NULL;
}
int gdroundupdown(FT_F26Dot6 v1, int updown) {
return (!updown)
? (v1 < 0 ? ((v1 - 63) >> 6) : v1 >> 6)
: (v1 > 0 ? ((v1 + 63) >> 6) : v1 >> 6);
}
#endif /* HAVE_LIBFREETYPE */

BIN
src/gdft.c.swp Executable file

Binary file not shown.

View File

@ -7,9 +7,7 @@
#include "gd.h"
#include "gdhelpers.h"
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
#if defined(HAVE_ICONV_H) || defined(HAVE_ICONV)
#include <iconv.h>
#ifdef HAVE_ERRNO_H
@ -56,15 +54,9 @@
#define ESC 27
#define SS2 142
#ifdef __STDC__
static void debug(const char *format, ...)
#else
static debug(format, ...)
char *format;
#endif
{
#ifdef DEBUG
#ifdef HAVE_STDARG_H
va_list args;
va_start(args, format);
@ -73,17 +65,10 @@ char *format;
fprintf(stdout, "\n");
va_end(args);
#endif
#endif
}
#ifdef __STDC__
static void error(const char *format, ...)
#else
static error(format, ...)
char *format;
#endif
{
#ifdef HAVE_STDARG_H
va_list args;
va_start(args, format);
@ -91,17 +76,11 @@ char *format;
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
va_end(args);
#endif
}
/* DetectKanjiCode() derived from DetectCodeType() by Ken Lunde. */
#ifdef __STDC__
static int DetectKanjiCode(unsigned char *str)
#else
static int DetectKanjiCode(str)
unsigned char *str;
#endif
{
static int whatcode;
int c, i;
@ -221,12 +200,7 @@ unsigned char *str;
/* SJIStoJIS() is sjis2jis() by Ken Lunde. */
#ifdef __STDC__
static void SJIStoJIS(int *p1, int *p2)
#else
static SJIStoJIS(p1, p2)
int *p1, *p2;
#endif
{
register unsigned char c1 = *p1;
register unsigned char c2 = *p2;
@ -243,12 +217,7 @@ int *p1, *p2;
#define IS_DAKU(c) ((c >= 182 && c <= 196) || (c >= 202 && c <= 206) || (c == 179))
#define IS_HANDAKU(c) (c >= 202 && c <= 206)
#ifdef __STDC__
static void han2zen(int *p1, int *p2)
#else
static han2zen(p1, p2)
int *p1, *p2;
#endif
{
int c = *p1;
int daku = FALSE;
@ -291,13 +260,7 @@ int *p1, *p2;
/* Recast strcpy to handle unsigned chars used below. */
#define ustrcpy(A,B) (strcpy((char*)(A),(const char*)(B)))
#ifdef __STDC__
static void do_convert(unsigned char *to, unsigned char *from, const char *code)
#else
static do_convert(to, from, code)
unsigned char *to, *from;
char *code;
#endif
{
#ifdef HAVE_ICONV
iconv_t cd;
@ -399,12 +362,7 @@ char *code;
#endif /* HAVE_ICONV */
}
#ifdef __STDC__
static int do_check_and_conv(unsigned char *to, unsigned char *from)
#else
static int do_check_and_conv(to, from)
unsigned char *to, *from;
#endif
{
static unsigned char tmp[BUFSIZ];
int p1, p2, i, j;
@ -484,13 +442,7 @@ unsigned char *to, *from;
return kanji;
}
#ifdef __STDC__
int any2eucjp(unsigned char *dest, unsigned char *src, unsigned int dest_max)
#else
int any2eucjp(dest, src, dest_max)
unsigned char *dest, *src;
unsigned int dest_max;
#endif
{
static unsigned char tmp_dest[BUFSIZ];
int ret;
@ -514,12 +466,7 @@ unsigned int dest_max;
}
#if 0
#ifdef __STDC__
unsigned int strwidth(unsigned char *s)
#else
unsigned int strwidth(s)
unsigned char *s;
#endif
{
unsigned char *t;
unsigned int i;

View File

@ -64,11 +64,14 @@ int main(int argc, char *argv[])
#if 0
im = gdImageCreate(500,500);
#else
im = gdImageCreate(x,y);
/* gd 2.0: true color images can use freetype too */
im = gdImageCreateTrueColor(x,y);
#endif
/* Background color (first allocated) */
/* Background color. gd 2.0: fill the image with it; truecolor
images have a black background otherwise. */
white = gdImageColorResolve(im, 255, 255, 255);
gdImageFilledRectangle(im, 0, 0, x, y, white);
black = gdImageColorResolve(im, 0, 0, 0);
/* render the string, offset origin to center string*/

View File

@ -1,17 +1,24 @@
<HTML>
<HEAD>
<TITLE>gd 1.8.4</TITLE>
<TITLE>gd 2.0.0</TITLE>
</HEAD>
<BODY>
<!-- BANNER HERE -->
<H1>gd 1.8.4</H1>
<H2>A graphics library for fast image creation</H2>
<H2>Follow this link to the
<h1>This is gd 2.0.0 BETA.</h1>
<strong>If you have problems, report them
in detail, and consider using gd 1.8.4 until gd 2.0 final is out.</strong>
<p>
The gd 2.0 documentation update is not complete, but most new features
are documented to some degree and the what's new section is reasonably
complete. Enjoy!
<H2>gd 2.0.0</H2>
<H3>A graphics library for fast image creation</H3>
<H3>Follow this link to the
<A HREF="http://www.boutell.com/gd/">latest version
of this document</A>.</H2>
of this document</A>.</H3>
<blockquote>
<strong>HEY! READ THIS!</strong>
gd 1.8.4 creates PNG, JPEG and WBMP images, not GIF images. This is a
gd 2.0.0 creates PNG, JPEG and WBMP images, not GIF images. This is a
good thing. PNG is a more compact format, and full compression is
available. JPEG works well with photographic images, and is still
more compatible with the major Web browsers than even PNG is. WBMP is
@ -24,7 +31,7 @@ solution is to move to legally unencumbered, well-compressed,
modern image formats such as PNG and JPEG as soon as possible.
<p>
gd 1.8.4 <strong>requires</strong> that the following libraries
gd 2.0.0 <strong>requires</strong> that the following libraries
also be installed:
<p>
libpng (see the <a href="http://www.libpng.org/pub/png/">libpng home page</a>)
@ -47,13 +54,14 @@ included in modern X distributions).
<p>
Please read the documentation and install the required libraries.
Do not send email asking why <code>png.h</code> is not found.
Do not send email asking why <code>libgd.so</code> is not found, either.
See the <a href="#required">requirements section</a> for more
information. Thank you!
</blockquote>
<H3>Table of Contents</H3>
<UL>
<LI><A HREF="#notice">Credits and license terms</A>
<LI><A HREF="#whatsnew1.8.4">What's new in version "XYZ" of GD?</A>
<LI><A HREF="#whatsnew2.0">What's new in version "XYZ" of GD?</A>
<LI><A HREF="#whatis">What is gd?</A>
<LI><A HREF="#gdother">What if I want to use another programming language?</A>
<LI><A HREF="#required">What else do I need to use gd?</A>
@ -83,11 +91,11 @@ COPYRIGHT STATEMENT FOLLOWS THIS LINE
</pre>
<blockquote>
Portions copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000 by Cold Spring
Portions copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 by Cold Spring
Harbor Laboratory. Funded under Grant P41-RR02188 by the National
Institutes of Health.
<P>
Portions copyright 1996, 1997, 1998, 1999, 2000 by Boutell.Com, Inc.
Portions copyright 1996, 1997, 1998, 1999, 2000, 2001 by Boutell.Com, Inc.
<p>
Portions relating to GD2 format copyright 1999, 2000 Philip Warner.
<p>
@ -95,9 +103,10 @@ Portions relating to PNG copyright 1999, 2000 Greg Roelofs.
<p>
Portions relating to libttf copyright 1999, 2000 John Ellson (ellson@lucent.com).
<p>
Portions relating to JPEG copyright 2000, Doug Becker and copyright (C)
1994-1998, Thomas G. Lane. This software is based in part on the work
of the Independent JPEG Group.
Portions relating to JPEG and to color quantization copyright 2000, Doug
Becker and copyright (C) 1994-1998, Thomas G. Lane. This software is based
in part on the work of the Independent JPEG Group. See the file
README-JPEG.TXT for more information.
<p>
Portions relating to WBMP copyright 2000 Maurice Szmurlo and Johan Van
den Brande.
@ -118,7 +127,7 @@ including but not limited to implied warranties of merchantability and
fitness for a particular purpose, with respect to this code and accompanying
documentation.
<p>
Although their code does not appear in gd 1.8.4, the authors wish to
Although their code does not appear in gd 2.0.0, the authors wish to
thank David Koblas, David Rowley, and Hutchison Avenue Software
Corporation for their prior contributions.
</blockquote>
@ -137,17 +146,20 @@ of the formats accepted for inline images by most browsers.
gd is not a paint program.
If you are looking for a paint program, you are looking in
the wrong place. If you are not a programmer, you are looking
in the wrong place.
in the wrong place, unless you are installing a required
library in order to run an application.
<P>
gd does not provide for every possible desirable graphics
operation. It is not necessary or desirable for gd to become
a kitchen-sink graphics package, but version 1.7.3 incorporates
most of the commonly requested features for an 8-bit 2D package.
Support for truecolor images, including truecolor JPEG and PNG,
is planned for version 2.0.
a kitchen-sink graphics package, but version 2.0 does include
most frequently requested features, including both truecolor and
palette images, resampling (smooth resizing of truecolor images)
and so forth.
<P>
<A NAME="gdother"><H3>What if I want to use another programming
language?</h3></A>
Not all of these tools are necessarily up to date and fully compatible
with 2.0.0.
<h4>Perl</h4>
gd can also be used from Perl, courtesy of
Lincoln Stein's
@ -181,6 +193,88 @@ invoke the interpreter.
<li><a href="http://s27w007.pswfs.gov/tgd/">tgd</a>, by Bradley K. Sherman
<li><a href="http://www.unimelb.edu.au/fly/fly.html">fly</a>, by Martin Gleeson
</ul>
<P><A NAME="whatsnew2.0"><H3>What's new in version 2.0?</H3></A>
<ul>
<li><strong>Support for truecolor images!</strong> Version 2.0 can
load truecolor PNGs with no loss of color information, and almost
no loss of alpha channel information. Version 2.0 can also load
truecolor JPEGs with as little loss as possible; however, bear in
mind that JPEG is a lossy format, so repeated load/save cycles
always reduce image quality. This is not a bug. To create
a truecolor image from scratch, call the new
<a href="#gdImageCreateTrueColor">gdImageCreateTrueColor</a>
function. The <a href="#gdImageCreate">gdImageCreate</a> function
is still available to create palette images, and may also be
referred to as <a href="#gdImageCreatePalette">gdImageCreatePalette</a>.
<li><strong>Support for alpha channels!</strong> In addition to
24 bits of color information for each pixel (eight bits of
red, green, and blue respectively), version 2.0 supports
7 bits of "alpha channel" information. This is used to determine
exactly how transparent the pixel should be. There is also support
for a full 7 bits of transparency for each individual palette index
in a palette-based image. Please note that, as of this writing,
only Macintosh Internet Explorer 5.x and Mozilla/Netscape 6.x
display partial transparency properly.
<li>The new <a href="#gdImageAlphaBlending">gdImageAlphaBlending</a>
function allows for two different modes of drawing. In blending mode,
the alpha channel component of the color supplied to all drawing
functions, such as <a href="#gdImageSetPixel">gdImageSetPixel</a>,
determines how much of the underlying color should be allowed to
shine through. The resulting image is not transparent. In non-blending
mode, drawing color is copied literally with the alpha channel
information, resulting in a transparent image. Blending mode is
not available when drawing on palette images.
<li>The <a href="#gdImageCopyResampled">gdImageCopyResampled</a>
function provides "smooth" copying from a large image to a smaller
one, using a weighted average of the pixels of the source area rather
than selecting one representative pixel. This function is identical
to <a href="#gdImageCopyResized">gdImageCopyResized</a> when the
destination image is a palette image.
<li>The <a href="#gdImageTrueColorToPalette">gdImageTrueColorToPalette</a>
function converts a truecolor image to a palette image. The code for
this function was originally drawn from the Independent JPEG Group library
code, which is excellent. The code has been modified to preserve as much
alpha channel information as possible in the resulting palette, in addition
to preserving colors as well as possible. This does not work as well as
might be hoped. It is usually best to simply produce a truecolor
output image instead, which guarantees the highest output quality.
<li>A very high degree of backwards compatibility with existing
gd 1.x code has been maintained, at both the source code and binary
level. <strong>Code which directly accesses the <code>pixels</code> array
will fail only if it encounters an existing truecolor image</strong>, which may
happen if the code attempts to open and modify an existing JPEG or
truecolor PNG. Such code should be modified to check the
<code>trueColor</code> flag of the <code>gdImage</code> structure, and
refer to the <code>tpixels</code> array instead when it is set.
<li>gd is now compiled and installed as a shared library. However,
gd still does not use autoconf, because I (TBB) have very limited
patience with autoconf. These days, most Unix systems provide a fairly
POSIX-standard environment, and the provided Makefile is likely to work well
if users read it and follow the instructions at the top.
<li>Support for line thickness was added by Michael Schwartz. My apologies
to him for sitting on his patches for so long. See the new
<a href="#gdImageSetThickness">gdImageSetThickness</a> function, which
affects all standard gd functions that draw lines and curves. In addition,
Michael added a convenient <a href="#gdImageEllipse">gdImageEllipse</a>
function.
<li>The new <a href="#gdImageFilledArc">gdImageFilledArc</a> function
provides a straightforward way to draw filled arcs. Also,
<a href="#gdImageFilledEllipse">gdImageFilledEllipse</a> is a
convenient way to fill an ellipse without specifying starting
and ending angles. Thanks go out to F J Franklin.
<li>To put an end to the confusion, TrueType 1.x support has been
removed in favor of TrueType 2.x support. The old
gdImageStringTTF function simply invokes gdImageStringFT.
<li>The specialized .gd and .gd2 file formats have been upgraded to support
truecolor. New images written by the versions of these functions
found in 2.0 will be rejected, with varying degrees of grace, by
older versions of gd. THIS AFFECTS THE .GD and .GD2 FORMATS ONLY. IF YOU
ARE CONFUSED BY THIS PARAGRAPH, IT PROBABLY DOESN'T APPLY TO ANYTHING
YOU WILL EVER ENCOUNTER. Since these file formats are absolutely,
positively *not* designed for distributing images, just for
preprocessing them, this should not be a big problem. gd 2.0 should
read old .gd and .gd2 files correctly.
</ul>
<P><A NAME="whatsnew1.8.4"><H3>What's new in version 1.8.4?</H3></A>
<ul>
<li>Add support for FreeType2 (John Ellson ellson@lucent.com)
@ -482,13 +576,13 @@ newsgroups relevant to your particular system.
<A NAME="getgd"><H3>How do I get gd?</H3></A>
<h4>By HTTP</h4>
<ul>
<li><a href="http://www.boutell.com/gd/http/gd-1.8.4.tar.gz">Gzipped Tar File (Unix)</a>
<li><a href="http://www.boutell.com/gd/http/gd-1.8.4.zip">.ZIP File (Windows)</a>
<li><a href="http://www.boutell.com/gd/http/gd-2.0.0.tar.gz">Gzipped Tar File (Unix)</a>
<li><a href="http://www.boutell.com/gd/http/gd-2.0.0.zip">.ZIP File (Windows)</a>
</ul>
<h4>By FTP</h4>
<ul>
<li><a href="ftp://ftp.boutell.com/pub/boutell/gd/gd-1.8.4.tar.gz">Gzipped Tar File (Unix)</a>
<li><a href="ftp://ftp.boutell.com/pub/boutell/gd/gd-1.8.4.zip">.ZIP File (Windows)</a>
<li><a href="ftp://ftp.boutell.com/pub/boutell/gd/gd-2.0.0.tar.gz">Gzipped Tar File (Unix)</a>
<li><a href="ftp://ftp.boutell.com/pub/boutell/gd/gd-2.0.0.zip">.ZIP File (Windows)</a>
</ul>
<P>
<A NAME="buildgd"><H3>How do I build gd?</H3></A>
@ -499,15 +593,15 @@ downloaded. If you are not familiar with <code>tar</code> and
consult with an experienced user of your system. Sorry, we cannot
answer questions about basic Internet skills.
<p>
Unpacking the archive will produce a directory called "gd-1.8.4".
Unpacking the archive will produce a directory called "gd-2.0.0".
<p>
<h4>For Unix</h4>
<code>cd</code> to the 1.8.4 directory. Edit the Makefile with
<code>cd</code> to the 2.0.0 directory. Edit the Makefile with
your preferred text editor and make any necessary changes to the
settings at the top, especially if you want Xpm or TrueType support.
Next, type "make". If you are the system administrator, and you
wish to make the gd library available to other programs, you may
also wish to type "make install".
Next, type "make install". Because gd 2.0 and above installs
as a shared library, it is necessary to install the library properly
before running gd-based programs.
<p>
If you get errors, edit the Makefile again, paying special attention
to the INCLUDEDIRS and LIBDIRS settings.
@ -522,9 +616,10 @@ to your project. Add other source files as appropriate. Learning the
basic skills of creating projects with your chosen C environment
is up to you.
<P>
You have now built both the gd library and a demonstration program which
shows off the capabilities of gd. To see it in action, type
"gddemo".
If you wish to test the library, type "make test" AFTER you have
successfully executed "make install". This will build
several test programs, including "gddemo". Run gddemo to see some of
the capabilities of gd.
<P>
gddemo should execute without incident, creating the file
demoout.png. (Note there is also a file named demoin.png,
@ -653,31 +748,93 @@ filling functions</A></LI>
<DT><A NAME="gdImage"><code>gdImage</code><strong>(TYPE)</strong></A>
<DD>
The data structure in which gd stores images. <A HREF="#gdImageCreate">
gdImageCreate</A> returns
gdImageCreate</A>, <a href="#gdImageCreateTrueColor">gdImageCreateTrueColor</a>
and the various image file-loading functions return
a pointer to this type, and the other functions expect to receive
a pointer to this type as their first argument. You may
read the members <code>sx</code> (size on X axis),
<code>sy</code> (size on Y axis), <code>colorsTotal</code>
(total colors), <code>red</code> (red component of colors;
an array of 256 integers between 0 and 255), <code>green</code>
(green component of colors, as above), <code>blue</code>
(blue component of colors, as above), and <code>transparent</code>
(index of transparent color, -1 if none); please do so
using the macros provided. Do NOT set the members directly
from your code; use the functions provided.
a pointer to this type as their first argument. It is reasonably safe to
examine any of the members of this structure. It is also reasonably
safe to modify individual pixels within the <code>pixels</code>
or <code>tpixels</code> arrays. If the <code>trueColor</code> flag
is set, the <code>tpixels</code> array is valid; otherwise the
<code>pixels</code> array is valid.
<p>
The <code>colorsTotal</code>, <code>red</code>, <code>green</code>,
<code>blue</code>, <code>alpha</code> and <code>open</code> arrays
manage the palette. They are valid only when the <code>trueColor</code>
flag is not set.
The <code>transparent</code> value contains the palette index of the first
transparent color as read-only information for backwards compatibility;
gd 2.0 stores this information in the <code>alpha</code> array so that
variable transparency can be supported for each palette entry. However,
for truecolor images, <code>transparent</code> represents a single
RGB color which is <strong>always 100% transparent</strong>, and this
feature is generally supported by browsers which do not support
full alpha channels.
<PRE>
typedef struct {
/* Palette-based image pixels */
unsigned char ** pixels;
int sx;
int sy;
/* These are valid in palette images only. See also
/* 'alpha', which appears later in the structure to
preserve binary backwards compatibility */
int colorsTotal;
int red[gdMaxColors];
int green[gdMaxColors];
int blue[gdMaxColors];
int blue[gdMaxColors];
int open[gdMaxColors];
/* For backwards compatibility, this is set to the
first palette entry with 100% transparency,
and is also set and reset by the
gdImageColorTransparent function. Newer
applications can allocate palette entries
with any desired level of transparency; however,
bear in mind that many viewers, notably
many web browsers, fail to implement
full alpha channel for PNG and provide
support for full opacity or transparency only. */
int transparent;
int *polyInts;
int polyAllocated;
struct gdImageStruct *brush;
struct gdImageStruct *tile;
int brushColorMap[gdMaxColors];
int tileColorMap[gdMaxColors];
int styleLength;
int stylePos;
int *style;
int interlace;
/* New in 2.0: alpha channel for palettes. Note that only
Macintosh Internet Explorer and (possibly) Netscape 6
really support multiple levels of transparency in
palettes, to my knowledge, as of 2/15/01. Most
common browsers will display 100% opaque and
100% transparent correctly, and do something
unpredictable and/or undesirable for levels
in between. TBB */
int alpha[gdMaxColors];
/* Truecolor flag and pixels. New 2.0 fields appear here at the
end to minimize breakage of existing object code. */
int trueColor;
int ** tpixels;
/* Should alpha channel be copied, or applied, each time a
pixel is drawn? This applies to truecolor images only.
No attempt is made to alpha-blend in palette images,
even if semitransparent palette entries exist.
To do that, build your image as a truecolor image,
then quantize down to 8 bits. */
int alphaBlendingFlag;
/* Should the alpha channel of the image be saved? This affects
PNG at the moment; other future formats may also
have that capability. JPEG doesn't. */
int saveAlphaFlag;
} gdImage;
</PRE>
<p>
The order of the structure members may appear confusing, but was chosen
deliberately to increase backwards compatibility with existing gd 1.x-based
binary code that references particular structure members.
<DT><A NAME="gdImagePtr">gdImagePtr</A> <strong>(TYPE)</strong>
<DD>
A pointer to an image structure. <A HREF="#gdImageCreate">gdImageCreate</A>
@ -764,7 +921,25 @@ proper use of this type.
<DT><A NAME="gdImageCreate">gdImageCreate(sx, sy)</A>
<strong>(FUNCTION)</strong>
<DD>
gdImageCreate is called to create images. Invoke gdImageCreate
gdImageCreate is called to create palette-based images, with no
more than 256 colors. Invoke gdImageCreate
with the x and y dimensions of the desired image. gdImageCreate
returns a <A HREF="#gdImagePtr">gdImagePtr</A> to the new image, or
NULL if unable to
allocate the image. The image must eventually be destroyed
using <A HREF="#gdImageDestroy">gdImageDestroy()</A>.
<PRE>
... inside a function ...
<A HREF="#gdImagePtr">gdImagePtr</A> im;
im = gdImageCreate(64, 64);
/* ... Use the image ... */
<A HREF="#gdImageDestroy">gdImageDestroy</A>(im);
</PRE>
<DT><A NAME="gdImageCreateTrueColor">gdImageCreateTrueColor(sx, sy)</A>
<strong>(FUNCTION)</strong>
<DD>
gdImageCreateTrueColor is called to create truecolor images, with
an essentially unlimited number of colors. Invoke gdImageCreate
with the x and y dimensions of the desired image. gdImageCreate
returns a <A HREF="#gdImagePtr">gdImagePtr</A> to the new image, or
NULL if unable to
@ -782,18 +957,25 @@ im = gdImageCreate(64, 64);
<br>
<A NAME="gdImageCreateFromJpegCtx">gdImageCreateFromJpegCtx(FILE *in)</A>
<strong>(FUNCTION)</strong>
<p><DT><A NAME="gdImageCreateFromJpeg">gdImageCreateFromJpeg(FILE *in)</A>
<strong>(FUNCTION)</strong>
<br>
<A NAME="gdImageCreateFromJpegCtx">gdImageCreateFromJpegCtx(FILE *in)</A>
<strong>(FUNCTION)</strong>
<p>
<DD>
gdImageCreateFromJpeg is called to load images from JPEG format files.
Invoke gdImageCreateFromJpeg with an already opened pointer to a file
containing the desired image.
gdImageCreateFromJpeg
returns a <A HREF="#gdImagePtr">gdImagePtr</A> to the new image, or NULL
returns a <A HREF="#gdImagePtr">gdImagePtr</A> to the new
truecolor image, or NULL
if unable to load the image (most often because the file is corrupt or
does not contain a JPEG image). gdImageCreateFromPng does <em>not</em>
does not contain a JPEG image). gdImageCreateFromJpeg does <em>not</em>
close the file. You can inspect the sx and sy members of the
image to determine its size. The image must eventually be destroyed
using <A HREF="#gdImageDestroy">gdImageDestroy()</A>.
using <A HREF="#gdImageDestroy">gdImageDestroy()</A>. <strong>The
returned image is always a truecolor image.</strong>
<PRE>
<A HREF="#gdImagePtr">gdImagePtr</A> im;
... inside a function ...
@ -820,6 +1002,18 @@ does not contain a PNG image). gdImageCreateFromPng does <em>not</em>
close the file. You can inspect the sx and sy members of the
image to determine its size. The image must eventually be destroyed
using <A HREF="#gdImageDestroy">gdImageDestroy()</A>.
<p>
If the PNG image being loaded is a truecolor image, the resulting
gdImagePtr will refer to a truecolor image. If the PNG image
being loaded is a palette or grayscale image, the resulting
gdImagePtr will refer to a palette image. gd retains only 8 bits
of resolution for each of the red, green and blue channels, and
only 7 bits of resolution for the alpha channel. The former
restriction affects only a handful of very rare 48-bit color
and 16-bit grayscale PNG images. The second restriction affects
all semitransparent PNG images, but the difference is essentially
invisible to the eye. 7 bits of alpha channel resolution is,
in practice, quite a lot.
<PRE>
<A HREF="#gdImagePtr">gdImagePtr</A> im;
... inside a function ...
@ -912,7 +1106,8 @@ Invoke gdImageCreateFromGd2
with an already opened pointer to a file containing the desired image
in the <A HREF="#gdformat">gd2 file format</A>, which is specific to
gd2 and intended for fast loading of parts of large images.
(It is a compressed format, but generally not as good a LZW compression).
(It is a compressed format, but generally not as good as maximum
compression of the entire image would be.)
gdImageCreateFromGd
returns a <A HREF="#gdImagePtr">gdImagePtr</A> to the new image, or NULL
if unable to load the image (most often because the file is corrupt or
@ -1516,7 +1711,36 @@ gdImageArc(im, 50, 25, 98, 48, 0, 360, white);
/* Destroy it */
<A HREF="#gdImageDestroy">gdImageDestroy</A>(im);
</PRE>
<DT><A NAME="gdImageFillToBorder">void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color)
<DT><A NAME="gdImageFilledArc">void gdImageFilledArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)</A>
<STRONG> (FUNCTION)</STRONG>
<DD>
gdImageArc is used to draw a partial ellipse centered at the given point,
with the specified width and height in pixels. The arc begins at
the position in degrees specified by <code>s</code> and ends at
the position specified by <code>e</code>. The arc is filled in
the color specified by the second to last argument. A circle can be drawn
by beginning from 0 degrees and ending at 360 degrees, with
width and height being equal. e must be greater than s. Values greater
than 360 are interpreted modulo 360. The last argument specifies
whether the function should draw a triangular chord
(<code>gdImageChord</code>) or the more frequently desired pie slice
(<code>gdImagePie</code>).
<PRE>
... inside a function ...
<A HREF="#gdImagePtr">gdImagePtr</A> im;
int black;
int white;
im = <A HREF="#gdImageCreate">gdImageCreate</A>(100, 50);
/* Background color (first allocated) */
black = <A HREF="#gdImageColorAllocate">gdImageColorAllocate</A>(im, 0, 0, 0);
/* Allocate the color white (red, green and blue all maximum). */
white = <A HREF="#gdImageColorAllocate">gdImageColorAllocate</A>(im, 255, 255, 255);
/* Inscribe a filled pie slice in the image. */
gdImageFilledArc(im, 50, 25, 98, 48, 0, 45, white, gdPie);
/* ... Do something with the image, such as saving it to a file... */
/* Destroy it */
<A HREF="#gdImageDestroy">gdImageDestroy</A>(im);
</PRE><DT><A NAME="gdImageFillToBorder">void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color)
<STRONG> (FUNCTION)</STRONG>
<DD>
gdImageFillToBorder floods a portion of the image with the specified
@ -1788,10 +2012,58 @@ gdImageSetStyle(im, styleDashed, 6);
/* Destroy it */
<A HREF="#gdImageDestroy">gdImageDestroy</A>(im);
</PRE>
<DT><A NAME="gdImageAlphaBlending">void gdImageAlphaBlending(gdImagePtr im, int blending)</A>
<STRONG>(FUNCTION)</STRONG>
<DD>
The <a href="#gdImageAlphaBlending">gdImageAlphaBlending</a>
function allows for two different modes of drawing on truecolor
images. In blending mode, the alpha channel component of the color
supplied to all drawing functions, such as
<a href="#gdImageSetPixel">gdImageSetPixel</a>, determines how much of
the underlying color should be allowed to shine through. As a result,
gd automatically blends the existing color at that point with the
drawing color, and stores the result in the image. The resulting pixel
is opaque. In non-blending mode, the drawing color is copied literally
with its alpha channel information, replacing the destination pixel.
Blending mode is not available when drawing on palette images.
<PRE>
<A HREF="#gdImagePtr">gdImagePtr</A> im;
int red, blue;
im = <A HREF="#gdImageCreate">gdImageCreateTrueColor</A>(100, 100);
/* Background color */
red = <A HREF="#gdTrueColor">gdTrueColor</A>(im, 255, 0, 0);
gdImageFilledRectangle(im, 0, 0, 100, 100, red);
/* Drawing color. Full transparency would be an alpha channel value
of 127 (gd has a 7 bit alpha chnanel). 0 is opaque,
127 is transparent. So cut gdAlphaTransparent in half to get
50% blending. */
blue = <A HREF="#gdTrueColor">gdTrueColorAlpha</A>(im, 0, 0, 255, gdAlphaTransparent / 2);
/* Draw with blending. Result will be 50% red, 50% blue: yellow
(emitted light, remember, not reflected light. What you learned
in Kindergarten is wrong here). */
gdImageAlphaBlending(im, 1);
<a href="#gdImageFilledRectangle">gdImageFilledRectangle</a>(im, 0, 0, 25, 25, blue);
/* Draw without blending. Result will be 50% blue, 50%
the background color of the image viewer or web browser
used; results in browsers that don't support
semi-transparent pixels are unpredictable! */
gdImageAlphaBlending(im, 0);
<a href="#gdImageFilledRectangle">gdImageFilledRectangle</a>(im, 75, 75, 25, 25, blue);
/* Write the image to disk, etc. */
</pre>
</DL>
<H3><A NAME="query">Query Functions</A></H3>
<DL>
<DT><A NAME="gdImageBlue">
int gdImageAlpha(gdImagePtr im, int color)</A>
<STRONG>(MACRO)</STRONG>
<DD>
gdImageAlpha is a macro which returns the alpha channel component of
the specified color index. Alpha channel values vary between
0 (gdAlphaOpaque), which does not blend at all with the background,
through 127 (gdAlphaTransparent), which allows the background to
shine through 100%. Use this macro rather than accessing the
structure members directly.
int gdImageBlue(gdImagePtr im, int color)</A>
<STRONG>(MACRO)</STRONG>
<DD>
@ -2199,102 +2471,10 @@ char *gdImageStringTTF(gdImagePtr im, int *brect,
int x, int y, char *string)</A>
<STRONG>(FUNCTION)</STRONG>
<DD>
<strong>DEPRECATED.</strong> gdImageStringTTF draws text using the
FreeType 1.x library. For better results, use
<a href="#gdImageStringFT">gdImageStringFT</a> and FreeType 2.x.
<p>
gdImageStringTTF draws a string of anti-aliased characters on the image using
the <A HREF=http://www.freetype.org/>FreeType</A>
library to render user-supplied TrueType fonts. <strong>We do not provide
TrueType fonts (.ttf and .ttc files). Obtaining them is entirely up to
you.</strong> The string is anti-aliased, meaning that there should be
fewer "jaggies" visible. The fontname is the full pathname to a TrueType
font file, or a font face name if the GDFONTPATH environment variable
or FreeType's DEFAULT_FONTPATH variable have been set intelligently.
The string may be arbitrarily scaled (ptsize) and rotated (angle in radians).
<p>
The user-supplied int brect[8] array is filled on return from gdImageStringTTF
with the 8 elements representing the 4 corner coordinates of the
bounding rectangle.
<TABLE BORDER="1">
<TR><TD ALIGN="LEFT" VALIGN="TOP" >0</TD><TD ALIGN="LEFT" VALIGN="TOP">
lower left corner, X position</TD></TR>
<TR><TD ALIGN="LEFT" VALIGN="TOP >1</TD><TD ALIGN="LEFT" VALIGN="TOP">
lower left corner, Y position</TD></TR>
<TR><TD ALIGN="LEFT" VALIGN="TOP >2</TD><TD ALIGN="LEFT" VALIGN="TOP">
lower right corner, X position</TD></TR>
<TR><TD ALIGN="LEFT" VALIGN="TOP">3</TD><TD ALIGN="LEFT" VALIGN="TOP">
lower right corner, Y position</TD></TR>
<TR><TD ALIGN="LEFT" VALIGN="TOP">4</TD><TD ALIGN="LEFT" VALIGN="TOP">
upper right corner, X position</TD></TR>
<TR><TD ALIGN="LEFT" VALIGN="TOP">5</TD><TD ALIGN="LEFT" VALIGN="TOP">
upper right corner, Y position</TD></TR>
<TR><TD ALIGN="LEFT" VALIGN="TOP">6</TD><TD ALIGN="LEFT" VALIGN="TOP">
upper left corner, X position</TD></TR>
<TR><TD ALIGN="LEFT" VALIGN="TOP">7</TD><TD ALIGN="LEFT" VALIGN="TOP">
upper left corner, Y position</TD></TR>
</TABLE>
<p>
The points are relative to the text regardless of the angle, so "upper left"
means in the top left-hand corner seeing the text horizontally.
<p>
Use a NULL gdImagePtr to get the bounding rectangle without rendering.
This is a relatively cheap operation if followed by a rendering of the same
string, because of the caching of the partial rendering during bounding
rectangle calculation.
<p>
The string is rendered in the color indicated by the gf color index.
<strong>Use the negative of the desired color index to
disable anti-aliasing.</strong>
<p>
The string may contain UTF-8 sequences like: "&amp;#192;"
<p>
gdImageStringTTF will return a null char* on success, or an error
string on failure.
<PRE>
#include "gd.h"
#include &lt;string.h&gt;
... inside a function ...
<A HREF="#gdImagePtr">gdImagePtr</A> im;
int black;
int white;
int brect[8];
int x, y;
char *err;
char *s = "Hello."; /* String to draw. */
double sz = 40.;
char *f = "/usr/local/share/ttf/Times.ttf"; /* User supplied font */
/* obtain brect so that we can size the image */
err = <A HREF="#gdImageStringTTF">gdImageStringTTF</A>(NULL,&brect[0],0,f,sz,0.,0,0,s);
if (err) {fprintf(stderr,err); return 1;}
/* create an image big enough for the string plus a little whitespace */
x = brect[2]-brect[6] + 6;
y = brect[3]-brect[7] + 6;
im = <A HREF="#gdImageCreate">gdImageCreate</A>(x,y);
/* Background color (first allocated) */
white = <A HREF="#gdImageColorResolve">gdImageColorResolve</A>(im, 255, 255, 255);
black = <A HREF="#gdImageColorResolve">gdImageColorResolve</A>(im, 0, 0, 0);
/* render the string, offset origin to center string*/
/* note that we use top-left coordinate for adjustment
* since gd origin is in top-left with y increasing downwards. */
x = 3 - brect[6];
y = 3 - brect[7];
err = <A HREF="#gdImageStringTTF">gdImageStringTTF</A>(im,&brect[0],black,f,sz,0.0,x,y,s);
if (err) {fprintf(stderr,err); return 1;}
/* Write img to stdout */
<A HREF="#gdImagePng">gdImagePng</A>(im, stdout);
/* Destroy it */
<A HREF="#gdImageDestroy">gdImageDestroy</A>(im);
</PRE>
</DL>
<strong>DEPRECATED.</strong> THis function simply invokes
<a href="#gdImageStringFT">gdImageStringFT</a> for backwards
compatibility with old code that was written with FreeType 1.x.
/DL>
<H3><A NAME="colors">Color-handling functions</A></H3>
<DL>
<DT><A NAME="gdImageColorAllocate">
@ -2753,6 +2933,73 @@ fclose(out);
<A HREF="#gdImageDestroy">gdImageDestroy</A>(im_in);
<A HREF="#gdImageDestroy">gdImageDestroy</A>(im_out);
</PRE>
<DT><A NAME="gdImageCopyResampled">void gdImageCopyResampled(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int destW, int destH, int srcW, int srcH)
<STRONG> (FUNCTION)</STRONG>
<DD>
gdImageCopyResampled is used to copy a rectangular portion of one image to
another image, smoothly interpolating pixel values so that, in particular,
reducing the size of an image still retains a great deal of clarity. The
X and Y dimensions of the original region and the
destination region can vary, resulting in stretching or shrinking of
the region as appropriate. (For a simpler version of this function
which does not deal with resizing, see <A HREF="#gdImageCopy">
gdImageCopy</A>. For a version which does not interpolate pixel values,
see <A HREF="#gdImageCopyResized">gdImageCopyResized</A>.
<p>
Pixel values are only interpolated if the destination image is a
truecolor image. Otherwise,
<a href="#gdImageCopyResized">gdImageCopyResized</a> is
automatically invoked.
<P>
The <code>dst</code> argument is the destination image to which the
region will be copied. The <code>src</code> argument is the source
image from which the region is copied. The <code>dstX</code>
and <code>dstY</code> arguments specify the point in the destination
image to which the region will be copied. The <code>srcX</code>
and <code>srcY</code> arguments specify the upper left corner
of the region in the source image. The <code>dstW</code>
and <code>dstH</code> arguments specify the width and height
of the destination region. The <code>srcW</code>
and <code>srcH</code> arguments specify the width and height
of the source region and can differ from the destination size,
allowing a region to be scaled during the copying process.
<P>
When you copy a region from one location in an image to another
location in the same image, gdImageCopy will perform as expected
unless the regions overlap, in which case the result is
unpredictable. If this presents a problem, create a scratch image
in which to keep intermediate results.
<P>
<strong>Important note on copying between images:</strong> since images
do not necessarily have the same color tables, pixels are not simply set
to the same color index values to copy them. If the destination image
is a palette image, gd will use the
<a href="#gdImageColorResolve">gdImageColorResolve</a> function to
determine the best color available.
<PRE>
... Inside a function ...
<A HREF="#gdImagePtr">gdImagePtr</A> im_in;
<A HREF="#gdImagePtr">gdImagePtr</A> im_out;
int x, y;
FILE *in;
FILE *out;
/* Load a large png to shrink in the smaller one */
in = fopen("large.png", "rb");
im_in = <A HREF="#gdImageCreateFromPng">gdImageCreateFromPng</A>(in);
fclose(in);
/* Make the output image four times as small on both axes. Use
a true color image so that we can interpolate colors. */
im_out = <A HREF="#gdImageCreate">gdImageCreateTrueColor</A>(im_in->sx / 4, im_in->sy / 4);
/* Now copy the large image, but four times smaller */
gdImageCopyResampled(im_out, im_in, 0, 0, 0, 0,
im_out->sx, im_out->sy,
im_in->sx, im_in->sy);
out = fopen("large.png", "wb");
<A HREF="#gdImagePng">gdImagePng</A>(im_out, out);
fclose(out);
<A HREF="#gdImageDestroy">gdImageDestroy</A>(im_in);
<A HREF="#gdImageDestroy">gdImageDestroy</A>(im_out);
</PRE>
<DT><A NAME="gdImageCopyMerge">void gdImageCopyMerge(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
<STRONG> (FUNCTION)</STRONG>
@ -3045,6 +3292,7 @@ Be sure to read this manual carefully first.
<A HREF="#gdFontPtr">gdFontPtr</A> |
<A HREF="#gdFree">gdFree</A> |
<A HREF="#gdImage">gdImage</A> |
<A HREF="#gdImageAlphaBlending">gdImageAlphaBlending</A> |
<A HREF="#gdImageArc">gdImageArc</A> |
<A HREF="#gdImageBlue">gdImageBlue</A> |
<A HREF="#gdImageBoundsSafe">gdImageBoundsSafe</A> |
@ -3057,8 +3305,13 @@ Be sure to read this manual carefully first.
<A HREF="#gdImageColorResolve">gdImageColorResolve</A> |
<A HREF="#gdImageColorTransparent">gdImageColorTransparent</A> |
<A HREF="#gdImageCopy">gdImageCopy</A> |
<A HREF="#gdImageCopyMerge">gdImageCopyMerge</A> |
<A HREF="#gdImageCopyMergeGray">gdImageMergeGray</A> |
<A HREF="#gdImageCopyResized">gdImageCopyResized</A> |
<A HREF="#gdImageCopyResampled">gdImageCopyResampled</A> |
<A HREF="#gdImageCreate">gdImageCreate</A> |
<A HREF="#gdImageCreate">gdImageCreatePalette</A> |
<A HREF="#gdImageCreate">gdImageCreateTrueColor</A> |
<A HREF="#gdImageCreateFromGd">gdImageCreateFromGd</A> |
<A HREF="#gdImageCreateFromGd2">gdImageCreateFromGd2</A> |
<A HREF="#gdImageCreateFromGd2Part">gdImageCreateFromGd2Part</A> |
@ -3070,6 +3323,7 @@ Be sure to read this manual carefully first.
<A HREF="#gdImageDashedLine">gdImageDashedLine</A> |
<A HREF="#gdImageDestroy">gdImageDestroy</A> |
<A HREF="#gdImageFill">gdImageFill</A> |
<A HREF="#gdImageArc">gdImageFilledArc</A> |
<A HREF="#gdImageFillToBorder">gdImageFillToBorder</A> |
<A HREF="#gdImageFilledRectangle">gdImageFilledRectangle</A> |
<A HREF="#gdImageGd">gdImageGd</A> |

BIN
src/libgd.so.2.0.0 Executable file

Binary file not shown.

File diff suppressed because it is too large Load Diff

12
src/tc Normal file
View File

@ -0,0 +1,12 @@
if (im->trueColor) {
a->tweencolor = gdTrueColorAlpha(im,
(pixel * gdTrueColorGetRed(fg) + npixel * gdTrueColorGetRed(bg)) / NUMCOLORS,
(pixel * gdTrueColorGetGreen(fg) + npixel * gdTrueColorGetGreen(bg)) / NUMCOLORS,
(pixel * gdTrueColorGetBlue(fg) + npixel * gdTrueColorGetBlue(bg)) / NUMCOLORS,
(pixel * gdTrueColorGetAlpha(fg) + npixel * gdTrueColorGetAlpha(bg)) / NUMCOLORS);
} else {
a->tweencolor = gdImageColorResolve(im,
(pixel * im->red[fg] + npixel * im->red[bg]) / NUMCOLORS,
(pixel * im->green[fg] + npixel * im->green[bg]) / NUMCOLORS,
(pixel * im->blue[fg] + npixel * im->blue[bg]) / NUMCOLORS);
}

122
src/testac.c Normal file
View File

@ -0,0 +1,122 @@
#include <stdio.h>
#include "gd.h"
/* If palette is true, we convert from truecolor to palette at the end,
to test gdImageTrueColorToPalette and see file size/
quality tradeoffs. */
void testDrawing(
gdImagePtr im_in,
double scale,
int blending,
int palette,
char *filename);
int main(int argc, char *argv[])
{
/* Input and output files */
FILE *in;
FILE *out;
/* Input image */
gdImagePtr im_in = 0;
/* Colors */
int lightBlue;
if (argc != 2) {
fprintf(stderr, "Usage: testac filename.png\n");
exit(1);
}
/* Load original PNG, which should contain alpha channel
information. We will use it in two ways: preserving it
literally, for use with compatible browsers, and
compositing it ourselves against a background of our
choosing (alpha blending). We'll change its size
and try creating palette versions of it. */
in = fopen(argv[1], "rb");
if (!in) {
fprintf(stderr, "Can't load %s.\n", argv[1]);
exit(1);
} else {
im_in = gdImageCreateFromPng(in);
fclose(in);
}
testDrawing(im_in, 1.0, 0, 0, "noblending-fullsize-truecolor.png");
testDrawing(im_in, 1.0, 1, 0, "blending-fullsize-truecolor.png");
testDrawing(im_in, 0.5, 0, 0, "noblending-halfsize-truecolor.png");
testDrawing(im_in, 0.5, 1, 0, "blending-halfsize-truecolor.png");
testDrawing(im_in, 2.0, 0, 0, "noblending-doublesize-truecolor.png");
testDrawing(im_in, 2.0, 1, 0, "blending-doublesize-truecolor.png");
testDrawing(im_in, 1.0, 0, 1, "noblending-fullsize-palette.png");
testDrawing(im_in, 1.0, 1, 1, "blending-fullsize-palette.png");
testDrawing(im_in, 0.5, 0, 1, "noblending-halfsize-palette.png");
testDrawing(im_in, 0.5, 1, 1, "blending-halfsize-palette.png");
testDrawing(im_in, 2.0, 0, 1, "noblending-doublesize-palette.png");
testDrawing(im_in, 2.0, 1, 1, "blending-doublesize-palette.png");
gdImageDestroy(im_in);
return 0;
}
/* If palette is true, we convert from truecolor to palette at the end,
to test gdImageTrueColorToPalette and see file size/
quality tradeoffs. */
void testDrawing(
gdImagePtr im_in,
double scale,
int blending,
int palette,
char *filename)
{
gdImagePtr im_out;
FILE *out;
/* Create output image. */
im_out = gdImageCreateTrueColor((int) (gdImageSX(im_in) * scale),
(int) (gdImageSY(im_in) * scale));
/*
Request alpha blending. This causes future
drawing operations to perform alpha channel blending
with the background, resulting in an opaque image.
Without this call, pixels in the foreground color are
copied literally, *including* the alpha channel value,
resulting in an output image which is potentially
not opaque. This flag can be set and cleared as often
as desired. */
gdImageAlphaBlending(im_out, blending);
/* Flood with light blue. */
gdImageFill(im_out, (int) (gdImageSX(im_in) * scale / 2),
(int) (gdImageSY(im_in) * scale / 2),
gdTrueColor(192, 192, 255));
/* Copy the source image. Alpha blending should result in
compositing against red. With blending turned off, the
browser or viewer will composite against its preferred
background, or, if it does not support an alpha channel,
we will see the original colors for the pixels that
ought to be transparent or semitransparent. */
gdImageCopyResampled(im_out, im_in,
0, 0,
0, 0,
(int) (gdImageSX(im_in) * scale), (int) (gdImageSY(im_in) * scale),
gdImageSX(im_in), gdImageSY(im_in));
/* Write PNG */
out = fopen(filename, "wb");
/* If this image is the result of alpha channel blending,
it will not contain an interesting alpha channel itself.
Save a little file size by not saving the alpha channel.
Otherwise the file would typically be slightly larger. */
gdImageSaveAlpha(im_out, !blending);
/* If requested, convert from truecolor to palette. */
if (palette) {
/* Dithering, 256 colors. */
gdImageTrueColorToPalette(im_out, 1, 256);
}
gdImagePng(im_out, out);
fclose(out);
gdImageDestroy(im_out);
}

View File

@ -110,15 +110,20 @@ int main(int argc, char **argv)
} else if (!strcmp(argv[i], "-l")) {
/* List the colors in the color table. */
int j;
/* Tabs used below. */
printf("Index Red Green Blue\n");
for (j=0; (j < gdImageColorsTotal(im)); j++) {
/* Use access macros to learn colors. */
printf("%d %d %d %d\n",
j,
gdImageRed(im, j),
gdImageGreen(im, j),
gdImageBlue(im, j));
if (!im->trueColor) {
/* Tabs used below. */
printf("Index Red Green Blue Alpha\n");
for (j=0; (j < gdImageColorsTotal(im)); j++) {
/* Use access macros to learn colors. */
printf("%d %d %d %d %d\n",
j,
gdImageRed(im, j),
gdImageGreen(im, j),
gdImageBlue(im, j),
gdImageAlpha(im, j));
}
} else {
printf("Truecolor image, no palette entries to list.\n");
}
no = 0;
} else if (!strcmp(argv[i], "-d")) {
@ -129,10 +134,10 @@ int main(int argc, char **argv)
gdImageColorsTotal(im));
t = gdImageGetTransparent(im);
if (t != (-1)) {
printf("Transparent index: %d\n", t);
printf("First 100% transparent index: %d\n", t);
} else {
/* -1 means the image is not transparent. */
printf("Transparent index: none\n");
printf("First 100% transparent index: none\n");
}
if (gdImageGetInterlaced(im)) {
printf("Interlaced: yes\n");