- sync to 2.0.0
parent
c9af8e769b
commit
fceb93d2b9
|
@ -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>
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
|
@ -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
|
229
src/gd.h
229
src/gd.h
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
86
src/gd_gd.c
86
src/gd_gd.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
118
src/gd_gd2.c
118
src/gd_gd2.c
|
@ -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)); */
|
||||
|
|
158
src/gd_jpeg.c
158
src/gd_jpeg.c
|
@ -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)
|
||||
|
|
502
src/gd_png.c
502
src/gd_png.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
46
src/gddemo.c
46
src/gddemo.c
|
@ -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 */
|
||||
|
|
208
src/gdft.c
208
src/gdft.c
|
@ -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 */
|
||||
|
|
Binary file not shown.
|
@ -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;
|
||||
|
|
|
@ -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*/
|
||||
|
|
544
src/index.html
544
src/index.html
|
@ -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: "&#192;"
|
||||
<p>
|
||||
gdImageStringTTF will return a null char* on success, or an error
|
||||
string on failure.
|
||||
<PRE>
|
||||
#include "gd.h"
|
||||
#include <string.h>
|
||||
... 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> |
|
||||
|
|
Binary file not shown.
1730
src/readme.txt
1730
src/readme.txt
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
27
src/webpng.c
27
src/webpng.c
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue