mirror of
https://github.com/php/php-src.git
synced 2025-01-27 14:13:41 +08:00
Initial commit of the built-in libgd based on GD-2.0.1
This initial checkin has no changes to any of the libgd code so it can be used as a basis for diffs. It also will not build currently because of this. The PHP gd checks need to be incorporated along with a bit of other config magic. It also shouldn't break the build and will only take effect if you use --with-gd=php right now.
This commit is contained in:
parent
c46199f5b9
commit
7a8cade379
@ -208,7 +208,17 @@ AC_DEFUN(PHP_GD_CHECK_VERSION,[
|
||||
PHP_ARG_WITH(gd, for GD support,
|
||||
[ --with-gd[=DIR] Include GD support (DIR is GD's install dir).])
|
||||
|
||||
if test "$PHP_GD" != "no"; then
|
||||
if test "$PHP_GD" == "php"; then
|
||||
GD_MODULE_TYPE=builtin
|
||||
sources="libgd/gd.c libgd/gd_gd.c libgd/gd_gd2.c libgd/gd_io.c libgd/gd_io_dp.c \
|
||||
libgd/gd_io_file.c libgd/gd_ss.c libgd/gd_io_ss.c libgd/gd_png.c libgd/gd_jpeg.c \
|
||||
libgd/gdxpm.c libgd/gdfontt.c libgd/gdfonts.c libgd/gdfontmb.c libgd/gdfontl.c \
|
||||
libgd/gdfontg.o libgd/gdtables.c libgd/gdft.c libgd/gdcache.c libgd/gdkanji.c \
|
||||
libgd/wbmp.c libgd/gd_wbmp.c libgd/gdhelpers.c libgd/gd_topal.c"
|
||||
PHP_NEW_EXTENSION(mysql, gd.c gdcache.c gdttf.c gdt1.c $sources, $ext_shared,,-I@ext_srcdir@/libgd)
|
||||
PHP_ADD_BUILD_DIR($ext_builddir/libgd)
|
||||
else
|
||||
if test "$PHP_GD" != "no"; then
|
||||
|
||||
PHP_NEW_EXTENSION(gd, gd.c gdcache.c gdttf.c gdt1.c, $ext_shared)
|
||||
PHP_SUBST(GD_SHARED_LIBADD)
|
||||
@ -259,4 +269,5 @@ dnl SuSE 6.x package structure
|
||||
PHP_EXPAND_PATH($GD_INCLUDE, GD_INCLUDE)
|
||||
PHP_ADD_INCLUDE($GD_INCLUDE)
|
||||
|
||||
fi
|
||||
fi
|
||||
|
72
ext/gd/libgd/README
Normal file
72
ext/gd/libgd/README
Normal file
@ -0,0 +1,72 @@
|
||||
This directory contains the GD library available from
|
||||
http://www.boutell.com/gd/
|
||||
|
||||
The inclusion of this library with PHP is in response to the
|
||||
popularity of the GD extension and the GD library itself. We felt
|
||||
it would be worthwhile to make sure everyone had access to the
|
||||
features of GD and by bundling GD with PHP we have a known target to
|
||||
work against.
|
||||
|
||||
In addition to the above, a number of motivated PHP hackers have
|
||||
expressed an interest in extending the functionality of the PHP-GD
|
||||
combination. By putting a version of GD into PHP CVS we have provided
|
||||
a sandbox for them to throw sand at each other in. Any and all
|
||||
improvements we make to the GD library will be contributed back to the
|
||||
original maintainers of this library at boutell.com.
|
||||
|
||||
The following statement is from the original GD package:
|
||||
|
||||
Credits and license terms
|
||||
|
||||
In order to resolve any possible confusion regarding the authorship of
|
||||
gd, the following copyright statement covers all of the authors who
|
||||
have required such a statement. _If you are aware of any oversights in
|
||||
this copyright notice, please contact Thomas Boutell who will be
|
||||
pleased to correct them._
|
||||
|
||||
COPYRIGHT STATEMENT FOLLOWS THIS LINE
|
||||
|
||||
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.
|
||||
|
||||
Portions copyright 1996, 1997, 1998, 1999, 2000, 2001 by
|
||||
Boutell.Com, Inc.
|
||||
|
||||
Portions relating to GD2 format copyright 1999, 2000 Philip Warner.
|
||||
|
||||
Portions relating to PNG copyright 1999, 2000 Greg Roelofs.
|
||||
|
||||
Portions relating to libttf copyright 1999, 2000 John Ellson
|
||||
(ellson@lucent.com).
|
||||
|
||||
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.
|
||||
|
||||
Portions relating to WBMP copyright 2000 Maurice Szmurlo and Johan
|
||||
Van den Brande.
|
||||
|
||||
_Permission has been granted to copy, distribute and modify gd in
|
||||
any context without fee, including a commercial application,
|
||||
provided that this notice is present in user-accessible supporting
|
||||
documentation._
|
||||
|
||||
This does not affect your ownership of the derived work itself, and
|
||||
the intent is to assure proper credit for the authors of gd, not to
|
||||
interfere with your productive use of gd. If you have questions,
|
||||
ask. "Derived works" includes all programs that utilize the
|
||||
library. Credit must be given in user-accessible documentation.
|
||||
|
||||
_This software is provided "AS IS."_ The copyright holders disclaim
|
||||
all warranties, either express or implied, including but not
|
||||
limited to implied warranties of merchantability and fitness for a
|
||||
particular purpose, with respect to this code and accompanying
|
||||
documentation.
|
||||
|
||||
Although their code does not appear in gd 2.0.1, the authors wish
|
||||
to thank David Koblas, David Rowley, and Hutchison Avenue Software
|
||||
Corporation for their prior contributions.
|
||||
|
||||
END OF COPYRIGHT STATEMENT
|
2526
ext/gd/libgd/gd.c
Normal file
2526
ext/gd/libgd/gd.c
Normal file
File diff suppressed because it is too large
Load Diff
496
ext/gd/libgd/gd.h
Normal file
496
ext/gd/libgd/gd.h
Normal file
@ -0,0 +1,496 @@
|
||||
#ifndef GD_H
|
||||
#define GD_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* default fontpath for unix systems */
|
||||
#define DEFAULT_FONTPATH "/usr/share/fonts/truetype"
|
||||
#define PATHSEPARATOR ":"
|
||||
|
||||
/* gd.h: declarations file for the graphic-draw module.
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation for any purpose and without fee is hereby granted, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation. This software is provided "AS IS." Thomas Boutell and
|
||||
* Boutell.Com, Inc. disclaim all warranties, either express or implied,
|
||||
* including but not limited to implied warranties of merchantability and
|
||||
* fitness for a particular purpose, with respect to this code and accompanying
|
||||
* documentation. */
|
||||
|
||||
/* stdio is needed for file I/O. */
|
||||
#include <stdio.h>
|
||||
#include "gd_io.h"
|
||||
|
||||
/* 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
|
||||
|
||||
/* Image type. See functions below; you will not need to change
|
||||
the elements directly. Use the provided macros to
|
||||
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;
|
||||
struct gdImageStruct *brush;
|
||||
struct gdImageStruct *tile;
|
||||
int brushColorMap[gdMaxColors];
|
||||
int tileColorMap[gdMaxColors];
|
||||
int styleLength;
|
||||
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;
|
||||
|
||||
typedef struct {
|
||||
/* # of characters in font */
|
||||
int nchars;
|
||||
/* First character is numbered... (usually 32 = space) */
|
||||
int offset;
|
||||
/* Character width and height */
|
||||
int w;
|
||||
int h;
|
||||
/* Font data; array of characters, one row after another.
|
||||
Easily included in code, also easily loaded from
|
||||
data files. */
|
||||
char *data;
|
||||
} gdFont;
|
||||
|
||||
/* Text functions take these. */
|
||||
typedef gdFont *gdFontPtr;
|
||||
|
||||
/* For backwards compatibility only. Use gdImageSetStyle()
|
||||
for MUCH more flexible line drawing. Also see
|
||||
gdImageSetBrush(). */
|
||||
#define gdDashSize 4
|
||||
|
||||
/* Special colors. */
|
||||
|
||||
#define gdStyled (-2)
|
||||
#define gdBrushed (-3)
|
||||
#define gdStyledBrushed (-4)
|
||||
#define gdTiled (-5)
|
||||
|
||||
/* NOT the same as the transparent color index.
|
||||
This is used in line styles only. */
|
||||
#define gdTransparent (-6)
|
||||
|
||||
/* 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);
|
||||
gdImagePtr gdImageCreateFromWBMPCtx(gdIOCtx *infile);
|
||||
gdImagePtr gdImageCreateFromJpeg(FILE *infile);
|
||||
gdImagePtr gdImageCreateFromJpegCtx(gdIOCtx *infile);
|
||||
|
||||
/* A custom data source. */
|
||||
/* The source function must return -1 on error, otherwise the number
|
||||
of bytes fetched. 0 is EOF, not an error! */
|
||||
/* context will be passed to your source function. */
|
||||
|
||||
typedef struct {
|
||||
int (*source) (void *context, char *buffer, int len);
|
||||
void *context;
|
||||
} gdSource, *gdSourcePtr;
|
||||
|
||||
gdImagePtr gdImageCreateFromPngSource(gdSourcePtr in);
|
||||
|
||||
gdImagePtr gdImageCreateFromGd(FILE *in);
|
||||
gdImagePtr gdImageCreateFromGdCtx(gdIOCtxPtr in);
|
||||
|
||||
gdImagePtr gdImageCreateFromGd2(FILE *in);
|
||||
gdImagePtr gdImageCreateFromGd2Ctx(gdIOCtxPtr in);
|
||||
|
||||
gdImagePtr gdImageCreateFromGd2Part(FILE *in, int srcx, int srcy, int w, int h);
|
||||
gdImagePtr gdImageCreateFromGd2PartCtx(gdIOCtxPtr in, int srcx, int srcy, int w, int h);
|
||||
|
||||
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);
|
||||
/* Corners specified (not width and height). Upper left first, lower right
|
||||
second. */
|
||||
void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
|
||||
/* Solid bar. Upper left corner first, lower right corner second. */
|
||||
void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
|
||||
int gdImageBoundsSafe(gdImagePtr im, int x, int y);
|
||||
void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color);
|
||||
void gdImageCharUp(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color);
|
||||
void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color);
|
||||
void gdImageStringUp(gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color);
|
||||
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);
|
||||
|
||||
/* 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 */
|
||||
char *gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
|
||||
double ptsize, double angle, int x, int y, char *string);
|
||||
|
||||
/* Point type for use in polygon drawing. */
|
||||
typedef struct {
|
||||
int x, y;
|
||||
} gdPoint, *gdPointPtr;
|
||||
|
||||
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);
|
||||
|
||||
void gdImageWBMP(gdImagePtr image, int fg, FILE *out);
|
||||
void gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out);
|
||||
|
||||
/* Guaranteed to correctly free memory returned
|
||||
by the gdImage*Ptr functions */
|
||||
void gdFree(void *m);
|
||||
|
||||
/* Best to free this memory with gdFree(), not free() */
|
||||
void *gdImageWBMPPtr(gdImagePtr im, int *size, int fg);
|
||||
|
||||
void gdImageJpeg(gdImagePtr im, FILE *out, int quality);
|
||||
void gdImageJpegCtx(gdImagePtr im, gdIOCtx *out, int quality);
|
||||
|
||||
/* Best to free this memory with gdFree(), not free() */
|
||||
void *gdImageJpegPtr(gdImagePtr im, int *size, int quality);
|
||||
|
||||
/* A custom data sink. For backwards compatibility. Use
|
||||
gdIOCtx instead. */
|
||||
/* The sink function must return -1 on error, otherwise the number
|
||||
of bytes written, which must be equal to len. */
|
||||
/* context will be passed to your sink function. */
|
||||
typedef struct {
|
||||
int (*sink) (void *context, const char *buffer, int len);
|
||||
void *context;
|
||||
} gdSink, *gdSinkPtr;
|
||||
|
||||
void gdImagePngToSink(gdImagePtr im, gdSinkPtr out);
|
||||
|
||||
void gdImageGd(gdImagePtr im, FILE *out);
|
||||
void gdImageGd2(gdImagePtr im, FILE *out, int cs, int fmt);
|
||||
|
||||
/* Best to free this memory with gdFree(), not free() */
|
||||
void* gdImagePngPtr(gdImagePtr im, int *size);
|
||||
|
||||
/* Best to free this memory with gdFree(), not free() */
|
||||
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);
|
||||
|
||||
/* Style is a bitwise OR ( | operator ) of these.
|
||||
gdArc and gdChord are mutually exclusive;
|
||||
gdChord just connects the starting and ending
|
||||
angles with a straight line, while gdArc produces
|
||||
a rounded edge. gdPie is a synonym for gdArc.
|
||||
gdNoFill indicates that the arc or chord should be
|
||||
outlined, not filled. gdEdged, used together with
|
||||
gdNoFill, indicates that the beginning and ending
|
||||
angles should be connected to the center; this is
|
||||
a good way to outline (rather than fill) a
|
||||
'pie slice'. */
|
||||
#define gdArc 0
|
||||
#define gdPie gdArc
|
||||
#define gdChord 1
|
||||
#define gdNoFill 2
|
||||
#define gdEdged 4
|
||||
|
||||
void gdImageFilledArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style);
|
||||
void gdImageArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color);
|
||||
void gdImageFilledEllipse(gdImagePtr im, int cx, int cy, int w, int h, int color);
|
||||
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);
|
||||
void gdImageCopyMerge(gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
|
||||
int srcX, int srcY, int w, int h, int pct);
|
||||
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. 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);
|
||||
/* 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)
|
||||
|
||||
#define gdImageSX(im) ((im)->sx)
|
||||
#define gdImageSY(im) ((im)->sy)
|
||||
#define gdImageColorsTotal(im) ((im)->colorsTotal)
|
||||
#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*);
|
||||
gdIOCtx* gdNewDynamicCtx(int, void*);
|
||||
gdIOCtx* gdNewSSCtx(gdSourcePtr in, gdSinkPtr out);
|
||||
void* gdDPExtractData(struct gdIOCtx* ctx, int *size);
|
||||
|
||||
#define GD2_CHUNKSIZE 128
|
||||
#define GD2_CHUNKSIZE_MIN 64
|
||||
#define GD2_CHUNKSIZE_MAX 4096
|
||||
|
||||
#define GD2_VERS 2
|
||||
#define GD2_ID "gd2"
|
||||
#define GD2_FMT_RAW 1
|
||||
#define GD2_FMT_COMPRESSED 2
|
||||
|
||||
/* Image comparison definitions */
|
||||
int gdImageCompare(gdImagePtr im1, gdImagePtr im2);
|
||||
|
||||
#define GD_CMP_IMAGE 1 /* Actual image IS different */
|
||||
#define GD_CMP_NUM_COLORS 2 /* Number of Colours in pallette differ */
|
||||
#define GD_CMP_COLOR 4 /* Image colours differ */
|
||||
#define GD_CMP_SIZE_X 8 /* Image width differs */
|
||||
#define GD_CMP_SIZE_Y 16 /* Image heights differ */
|
||||
#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 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GD_H */
|
64
ext/gd/libgd/gd2copypal.c
Normal file
64
ext/gd/libgd/gd2copypal.c
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include "gd.h"
|
||||
|
||||
/* A short program which converts a .png file into a .gd file, for
|
||||
your convenience in creating images on the fly from a
|
||||
basis image that must be loaded quickly. The .gd format
|
||||
is not intended to be a general-purpose format. */
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gdImagePtr im;
|
||||
gdImagePtr pal;
|
||||
FILE *in, *out;
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf (stderr, "Usage: gd2copypal palettefile.gd2 filename.gd2\n");
|
||||
exit (1);
|
||||
}
|
||||
in = fopen (argv[1], "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "Palette file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
pal = gdImageCreateFromGd2 (in);
|
||||
fclose (in);
|
||||
if (!pal)
|
||||
{
|
||||
fprintf (stderr, "Palette is not in GD2 format!\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
in = fopen (argv[2], "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "Input file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im = gdImageCreateFromGd2 (in);
|
||||
fclose (in);
|
||||
if (!im)
|
||||
{
|
||||
fprintf (stderr, "Input is not in GD2 format!\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
gdImagePaletteCopy (im, pal);
|
||||
|
||||
out = fopen (argv[2], "wb");
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr, "Output file cannot be written to!\n");
|
||||
gdImageDestroy (im);
|
||||
exit (1);
|
||||
}
|
||||
gdImageGd2 (im, out, 128, 2);
|
||||
fclose (out);
|
||||
gdImageDestroy (pal);
|
||||
gdImageDestroy (im);
|
||||
|
||||
return 0;
|
||||
}
|
60
ext/gd/libgd/gd2time.c
Normal file
60
ext/gd/libgd/gd2time.c
Normal file
@ -0,0 +1,60 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for atoi */
|
||||
#include <time.h> /* For time */
|
||||
#include "gd.h"
|
||||
|
||||
/* A short program which converts a .png file into a .gd file, for
|
||||
your convenience in creating images on the fly from a
|
||||
basis image that must be loaded quickly. The .gd format
|
||||
is not intended to be a general-purpose format. */
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gdImagePtr im;
|
||||
FILE *in;
|
||||
int x, y, w, h;
|
||||
int c;
|
||||
int i;
|
||||
int t0;
|
||||
|
||||
if (argc != 7)
|
||||
{
|
||||
fprintf (stderr, "Usage: gd2time filename.gd count x y w h\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
c = atoi (argv[2]);
|
||||
x = atoi (argv[3]);
|
||||
y = atoi (argv[4]);
|
||||
w = atoi (argv[5]);
|
||||
h = atoi (argv[6]);
|
||||
|
||||
printf ("Extracting %d times from (%d, %d), size is %dx%d\n", c, x, y, w, h);
|
||||
|
||||
t0 = time (0);
|
||||
for (i = 0; i < c; i++)
|
||||
{
|
||||
in = fopen (argv[1], "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "Input file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
im = gdImageCreateFromGd2Part (in, x, y, w, h);
|
||||
fclose (in);
|
||||
|
||||
if (!im)
|
||||
{
|
||||
fprintf (stderr, "Error reading source file!\n");
|
||||
exit (1);
|
||||
}
|
||||
gdImageDestroy (im);
|
||||
};
|
||||
t0 = time (0) - t0;
|
||||
printf ("%d seconds to extract (& destroy) %d times\n", t0, c);
|
||||
|
||||
return 0;
|
||||
}
|
45
ext/gd/libgd/gd2topng.c
Normal file
45
ext/gd/libgd/gd2topng.c
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include "gd.h"
|
||||
|
||||
/* A short program which converts a .png file into a .gd file, for
|
||||
your convenience in creating images on the fly from a
|
||||
basis image that must be loaded quickly. The .gd format
|
||||
is not intended to be a general-purpose format. */
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gdImagePtr im;
|
||||
FILE *in, *out;
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf (stderr, "Usage: gd2topng filename.gd2 filename.png\n");
|
||||
exit (1);
|
||||
}
|
||||
in = fopen (argv[1], "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "Input file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im = gdImageCreateFromGd2 (in);
|
||||
fclose (in);
|
||||
if (!im)
|
||||
{
|
||||
fprintf (stderr, "Input is not in GD2 format!\n");
|
||||
exit (1);
|
||||
}
|
||||
out = fopen (argv[2], "wb");
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr, "Output file cannot be written to!\n");
|
||||
gdImageDestroy (im);
|
||||
exit (1);
|
||||
}
|
||||
gdImagePng (im, out);
|
||||
fclose (out);
|
||||
gdImageDestroy (im);
|
||||
|
||||
return 0;
|
||||
}
|
741
ext/gd/libgd/gd_arc_f_buggy.c
Normal file
741
ext/gd/libgd/gd_arc_f_buggy.c
Normal file
@ -0,0 +1,741 @@
|
||||
/* This is potentially great stuff, but fails against the test
|
||||
program at the end. This would probably be much more
|
||||
efficent than the implementation currently in gd.c if the
|
||||
errors in the output were corrected. TBB */
|
||||
|
||||
#if 0
|
||||
|
||||
#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)
|
||||
{
|
||||
gdImageFilledArc (im, cx, cy, width, height, 0, 360, color, gdChord);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#include "gd.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define WIDTH 500
|
||||
#define HEIGHT 300
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gdImagePtr im = gdImageCreate (WIDTH, HEIGHT);
|
||||
int white = gdImageColorResolve (im, 0xFF, 0xFF, 0xFF), black = gdImageColorResolve (im, 0, 0, 0),
|
||||
red = gdImageColorResolve (im, 0xFF, 0xA0, 0xA0);
|
||||
FILE *out;
|
||||
|
||||
/* filled arc - circle */
|
||||
gdImageFilledArc (im, WIDTH / 5, HEIGHT / 4, 200, 200, 45, 90, red, gdPie);
|
||||
gdImageArc (im, WIDTH / 5, HEIGHT / 4, 200, 200, 45, 90, black);
|
||||
|
||||
/* filled arc - ellipse */
|
||||
gdImageFilledArc (im, WIDTH / 2, HEIGHT / 4, 200, 150, 45, 90, red, gdPie);
|
||||
gdImageArc (im, WIDTH / 2, HEIGHT / 4, 200, 150, 45, 90, black);
|
||||
|
||||
|
||||
/* reference lines */
|
||||
gdImageLine (im, 0, HEIGHT / 4, WIDTH, HEIGHT / 4, black);
|
||||
gdImageLine (im, WIDTH / 5, 0, WIDTH / 5, HEIGHT, black);
|
||||
gdImageLine (im, WIDTH / 2, 0, WIDTH / 2, HEIGHT, black);
|
||||
gdImageLine (im, WIDTH / 2, HEIGHT / 4, WIDTH / 2 + 300, HEIGHT / 4 + 300, black);
|
||||
gdImageLine (im, WIDTH / 5, HEIGHT / 4, WIDTH / 5 + 300, HEIGHT / 4 + 300, black);
|
||||
|
||||
/* TBB: Write img to test/arctest.png */
|
||||
out = fopen ("test/arctest.png", "wb");
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr, "Can't create test/arctest.png\n");
|
||||
exit (1);
|
||||
}
|
||||
gdImagePng (im, out);
|
||||
fclose (out);
|
||||
fprintf (stderr, "Test image written to test/arctest.png\n");
|
||||
/* Destroy it */
|
||||
gdImageDestroy (im);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
272
ext/gd/libgd/gd_gd.c
Normal file
272
ext/gd/libgd/gd_gd.c
Normal file
@ -0,0 +1,272 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "gd.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/* Exported functions: */
|
||||
extern void gdImageGd (gdImagePtr im, FILE * out);
|
||||
|
||||
|
||||
/* Use this for commenting out debug-print statements. */
|
||||
/* Just use the first '#define' to allow all the prints... */
|
||||
/*#define GD2_DBG(s) (s) */
|
||||
#define GD2_DBG(s)
|
||||
|
||||
/* */
|
||||
/* Shared code to read color tables from gd file. */
|
||||
/* */
|
||||
int
|
||||
_gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag)
|
||||
{
|
||||
int i;
|
||||
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++)
|
||||
{
|
||||
if (!gdGetByte (&im->red[i], in))
|
||||
{
|
||||
goto fail1;
|
||||
}
|
||||
if (!gdGetByte (&im->green[i], in))
|
||||
{
|
||||
goto fail1;
|
||||
}
|
||||
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++)
|
||||
{
|
||||
im->open[i] = 0;
|
||||
};
|
||||
|
||||
return TRUE;
|
||||
fail1:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* Use the common basic header info to make the image object. */
|
||||
/* This is also called from _gd2CreateFromFile */
|
||||
/* */
|
||||
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;
|
||||
}
|
||||
|
||||
GD2_DBG (printf ("Image is %dx%d\n", *sx, *sy));
|
||||
|
||||
im = gdImageCreate (*sx, *sy);
|
||||
|
||||
if (!_gdGetColors (in, im, gd2xFlag))
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
return im;
|
||||
fail2:
|
||||
gdImageDestroy (im);
|
||||
fail1:
|
||||
return 0;
|
||||
}
|
||||
|
||||
gdImagePtr
|
||||
gdImageCreateFromGd (FILE * inFile)
|
||||
{
|
||||
gdImagePtr im;
|
||||
gdIOCtx *in;
|
||||
|
||||
in = gdNewFileCtx (inFile);
|
||||
im = gdImageCreateFromGdCtx (in);
|
||||
|
||||
in->free (in);
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
gdImagePtr
|
||||
gdImageCreateFromGdCtx (gdIOCtxPtr in)
|
||||
{
|
||||
int sx, sy;
|
||||
int x, y;
|
||||
gdImagePtr im;
|
||||
|
||||
/* Read the header */
|
||||
im = _gdCreateFromFile (in, &sx, &sy);
|
||||
|
||||
if (im == NULL)
|
||||
{
|
||||
goto fail1;
|
||||
};
|
||||
|
||||
/* Then the data... */
|
||||
for (y = 0; (y < sy); y++)
|
||||
{
|
||||
for (x = 0; (x < sx); x++)
|
||||
{
|
||||
int ch;
|
||||
ch = gdGetC (in);
|
||||
if (ch == EOF)
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
/* ROW-MAJOR IN GD 1.3 */
|
||||
im->pixels[y][x] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
return im;
|
||||
|
||||
fail2:
|
||||
gdImageDestroy (im);
|
||||
fail1:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
_gdPutColors (gdImagePtr im, gdIOCtx * out)
|
||||
{
|
||||
int i;
|
||||
int trans;
|
||||
|
||||
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);
|
||||
|
||||
_gdPutColors (im, out);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
_gdImageGd (gdImagePtr im, gdIOCtx * out)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
_gdPutHeader (im, out);
|
||||
|
||||
for (y = 0; (y < im->sy); y++)
|
||||
{
|
||||
for (x = 0; (x < im->sx); x++)
|
||||
{
|
||||
/* ROW-MAJOR IN GD 1.3 */
|
||||
if (im->trueColor)
|
||||
{
|
||||
gdPutInt (im->tpixels[y][x], out);
|
||||
}
|
||||
else
|
||||
{
|
||||
gdPutC ((unsigned char) im->pixels[y][x], out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gdImageGd (gdImagePtr im, FILE * outFile)
|
||||
{
|
||||
gdIOCtx *out = gdNewFileCtx (outFile);
|
||||
_gdImageGd (im, out);
|
||||
out->free (out);
|
||||
}
|
||||
|
||||
void *
|
||||
gdImageGdPtr (gdImagePtr im, int *size)
|
||||
{
|
||||
void *rv;
|
||||
gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
|
||||
_gdImageGd (im, out);
|
||||
rv = gdDPExtractData (out, size);
|
||||
out->free (out);
|
||||
return rv;
|
||||
}
|
923
ext/gd/libgd/gd_gd2.c
Normal file
923
ext/gd/libgd/gd_gd2.c
Normal file
@ -0,0 +1,923 @@
|
||||
/*
|
||||
* gd_gd2.c
|
||||
*
|
||||
* Implements the I/O and support for the GD2 format.
|
||||
*
|
||||
* Changing the definition of GD2_DBG (below) will cause copious messages
|
||||
* to be displayed while it processes requests.
|
||||
*
|
||||
* Designed, Written & Copyright 1999, Philip Warner.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <zlib.h>
|
||||
#include "gd.h"
|
||||
#include "gdhelpers.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/* Use this for commenting out debug-print statements. */
|
||||
/* Just use the first '#define' to allow all the prints... */
|
||||
/*#define GD2_DBG(s) (s) */
|
||||
#define GD2_DBG(s)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int offset;
|
||||
int size;
|
||||
}
|
||||
t_chunk_info;
|
||||
|
||||
extern int _gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag);
|
||||
extern void _gdPutColors (gdImagePtr im, gdIOCtx * out);
|
||||
|
||||
/* */
|
||||
/* Read the extra info in the gd2 header. */
|
||||
/* */
|
||||
static
|
||||
int
|
||||
_gd2GetHeader (gdIOCtxPtr in, int *sx, int *sy,
|
||||
int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** chunkIdx)
|
||||
{
|
||||
int i;
|
||||
int ch;
|
||||
char id[5];
|
||||
t_chunk_info *cidx;
|
||||
int sidx;
|
||||
int nc;
|
||||
|
||||
GD2_DBG (printf ("Reading gd2 header info\n"));
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
ch = gdGetC (in);
|
||||
if (ch == EOF)
|
||||
{
|
||||
goto fail1;
|
||||
};
|
||||
id[i] = ch;
|
||||
};
|
||||
id[4] = 0;
|
||||
|
||||
GD2_DBG (printf ("Got file code: %s\n", id));
|
||||
|
||||
/* Equiv. of 'magick'. */
|
||||
if (strcmp (id, GD2_ID) != 0)
|
||||
{
|
||||
GD2_DBG (printf ("Not a valid gd2 file\n"));
|
||||
goto fail1;
|
||||
};
|
||||
|
||||
/* Version */
|
||||
if (gdGetWord (vers, in) != 1)
|
||||
{
|
||||
goto fail1;
|
||||
};
|
||||
GD2_DBG (printf ("Version: %d\n", *vers));
|
||||
|
||||
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"));
|
||||
goto fail1;
|
||||
}
|
||||
if (!gdGetWord (sy, in))
|
||||
{
|
||||
GD2_DBG (printf ("Could not get y-size\n"));
|
||||
goto fail1;
|
||||
}
|
||||
GD2_DBG (printf ("Image is %dx%d\n", *sx, *sy));
|
||||
|
||||
/* Chunk Size (pixels, not bytes!) */
|
||||
if (gdGetWord (cs, in) != 1)
|
||||
{
|
||||
goto fail1;
|
||||
};
|
||||
GD2_DBG (printf ("ChunkSize: %d\n", *cs));
|
||||
|
||||
if ((*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX))
|
||||
{
|
||||
GD2_DBG (printf ("Bad chunk size: %d\n", *cs));
|
||||
goto fail1;
|
||||
};
|
||||
|
||||
/* Data Format */
|
||||
if (gdGetWord (fmt, in) != 1)
|
||||
{
|
||||
goto fail1;
|
||||
};
|
||||
GD2_DBG (printf ("Format: %d\n", *fmt));
|
||||
|
||||
if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED))
|
||||
{
|
||||
GD2_DBG (printf ("Bad data format: %d\n", *fmt));
|
||||
goto fail1;
|
||||
};
|
||||
|
||||
|
||||
/* # of chunks wide */
|
||||
if (gdGetWord (ncx, in) != 1)
|
||||
{
|
||||
goto fail1;
|
||||
};
|
||||
GD2_DBG (printf ("%d Chunks Wide\n", *ncx));
|
||||
|
||||
/* # of chunks high */
|
||||
if (gdGetWord (ncy, in) != 1)
|
||||
{
|
||||
goto fail1;
|
||||
};
|
||||
GD2_DBG (printf ("%d Chunks vertically\n", *ncy));
|
||||
|
||||
if ((*fmt) == GD2_FMT_COMPRESSED)
|
||||
{
|
||||
nc = (*ncx) * (*ncy);
|
||||
GD2_DBG (printf ("Reading %d chunk index entries\n", nc));
|
||||
sidx = sizeof (t_chunk_info) * nc;
|
||||
cidx = gdCalloc (sidx, 1);
|
||||
for (i = 0; i < nc; i++)
|
||||
{
|
||||
if (gdGetInt (&cidx[i].offset, in) != 1)
|
||||
{
|
||||
goto fail1;
|
||||
};
|
||||
if (gdGetInt (&cidx[i].size, in) != 1)
|
||||
{
|
||||
goto fail1;
|
||||
};
|
||||
};
|
||||
*chunkIdx = cidx;
|
||||
};
|
||||
|
||||
GD2_DBG (printf ("gd2 header complete\n"));
|
||||
|
||||
return 1;
|
||||
|
||||
fail1:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
gdImagePtr
|
||||
_gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy,
|
||||
int *cs, int *vers, int *fmt,
|
||||
int *ncx, int *ncy, t_chunk_info ** cidx)
|
||||
{
|
||||
gdImagePtr im;
|
||||
|
||||
if (_gd2GetHeader (in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1)
|
||||
{
|
||||
GD2_DBG (printf ("Bad GD2 header\n"));
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
im = gdImageCreate (*sx, *sy);
|
||||
if (im == NULL)
|
||||
{
|
||||
GD2_DBG (printf ("Could not create gdImage\n"));
|
||||
goto fail1;
|
||||
};
|
||||
|
||||
if (!_gdGetColors (in, im, (*vers) == 2))
|
||||
{
|
||||
GD2_DBG (printf ("Could not read color palette\n"));
|
||||
goto fail2;
|
||||
}
|
||||
GD2_DBG (printf ("Image palette completed: %d colours\n", im->colorsTotal));
|
||||
|
||||
return im;
|
||||
|
||||
fail2:
|
||||
gdImageDestroy (im);
|
||||
return 0;
|
||||
|
||||
fail1:
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_gd2ReadChunk (int offset, char *compBuf, int compSize, char *chunkBuf, uLongf * chunkLen, gdIOCtx * in)
|
||||
{
|
||||
int zerr;
|
||||
|
||||
if (gdTell (in) != offset)
|
||||
{
|
||||
GD2_DBG (printf ("Positioning in file to %d\n", offset));
|
||||
gdSeek (in, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
GD2_DBG (printf ("Already Positioned in file to %d\n", offset));
|
||||
};
|
||||
|
||||
/* Read and uncompress an entire chunk. */
|
||||
GD2_DBG (printf ("Reading file\n"));
|
||||
if (gdGetBuf (compBuf, compSize, in) != compSize)
|
||||
{
|
||||
return FALSE;
|
||||
};
|
||||
GD2_DBG (printf ("Got %d bytes. Uncompressing into buffer of %d bytes\n", compSize, *chunkLen));
|
||||
zerr = uncompress ((unsigned char *) chunkBuf, chunkLen,
|
||||
(unsigned char *) compBuf, compSize);
|
||||
if (zerr != Z_OK)
|
||||
{
|
||||
GD2_DBG (printf ("Error %d from uncompress\n", zerr));
|
||||
return FALSE;
|
||||
};
|
||||
GD2_DBG (printf ("Got chunk\n"));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gdImagePtr
|
||||
gdImageCreateFromGd2 (FILE * inFile)
|
||||
{
|
||||
gdIOCtx *in = gdNewFileCtx (inFile);
|
||||
gdImagePtr im;
|
||||
|
||||
im = gdImageCreateFromGd2Ctx (in);
|
||||
|
||||
in->free (in);
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
gdImagePtr
|
||||
gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
|
||||
{
|
||||
int sx, sy;
|
||||
int i;
|
||||
int ncx, ncy, nc, cs, cx, cy;
|
||||
int x, y, ylo, yhi, xlo, xhi;
|
||||
int ch, vers, fmt;
|
||||
t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */
|
||||
unsigned char *chunkBuf = NULL; /* So we can gdFree it with impunity. */
|
||||
int chunkNum = 0;
|
||||
int chunkMax;
|
||||
uLongf chunkLen;
|
||||
int chunkPos;
|
||||
int compMax;
|
||||
int bytesPerPixel;
|
||||
char *compBuf = NULL; /* So we can gdFree it with impunity. */
|
||||
|
||||
gdImagePtr im;
|
||||
|
||||
/* Get the header */
|
||||
im = _gd2CreateFromFile (in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx);
|
||||
|
||||
if (im == NULL)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
bytesPerPixel = im->trueColor ? 4 : 1;
|
||||
nc = ncx * ncy;
|
||||
|
||||
if (fmt == GD2_FMT_COMPRESSED)
|
||||
{
|
||||
/* Find the maximum compressed chunk size. */
|
||||
compMax = 0;
|
||||
for (i = 0; (i < nc); i++)
|
||||
{
|
||||
if (chunkIdx[i].size > compMax)
|
||||
{
|
||||
compMax = chunkIdx[i].size;
|
||||
};
|
||||
};
|
||||
compMax++;
|
||||
|
||||
/* Allocate buffers */
|
||||
chunkMax = cs * bytesPerPixel * cs;
|
||||
chunkBuf = gdCalloc (chunkMax, 1);
|
||||
compBuf = gdCalloc (compMax, 1);
|
||||
GD2_DBG (printf ("Largest compressed chunk is %d bytes\n", compMax));
|
||||
};
|
||||
|
||||
/* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
|
||||
/* goto fail2; */
|
||||
/* }; */
|
||||
|
||||
/* Read the data... */
|
||||
for (cy = 0; (cy < ncy); cy++)
|
||||
{
|
||||
for (cx = 0; (cx < ncx); cx++)
|
||||
{
|
||||
|
||||
ylo = cy * cs;
|
||||
yhi = ylo + cs;
|
||||
if (yhi > im->sy)
|
||||
{
|
||||
yhi = im->sy;
|
||||
};
|
||||
|
||||
GD2_DBG (printf ("Processing Chunk %d (%d, %d), y from %d to %d\n", chunkNum, cx, cy, ylo, yhi));
|
||||
|
||||
if (fmt == GD2_FMT_COMPRESSED)
|
||||
{
|
||||
|
||||
chunkLen = chunkMax;
|
||||
|
||||
if (!_gd2ReadChunk (chunkIdx[chunkNum].offset,
|
||||
compBuf,
|
||||
chunkIdx[chunkNum].size,
|
||||
chunkBuf, &chunkLen, in))
|
||||
{
|
||||
GD2_DBG (printf ("Error reading comproessed chunk\n"));
|
||||
goto fail2;
|
||||
};
|
||||
|
||||
chunkPos = 0;
|
||||
};
|
||||
|
||||
for (y = ylo; (y < yhi); y++)
|
||||
{
|
||||
|
||||
xlo = cx * cs;
|
||||
xhi = xlo + cs;
|
||||
if (xhi > im->sx)
|
||||
{
|
||||
xhi = im->sx;
|
||||
};
|
||||
/*GD2_DBG(printf("y=%d: ",y)); */
|
||||
if (fmt == GD2_FMT_RAW)
|
||||
{
|
||||
for (x = xlo; x < xhi; x++)
|
||||
{
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (x = xlo; x < xhi; x++)
|
||||
{
|
||||
if (im->trueColor)
|
||||
{
|
||||
/* 2.0.1: work around a gcc bug by being verbose.
|
||||
TBB */
|
||||
int a = chunkBuf[chunkPos++] << 24;
|
||||
int r = chunkBuf[chunkPos++] << 16;
|
||||
int g = chunkBuf[chunkPos++] << 8;
|
||||
int b = chunkBuf[chunkPos++];
|
||||
im->pixels[y][x] = a + r + g + b;
|
||||
}
|
||||
else
|
||||
{
|
||||
im->pixels[y][x] = chunkBuf[chunkPos++];
|
||||
}
|
||||
};
|
||||
};
|
||||
/*GD2_DBG(printf("\n")); */
|
||||
};
|
||||
chunkNum++;
|
||||
};
|
||||
};
|
||||
|
||||
GD2_DBG (printf ("Freeing memory\n"));
|
||||
|
||||
gdFree (chunkBuf);
|
||||
gdFree (compBuf);
|
||||
gdFree (chunkIdx);
|
||||
|
||||
GD2_DBG (printf ("Done\n"));
|
||||
|
||||
return im;
|
||||
|
||||
fail2:
|
||||
gdImageDestroy (im);
|
||||
gdFree (chunkBuf);
|
||||
gdFree (compBuf);
|
||||
gdFree (chunkIdx);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
gdImagePtr
|
||||
gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h)
|
||||
{
|
||||
gdImagePtr im;
|
||||
gdIOCtx *in = gdNewFileCtx (inFile);
|
||||
|
||||
im = gdImageCreateFromGd2PartCtx (in, srcx, srcy, w, h);
|
||||
|
||||
in->free (in);
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
gdImagePtr
|
||||
gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h)
|
||||
{
|
||||
int scx, scy, ecx, ecy, fsx, fsy;
|
||||
int nc, ncx, ncy, cs, cx, cy;
|
||||
int x, y, ylo, yhi, xlo, xhi;
|
||||
int dstart, dpos;
|
||||
int i;
|
||||
int ch, vers, fmt;
|
||||
t_chunk_info *chunkIdx = NULL;
|
||||
char *chunkBuf = NULL;
|
||||
int chunkNum;
|
||||
int chunkMax;
|
||||
uLongf chunkLen;
|
||||
int chunkPos;
|
||||
int compMax;
|
||||
char *compBuf = NULL;
|
||||
|
||||
gdImagePtr im;
|
||||
|
||||
/* */
|
||||
/* The next few lines are basically copied from gd2CreateFromFile */
|
||||
/* - we change the file size, so don't want to use the code directly. */
|
||||
/* but we do need to know the file size. */
|
||||
/* */
|
||||
if (_gd2GetHeader (in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx) != 1)
|
||||
{
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
GD2_DBG (printf ("File size is %dx%d\n", fsx, fsy));
|
||||
|
||||
/* This is the difference - make a file based on size of chunks. */
|
||||
im = gdImageCreate (w, h);
|
||||
if (im == NULL)
|
||||
{
|
||||
goto fail1;
|
||||
};
|
||||
|
||||
if (!_gdGetColors (in, im, vers == 2))
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
GD2_DBG (printf ("Image palette completed: %d colours\n", im->colorsTotal));
|
||||
|
||||
/* Process the header info */
|
||||
nc = ncx * ncy;
|
||||
|
||||
if (fmt == GD2_FMT_COMPRESSED)
|
||||
{
|
||||
/* Find the maximum compressed chunk size. */
|
||||
compMax = 0;
|
||||
for (i = 0; (i < nc); i++)
|
||||
{
|
||||
if (chunkIdx[i].size > compMax)
|
||||
{
|
||||
compMax = chunkIdx[i].size;
|
||||
};
|
||||
};
|
||||
compMax++;
|
||||
|
||||
if (im->trueColor)
|
||||
{
|
||||
chunkMax = cs * cs * 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
chunkMax = cs * cs;
|
||||
}
|
||||
chunkBuf = gdCalloc (chunkMax, 1);
|
||||
compBuf = gdCalloc (compMax, 1);
|
||||
};
|
||||
|
||||
/* Don't bother with this... */
|
||||
/* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
|
||||
/* goto fail2; */
|
||||
/* }; */
|
||||
|
||||
|
||||
/* Work out start/end chunks */
|
||||
scx = srcx / cs;
|
||||
scy = srcy / cs;
|
||||
if (scx < 0)
|
||||
{
|
||||
scx = 0;
|
||||
};
|
||||
if (scy < 0)
|
||||
{
|
||||
scy = 0;
|
||||
};
|
||||
|
||||
ecx = (srcx + w) / cs;
|
||||
ecy = (srcy + h) / cs;
|
||||
if (ecx >= ncx)
|
||||
{
|
||||
ecx = ncx - 1;
|
||||
};
|
||||
if (ecy >= ncy)
|
||||
{
|
||||
ecy = ncy - 1;
|
||||
};
|
||||
|
||||
/* Remember file position of image data. */
|
||||
dstart = gdTell (in);
|
||||
GD2_DBG (printf ("Data starts at %d\n", dstart));
|
||||
|
||||
/* Loop through the chunks. */
|
||||
for (cy = scy; (cy <= ecy); cy++)
|
||||
{
|
||||
|
||||
ylo = cy * cs;
|
||||
yhi = ylo + cs;
|
||||
if (yhi > fsy)
|
||||
{
|
||||
yhi = fsy;
|
||||
};
|
||||
|
||||
for (cx = scx; (cx <= ecx); cx++)
|
||||
{
|
||||
|
||||
xlo = cx * cs;
|
||||
xhi = xlo + cs;
|
||||
if (xhi > fsx)
|
||||
{
|
||||
xhi = fsx;
|
||||
};
|
||||
|
||||
GD2_DBG (printf ("Processing Chunk (%d, %d), from %d to %d\n", cx, cy, ylo, yhi));
|
||||
|
||||
if (fmt == GD2_FMT_RAW)
|
||||
{
|
||||
GD2_DBG (printf ("Using raw format data\n"));
|
||||
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);
|
||||
goto fail2;
|
||||
};
|
||||
GD2_DBG (printf ("Reading (%d, %d) from position %d\n", cx, cy, dpos - dstart));
|
||||
}
|
||||
else
|
||||
{
|
||||
chunkNum = cx + cy * ncx;
|
||||
|
||||
chunkLen = chunkMax;
|
||||
if (!_gd2ReadChunk (chunkIdx[chunkNum].offset,
|
||||
compBuf,
|
||||
chunkIdx[chunkNum].size,
|
||||
chunkBuf, &chunkLen, in))
|
||||
{
|
||||
printf ("Error reading comproessed chunk\n");
|
||||
goto fail2;
|
||||
};
|
||||
chunkPos = 0;
|
||||
GD2_DBG (printf ("Reading (%d, %d) from chunk %d\n", cx, cy, chunkNum));
|
||||
};
|
||||
|
||||
GD2_DBG (printf (" into (%d, %d) - (%d, %d)\n", xlo, ylo, xhi, yhi));
|
||||
for (y = ylo; (y < yhi); y++)
|
||||
{
|
||||
|
||||
for (x = xlo; x < xhi; x++)
|
||||
{
|
||||
if (fmt == GD2_FMT_RAW)
|
||||
{
|
||||
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
|
||||
{
|
||||
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. */
|
||||
if ((x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0)
|
||||
&& (y >= srcy) && (y < (srcy + h)) && (y < fsy) && (y >= 0)
|
||||
)
|
||||
{
|
||||
im->pixels[y - srcy][x - srcx] = ch;
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
gdFree (chunkBuf);
|
||||
gdFree (compBuf);
|
||||
gdFree (chunkIdx);
|
||||
|
||||
return im;
|
||||
|
||||
fail2:
|
||||
gdImageDestroy (im);
|
||||
fail1:
|
||||
gdFree (chunkBuf);
|
||||
gdFree (compBuf);
|
||||
gdFree (chunkIdx);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_gd2PutHeader (gdImagePtr im, gdIOCtx * out, int cs, int fmt, int cx, int cy)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Send the gd2 id, to verify file format. */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
gdPutC ((unsigned char) (GD2_ID[i]), out);
|
||||
};
|
||||
|
||||
/* */
|
||||
/* We put the version info first, so future versions can easily change header info. */
|
||||
/* */
|
||||
gdPutWord (GD2_VERS, out);
|
||||
gdPutWord (im->sx, out);
|
||||
gdPutWord (im->sy, out);
|
||||
gdPutWord (cs, out);
|
||||
gdPutWord (fmt, out);
|
||||
gdPutWord (cx, out);
|
||||
gdPutWord (cy, out);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
_gdImageGd2 (gdImagePtr im, gdIOCtx * out, int cs, int fmt)
|
||||
{
|
||||
int ncx, ncy, cx, cy;
|
||||
int x, y, ylo, yhi, xlo, xhi;
|
||||
int chunkLen;
|
||||
int chunkNum = 0;
|
||||
char *chunkData = NULL; /* So we can gdFree it with impunity. */
|
||||
char *compData = NULL; /* So we can gdFree it with impunity. */
|
||||
uLongf compLen;
|
||||
int idxPos;
|
||||
int idxSize;
|
||||
t_chunk_info *chunkIdx = NULL;
|
||||
int posSave;
|
||||
int bytesPerPixel = im->trueColor ? 4 : 1;
|
||||
int compMax;
|
||||
|
||||
/*printf("Trying to write GD2 file\n"); */
|
||||
|
||||
/* */
|
||||
/* Force fmt to a valid value since we don't return anything. */
|
||||
/* */
|
||||
if ((fmt == 0) || ((fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED)))
|
||||
{
|
||||
fmt = GD2_FMT_COMPRESSED;
|
||||
};
|
||||
|
||||
/* */
|
||||
/* Make sure chunk size is valid. These are arbitrary values; 64 because it seems */
|
||||
/* a little silly to expect performance improvements on a 64x64 bit scale, and */
|
||||
/* 4096 because we buffer one chunk, and a 16MB buffer seems a little largei - it may be */
|
||||
/* OK for one user, but for another to read it, they require the buffer. */
|
||||
/* */
|
||||
if (cs == 0)
|
||||
{
|
||||
cs = GD2_CHUNKSIZE;
|
||||
}
|
||||
else if (cs < GD2_CHUNKSIZE_MIN)
|
||||
{
|
||||
cs = GD2_CHUNKSIZE_MIN;
|
||||
}
|
||||
else if (cs > GD2_CHUNKSIZE_MAX)
|
||||
{
|
||||
cs = GD2_CHUNKSIZE_MAX;
|
||||
};
|
||||
|
||||
/* Work out number of chunks. */
|
||||
ncx = im->sx / cs + 1;
|
||||
ncy = im->sy / cs + 1;
|
||||
|
||||
/* Write the standard header. */
|
||||
_gd2PutHeader (im, out, cs, fmt, ncx, ncy);
|
||||
|
||||
if (fmt == GD2_FMT_COMPRESSED)
|
||||
{
|
||||
/* */
|
||||
/* Work out size of buffer for compressed data, If CHUNKSIZE is large, */
|
||||
/* then these will be large! */
|
||||
/* */
|
||||
/* The zlib notes say output buffer size should be (input size) * 1.01 * 12 */
|
||||
/* - we'll use 1.02 to be paranoid. */
|
||||
/* */
|
||||
compMax = cs * bytesPerPixel * cs * 1.02 + 12;
|
||||
|
||||
/* */
|
||||
/* Allocate the buffers. */
|
||||
/* */
|
||||
chunkData = gdCalloc (cs * bytesPerPixel * cs, 1);
|
||||
compData = gdCalloc (compMax, 1);
|
||||
|
||||
/* */
|
||||
/* Save the file position of chunk index, and allocate enough space for */
|
||||
/* each chunk_info block . */
|
||||
/* */
|
||||
idxPos = gdTell (out);
|
||||
idxSize = ncx * ncy * sizeof (t_chunk_info);
|
||||
GD2_DBG (printf ("Index size is %d\n", idxSize));
|
||||
gdSeek (out, idxPos + idxSize);
|
||||
|
||||
chunkIdx = gdCalloc (idxSize * sizeof (t_chunk_info), 1);
|
||||
};
|
||||
|
||||
_gdPutColors (im, out);
|
||||
|
||||
GD2_DBG (printf ("Size: %dx%d\n", im->sx, im->sy));
|
||||
GD2_DBG (printf ("Chunks: %dx%d\n", ncx, ncy));
|
||||
|
||||
for (cy = 0; (cy < ncy); cy++)
|
||||
{
|
||||
for (cx = 0; (cx < ncx); cx++)
|
||||
{
|
||||
|
||||
ylo = cy * cs;
|
||||
yhi = ylo + cs;
|
||||
if (yhi > im->sy)
|
||||
{
|
||||
yhi = im->sy;
|
||||
};
|
||||
|
||||
GD2_DBG (printf ("Processing Chunk (%dx%d), y from %d to %d\n", cx, cy, ylo, yhi));
|
||||
chunkLen = 0;
|
||||
for (y = ylo; (y < yhi); y++)
|
||||
{
|
||||
|
||||
/*GD2_DBG(printf("y=%d: ",y)); */
|
||||
|
||||
xlo = cx * cs;
|
||||
xhi = xlo + cs;
|
||||
if (xhi > im->sx)
|
||||
{
|
||||
xhi = im->sx;
|
||||
};
|
||||
|
||||
if (fmt == GD2_FMT_COMPRESSED)
|
||||
{
|
||||
for (x = xlo; x < xhi; x++)
|
||||
{
|
||||
int p = im->pixels[y][x];
|
||||
/*GD2_DBG(printf("%d...",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)); */
|
||||
|
||||
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)); */
|
||||
};
|
||||
if (fmt == GD2_FMT_COMPRESSED)
|
||||
{
|
||||
compLen = compMax;
|
||||
if (compress ((unsigned char *)
|
||||
&compData[0], &compLen,
|
||||
(unsigned char *) &chunkData[0],
|
||||
chunkLen) != Z_OK)
|
||||
{
|
||||
printf ("Error from compressing\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
chunkIdx[chunkNum].offset = gdTell (out);
|
||||
chunkIdx[chunkNum++].size = compLen;
|
||||
GD2_DBG (printf ("Chunk %d size %d offset %d\n", chunkNum, chunkIdx[chunkNum - 1].size, chunkIdx[chunkNum - 1].offset));
|
||||
|
||||
if (gdPutBuf (compData, compLen, out) <= 0)
|
||||
{
|
||||
/* Any alternate suggestions for handling this? */
|
||||
printf ("Error %d on write\n", errno);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (fmt == GD2_FMT_COMPRESSED)
|
||||
{
|
||||
/* Save the position, write the index, restore position (paranoia). */
|
||||
GD2_DBG (printf ("Seeking %d to write index\n", idxPos));
|
||||
posSave = gdTell (out);
|
||||
gdSeek (out, idxPos);
|
||||
GD2_DBG (printf ("Writing index\n"));
|
||||
for (x = 0; x < chunkNum; x++)
|
||||
{
|
||||
GD2_DBG (printf ("Chunk %d size %d offset %d\n", x, chunkIdx[x].size, chunkIdx[x].offset));
|
||||
gdPutInt (chunkIdx[x].offset, out);
|
||||
gdPutInt (chunkIdx[x].size, out);
|
||||
};
|
||||
/* We don't use fwrite for *endian reasons. */
|
||||
/*fwrite(chunkIdx, sizeof(int)*2, chunkNum, out); */
|
||||
gdSeek (out, posSave);
|
||||
};
|
||||
|
||||
GD2_DBG (printf ("Freeing memory\n"));
|
||||
gdFree (chunkData);
|
||||
gdFree (compData);
|
||||
gdFree (chunkIdx);
|
||||
GD2_DBG (printf ("Done\n"));
|
||||
|
||||
/*printf("Memory block size is %d\n",gdTell(out)); */
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt)
|
||||
{
|
||||
gdIOCtx *out = gdNewFileCtx (outFile);
|
||||
_gdImageGd2 (im, out, cs, fmt);
|
||||
out->free (out);
|
||||
}
|
||||
|
||||
void *
|
||||
gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size)
|
||||
{
|
||||
void *rv;
|
||||
gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
|
||||
_gdImageGd2 (im, out, cs, fmt);
|
||||
rv = gdDPExtractData (out, size);
|
||||
out->free (out);
|
||||
return rv;
|
||||
}
|
175
ext/gd/libgd/gd_io.c
Normal file
175
ext/gd/libgd/gd_io.c
Normal file
@ -0,0 +1,175 @@
|
||||
|
||||
|
||||
/*
|
||||
* io.c
|
||||
*
|
||||
* Implements the imple I/O 'helper' routines.
|
||||
*
|
||||
* Not really essential, but these routines were used extensively in GD,
|
||||
* so they were moved here. They also make IOCtx calls look better...
|
||||
*
|
||||
* Written (or, at least, moved) 1999, Philip Warner.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "gd.h"
|
||||
|
||||
/* Use this for commenting out debug-print statements. */
|
||||
/* Just use the first '#define' to allow all the prints... */
|
||||
/*#define IO_DBG(s) (s) */
|
||||
#define IO_DBG(s)
|
||||
|
||||
|
||||
/*
|
||||
* Write out a word to the I/O context pointer
|
||||
*/
|
||||
void
|
||||
Putword (int w, gdIOCtx * ctx)
|
||||
{
|
||||
unsigned char buf[2];
|
||||
buf[0] = w & 0xff;
|
||||
buf[1] = (w / 256) & 0xff;
|
||||
(ctx->putBuf) (ctx, (char *) buf, 2);
|
||||
}
|
||||
|
||||
void
|
||||
Putchar (int c, gdIOCtx * ctx)
|
||||
{
|
||||
(ctx->putC) (ctx, c & 0xff);
|
||||
}
|
||||
|
||||
void
|
||||
gdPutC (const unsigned char c, gdIOCtx * ctx)
|
||||
{
|
||||
(ctx->putC) (ctx, c);
|
||||
}
|
||||
|
||||
void
|
||||
gdPutWord (int w, gdIOCtx * ctx)
|
||||
{
|
||||
IO_DBG (printf ("Putting word...\n"));
|
||||
(ctx->putC) (ctx, (unsigned char) (w >> 8));
|
||||
(ctx->putC) (ctx, (unsigned char) (w & 0xFF));
|
||||
IO_DBG (printf ("put.\n"));
|
||||
}
|
||||
|
||||
void
|
||||
gdPutInt (int w, gdIOCtx * ctx)
|
||||
{
|
||||
IO_DBG (printf ("Putting int...\n"));
|
||||
(ctx->putC) (ctx, (unsigned char) (w >> 24));
|
||||
(ctx->putC) (ctx, (unsigned char) ((w >> 16) & 0xFF));
|
||||
(ctx->putC) (ctx, (unsigned char) ((w >> 8) & 0xFF));
|
||||
(ctx->putC) (ctx, (unsigned char) (w & 0xFF));
|
||||
IO_DBG (printf ("put.\n"));
|
||||
}
|
||||
|
||||
int
|
||||
gdGetC (gdIOCtx * ctx)
|
||||
{
|
||||
return ((ctx->getC) (ctx));
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
gdGetByte (int *result, gdIOCtx * ctx)
|
||||
{
|
||||
int r;
|
||||
r = (ctx->getC) (ctx);
|
||||
if (r == EOF)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*result = r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
gdGetWord (int *result, gdIOCtx * ctx)
|
||||
{
|
||||
int r;
|
||||
r = (ctx->getC) (ctx);
|
||||
if (r == EOF)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*result = r << 8;
|
||||
r = (ctx->getC) (ctx);
|
||||
if (r == EOF)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*result += r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gdGetInt (int *result, gdIOCtx * ctx)
|
||||
{
|
||||
int r;
|
||||
r = (ctx->getC) (ctx);
|
||||
if (r == EOF)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*result = r << 24;
|
||||
|
||||
r = (ctx->getC) (ctx);
|
||||
if (r == EOF)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*result += r << 16;
|
||||
|
||||
r = (ctx->getC) (ctx);
|
||||
if (r == EOF)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*result += r << 8;
|
||||
|
||||
r = (ctx->getC) (ctx);
|
||||
if (r == EOF)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*result += r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
gdPutBuf (const void *buf, int size, gdIOCtx * ctx)
|
||||
{
|
||||
IO_DBG (printf ("Putting buf...\n"));
|
||||
return (ctx->putBuf) (ctx, buf, size);
|
||||
IO_DBG (printf ("put.\n"));
|
||||
}
|
||||
|
||||
int
|
||||
gdGetBuf (void *buf, int size, gdIOCtx * ctx)
|
||||
{
|
||||
return (ctx->getBuf) (ctx, buf, size);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gdSeek (gdIOCtx * ctx, const int pos)
|
||||
{
|
||||
IO_DBG (printf ("Seeking...\n"));
|
||||
return ((ctx->seek) (ctx, pos));
|
||||
IO_DBG (printf ("Done.\n"));
|
||||
}
|
||||
|
||||
long
|
||||
gdTell (gdIOCtx * ctx)
|
||||
{
|
||||
IO_DBG (printf ("Telling...\n"));
|
||||
return ((ctx->tell) (ctx));
|
||||
IO_DBG (printf ("told.\n"));
|
||||
}
|
39
ext/gd/libgd/gd_io.h
Normal file
39
ext/gd/libgd/gd_io.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef GD_IO_H
|
||||
#define GD_IO_H 1
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct gdIOCtx {
|
||||
int (*getC)(struct gdIOCtx*);
|
||||
int (*getBuf)(struct gdIOCtx*, void*, int);
|
||||
|
||||
void (*putC)(struct gdIOCtx*, int);
|
||||
int (*putBuf)(struct gdIOCtx*, const void*, int);
|
||||
|
||||
int (*seek)(struct gdIOCtx*, const int);
|
||||
long (*tell)(struct gdIOCtx*);
|
||||
|
||||
void (*free)(struct gdIOCtx*);
|
||||
|
||||
} gdIOCtx;
|
||||
|
||||
typedef struct gdIOCtx *gdIOCtxPtr;
|
||||
|
||||
void Putword(int w, gdIOCtx *ctx);
|
||||
void Putchar(int c, gdIOCtx *ctx);
|
||||
|
||||
void gdPutC(const unsigned char c, gdIOCtx *ctx);
|
||||
int gdPutBuf(const void *, int, gdIOCtx*);
|
||||
void gdPutWord(int w, gdIOCtx *ctx);
|
||||
void gdPutInt(int w, gdIOCtx *ctx);
|
||||
|
||||
int gdGetC(gdIOCtx *ctx);
|
||||
int gdGetBuf(void *, int, gdIOCtx*);
|
||||
int gdGetByte(int *result, gdIOCtx *ctx);
|
||||
int gdGetWord(int *result, gdIOCtx *ctx);
|
||||
int gdGetInt(int *result, gdIOCtx *ctx);
|
||||
|
||||
int gdSeek(gdIOCtx *ctx, const int);
|
||||
long gdTell(gdIOCtx *ctx);
|
||||
|
||||
#endif
|
419
ext/gd/libgd/gd_io_dp.c
Normal file
419
ext/gd/libgd/gd_io_dp.c
Normal file
@ -0,0 +1,419 @@
|
||||
|
||||
/*
|
||||
* io_dp.c
|
||||
*
|
||||
* Implements the dynamic pointer interface.
|
||||
*
|
||||
* Based on GD.pm code by Lincoln Stein for interfacing to libgd.
|
||||
* Added support for reading as well as support for 'tell' and 'seek'.
|
||||
*
|
||||
* As will all I/O modules, most functions are for local use only (called
|
||||
* via function pointers in the I/O context).
|
||||
*
|
||||
* gdDPExtractData is the exception to this: it will return the pointer to
|
||||
* the internal data, and reset the internal storage.
|
||||
*
|
||||
* Written/Modified 1999, Philip Warner.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "gd.h"
|
||||
#include "gdhelpers.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/* this is used for creating images in main memory */
|
||||
typedef struct dpStruct
|
||||
{
|
||||
void *data;
|
||||
int logicalSize;
|
||||
int realSize;
|
||||
int dataGood;
|
||||
int pos;
|
||||
}
|
||||
dynamicPtr;
|
||||
|
||||
typedef struct dpIOCtx
|
||||
{
|
||||
gdIOCtx ctx;
|
||||
dynamicPtr *dp;
|
||||
}
|
||||
dpIOCtx;
|
||||
|
||||
typedef struct dpIOCtx *dpIOCtxPtr;
|
||||
|
||||
|
||||
/* these functions operate on in-memory dynamic pointers */
|
||||
static int allocDynamic (dynamicPtr * dp, int initialSize, void *data);
|
||||
static int appendDynamic (dynamicPtr * dp, const void *src, int size);
|
||||
static int gdReallocDynamic (dynamicPtr * dp, int required);
|
||||
static int trimDynamic (dynamicPtr * dp);
|
||||
static void gdFreeDynamicCtx (struct gdIOCtx *ctx);
|
||||
static dynamicPtr *newDynamic (int initialSize, void *data);
|
||||
|
||||
static int dynamicPutbuf (struct gdIOCtx *, const void *, int);
|
||||
static void dynamicPutchar (struct gdIOCtx *, int a);
|
||||
|
||||
static int dynamicGetbuf (gdIOCtxPtr ctx, void *buf, int len);
|
||||
static int dynamicGetchar (gdIOCtxPtr ctx);
|
||||
|
||||
static int dynamicSeek (struct gdIOCtx *, const int);
|
||||
static long dynamicTell (struct gdIOCtx *);
|
||||
|
||||
/* return data as a dynamic pointer */
|
||||
gdIOCtx *
|
||||
gdNewDynamicCtx (int initialSize, void *data)
|
||||
{
|
||||
dpIOCtx *ctx;
|
||||
dynamicPtr *dp;
|
||||
|
||||
ctx = (dpIOCtx *) gdMalloc (sizeof (dpIOCtx));
|
||||
if (ctx == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dp = newDynamic (initialSize, data);
|
||||
if (!dp)
|
||||
{
|
||||
gdFree (ctx);
|
||||
return NULL;
|
||||
};
|
||||
|
||||
ctx->dp = dp;
|
||||
|
||||
ctx->ctx.getC = dynamicGetchar;
|
||||
ctx->ctx.putC = dynamicPutchar;
|
||||
|
||||
ctx->ctx.getBuf = dynamicGetbuf;
|
||||
ctx->ctx.putBuf = dynamicPutbuf;
|
||||
|
||||
ctx->ctx.seek = dynamicSeek;
|
||||
ctx->ctx.tell = dynamicTell;
|
||||
|
||||
ctx->ctx.free = gdFreeDynamicCtx;
|
||||
|
||||
return (gdIOCtx *) ctx;
|
||||
}
|
||||
|
||||
void *
|
||||
gdDPExtractData (struct gdIOCtx *ctx, int *size)
|
||||
{
|
||||
dynamicPtr *dp;
|
||||
dpIOCtx *dctx;
|
||||
void *data;
|
||||
|
||||
dctx = (dpIOCtx *) ctx;
|
||||
dp = dctx->dp;
|
||||
|
||||
/* clean up the data block and return it */
|
||||
if (dp->dataGood)
|
||||
{
|
||||
trimDynamic (dp);
|
||||
*size = dp->logicalSize;
|
||||
data = dp->data;
|
||||
}
|
||||
else
|
||||
{
|
||||
*size = 0;
|
||||
data = NULL;
|
||||
if (dp->data != NULL)
|
||||
{
|
||||
gdFree (dp->data);
|
||||
}
|
||||
}
|
||||
|
||||
dp->data = NULL;
|
||||
dp->realSize = 0;
|
||||
dp->logicalSize = 0;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gdFreeDynamicCtx (struct gdIOCtx *ctx)
|
||||
{
|
||||
dynamicPtr *dp;
|
||||
dpIOCtx *dctx;
|
||||
|
||||
dctx = (dpIOCtx *) ctx;
|
||||
dp = dctx->dp;
|
||||
|
||||
gdFree (ctx);
|
||||
|
||||
/* clean up the data block and return it */
|
||||
if (dp->data != NULL)
|
||||
{
|
||||
gdFree (dp->data);
|
||||
dp->data = NULL;
|
||||
}
|
||||
|
||||
dp->realSize = 0;
|
||||
dp->logicalSize = 0;
|
||||
|
||||
gdFree (dp);
|
||||
|
||||
}
|
||||
|
||||
static long
|
||||
dynamicTell (struct gdIOCtx *ctx)
|
||||
{
|
||||
dpIOCtx *dctx;
|
||||
|
||||
dctx = (dpIOCtx *) ctx;
|
||||
return (dctx->dp->pos);
|
||||
}
|
||||
|
||||
static int
|
||||
dynamicSeek (struct gdIOCtx *ctx, const int pos)
|
||||
{
|
||||
int bytesNeeded;
|
||||
dynamicPtr *dp;
|
||||
dpIOCtx *dctx;
|
||||
|
||||
dctx = (dpIOCtx *) ctx;
|
||||
dp = dctx->dp;
|
||||
|
||||
if (!dp->dataGood)
|
||||
return FALSE;
|
||||
|
||||
bytesNeeded = pos;
|
||||
if (bytesNeeded > dp->realSize)
|
||||
{
|
||||
if (!gdReallocDynamic (dp, dp->realSize * 2))
|
||||
{
|
||||
dp->dataGood = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we get here, we can be sure that we have enough bytes
|
||||
to copy safely */
|
||||
|
||||
/* Extend the logical size if we seek beyond EOF. */
|
||||
if (pos > dp->logicalSize)
|
||||
{
|
||||
dp->logicalSize = pos;
|
||||
};
|
||||
|
||||
dp->pos = pos;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* return data as a dynamic pointer */
|
||||
static dynamicPtr *
|
||||
newDynamic (int initialSize, void *data)
|
||||
{
|
||||
dynamicPtr *dp;
|
||||
dp = (dynamicPtr *) gdMalloc (sizeof (dynamicPtr));
|
||||
if (dp == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!allocDynamic (dp, initialSize, data))
|
||||
return NULL;
|
||||
|
||||
dp->pos = 0;
|
||||
|
||||
return dp;
|
||||
}
|
||||
|
||||
static int
|
||||
dynamicPutbuf (struct gdIOCtx *ctx, const void *buf, int size)
|
||||
{
|
||||
dpIOCtx *dctx;
|
||||
dctx = (dpIOCtx *) ctx;
|
||||
|
||||
appendDynamic (dctx->dp, buf, size);
|
||||
|
||||
if (dctx->dp->dataGood)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
dynamicPutchar (struct gdIOCtx *ctx, int a)
|
||||
{
|
||||
unsigned char b;
|
||||
dpIOCtxPtr dctx;
|
||||
|
||||
b = a;
|
||||
dctx = (dpIOCtxPtr) ctx;
|
||||
|
||||
appendDynamic (dctx->dp, &b, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
dynamicGetbuf (gdIOCtxPtr ctx, void *buf, int len)
|
||||
{
|
||||
int rlen, remain;
|
||||
dpIOCtxPtr dctx;
|
||||
dynamicPtr *dp;
|
||||
|
||||
dctx = (dpIOCtxPtr) ctx;
|
||||
dp = dctx->dp;
|
||||
|
||||
remain = dp->logicalSize - dp->pos;
|
||||
if (remain >= len)
|
||||
{
|
||||
rlen = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (remain == 0)
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
rlen = remain;
|
||||
}
|
||||
|
||||
memcpy (buf, (void *) ((char *) dp->data + dp->pos), rlen);
|
||||
dp->pos += rlen;
|
||||
|
||||
return rlen;
|
||||
}
|
||||
|
||||
static int
|
||||
dynamicGetchar (gdIOCtxPtr ctx)
|
||||
{
|
||||
unsigned char b;
|
||||
int rv;
|
||||
|
||||
rv = dynamicGetbuf (ctx, &b, 1);
|
||||
|
||||
if (rv != 1)
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
return b; /* (b & 0xff); */
|
||||
}
|
||||
}
|
||||
|
||||
/* *********************************************************************
|
||||
|
||||
* InitDynamic - Return a dynamically resizable void*
|
||||
*
|
||||
* *********************************************************************
|
||||
*/
|
||||
static int
|
||||
allocDynamic (dynamicPtr * dp, int initialSize, void *data)
|
||||
{
|
||||
|
||||
if (data == NULL)
|
||||
{
|
||||
dp->logicalSize = 0;
|
||||
dp->dataGood = FALSE;
|
||||
dp->data = gdMalloc (initialSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
dp->logicalSize = initialSize;
|
||||
dp->dataGood = TRUE;
|
||||
dp->data = data;
|
||||
}
|
||||
|
||||
if (dp->data != NULL)
|
||||
{
|
||||
dp->realSize = initialSize;
|
||||
dp->dataGood = TRUE;
|
||||
dp->pos = 0;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dp->realSize = 0;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* append bytes to the end of a dynamic pointer */
|
||||
static int
|
||||
appendDynamic (dynamicPtr * dp, const void *src, int size)
|
||||
{
|
||||
int bytesNeeded;
|
||||
char *tmp;
|
||||
|
||||
if (!dp->dataGood)
|
||||
return FALSE;
|
||||
|
||||
/* bytesNeeded = dp->logicalSize + size; */
|
||||
bytesNeeded = dp->pos + size;
|
||||
|
||||
if (bytesNeeded > dp->realSize)
|
||||
{
|
||||
if (!gdReallocDynamic (dp, bytesNeeded * 2))
|
||||
{
|
||||
dp->dataGood = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we get here, we can be sure that we have enough bytes
|
||||
to copy safely */
|
||||
/*printf("Mem OK Size: %d, Pos: %d\n", dp->realSize, dp->pos); */
|
||||
|
||||
tmp = (char *) dp->data;
|
||||
memcpy ((void *) (tmp + (dp->pos)), src, size);
|
||||
dp->pos += size;
|
||||
|
||||
if (dp->pos > dp->logicalSize)
|
||||
{
|
||||
dp->logicalSize = dp->pos;
|
||||
};
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* grow (or shrink) dynamic pointer */
|
||||
static int
|
||||
gdReallocDynamic (dynamicPtr * dp, int required)
|
||||
{
|
||||
void *newPtr;
|
||||
|
||||
/* First try gdRealloc(). If that doesn't work, make a new
|
||||
memory block and copy. */
|
||||
if ((newPtr = gdRealloc (dp->data, required)))
|
||||
{
|
||||
dp->realSize = required;
|
||||
dp->data = newPtr;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* create a new pointer */
|
||||
newPtr = gdMalloc (required);
|
||||
if (!newPtr)
|
||||
{
|
||||
dp->dataGood = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* copy the old data into it */
|
||||
memcpy (newPtr, dp->data, dp->logicalSize);
|
||||
gdFree (dp->data);
|
||||
dp->data = newPtr;
|
||||
|
||||
dp->realSize = required;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* trim pointer so that its real and logical sizes match */
|
||||
static int
|
||||
trimDynamic (dynamicPtr * dp)
|
||||
{
|
||||
return gdReallocDynamic (dp, dp->logicalSize);
|
||||
}
|
145
ext/gd/libgd/gd_io_file.c
Normal file
145
ext/gd/libgd/gd_io_file.c
Normal file
@ -0,0 +1,145 @@
|
||||
|
||||
/*
|
||||
* io_file.c
|
||||
*
|
||||
* Implements the file interface.
|
||||
*
|
||||
* As will all I/O modules, most functions are for local use only (called
|
||||
* via function pointers in the I/O context).
|
||||
*
|
||||
* Most functions are just 'wrappers' for standard file functions.
|
||||
*
|
||||
* Written/Modified 1999, Philip Warner.
|
||||
*
|
||||
*/
|
||||
|
||||
/* For platforms with incomplete ANSI defines. Fortunately,
|
||||
SEEK_SET is defined to be zero by the standard. */
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif /* SEEK_SET */
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "gd.h"
|
||||
#include "gdhelpers.h"
|
||||
|
||||
/* this is used for creating images in main memory */
|
||||
|
||||
typedef struct fileIOCtx
|
||||
{
|
||||
gdIOCtx ctx;
|
||||
FILE *f;
|
||||
}
|
||||
fileIOCtx;
|
||||
|
||||
struct fileIOCtx *fileIOCtxPtr;
|
||||
|
||||
gdIOCtx *newFileCtx (FILE * f);
|
||||
|
||||
static int fileGetbuf (gdIOCtx *, void *, int);
|
||||
static int filePutbuf (gdIOCtx *, const void *, int);
|
||||
static void filePutchar (gdIOCtx *, int);
|
||||
static int fileGetchar (gdIOCtx * ctx);
|
||||
|
||||
static int fileSeek (struct gdIOCtx *, const int);
|
||||
static long fileTell (struct gdIOCtx *);
|
||||
static void gdFreeFileCtx (gdIOCtx * ctx);
|
||||
|
||||
/* return data as a dynamic pointer */
|
||||
gdIOCtx *
|
||||
gdNewFileCtx (FILE * f)
|
||||
{
|
||||
fileIOCtx *ctx;
|
||||
|
||||
ctx = (fileIOCtx *) gdMalloc (sizeof (fileIOCtx));
|
||||
if (ctx == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->f = f;
|
||||
|
||||
ctx->ctx.getC = fileGetchar;
|
||||
ctx->ctx.putC = filePutchar;
|
||||
|
||||
ctx->ctx.getBuf = fileGetbuf;
|
||||
ctx->ctx.putBuf = filePutbuf;
|
||||
|
||||
ctx->ctx.tell = fileTell;
|
||||
ctx->ctx.seek = fileSeek;
|
||||
|
||||
ctx->ctx.free = gdFreeFileCtx;
|
||||
|
||||
return (gdIOCtx *) ctx;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gdFreeFileCtx (gdIOCtx * ctx)
|
||||
{
|
||||
gdFree (ctx);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
filePutbuf (gdIOCtx * ctx, const void *buf, int size)
|
||||
{
|
||||
fileIOCtx *fctx;
|
||||
fctx = (fileIOCtx *) ctx;
|
||||
|
||||
return fwrite (buf, 1, size, fctx->f);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
fileGetbuf (gdIOCtx * ctx, void *buf, int size)
|
||||
{
|
||||
fileIOCtx *fctx;
|
||||
fctx = (fileIOCtx *) ctx;
|
||||
|
||||
return (fread (buf, 1, size, fctx->f));
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
filePutchar (gdIOCtx * ctx, int a)
|
||||
{
|
||||
unsigned char b;
|
||||
fileIOCtx *fctx;
|
||||
fctx = (fileIOCtx *) ctx;
|
||||
|
||||
b = a;
|
||||
|
||||
putc (b, fctx->f);
|
||||
}
|
||||
|
||||
static int
|
||||
fileGetchar (gdIOCtx * ctx)
|
||||
{
|
||||
fileIOCtx *fctx;
|
||||
fctx = (fileIOCtx *) ctx;
|
||||
|
||||
return getc (fctx->f);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fileSeek (struct gdIOCtx *ctx, const int pos)
|
||||
{
|
||||
fileIOCtx *fctx;
|
||||
fctx = (fileIOCtx *) ctx;
|
||||
|
||||
return (fseek (fctx->f, pos, SEEK_SET) == 0);
|
||||
}
|
||||
|
||||
static long
|
||||
fileTell (struct gdIOCtx *ctx)
|
||||
{
|
||||
fileIOCtx *fctx;
|
||||
fctx = (fileIOCtx *) ctx;
|
||||
|
||||
return ftell (fctx->f);
|
||||
}
|
165
ext/gd/libgd/gd_io_ss.c
Normal file
165
ext/gd/libgd/gd_io_ss.c
Normal file
@ -0,0 +1,165 @@
|
||||
|
||||
/*
|
||||
* io_ss.c
|
||||
*
|
||||
* Implements the Source/Sink interface.
|
||||
*
|
||||
* As will all I/O modules, most functions are for local use only (called
|
||||
* via function pointers in the I/O context).
|
||||
*
|
||||
* The Source/Sink model is the primary 'user' interface for alternate data
|
||||
* sources; the IOCtx interface is intended (at least in version 1.5) to be
|
||||
* used internally until it settles down a bit.
|
||||
*
|
||||
* This module just layers the Source/Sink interface on top of the IOCtx; no
|
||||
* support is provided for tell/seek, so GD2 writing is not possible, and
|
||||
* retrieving parts of GD2 files is also not possible.
|
||||
*
|
||||
* A new SS context does not need to be created with both a Source and a Sink.
|
||||
*
|
||||
* Written/Modified 1999, Philip Warner.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "gd.h"
|
||||
#include "gdhelpers.h"
|
||||
|
||||
/* this is used for creating images in main memory */
|
||||
|
||||
typedef struct ssIOCtx
|
||||
{
|
||||
gdIOCtx ctx;
|
||||
gdSourcePtr src;
|
||||
gdSinkPtr snk;
|
||||
}
|
||||
ssIOCtx;
|
||||
|
||||
typedef struct ssIOCtx *ssIOCtxPtr;
|
||||
|
||||
gdIOCtx *gdNewSSCtx (gdSourcePtr src, gdSinkPtr snk);
|
||||
|
||||
static int sourceGetbuf (gdIOCtx *, void *, int);
|
||||
static int sourceGetchar (gdIOCtx * ctx);
|
||||
static int sinkPutbuf (gdIOCtx * ctx, const void *buf, int size);
|
||||
static void sinkPutchar (gdIOCtx * ctx, int a);
|
||||
static void gdFreeSsCtx (gdIOCtx * ctx);
|
||||
|
||||
/* return data as a dynamic pointer */
|
||||
gdIOCtx *
|
||||
gdNewSSCtx (gdSourcePtr src, gdSinkPtr snk)
|
||||
{
|
||||
ssIOCtxPtr ctx;
|
||||
|
||||
ctx = (ssIOCtxPtr) gdMalloc (sizeof (ssIOCtx));
|
||||
if (ctx == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->src = src;
|
||||
ctx->snk = snk;
|
||||
|
||||
ctx->ctx.getC = sourceGetchar;
|
||||
ctx->ctx.getBuf = sourceGetbuf;
|
||||
|
||||
ctx->ctx.putC = sinkPutchar;
|
||||
ctx->ctx.putBuf = sinkPutbuf;
|
||||
|
||||
ctx->ctx.tell = NULL;
|
||||
ctx->ctx.seek = NULL;
|
||||
|
||||
ctx->ctx.free = gdFreeSsCtx;
|
||||
|
||||
return (gdIOCtx *) ctx;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gdFreeSsCtx (gdIOCtx * ctx)
|
||||
{
|
||||
gdFree (ctx);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
sourceGetbuf (gdIOCtx * ctx, void *buf, int size)
|
||||
{
|
||||
ssIOCtx *lctx;
|
||||
int res;
|
||||
|
||||
lctx = (ssIOCtx *) ctx;
|
||||
|
||||
res = ((lctx->src->source) (lctx->src->context, buf, size));
|
||||
|
||||
/*
|
||||
** Translate the return values from the Source object:
|
||||
** 0 is EOF, -1 is error
|
||||
*/
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
else if (res < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return res;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
sourceGetchar (gdIOCtx * ctx)
|
||||
{
|
||||
int res;
|
||||
unsigned char buf;
|
||||
|
||||
res = sourceGetbuf (ctx, &buf, 1);
|
||||
|
||||
if (res == 1)
|
||||
{
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EOF;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
sinkPutbuf (gdIOCtx * ctx, const void *buf, int size)
|
||||
{
|
||||
ssIOCtxPtr lctx;
|
||||
int res;
|
||||
|
||||
lctx = (ssIOCtx *) ctx;
|
||||
|
||||
res = (lctx->snk->sink) (lctx->snk->context, buf, size);
|
||||
|
||||
if (res <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return res;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
sinkPutchar (gdIOCtx * ctx, int a)
|
||||
{
|
||||
unsigned char b;
|
||||
|
||||
b = a;
|
||||
sinkPutbuf (ctx, &b, 1);
|
||||
|
||||
}
|
852
ext/gd/libgd/gd_jpeg.c
Normal file
852
ext/gd/libgd/gd_jpeg.c
Normal file
@ -0,0 +1,852 @@
|
||||
|
||||
|
||||
/*
|
||||
* gd_jpeg.c: Read and write JPEG (JFIF) format image files using the
|
||||
* gd graphics library (http://www.boutell.com/gd/).
|
||||
*
|
||||
* This software is based in part on the work of the Independent JPEG
|
||||
* 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 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
|
||||
*
|
||||
* Modification 4/18/00 TBB: JPEG_DEBUG rather than just DEBUG,
|
||||
* so VC++ builds don't spew to standard output, causing
|
||||
* 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"
|
||||
|
||||
static const char *const GD_JPEG_VERSION = "1.0";
|
||||
|
||||
typedef struct _jmpbuf_wrapper
|
||||
{
|
||||
jmp_buf jmpbuf;
|
||||
}
|
||||
jmpbuf_wrapper;
|
||||
|
||||
/* Called by the IJG JPEG library upon encountering a fatal error */
|
||||
static void
|
||||
fatal_jpeg_error (j_common_ptr cinfo)
|
||||
{
|
||||
jmpbuf_wrapper *jmpbufw;
|
||||
|
||||
fprintf (stderr, "gd-jpeg: JPEG library reports unrecoverable error: ");
|
||||
(*cinfo->err->output_message) (cinfo);
|
||||
fflush (stderr);
|
||||
|
||||
jmpbufw = (jmpbuf_wrapper *) cinfo->client_data;
|
||||
jpeg_destroy (cinfo);
|
||||
|
||||
if (jmpbufw != 0)
|
||||
{
|
||||
longjmp (jmpbufw->jmpbuf, 1);
|
||||
fprintf (stderr, "gd-jpeg: EXTREMELY fatal error: longjmp"
|
||||
" returned control; terminating\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "gd-jpeg: EXTREMELY fatal error: jmpbuf"
|
||||
" unrecoverable; terminating\n");
|
||||
}
|
||||
|
||||
fflush (stderr);
|
||||
exit (99);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write IM to OUTFILE as a JFIF-formatted JPEG image, using quality
|
||||
* QUALITY. If QUALITY is in the range 0-100, increasing values
|
||||
* represent higher quality but also larger image size. If QUALITY is
|
||||
* negative, the IJG JPEG library's default quality is used (which
|
||||
* should be near optimal for many applications). See the IJG JPEG
|
||||
* library documentation for more details. */
|
||||
|
||||
void
|
||||
gdImageJpeg (gdImagePtr im, FILE * outFile, int quality)
|
||||
{
|
||||
gdIOCtx *out = gdNewFileCtx (outFile);
|
||||
gdImageJpegCtx (im, out, quality);
|
||||
out->free (out);
|
||||
}
|
||||
|
||||
void *
|
||||
gdImageJpegPtr (gdImagePtr im, int *size, int quality)
|
||||
{
|
||||
void *rv;
|
||||
gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
|
||||
gdImageJpegCtx (im, out, quality);
|
||||
rv = gdDPExtractData (out, size);
|
||||
out->free (out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile);
|
||||
|
||||
void
|
||||
gdImageJpegCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
|
||||
{
|
||||
struct jpeg_compress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
int i, j, jidx;
|
||||
/* volatile so we can gdFree it on return from longjmp */
|
||||
volatile JSAMPROW row = 0;
|
||||
JSAMPROW rowptr[1];
|
||||
jmpbuf_wrapper jmpbufw;
|
||||
JDIMENSION nlines;
|
||||
char comment[255];
|
||||
|
||||
#ifdef JPEG_DEBUG
|
||||
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);
|
||||
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 */
|
||||
|
||||
memset (&cinfo, 0, sizeof (cinfo));
|
||||
memset (&jerr, 0, sizeof (jerr));
|
||||
|
||||
cinfo.err = jpeg_std_error (&jerr);
|
||||
cinfo.client_data = &jmpbufw;
|
||||
if (setjmp (jmpbufw.jmpbuf) != 0)
|
||||
{
|
||||
/* we're here courtesy of longjmp */
|
||||
if (row)
|
||||
gdFree (row);
|
||||
return;
|
||||
}
|
||||
|
||||
cinfo.err->error_exit = fatal_jpeg_error;
|
||||
|
||||
jpeg_create_compress (&cinfo);
|
||||
|
||||
cinfo.image_width = im->sx;
|
||||
cinfo.image_height = im->sy;
|
||||
cinfo.input_components = 3; /* # of color components per pixel */
|
||||
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
|
||||
jpeg_set_defaults (&cinfo);
|
||||
if (quality >= 0)
|
||||
jpeg_set_quality (&cinfo, quality, TRUE);
|
||||
|
||||
/* If user requests interlace, translate that to progressive JPEG */
|
||||
if (gdImageGetInterlaced (im))
|
||||
{
|
||||
#ifdef JPEG_DEBUG
|
||||
printf ("gd-jpeg: interlace set, outputting progressive"
|
||||
" JPEG image\n");
|
||||
#endif
|
||||
jpeg_simple_progression (&cinfo);
|
||||
}
|
||||
|
||||
jpeg_gdIOCtx_dest (&cinfo, outfile);
|
||||
|
||||
row = (JSAMPROW) gdCalloc (1, cinfo.image_width * cinfo.input_components
|
||||
* sizeof (JSAMPLE));
|
||||
if (row == 0)
|
||||
{
|
||||
fprintf (stderr, "gd-jpeg: error: unable to allocate JPEG row "
|
||||
"structure: gdCalloc returns NULL\n");
|
||||
jpeg_destroy_compress (&cinfo);
|
||||
return;
|
||||
}
|
||||
|
||||
rowptr[0] = row;
|
||||
|
||||
jpeg_start_compress (&cinfo, TRUE);
|
||||
|
||||
sprintf (comment, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d),",
|
||||
GD_JPEG_VERSION, JPEG_LIB_VERSION);
|
||||
if (quality >= 0)
|
||||
sprintf (comment + strlen (comment), " quality = %d\n",
|
||||
quality);
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
gdImagePtr
|
||||
gdImageCreateFromJpeg (FILE * inFile)
|
||||
{
|
||||
gdImagePtr im;
|
||||
gdIOCtx *in = gdNewFileCtx (inFile);
|
||||
im = gdImageCreateFromJpegCtx (in);
|
||||
in->free (in);
|
||||
return im;
|
||||
}
|
||||
|
||||
void
|
||||
jpeg_gdIOCtx_src (j_decompress_ptr cinfo,
|
||||
gdIOCtx * infile);
|
||||
|
||||
/*
|
||||
* Create a gd-format image from the JPEG-format INFILE. Returns the
|
||||
* image, or NULL upon error.
|
||||
*/
|
||||
gdImagePtr
|
||||
gdImageCreateFromJpegCtx (gdIOCtx * infile)
|
||||
{
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
jmpbuf_wrapper jmpbufw;
|
||||
/* volatile so we can gdFree them after longjmp */
|
||||
volatile JSAMPROW row = 0;
|
||||
volatile gdImagePtr im = 0;
|
||||
JSAMPROW rowptr[1];
|
||||
int i, j, retval;
|
||||
JDIMENSION nrows;
|
||||
|
||||
#ifdef JPEG_DEBUG
|
||||
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);
|
||||
#endif
|
||||
|
||||
memset (&cinfo, 0, sizeof (cinfo));
|
||||
memset (&jerr, 0, sizeof (jerr));
|
||||
|
||||
cinfo.err = jpeg_std_error (&jerr);
|
||||
cinfo.client_data = &jmpbufw;
|
||||
if (setjmp (jmpbufw.jmpbuf) != 0)
|
||||
{
|
||||
/* we're here courtesy of longjmp */
|
||||
if (row)
|
||||
gdFree (row);
|
||||
if (im)
|
||||
gdImageDestroy (im);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cinfo.err->error_exit = fatal_jpeg_error;
|
||||
|
||||
jpeg_create_decompress (&cinfo);
|
||||
|
||||
jpeg_gdIOCtx_src (&cinfo, infile);
|
||||
|
||||
retval = jpeg_read_header (&cinfo, TRUE);
|
||||
if (retval != JPEG_HEADER_OK)
|
||||
fprintf (stderr, "gd-jpeg: warning: jpeg_read_header returns"
|
||||
" %d, expected %d\n", retval, JPEG_HEADER_OK);
|
||||
|
||||
if (cinfo.image_height > INT_MAX)
|
||||
fprintf (stderr, "gd-jpeg: warning: JPEG image height (%u) is"
|
||||
" greater than INT_MAX (%d) (and thus greater than"
|
||||
" gd can handle)", cinfo.image_height,
|
||||
INT_MAX);
|
||||
|
||||
if (cinfo.image_width > INT_MAX)
|
||||
fprintf (stderr, "gd-jpeg: warning: JPEG image width (%u) is"
|
||||
" greater than INT_MAX (%d) (and thus greater than"
|
||||
" gd can handle)\n", cinfo.image_width, INT_MAX);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the image into RGB colorspace, but don't
|
||||
* reduce the number of colors anymore (GD 2.0)
|
||||
*/
|
||||
cinfo.out_color_space = JCS_RGB;
|
||||
|
||||
if (jpeg_start_decompress (&cinfo) != TRUE)
|
||||
fprintf (stderr, "gd-jpeg: warning: jpeg_start_decompress"
|
||||
" reports suspended data source\n");
|
||||
|
||||
#ifdef JPEG_DEBUG
|
||||
printf ("gd-jpeg: JPEG image information:");
|
||||
if (cinfo.saw_JFIF_marker)
|
||||
printf (" JFIF version %d.%.2d",
|
||||
(int) cinfo.JFIF_major_version,
|
||||
(int) cinfo.JFIF_minor_version);
|
||||
else if (cinfo.saw_Adobe_marker)
|
||||
printf (" Adobe format");
|
||||
else
|
||||
printf (" UNKNOWN format");
|
||||
|
||||
printf (" %ux%u (raw) / %ux%u (scaled) %d-bit", cinfo.image_width,
|
||||
cinfo.image_height, cinfo.output_width,
|
||||
cinfo.output_height, cinfo.data_precision);
|
||||
printf (" %s", (cinfo.progressive_mode ? "progressive" :
|
||||
"baseline"));
|
||||
printf (" image, %d quantized colors, ",
|
||||
cinfo.actual_number_of_colors);
|
||||
|
||||
switch (cinfo.jpeg_color_space)
|
||||
{
|
||||
case JCS_GRAYSCALE:
|
||||
printf ("grayscale");
|
||||
break;
|
||||
|
||||
case JCS_RGB:
|
||||
printf ("RGB");
|
||||
break;
|
||||
|
||||
case JCS_YCbCr:
|
||||
printf ("YCbCr (a.k.a. YUV)");
|
||||
break;
|
||||
|
||||
case JCS_CMYK:
|
||||
printf ("CMYK");
|
||||
break;
|
||||
|
||||
case JCS_YCCK:
|
||||
printf ("YCbCrK");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("UNKNOWN (value: %d)", (int) cinfo.jpeg_color_space);
|
||||
break;
|
||||
}
|
||||
printf (" colorspace\n");
|
||||
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);
|
||||
#endif
|
||||
if (cinfo.output_components != 3)
|
||||
{
|
||||
fprintf (stderr, "gd-jpeg: error: JPEG color quantization"
|
||||
" request resulted in output_components == %d"
|
||||
" (expected 3)\n", cinfo.output_components);
|
||||
goto error;
|
||||
}
|
||||
|
||||
#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 * 3, sizeof (JSAMPLE));
|
||||
if (row == 0)
|
||||
{
|
||||
fprintf (stderr, "gd-jpeg: error: unable to allocate row for"
|
||||
" JPEG scanline: gdCalloc returns NULL\n");
|
||||
goto error;
|
||||
}
|
||||
rowptr[0] = row;
|
||||
|
||||
for (i = 0; i < cinfo.output_height; i++)
|
||||
{
|
||||
nrows = jpeg_read_scanlines (&cinfo, rowptr, 1);
|
||||
if (nrows != 1)
|
||||
{
|
||||
fprintf (stderr, "gd-jpeg: error: jpeg_read_scanlines"
|
||||
" returns %u, expected 1\n", nrows);
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (j = 0; j < cinfo.output_width; j++)
|
||||
im->tpixels[i][j] = gdTrueColor (row[j * 3], row[j * 3 + 1],
|
||||
row[j * 3 + 2]);
|
||||
}
|
||||
|
||||
if (jpeg_finish_decompress (&cinfo) != TRUE)
|
||||
fprintf (stderr, "gd-jpeg: warning: jpeg_finish_decompress"
|
||||
" reports suspended data source\n");
|
||||
|
||||
|
||||
jpeg_destroy_decompress (&cinfo);
|
||||
gdFree (row);
|
||||
return im;
|
||||
|
||||
error:
|
||||
jpeg_destroy_decompress (&cinfo);
|
||||
if (row)
|
||||
gdFree (row);
|
||||
if (im)
|
||||
gdImageDestroy (im);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
* gdIOCtx JPEG data sources and sinks, T. Boutell
|
||||
* almost a simple global replace from T. Lane's stdio versions.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Different versions of libjpeg use either 'jboolean' or 'boolean', and
|
||||
some platforms define 'boolean', and so forth. Deal with this
|
||||
madness by typedeffing 'safeboolean' to 'boolean' if HAVE_BOOLEAN
|
||||
is already set, because this is the test that libjpeg uses.
|
||||
Otherwise, typedef it to int, because that's what libjpeg does
|
||||
if HAVE_BOOLEAN is not defined. -TBB */
|
||||
|
||||
#ifdef HAVE_BOOLEAN
|
||||
typedef boolean safeboolean;
|
||||
#else
|
||||
typedef int safeboolean;
|
||||
#endif /* HAVE_BOOLEAN */
|
||||
|
||||
/* Expanded data source object for gdIOCtx input */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct jpeg_source_mgr pub; /* public fields */
|
||||
|
||||
gdIOCtx *infile; /* source stream */
|
||||
unsigned char *buffer; /* start of buffer */
|
||||
safeboolean start_of_file; /* have we gotten any data yet? */
|
||||
|
||||
}
|
||||
my_source_mgr;
|
||||
|
||||
typedef my_source_mgr *my_src_ptr;
|
||||
|
||||
#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
|
||||
|
||||
/*
|
||||
* Initialize source --- called by jpeg_read_header
|
||||
* before any data is actually read.
|
||||
*/
|
||||
|
||||
void
|
||||
init_source (j_decompress_ptr cinfo)
|
||||
{
|
||||
my_src_ptr src = (my_src_ptr) cinfo->src;
|
||||
|
||||
/* We reset the empty-input-file flag for each image,
|
||||
* but we don't clear the input buffer.
|
||||
* This is correct behavior for reading a series of images from one source.
|
||||
*/
|
||||
src->start_of_file = TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Fill the input buffer --- called whenever buffer is emptied.
|
||||
*
|
||||
* In typical applications, this should read fresh data into the buffer
|
||||
* (ignoring the current state of next_input_byte & bytes_in_buffer),
|
||||
* reset the pointer & count to the start of the buffer, and return TRUE
|
||||
* indicating that the buffer has been reloaded. It is not necessary to
|
||||
* fill the buffer entirely, only to obtain at least one more byte.
|
||||
*
|
||||
* There is no such thing as an EOF return. If the end of the file has been
|
||||
* reached, the routine has a choice of ERREXIT() or inserting fake data into
|
||||
* the buffer. In most cases, generating a warning message and inserting a
|
||||
* fake EOI marker is the best course of action --- this will allow the
|
||||
* decompressor to output however much of the image is there. However,
|
||||
* the resulting error message is misleading if the real problem is an empty
|
||||
* input file, so we handle that case specially.
|
||||
*
|
||||
* In applications that need to be able to suspend compression due to input
|
||||
* not being available yet, a FALSE return indicates that no more data can be
|
||||
* obtained right now, but more may be forthcoming later. In this situation,
|
||||
* the decompressor will return to its caller (with an indication of the
|
||||
* number of scanlines it has read, if any). The application should resume
|
||||
* decompression after it has loaded more data into the input buffer. Note
|
||||
* that there are substantial restrictions on the use of suspension --- see
|
||||
* the documentation.
|
||||
*
|
||||
* When suspending, the decompressor will back up to a convenient restart point
|
||||
* (typically the start of the current MCU). next_input_byte & bytes_in_buffer
|
||||
* indicate where the restart point will be if the current call returns FALSE.
|
||||
* Data beyond this point must be rescanned after resumption, so move it to
|
||||
* the front of the buffer rather than discarding it.
|
||||
*/
|
||||
|
||||
#define END_JPEG_SEQUENCE "\r\n[*]--:END JPEG:--[*]\r\n"
|
||||
|
||||
safeboolean
|
||||
fill_input_buffer (j_decompress_ptr cinfo)
|
||||
{
|
||||
my_src_ptr src = (my_src_ptr) cinfo->src;
|
||||
size_t nbytes = 0;
|
||||
|
||||
/* size_t got; */
|
||||
/* char *s; */
|
||||
memset (src->buffer, 0, INPUT_BUF_SIZE);
|
||||
|
||||
while (nbytes < INPUT_BUF_SIZE)
|
||||
{
|
||||
|
||||
int got = gdGetBuf (src->buffer + nbytes,
|
||||
INPUT_BUF_SIZE - nbytes,
|
||||
src->infile);
|
||||
|
||||
if ((got == EOF) || (got == 0))
|
||||
{
|
||||
|
||||
/* EOF or error. If we got any data, don't worry about it.
|
||||
If we didn't, then this is unexpected. */
|
||||
if (!nbytes)
|
||||
{
|
||||
|
||||
nbytes = -1;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
nbytes += got;
|
||||
|
||||
}
|
||||
|
||||
if (nbytes <= 0)
|
||||
{
|
||||
if (src->start_of_file) /* Treat empty input file as fatal error */
|
||||
ERREXIT (cinfo, JERR_INPUT_EMPTY);
|
||||
WARNMS (cinfo, JWRN_JPEG_EOF);
|
||||
/* Insert a fake EOI marker */
|
||||
src->buffer[0] = (unsigned char) 0xFF;
|
||||
src->buffer[1] = (unsigned char) JPEG_EOI;
|
||||
nbytes = 2;
|
||||
}
|
||||
|
||||
src->pub.next_input_byte = src->buffer;
|
||||
src->pub.bytes_in_buffer = nbytes;
|
||||
src->start_of_file = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Skip data --- used to skip over a potentially large amount of
|
||||
* uninteresting data (such as an APPn marker).
|
||||
*
|
||||
* Writers of suspendable-input applications must note that skip_input_data
|
||||
* is not granted the right to give a suspension return. If the skip extends
|
||||
* beyond the data currently in the buffer, the buffer can be marked empty so
|
||||
* that the next read will cause a fill_input_buffer call that can suspend.
|
||||
* Arranging for additional bytes to be discarded before reloading the input
|
||||
* buffer is the application writer's problem.
|
||||
*/
|
||||
|
||||
void
|
||||
skip_input_data (j_decompress_ptr cinfo, long num_bytes)
|
||||
{
|
||||
my_src_ptr src = (my_src_ptr) cinfo->src;
|
||||
|
||||
/* Just a dumb implementation for now. Not clear that being smart is worth
|
||||
* any trouble anyway --- large skips are infrequent.
|
||||
*/
|
||||
if (num_bytes > 0)
|
||||
{
|
||||
while (num_bytes > (long) src->pub.bytes_in_buffer)
|
||||
{
|
||||
num_bytes -= (long) src->pub.bytes_in_buffer;
|
||||
(void) fill_input_buffer (cinfo);
|
||||
/* note we assume that fill_input_buffer will never return FALSE,
|
||||
* so suspension need not be handled.
|
||||
*/
|
||||
}
|
||||
src->pub.next_input_byte += (size_t) num_bytes;
|
||||
src->pub.bytes_in_buffer -= (size_t) num_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* An additional method that can be provided by data source modules is the
|
||||
* resync_to_restart method for error recovery in the presence of RST markers.
|
||||
* For the moment, this source module just uses the default resync method
|
||||
* provided by the JPEG library. That method assumes that no backtracking
|
||||
* is possible.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Terminate source --- called by jpeg_finish_decompress
|
||||
* after all data has been read. Often a no-op.
|
||||
*
|
||||
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
|
||||
* application must deal with any cleanup that should happen even
|
||||
* for error exit.
|
||||
*/
|
||||
|
||||
void
|
||||
term_source (j_decompress_ptr cinfo)
|
||||
{
|
||||
|
||||
#if 0
|
||||
/* never used */
|
||||
my_src_ptr src = (my_src_ptr) cinfo->src;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prepare for input from a gdIOCtx stream.
|
||||
* The caller must have already opened the stream, and is responsible
|
||||
* for closing it after finishing decompression.
|
||||
*/
|
||||
|
||||
void
|
||||
jpeg_gdIOCtx_src (j_decompress_ptr cinfo,
|
||||
gdIOCtx * infile)
|
||||
{
|
||||
my_src_ptr src;
|
||||
|
||||
/* The source object and input buffer are made permanent so that a series
|
||||
* of JPEG images can be read from the same file by calling jpeg_gdIOCtx_src
|
||||
* only before the first one. (If we discarded the buffer at the end of
|
||||
* one image, we'd likely lose the start of the next one.)
|
||||
* This makes it unsafe to use this manager and a different source
|
||||
* manager serially with the same JPEG object. Caveat programmer.
|
||||
*/
|
||||
if (cinfo->src == NULL)
|
||||
{ /* first time for this JPEG object? */
|
||||
cinfo->src = (struct jpeg_source_mgr *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||
sizeof (my_source_mgr));
|
||||
src = (my_src_ptr) cinfo->src;
|
||||
src->buffer = (unsigned char *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||
INPUT_BUF_SIZE * sizeof (unsigned char));
|
||||
|
||||
}
|
||||
|
||||
src = (my_src_ptr) cinfo->src;
|
||||
src->pub.init_source = init_source;
|
||||
src->pub.fill_input_buffer = fill_input_buffer;
|
||||
src->pub.skip_input_data = skip_input_data;
|
||||
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
|
||||
src->pub.term_source = term_source;
|
||||
src->infile = infile;
|
||||
src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
|
||||
src->pub.next_input_byte = NULL; /* until buffer loaded */
|
||||
}
|
||||
|
||||
/* Expanded data destination object for stdio output */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct jpeg_destination_mgr pub; /* public fields */
|
||||
gdIOCtx *outfile; /* target stream */
|
||||
unsigned char *buffer; /* start of buffer */
|
||||
}
|
||||
my_destination_mgr;
|
||||
|
||||
typedef my_destination_mgr *my_dest_ptr;
|
||||
|
||||
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
|
||||
|
||||
/*
|
||||
* Initialize destination --- called by jpeg_start_compress
|
||||
* before any data is actually written.
|
||||
*/
|
||||
|
||||
void
|
||||
init_destination (j_compress_ptr cinfo)
|
||||
{
|
||||
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
|
||||
|
||||
/* Allocate the output buffer --- it will be released when done with image */
|
||||
dest->buffer = (unsigned char *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||
OUTPUT_BUF_SIZE * sizeof (unsigned char));
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Empty the output buffer --- called whenever buffer fills up.
|
||||
*
|
||||
* In typical applications, this should write the entire output buffer
|
||||
* (ignoring the current state of next_output_byte & free_in_buffer),
|
||||
* reset the pointer & count to the start of the buffer, and return TRUE
|
||||
* indicating that the buffer has been dumped.
|
||||
*
|
||||
* In applications that need to be able to suspend compression due to output
|
||||
* overrun, a FALSE return indicates that the buffer cannot be emptied now.
|
||||
* In this situation, the compressor will return to its caller (possibly with
|
||||
* an indication that it has not accepted all the supplied scanlines). The
|
||||
* application should resume compression after it has made more room in the
|
||||
* output buffer. Note that there are substantial restrictions on the use of
|
||||
* suspension --- see the documentation.
|
||||
*
|
||||
* When suspending, the compressor will back up to a convenient restart point
|
||||
* (typically the start of the current MCU). next_output_byte & free_in_buffer
|
||||
* indicate where the restart point will be if the current call returns FALSE.
|
||||
* Data beyond this point will be regenerated after resumption, so do not
|
||||
* write it out when emptying the buffer externally.
|
||||
*/
|
||||
|
||||
safeboolean
|
||||
empty_output_buffer (j_compress_ptr cinfo)
|
||||
{
|
||||
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
|
||||
|
||||
if (gdPutBuf (dest->buffer, OUTPUT_BUF_SIZE, dest->outfile) !=
|
||||
(size_t) OUTPUT_BUF_SIZE)
|
||||
ERREXIT (cinfo, JERR_FILE_WRITE);
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Terminate destination --- called by jpeg_finish_compress
|
||||
* after all data has been written. Usually needs to flush buffer.
|
||||
*
|
||||
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
|
||||
* application must deal with any cleanup that should happen even
|
||||
* for error exit.
|
||||
*/
|
||||
|
||||
void
|
||||
term_destination (j_compress_ptr cinfo)
|
||||
{
|
||||
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
|
||||
size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
|
||||
|
||||
/* Write any data remaining in the buffer */
|
||||
if (datacount > 0)
|
||||
{
|
||||
if (gdPutBuf (dest->buffer, datacount, dest->outfile) != datacount)
|
||||
ERREXIT (cinfo, JERR_FILE_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prepare for output to a stdio stream.
|
||||
* The caller must have already opened the stream, and is responsible
|
||||
* for closing it after finishing compression.
|
||||
*/
|
||||
|
||||
void
|
||||
jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile)
|
||||
{
|
||||
my_dest_ptr dest;
|
||||
|
||||
/* The destination object is made permanent so that multiple JPEG images
|
||||
* can be written to the same file without re-executing jpeg_stdio_dest.
|
||||
* This makes it dangerous to use this manager and a different destination
|
||||
* manager serially with the same JPEG object, because their private object
|
||||
* sizes may be different. Caveat programmer.
|
||||
*/
|
||||
if (cinfo->dest == NULL)
|
||||
{ /* first time for this JPEG object? */
|
||||
cinfo->dest = (struct jpeg_destination_mgr *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||
sizeof (my_destination_mgr));
|
||||
}
|
||||
|
||||
dest = (my_dest_ptr) cinfo->dest;
|
||||
dest->pub.init_destination = init_destination;
|
||||
dest->pub.empty_output_buffer = empty_output_buffer;
|
||||
dest->pub.term_destination = term_destination;
|
||||
dest->outfile = outfile;
|
||||
}
|
||||
|
||||
#endif /* HAVE_JPEG */
|
753
ext/gd/libgd/gd_png.c
Normal file
753
ext/gd/libgd/gd_png.c
Normal file
@ -0,0 +1,753 @@
|
||||
|
||||
#ifdef HAVE_LIBPNG
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "gd.h"
|
||||
#include "gdhelpers.h"
|
||||
#include "png.h" /* includes zlib.h and setjmp.h */
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
|
||||
gd_png.c Copyright 1999 Greg Roelofs and Thomas Boutell
|
||||
|
||||
The routines in this file, gdImagePng*() and gdImageCreateFromPng*(),
|
||||
are drop-in replacements for gdImageGif*() and gdImageCreateFromGif*(),
|
||||
except that these functions are noisier in the case of errors (comment
|
||||
out all fprintf() statements to disable that).
|
||||
|
||||
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.
|
||||
|
||||
Gamma is ignored, and there is no support for text annotations.
|
||||
|
||||
Last updated: 9 February 2001
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef PNG_SETJMP_NOT_SUPPORTED
|
||||
typedef struct _jmpbuf_wrapper
|
||||
{
|
||||
jmp_buf jmpbuf;
|
||||
}
|
||||
jmpbuf_wrapper;
|
||||
|
||||
static jmpbuf_wrapper gdPngJmpbufStruct;
|
||||
|
||||
static void
|
||||
gdPngErrorHandler (png_structp png_ptr, png_const_charp msg)
|
||||
{
|
||||
jmpbuf_wrapper *jmpbuf_ptr;
|
||||
|
||||
/* This function, aside from the extra step of retrieving the "error
|
||||
* pointer" (below) and the fact that it exists within the application
|
||||
* rather than within libpng, is essentially identical to libpng's
|
||||
* default error handler. The second point is critical: since both
|
||||
* setjmp() and longjmp() are called from the same code, they are
|
||||
* guaranteed to have compatible notions of how big a jmp_buf is,
|
||||
* regardless of whether _BSD_SOURCE or anything else has (or has not)
|
||||
* been defined. */
|
||||
|
||||
fprintf (stderr, "gd-png: fatal libpng error: %s\n", msg);
|
||||
fflush (stderr);
|
||||
|
||||
jmpbuf_ptr = png_get_error_ptr (png_ptr);
|
||||
if (jmpbuf_ptr == NULL)
|
||||
{ /* we are completely hosed now */
|
||||
fprintf (stderr,
|
||||
"gd-png: EXTREMELY fatal error: jmpbuf unrecoverable; terminating.\n");
|
||||
fflush (stderr);
|
||||
exit (99);
|
||||
}
|
||||
|
||||
longjmp (jmpbuf_ptr->jmpbuf, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
gdPngReadData (png_structp png_ptr,
|
||||
png_bytep data, png_size_t length)
|
||||
{
|
||||
gdGetBuf (data, length, (gdIOCtx *)
|
||||
png_get_io_ptr (png_ptr));
|
||||
}
|
||||
|
||||
static void
|
||||
gdPngWriteData (png_structp png_ptr,
|
||||
png_bytep data, png_size_t length)
|
||||
{
|
||||
gdPutBuf (data, length, (gdIOCtx *)
|
||||
png_get_io_ptr (png_ptr));
|
||||
}
|
||||
|
||||
static void
|
||||
gdPngFlushData (png_structp png_ptr)
|
||||
{
|
||||
}
|
||||
|
||||
gdImagePtr
|
||||
gdImageCreateFromPng (FILE * inFile)
|
||||
{
|
||||
gdImagePtr im;
|
||||
gdIOCtx *in = gdNewFileCtx (inFile);
|
||||
im = gdImageCreateFromPngCtx (in);
|
||||
in->free (in);
|
||||
return im;
|
||||
}
|
||||
|
||||
|
||||
/* This routine is based in part on the Chapter 13 demo code in "PNG: The
|
||||
* Definitive Guide" (http://www.cdrom.com/pub/png/pngbook.html).
|
||||
*/
|
||||
gdImagePtr
|
||||
gdImageCreateFromPngCtx (gdIOCtx * infile)
|
||||
{
|
||||
png_byte sig[8];
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_uint_32 width, height, rowbytes;
|
||||
int bit_depth, color_type, interlace_type;
|
||||
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;
|
||||
gdImagePtr im = NULL;
|
||||
int i, j, *open;
|
||||
volatile int transparent = -1;
|
||||
volatile int palette_allocated = FALSE;
|
||||
|
||||
/* Make sure the signature can't match by dumb luck -- TBB */
|
||||
/* GRR: isn't sizeof(infile) equal to the size of the pointer? */
|
||||
memset (infile, 0, sizeof (infile));
|
||||
|
||||
/* first do a quick check that the file really is a PNG image; could
|
||||
* have used slightly more general png_sig_cmp() function instead */
|
||||
gdGetBuf (sig, 8, infile);
|
||||
if (!png_check_sig (sig, 8))
|
||||
return NULL; /* bad signature */
|
||||
|
||||
#ifndef PNG_SETJMP_NOT_SUPPORTED
|
||||
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, &gdPngJmpbufStruct,
|
||||
gdPngErrorHandler, NULL);
|
||||
#else
|
||||
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
#endif
|
||||
if (png_ptr == NULL)
|
||||
{
|
||||
fprintf (stderr, "gd-png error: cannot allocate libpng main struct\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info_ptr = png_create_info_struct (png_ptr);
|
||||
if (info_ptr == NULL)
|
||||
{
|
||||
fprintf (stderr, "gd-png error: cannot allocate libpng info struct\n");
|
||||
png_destroy_read_struct (&png_ptr, NULL, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* we could create a second info struct here (end_info), but it's only
|
||||
* useful if we want to keep pre- and post-IDAT chunk info separated
|
||||
* (mainly for PNG-aware image editors and converters) */
|
||||
|
||||
/* setjmp() must be called in every non-callback function that calls a
|
||||
* PNG-reading libpng function */
|
||||
#ifndef PNG_SETJMP_NOT_SUPPORTED
|
||||
if (setjmp (gdPngJmpbufStruct.jmpbuf))
|
||||
{
|
||||
fprintf (stderr, "gd-png error: setjmp returns error condition\n");
|
||||
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */
|
||||
|
||||
png_set_read_fn (png_ptr, (void *) infile, gdPngReadData);
|
||||
png_read_info (png_ptr, info_ptr); /* read all PNG info up to image data */
|
||||
|
||||
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 */
|
||||
switch (color_type)
|
||||
{
|
||||
case PNG_COLOR_TYPE_PALETTE:
|
||||
png_get_PLTE (png_ptr, info_ptr, &palette, &num_palette);
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "gd-png color_type is palette, colors: %d\n",
|
||||
num_palette);
|
||||
#endif /* DEBUG */
|
||||
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
im->alpha[i] = gdAlphaMax - (trans[i] >> 1);
|
||||
if ((trans[i] == 0) && (firstZero))
|
||||
{
|
||||
im->transparent = i;
|
||||
firstZero = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PNG_COLOR_TYPE_GRAY:
|
||||
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
||||
/* create a fake palette and check for single-shade transparency */
|
||||
if ((palette = (png_colorp) gdMalloc (256 * sizeof (png_color))) == NULL)
|
||||
{
|
||||
fprintf (stderr, "gd-png error: cannot allocate gray palette\n");
|
||||
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
|
||||
return NULL;
|
||||
}
|
||||
palette_allocated = TRUE;
|
||||
if (bit_depth < 8)
|
||||
{
|
||||
num_palette = 1 << bit_depth;
|
||||
for (i = 0; i < 256; ++i)
|
||||
{
|
||||
j = (255 * i) / (num_palette - 1);
|
||||
palette[i].red = palette[i].green = palette[i].blue = j;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
num_palette = 256;
|
||||
for (i = 0; i < 256; ++i)
|
||||
{
|
||||
palette[i].red = palette[i].green = palette[i].blue = i;
|
||||
}
|
||||
}
|
||||
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 in effect */
|
||||
transparent = trans_gray_rgb->gray >> 8;
|
||||
else
|
||||
transparent = trans_gray_rgb->gray;
|
||||
/* Note slight error in 16-bit case: up to 256 16-bit shades
|
||||
* may get mapped to a single 8-bit shade, and only one of them
|
||||
* is supposed to be transparent. IOW, both opaque pixels and
|
||||
* transparent pixels will be mapped into the transparent entry.
|
||||
* There is no particularly good way around this in the case
|
||||
* that all 256 8-bit shades are used, but one could write some
|
||||
* custom 16-bit code to handle the case where there are gdFree
|
||||
* palette entries. This error will be extremely rare in
|
||||
* general, though. (Quite possibly there is only one such
|
||||
* image in existence.) */
|
||||
}
|
||||
break;
|
||||
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
/* 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_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;
|
||||
}
|
||||
|
||||
png_read_update_info (png_ptr, info_ptr);
|
||||
|
||||
/* allocate space for the PNG image data */
|
||||
rowbytes = png_get_rowbytes (png_ptr, info_ptr);
|
||||
if ((image_data = (png_bytep) gdMalloc (rowbytes * height)) == NULL)
|
||||
{
|
||||
fprintf (stderr, "gd-png error: cannot allocate image data\n");
|
||||
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
|
||||
return NULL;
|
||||
}
|
||||
if ((row_pointers = (png_bytepp) gdMalloc (height * sizeof (png_bytep))) == NULL)
|
||||
{
|
||||
fprintf (stderr, "gd-png error: cannot allocate row pointers\n");
|
||||
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
|
||||
gdFree (image_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set the individual row_pointers to point at the correct offsets */
|
||||
for (j = 0; j < height; ++j)
|
||||
{
|
||||
row_pointers[j] = image_data + j * rowbytes;
|
||||
}
|
||||
|
||||
png_read_image (png_ptr, row_pointers); /* read whole image... */
|
||||
png_read_end (png_ptr, NULL); /* ...done! */
|
||||
|
||||
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->interlace = (interlace_type == PNG_INTERLACE_ADAM7);
|
||||
|
||||
/* can't nuke structs until done with palette */
|
||||
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
|
||||
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
|
||||
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
|
||||
|
||||
if (palette_allocated)
|
||||
gdFree (palette);
|
||||
gdFree (image_data);
|
||||
gdFree (row_pointers);
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gdImagePng (gdImagePtr im, FILE * outFile)
|
||||
{
|
||||
gdIOCtx *out = gdNewFileCtx (outFile);
|
||||
gdImagePngCtx (im, out);
|
||||
out->free (out);
|
||||
}
|
||||
|
||||
void *
|
||||
gdImagePngPtr (gdImagePtr im, int *size)
|
||||
{
|
||||
void *rv;
|
||||
gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
|
||||
gdImagePngCtx (im, out);
|
||||
rv = gdDPExtractData (out, size);
|
||||
out->free (out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* This routine is based in part on code from Dale Lutz (Safe Software Inc.)
|
||||
* and in part on demo code from Chapter 15 of "PNG: The Definitive Guide"
|
||||
* (http://www.cdrom.com/pub/png/pngbook.html).
|
||||
*/
|
||||
void
|
||||
gdImagePngCtx (gdImagePtr im, gdIOCtx * outfile)
|
||||
{
|
||||
int i, j, bit_depth, interlace_type;
|
||||
int width = im->sx;
|
||||
int height = im->sy;
|
||||
int colors = im->colorsTotal;
|
||||
int *open = im->open;
|
||||
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;
|
||||
volatile int transparent = im->transparent;
|
||||
volatile int remap = FALSE;
|
||||
|
||||
|
||||
#ifndef PNG_SETJMP_NOT_SUPPORTED
|
||||
png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
|
||||
&gdPngJmpbufStruct, gdPngErrorHandler, NULL);
|
||||
#else
|
||||
png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
#endif
|
||||
if (png_ptr == NULL)
|
||||
{
|
||||
fprintf (stderr, "gd-png error: cannot allocate libpng main struct\n");
|
||||
return;
|
||||
}
|
||||
|
||||
info_ptr = png_create_info_struct (png_ptr);
|
||||
if (info_ptr == NULL)
|
||||
{
|
||||
fprintf (stderr, "gd-png error: cannot allocate libpng info struct\n");
|
||||
png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef PNG_SETJMP_NOT_SUPPORTED
|
||||
if (setjmp (gdPngJmpbufStruct.jmpbuf))
|
||||
{
|
||||
fprintf (stderr, "gd-png error: setjmp returns error condition\n");
|
||||
png_destroy_write_struct (&png_ptr, &info_ptr);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
png_set_write_fn (png_ptr, (void *) outfile, gdPngWriteData, gdPngFlushData);
|
||||
|
||||
/* 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 */
|
||||
/* png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); */
|
||||
|
||||
/* can set this to a smaller value without compromising compression if all
|
||||
* image data is 16K or less; will save some decoder memory [min == 8] */
|
||||
/* png_set_compression_window_bits(png_ptr, 15); */
|
||||
|
||||
if (!im->trueColor)
|
||||
{
|
||||
if (transparent >= im->colorsTotal ||
|
||||
(transparent >= 0 && open[transparent]))
|
||||
transparent = -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
interlace_type = im->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
|
||||
|
||||
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 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);
|
||||
|
||||
/* make sure < 8-bit images are packed into pixels as tightly as possible */
|
||||
png_set_packing (png_ptr);
|
||||
|
||||
/* This code allocates a set of row buffers and copies the gd image data
|
||||
* into them only in the case that remapping is necessary; in gd 1.3 and
|
||||
* later, the im->pixels array is laid out identically to libpng's row
|
||||
* 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 (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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
png_write_end (png_ptr, info_ptr);
|
||||
|
||||
for (j = 0; j < height; ++j)
|
||||
gdFree (row_pointers[j]);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
#endif /* HAVE_LIBPNG */
|
38
ext/gd/libgd/gd_ss.c
Normal file
38
ext/gd/libgd/gd_ss.c
Normal file
@ -0,0 +1,38 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "gd.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/* Exported functions: */
|
||||
extern void gdImagePngToSink (gdImagePtr im, gdSinkPtr out);
|
||||
extern gdImagePtr gdImageCreateFromPngSource (gdSourcePtr inSource);
|
||||
|
||||
/* Use this for commenting out debug-print statements. */
|
||||
/* Just use the first '#define' to allow all the prints... */
|
||||
/*#define GD_SS_DBG(s) (s) */
|
||||
#define GD_SS_DBG(s)
|
||||
|
||||
void
|
||||
gdImagePngToSink (gdImagePtr im, gdSinkPtr outSink)
|
||||
{
|
||||
gdIOCtx *out = gdNewSSCtx (NULL, outSink);
|
||||
gdImagePngCtx (im, out);
|
||||
out->free (out);
|
||||
}
|
||||
|
||||
gdImagePtr
|
||||
gdImageCreateFromPngSource (gdSourcePtr inSource)
|
||||
{
|
||||
gdIOCtx *in = gdNewSSCtx (inSource, NULL);
|
||||
gdImagePtr im;
|
||||
|
||||
im = gdImageCreateFromPngCtx (in);
|
||||
|
||||
in->free (in);
|
||||
|
||||
return im;
|
||||
}
|
1688
ext/gd/libgd/gd_topal.c
Normal file
1688
ext/gd/libgd/gd_topal.c
Normal file
File diff suppressed because it is too large
Load Diff
218
ext/gd/libgd/gd_wbmp.c
Normal file
218
ext/gd/libgd/gd_wbmp.c
Normal file
@ -0,0 +1,218 @@
|
||||
|
||||
|
||||
/*
|
||||
WBMP: Wireless Bitmap Type 0: B/W, Uncompressed Bitmap
|
||||
Specification of the WBMP format can be found in the file:
|
||||
SPEC-WAESpec-19990524.pdf
|
||||
You can download the WAP specification on: http://www.wapforum.com/
|
||||
|
||||
gd_wbmp.c
|
||||
|
||||
Copyright (C) Johan Van den Brande (johan@vandenbrande.com)
|
||||
|
||||
Fixed: gdImageWBMPPtr, gdImageWBMP
|
||||
|
||||
Recoded: gdImageWBMPCtx for use with my wbmp library
|
||||
(wbmp library included, but you can find the latest distribution
|
||||
at http://www.vandenbrande.com/wbmp)
|
||||
|
||||
Implemented: gdImageCreateFromWBMPCtx, gdImageCreateFromWBMP
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Parts of this code are from Maurice Smurlo.
|
||||
|
||||
|
||||
** Copyright (C) Maurice Szmurlo --- T-SIT --- January 2000
|
||||
** (Maurice.Szmurlo@info.unicaen.fr)
|
||||
|
||||
** Permission to use, copy, modify, and distribute this software and its
|
||||
** documentation for any purpose and without fee is hereby granted, provided
|
||||
** that the above copyright notice appear in all copies and that both that
|
||||
** copyright notice and this permission notice appear in supporting
|
||||
** documentation. This software is provided "as is" without express or
|
||||
** implied warranty.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
Parts od this code are inspired by 'pbmtowbmp.c' and 'wbmptopbm.c' by
|
||||
Terje Sannum <terje@looplab.com>.
|
||||
**
|
||||
** Permission to use, copy, modify, and distribute this software and its
|
||||
** documentation for any purpose and without fee is hereby granted, provided
|
||||
** that the above copyright notice appear in all copies and that both that
|
||||
** copyright notice and this permission notice appear in supporting
|
||||
** documentation. This software is provided "as is" without express or
|
||||
** implied warranty.
|
||||
**
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Todo:
|
||||
|
||||
gdCreateFromWBMP function for reading WBMP files
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <gd.h>
|
||||
#include <gdfonts.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "wbmp.h"
|
||||
|
||||
|
||||
/* gd_putout
|
||||
** ---------
|
||||
** Wrapper around gdPutC for use with writewbmp
|
||||
**
|
||||
*/
|
||||
void
|
||||
gd_putout (int i, void *out)
|
||||
{
|
||||
gdPutC (i, (gdIOCtx *) out);
|
||||
}
|
||||
|
||||
|
||||
/* gd_getin
|
||||
** --------
|
||||
** Wrapper around gdGetC for use with readwbmp
|
||||
**
|
||||
*/
|
||||
int
|
||||
gd_getin (void *in)
|
||||
{
|
||||
return (gdGetC ((gdIOCtx *) in));
|
||||
}
|
||||
|
||||
|
||||
/* gdImageWBMPCtx
|
||||
** --------------
|
||||
** Write the image as a wbmp file
|
||||
** Parameters are:
|
||||
** image: gd image structure;
|
||||
** fg: the index of the foreground color. any other value will be
|
||||
** considered as background and will not be written
|
||||
** out: the stream where to write
|
||||
*/
|
||||
void
|
||||
gdImageWBMPCtx (gdImagePtr image, int fg, gdIOCtx * out)
|
||||
{
|
||||
|
||||
int x, y, pos;
|
||||
Wbmp *wbmp;
|
||||
|
||||
|
||||
/* create the WBMP */
|
||||
if ((wbmp = createwbmp (gdImageSX (image), gdImageSY (image), WBMP_WHITE)) == NULL)
|
||||
fprintf (stderr, "Could not create WBMP\n");
|
||||
|
||||
/* fill up the WBMP structure */
|
||||
pos = 0;
|
||||
for (y = 0; y < gdImageSY (image); y++)
|
||||
{
|
||||
for (x = 0; x < gdImageSX (image); x++)
|
||||
{
|
||||
if (gdImageGetPixel (image, x, y) == fg)
|
||||
{
|
||||
wbmp->bitmap[pos] = WBMP_BLACK;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
/* write the WBMP to a gd file descriptor */
|
||||
if (writewbmp (wbmp, &gd_putout, out))
|
||||
fprintf (stderr, "Could not save WBMP\n");
|
||||
/* des submitted this bugfix: gdFree the memory. */
|
||||
freewbmp (wbmp);
|
||||
}
|
||||
|
||||
|
||||
/* gdImageCreateFromWBMPCtx
|
||||
** ------------------------
|
||||
** Create a gdImage from a WBMP file input from an gdIOCtx
|
||||
*/
|
||||
gdImagePtr
|
||||
gdImageCreateFromWBMPCtx (gdIOCtx * infile)
|
||||
{
|
||||
/* FILE *wbmp_file; */
|
||||
Wbmp *wbmp;
|
||||
gdImagePtr im = NULL;
|
||||
int black, white;
|
||||
int col, row, pos;
|
||||
|
||||
if (readwbmp (&gd_getin, infile, &wbmp))
|
||||
return (NULL);
|
||||
|
||||
if (!(im = gdImageCreate (wbmp->width, wbmp->height)))
|
||||
{
|
||||
freewbmp (wbmp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* create the background color */
|
||||
white = gdImageColorAllocate (im, 255, 255, 255);
|
||||
/* create foreground color */
|
||||
black = gdImageColorAllocate (im, 0, 0, 0);
|
||||
|
||||
/* fill in image (in a wbmp 1 = white/ 0 = black) */
|
||||
pos = 0;
|
||||
for (row = 0; row < wbmp->height; row++)
|
||||
{
|
||||
for (col = 0; col < wbmp->width; col++)
|
||||
{
|
||||
if (wbmp->bitmap[pos++] == WBMP_WHITE)
|
||||
{
|
||||
gdImageSetPixel (im, col, row, white);
|
||||
}
|
||||
else
|
||||
{
|
||||
gdImageSetPixel (im, col, row, black);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freewbmp (wbmp);
|
||||
|
||||
return (im);
|
||||
}
|
||||
|
||||
|
||||
/* gdImageCreateFromWBMP
|
||||
** ---------------------
|
||||
*/
|
||||
gdImagePtr
|
||||
gdImageCreateFromWBMP (FILE * inFile)
|
||||
{
|
||||
gdImagePtr im;
|
||||
gdIOCtx *in = gdNewFileCtx (inFile);
|
||||
im = gdImageCreateFromWBMPCtx (in);
|
||||
in->free (in);
|
||||
return (im);
|
||||
}
|
||||
|
||||
/* gdImageWBMP
|
||||
** -----------
|
||||
*/
|
||||
void
|
||||
gdImageWBMP (gdImagePtr im, int fg, FILE * outFile)
|
||||
{
|
||||
gdIOCtx *out = gdNewFileCtx (outFile);
|
||||
gdImageWBMPCtx (im, fg, out);
|
||||
out->free (out);
|
||||
}
|
||||
|
||||
/* gdImageWBMPPtr
|
||||
** --------------
|
||||
*/
|
||||
void *
|
||||
gdImageWBMPPtr (gdImagePtr im, int *size, int fg)
|
||||
{
|
||||
void *rv;
|
||||
gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
|
||||
gdImageWBMPCtx (im, fg, out);
|
||||
rv = gdDPExtractData (out, size);
|
||||
out->free (out);
|
||||
return rv;
|
||||
}
|
214
ext/gd/libgd/gdcache.c
Normal file
214
ext/gd/libgd/gdcache.c
Normal file
@ -0,0 +1,214 @@
|
||||
#include "gd.h"
|
||||
#include "gdhelpers.h"
|
||||
|
||||
#ifdef HAVE_LIBTTF
|
||||
#define NEED_CACHE 1
|
||||
#else
|
||||
#ifdef HAVE_LIBFREETYPE
|
||||
#define NEED_CACHE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NEED_CACHE
|
||||
|
||||
/*
|
||||
* gdcache.c
|
||||
*
|
||||
* Caches of pointers to user structs in which the least-recently-used
|
||||
* element is replaced in the event of a cache miss after the cache has
|
||||
* reached a given size.
|
||||
*
|
||||
* John Ellson (ellson@lucent.com) Oct 31, 1997
|
||||
*
|
||||
* Test this with:
|
||||
* gcc -o gdcache -g -Wall -DTEST gdcache.c
|
||||
*
|
||||
* The cache is implemented by a singly-linked list of elements
|
||||
* each containing a pointer to a user struct that is being managed by
|
||||
* the cache.
|
||||
*
|
||||
* The head structure has a pointer to the most-recently-used
|
||||
* element, and elements are moved to this position in the list each
|
||||
* time they are used. The head also contains pointers to three
|
||||
* user defined functions:
|
||||
* - a function to test if a cached userdata matches some keydata
|
||||
* - a function to provide a new userdata struct to the cache
|
||||
* if there has been a cache miss.
|
||||
* - a function to release a userdata struct when it is
|
||||
* no longer being managed by the cache
|
||||
*
|
||||
* In the event of a cache miss the cache is allowed to grow up to
|
||||
* a specified maximum size. After the maximum size is reached then
|
||||
* the least-recently-used element is discarded to make room for the
|
||||
* new. The most-recently-returned value is always left at the
|
||||
* beginning of the list after retrieval.
|
||||
*
|
||||
* In the current implementation the cache is traversed by a linear
|
||||
* search from most-recent to least-recent. This linear search
|
||||
* probably limits the usefulness of this implementation to cache
|
||||
* sizes of a few tens of elements.
|
||||
*/
|
||||
|
||||
#include "gdcache.h"
|
||||
|
||||
/*********************************************************/
|
||||
/* implementation */
|
||||
/*********************************************************/
|
||||
|
||||
|
||||
/* create a new cache */
|
||||
gdCache_head_t *
|
||||
gdCacheCreate (
|
||||
int size,
|
||||
gdCacheTestFn_t gdCacheTest,
|
||||
gdCacheFetchFn_t gdCacheFetch,
|
||||
gdCacheReleaseFn_t gdCacheRelease)
|
||||
{
|
||||
gdCache_head_t *head;
|
||||
|
||||
head = (gdCache_head_t *) gdMalloc (sizeof (gdCache_head_t));
|
||||
head->mru = NULL;
|
||||
head->size = size;
|
||||
head->gdCacheTest = gdCacheTest;
|
||||
head->gdCacheFetch = gdCacheFetch;
|
||||
head->gdCacheRelease = gdCacheRelease;
|
||||
return head;
|
||||
}
|
||||
|
||||
void
|
||||
gdCacheDelete (gdCache_head_t * head)
|
||||
{
|
||||
gdCache_element_t *elem, *prev;
|
||||
|
||||
elem = head->mru;
|
||||
while (elem)
|
||||
{
|
||||
(*(head->gdCacheRelease)) (elem->userdata);
|
||||
prev = elem;
|
||||
elem = elem->next;
|
||||
gdFree ((char *) prev);
|
||||
}
|
||||
gdFree ((char *) head);
|
||||
}
|
||||
|
||||
void *
|
||||
gdCacheGet (gdCache_head_t * head, void *keydata)
|
||||
{
|
||||
int i = 0;
|
||||
gdCache_element_t *elem, *prev = NULL, *prevprev = NULL;
|
||||
void *userdata;
|
||||
|
||||
elem = head->mru;
|
||||
while (elem)
|
||||
{
|
||||
if ((*(head->gdCacheTest)) (elem->userdata, keydata))
|
||||
{
|
||||
if (i)
|
||||
{ /* if not already most-recently-used */
|
||||
/* relink to top of list */
|
||||
prev->next = elem->next;
|
||||
elem->next = head->mru;
|
||||
head->mru = elem;
|
||||
}
|
||||
return elem->userdata;
|
||||
}
|
||||
prevprev = prev;
|
||||
prev = elem;
|
||||
elem = elem->next;
|
||||
i++;
|
||||
}
|
||||
userdata = (*(head->gdCacheFetch)) (&(head->error), keydata);
|
||||
if (!userdata)
|
||||
{
|
||||
/* if there was an error in the fetch then don't cache */
|
||||
return NULL;
|
||||
}
|
||||
if (i < head->size)
|
||||
{ /* cache still growing - add new elem */
|
||||
elem = (gdCache_element_t *) gdMalloc (sizeof (gdCache_element_t));
|
||||
}
|
||||
else
|
||||
{ /* cache full - replace least-recently-used */
|
||||
/* preveprev becomes new end of list */
|
||||
prevprev->next = NULL;
|
||||
elem = prev;
|
||||
(*(head->gdCacheRelease)) (elem->userdata);
|
||||
}
|
||||
/* relink to top of list */
|
||||
elem->next = head->mru;
|
||||
head->mru = elem;
|
||||
elem->userdata = userdata;
|
||||
return userdata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************/
|
||||
/* test stub */
|
||||
/*********************************************************/
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int key;
|
||||
int value;
|
||||
}
|
||||
key_value_t;
|
||||
|
||||
static int
|
||||
cacheTest (void *map, void *key)
|
||||
{
|
||||
return (((key_value_t *) map)->key == *(int *) key);
|
||||
}
|
||||
|
||||
static void *
|
||||
cacheFetch (char **error, void *key)
|
||||
{
|
||||
key_value_t *map;
|
||||
|
||||
map = (key_value_t *) gdMalloc (sizeof (key_value_t));
|
||||
map->key = *(int *) key;
|
||||
map->value = 3;
|
||||
|
||||
*error = NULL;
|
||||
return (void *) map;
|
||||
}
|
||||
|
||||
static void
|
||||
cacheRelease (void *map)
|
||||
{
|
||||
gdFree ((char *) map);
|
||||
}
|
||||
|
||||
int
|
||||
main (char *argv[], int argc)
|
||||
{
|
||||
gdCache_head_t *cacheTable;
|
||||
int elem, key;
|
||||
|
||||
cacheTable = gdCacheCreate (3, cacheTest, cacheFetch, cacheRelease);
|
||||
|
||||
key = 20;
|
||||
elem = *(int *) gdCacheGet (cacheTable, &key);
|
||||
key = 30;
|
||||
elem = *(int *) gdCacheGet (cacheTable, &key);
|
||||
key = 40;
|
||||
elem = *(int *) gdCacheGet (cacheTable, &key);
|
||||
key = 50;
|
||||
elem = *(int *) gdCacheGet (cacheTable, &key);
|
||||
key = 30;
|
||||
elem = *(int *) gdCacheGet (cacheTable, &key);
|
||||
key = 30;
|
||||
elem = *(int *) gdCacheGet (cacheTable, &key);
|
||||
|
||||
gdCacheDelete (cacheTable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
||||
#endif /* HAVE_LIBTTF */
|
83
ext/gd/libgd/gdcache.h
Normal file
83
ext/gd/libgd/gdcache.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* gdcache.h
|
||||
*
|
||||
* Caches of pointers to user structs in which the least-recently-used
|
||||
* element is replaced in the event of a cache miss after the cache has
|
||||
* reached a given size.
|
||||
*
|
||||
* John Ellson (ellson@lucent.com) Oct 31, 1997
|
||||
*
|
||||
* Test this with:
|
||||
* gcc -o gdcache -g -Wall -DTEST gdcache.c
|
||||
*
|
||||
* The cache is implemented by a singly-linked list of elements
|
||||
* each containing a pointer to a user struct that is being managed by
|
||||
* the cache.
|
||||
*
|
||||
* The head structure has a pointer to the most-recently-used
|
||||
* element, and elements are moved to this position in the list each
|
||||
* time they are used. The head also contains pointers to three
|
||||
* user defined functions:
|
||||
* - a function to test if a cached userdata matches some keydata
|
||||
* - a function to provide a new userdata struct to the cache
|
||||
* if there has been a cache miss.
|
||||
* - a function to release a userdata struct when it is
|
||||
* no longer being managed by the cache
|
||||
*
|
||||
* In the event of a cache miss the cache is allowed to grow up to
|
||||
* a specified maximum size. After the maximum size is reached then
|
||||
* the least-recently-used element is discarded to make room for the
|
||||
* new. The most-recently-returned value is always left at the
|
||||
* beginning of the list after retrieval.
|
||||
*
|
||||
* In the current implementation the cache is traversed by a linear
|
||||
* search from most-recent to least-recent. This linear search
|
||||
* probably limits the usefulness of this implementation to cache
|
||||
* sizes of a few tens of elements.
|
||||
*/
|
||||
|
||||
/*********************************************************/
|
||||
/* header */
|
||||
/*********************************************************/
|
||||
|
||||
#include <malloc.h>
|
||||
#ifndef NULL
|
||||
#define NULL (void *)0
|
||||
#endif
|
||||
|
||||
/* user defined function templates */
|
||||
typedef int (*gdCacheTestFn_t)(void *userdata, void *keydata);
|
||||
typedef void *(*gdCacheFetchFn_t)(char **error, void *keydata);
|
||||
typedef void (*gdCacheReleaseFn_t)(void *userdata);
|
||||
|
||||
/* element structure */
|
||||
typedef struct gdCache_element_s gdCache_element_t;
|
||||
struct gdCache_element_s {
|
||||
gdCache_element_t *next;
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
/* head structure */
|
||||
typedef struct gdCache_head_s gdCache_head_t;
|
||||
struct gdCache_head_s {
|
||||
gdCache_element_t *mru;
|
||||
int size;
|
||||
char *error;
|
||||
gdCacheTestFn_t gdCacheTest;
|
||||
gdCacheFetchFn_t gdCacheFetch;
|
||||
gdCacheReleaseFn_t gdCacheRelease;
|
||||
};
|
||||
|
||||
/* function templates */
|
||||
gdCache_head_t *
|
||||
gdCacheCreate(
|
||||
int size,
|
||||
gdCacheTestFn_t gdCacheTest,
|
||||
gdCacheFetchFn_t gdCacheFetch,
|
||||
gdCacheReleaseFn_t gdCacheRelease );
|
||||
|
||||
void
|
||||
gdCacheDelete( gdCache_head_t *head );
|
||||
|
||||
void *
|
||||
gdCacheGet( gdCache_head_t *head, void *keydata );
|
118
ext/gd/libgd/gddemo.c
Normal file
118
ext/gd/libgd/gddemo.c
Normal file
@ -0,0 +1,118 @@
|
||||
#include <stdio.h>
|
||||
#include "gd.h"
|
||||
#include "gdfontg.h"
|
||||
#include "gdfonts.h"
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
/* Input and output files */
|
||||
FILE *in;
|
||||
FILE *out;
|
||||
|
||||
/* Input and output images */
|
||||
gdImagePtr im_in = 0, im_out = 0;
|
||||
|
||||
/* Brush image */
|
||||
gdImagePtr brush;
|
||||
|
||||
/* Color indexes */
|
||||
int white;
|
||||
int blue;
|
||||
int red;
|
||||
int green;
|
||||
|
||||
/* Points for polygon */
|
||||
gdPoint points[3];
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Set transparent color. */
|
||||
gdImageColorTransparent (im_out, white);
|
||||
|
||||
/* 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");
|
||||
fprintf (stderr, "is much more impressive if demoin.png\n");
|
||||
fprintf (stderr, "is available.\n");
|
||||
im_in = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
im_in = gdImageCreateFromPng (in);
|
||||
fclose (in);
|
||||
/* Now copy, and magnify as we do so */
|
||||
gdImageCopyResized (im_out, im_in,
|
||||
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, 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, 128, 128, 60, 20, 0, 720, blue);
|
||||
/* Arc */
|
||||
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 = 64;
|
||||
points[0].y = 0;
|
||||
points[1].x = 0;
|
||||
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 = gdImageCreateTrueColor (16, 16);
|
||||
gdImageCopyResized (brush, im_in,
|
||||
0, 0, 0, 0,
|
||||
gdImageSX (brush), gdImageSY (brush),
|
||||
gdImageSX (im_in), gdImageSY (im_in));
|
||||
gdImageSetBrush (im_out, brush);
|
||||
/* With a style, so they won't overprint each other.
|
||||
Normally, they would, yielding a fat-brush effect. */
|
||||
style[0] = 0;
|
||||
style[1] = 0;
|
||||
style[2] = 0;
|
||||
style[3] = 0;
|
||||
style[4] = 0;
|
||||
style[5] = 0;
|
||||
style[6] = 0;
|
||||
style[7] = 1;
|
||||
gdImageSetStyle (im_out, style, 8);
|
||||
/* Draw the styled, brushed line */
|
||||
gdImageLine (im_out, 0, 255, 255, 0, gdStyledBrushed);
|
||||
}
|
||||
/* Text */
|
||||
gdImageString (im_out, gdFontGiant, 32, 32,
|
||||
(unsigned char *) "hi", red);
|
||||
gdImageStringUp (im_out, gdFontSmall, 64, 64,
|
||||
(unsigned char *) "hi", red);
|
||||
/* Make output image interlaced (progressive, in the case of JPEG) */
|
||||
gdImageInterlace (im_out, 1);
|
||||
out = fopen ("demoout.png", "wb");
|
||||
/* Write PNG */
|
||||
gdImagePng (im_out, out);
|
||||
fclose (out);
|
||||
gdImageDestroy (im_out);
|
||||
if (im_in)
|
||||
{
|
||||
gdImageDestroy (im_in);
|
||||
}
|
||||
return 0;
|
||||
}
|
4384
ext/gd/libgd/gdfontg.c
Normal file
4384
ext/gd/libgd/gdfontg.c
Normal file
File diff suppressed because it is too large
Load Diff
29
ext/gd/libgd/gdfontg.h
Normal file
29
ext/gd/libgd/gdfontg.h
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
#ifndef _GDFONTG_H_
|
||||
#define _GDFONTG_H_ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
This is a header file for gd font, generated using
|
||||
bdftogd version 0.51 by Jan Pazdziora, adelton@fi.muni.cz
|
||||
from bdf font
|
||||
-Misc-Fixed-Bold-R-Normal-Sans-15-140-75-75-C-90-ISO8859-2
|
||||
at Mon Jan 26 14:45:58 1998.
|
||||
The original bdf was holding following copyright:
|
||||
"Libor Skarvada, libor@informatics.muni.cz"
|
||||
*/
|
||||
|
||||
|
||||
#include "gd.h"
|
||||
|
||||
extern gdFontPtr gdFontGiant;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
4641
ext/gd/libgd/gdfontl.c
Normal file
4641
ext/gd/libgd/gdfontl.c
Normal file
File diff suppressed because it is too large
Load Diff
30
ext/gd/libgd/gdfontl.h
Normal file
30
ext/gd/libgd/gdfontl.h
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
#ifndef _GDFONTL_H_
|
||||
#define _GDFONTL_H_ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
This is a header file for gd font, generated using
|
||||
bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz
|
||||
from bdf font
|
||||
-misc-fixed-medium-r-normal--16-140-75-75-c-80-iso8859-2
|
||||
at Tue Jan 6 19:39:27 1998.
|
||||
|
||||
The original bdf was holding following copyright:
|
||||
"Libor Skarvada, libor@informatics.muni.cz"
|
||||
*/
|
||||
|
||||
|
||||
#include "gd.h"
|
||||
|
||||
extern gdFontPtr gdFontLarge;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
3871
ext/gd/libgd/gdfontmb.c
Normal file
3871
ext/gd/libgd/gdfontmb.c
Normal file
File diff suppressed because it is too large
Load Diff
28
ext/gd/libgd/gdfontmb.h
Normal file
28
ext/gd/libgd/gdfontmb.h
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
#ifndef _GDFONTMB_H_
|
||||
#define _GDFONTMB_H_ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
This is a header file for gd font, generated using
|
||||
bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz
|
||||
from bdf font
|
||||
-misc-fixed-bold-r-normal-sans-13-94-100-100-c-70-iso8859-2
|
||||
at Thu Jan 8 13:54:57 1998.
|
||||
No copyright info was found in the original bdf.
|
||||
*/
|
||||
|
||||
|
||||
#include "gd.h"
|
||||
|
||||
extern gdFontPtr gdFontMediumBold;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
3871
ext/gd/libgd/gdfonts.c
Normal file
3871
ext/gd/libgd/gdfonts.c
Normal file
File diff suppressed because it is too large
Load Diff
28
ext/gd/libgd/gdfonts.h
Normal file
28
ext/gd/libgd/gdfonts.h
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
#ifndef _GDFONTS_H_
|
||||
#define _GDFONTS_H_ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
This is a header file for gd font, generated using
|
||||
bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz
|
||||
from bdf font
|
||||
-misc-fixed-medium-r-semicondensed-sans-12-116-75-75-c-60-iso8859-2
|
||||
at Thu Jan 8 14:13:20 1998.
|
||||
No copyright info was found in the original bdf.
|
||||
*/
|
||||
|
||||
|
||||
#include "gd.h"
|
||||
|
||||
extern gdFontPtr gdFontSmall;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
2592
ext/gd/libgd/gdfontt.c
Normal file
2592
ext/gd/libgd/gdfontt.c
Normal file
File diff suppressed because it is too large
Load Diff
29
ext/gd/libgd/gdfontt.h
Normal file
29
ext/gd/libgd/gdfontt.h
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
#ifndef _GDFONTT_H_
|
||||
#define _GDFONTT_H_ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
This is a header file for gd font, generated using
|
||||
bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz
|
||||
from bdf font
|
||||
-Misc-Fixed-Medium-R-Normal--8-80-75-75-C-50-ISO8859-2
|
||||
at Thu Jan 8 13:49:54 1998.
|
||||
The original bdf was holding following copyright:
|
||||
"Libor Skarvada, libor@informatics.muni.cz"
|
||||
*/
|
||||
|
||||
|
||||
#include "gd.h"
|
||||
|
||||
extern gdFontPtr gdFontTiny;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
936
ext/gd/libgd/gdft.c
Normal file
936
ext/gd/libgd/gdft.c
Normal file
@ -0,0 +1,936 @@
|
||||
|
||||
/********************************************/
|
||||
/* gd interface to freetype library */
|
||||
/* */
|
||||
/* John Ellson ellson@lucent.com */
|
||||
/********************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "gd.h"
|
||||
#include "gdhelpers.h"
|
||||
|
||||
#ifndef MSWIN32
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#define R_OK 2
|
||||
#endif
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return "libgd was not built with FreeType font support\n";
|
||||
}
|
||||
#else
|
||||
|
||||
#include "gdcache.h"
|
||||
#include "freetype/freetype.h"
|
||||
#include "freetype/ftglyph.h"
|
||||
|
||||
/* number of fonts cached before least recently used is replaced */
|
||||
#define FONTCACHESIZE 6
|
||||
|
||||
/* number of antialias color lookups cached */
|
||||
#define TWEENCOLORCACHESIZE 32
|
||||
|
||||
/*
|
||||
* Line separation as a factor of font height.
|
||||
* No space between if LINESPACE = 1.00
|
||||
* Line separation will be rounded up to next pixel row.
|
||||
*/
|
||||
#define LINESPACE 1.05
|
||||
|
||||
/*
|
||||
* The character (space) used to separate alternate fonts in the
|
||||
* fontlist parameter to gdImageStringFT.
|
||||
*/
|
||||
#define LISTSEPARATOR " "
|
||||
|
||||
/*
|
||||
* DEFAULT_FONTPATH and PATHSEPARATOR are host type dependent and
|
||||
* are normally set by configure in gvconfig.h. These are just
|
||||
* some last resort values that might match some Un*x system
|
||||
* if building this version of gd separate from graphviz.
|
||||
*/
|
||||
#ifndef DEFAULT_FONTPATH
|
||||
#define DEFAULT_FONTPATH "/usr/share/fonts/truetype"
|
||||
#endif
|
||||
#ifndef PATHSEPARATOR
|
||||
#define PATHSEPARATOR ":"
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define FALSE 0
|
||||
#define TRUE !FALSE
|
||||
#endif
|
||||
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *fontlist; /* key */
|
||||
FT_Library *library;
|
||||
FT_Face face;
|
||||
FT_Bool have_char_map_unicode, have_char_map_big5, have_char_map_sjis,
|
||||
have_char_map_apple_roman;
|
||||
gdCache_head_t *glyphCache;
|
||||
}
|
||||
font_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *fontlist; /* key */
|
||||
FT_Library *library;
|
||||
}
|
||||
fontkey_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int pixel; /* key */
|
||||
int bgcolor; /* key */
|
||||
int fgcolor; /* key *//* -ve means no antialias */
|
||||
gdImagePtr im; /* key */
|
||||
int tweencolor;
|
||||
}
|
||||
tweencolor_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int pixel; /* key */
|
||||
int bgcolor; /* key */
|
||||
int fgcolor; /* key *//* -ve means no antialias */
|
||||
gdImagePtr im; /* key */
|
||||
}
|
||||
tweencolorkey_t;
|
||||
|
||||
/********************************************************************
|
||||
* gdTcl_UtfToUniChar is borrowed from Tcl ...
|
||||
*/
|
||||
/*
|
||||
* tclUtf.c --
|
||||
*
|
||||
* Routines for manipulating UTF-8 strings.
|
||||
*
|
||||
* Copyright (c) 1997-1998 Sun Microsystems, Inc.
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution
|
||||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*
|
||||
* SCCS: @(#) tclUtf.c 1.25 98/01/28 18:02:43
|
||||
*/
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* gdTcl_UtfToUniChar --
|
||||
*
|
||||
* Extract the Tcl_UniChar represented by the UTF-8 string. Bad
|
||||
* UTF-8 sequences are converted to valid Tcl_UniChars and processing
|
||||
* continues. Equivalent to Plan 9 chartorune().
|
||||
*
|
||||
* The caller must ensure that the source buffer is long enough that
|
||||
* this routine does not run off the end and dereference non-existent
|
||||
* memory looking for trail bytes. If the source buffer is known to
|
||||
* be '\0' terminated, this cannot happen. Otherwise, the caller
|
||||
* should call Tcl_UtfCharComplete() before calling this routine to
|
||||
* ensure that enough bytes remain in the string.
|
||||
*
|
||||
* Results:
|
||||
* *chPtr is filled with the Tcl_UniChar, and the return value is the
|
||||
* number of bytes from the UTF-8 string that were consumed.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef JISX0208
|
||||
#include "jisx0208.h"
|
||||
#endif
|
||||
|
||||
#define Tcl_UniChar int
|
||||
#define TCL_UTF_MAX 3
|
||||
static int
|
||||
gdTcl_UtfToUniChar (char *str, Tcl_UniChar * chPtr)
|
||||
/* str is the UTF8 next character pointer */
|
||||
/* chPtr is the int for the result */
|
||||
{
|
||||
int byte;
|
||||
|
||||
/* HTML4.0 entities in decimal form, e.g. Å */
|
||||
byte = *((unsigned char *) str);
|
||||
if (byte == '&')
|
||||
{
|
||||
int i, n = 0;
|
||||
|
||||
byte = *((unsigned char *) (str + 1));
|
||||
if (byte == '#')
|
||||
{
|
||||
for (i = 2; i < 8; i++)
|
||||
{
|
||||
byte = *((unsigned char *) (str + i));
|
||||
if (byte >= '0' && byte <= '9')
|
||||
{
|
||||
n = (n * 10) + (byte - '0');
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (byte == ';')
|
||||
{
|
||||
*chPtr = (Tcl_UniChar) n;
|
||||
return ++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unroll 1 to 3 byte UTF-8 sequences, use loop to handle longer ones.
|
||||
*/
|
||||
|
||||
byte = *((unsigned char *) str);
|
||||
#ifdef JISX0208
|
||||
if (0xA1 <= byte && byte <= 0xFE)
|
||||
{
|
||||
int ku, ten;
|
||||
|
||||
ku = (byte & 0x7F) - 0x20;
|
||||
ten = (str[1] & 0x7F) - 0x20;
|
||||
if ((ku < 1 || ku > 92) || (ten < 1 || ten > 94))
|
||||
{
|
||||
*chPtr = (Tcl_UniChar) byte;
|
||||
return 1;
|
||||
}
|
||||
|
||||
*chPtr = (Tcl_UniChar) UnicodeTbl[ku - 1][ten - 1];
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
#endif /* JISX0208 */
|
||||
if (byte < 0xC0)
|
||||
{
|
||||
/*
|
||||
* Handles properly formed UTF-8 characters between
|
||||
* 0x01 and 0x7F. Also treats \0 and naked trail
|
||||
* bytes 0x80 to 0xBF as valid characters representing
|
||||
* themselves.
|
||||
*/
|
||||
|
||||
*chPtr = (Tcl_UniChar) byte;
|
||||
return 1;
|
||||
}
|
||||
else if (byte < 0xE0)
|
||||
{
|
||||
if ((str[1] & 0xC0) == 0x80)
|
||||
{
|
||||
/*
|
||||
* Two-byte-character lead-byte followed
|
||||
* by a trail-byte.
|
||||
*/
|
||||
|
||||
*chPtr = (Tcl_UniChar) (((byte & 0x1F) << 6)
|
||||
| (str[1] & 0x3F));
|
||||
return 2;
|
||||
}
|
||||
/*
|
||||
* A two-byte-character lead-byte not followed by trail-byte
|
||||
* represents itself.
|
||||
*/
|
||||
|
||||
*chPtr = (Tcl_UniChar) byte;
|
||||
return 1;
|
||||
}
|
||||
else if (byte < 0xF0)
|
||||
{
|
||||
if (((str[1] & 0xC0) == 0x80) && ((str[2] & 0xC0) == 0x80))
|
||||
{
|
||||
/*
|
||||
* Three-byte-character lead byte followed by
|
||||
* two trail bytes.
|
||||
*/
|
||||
|
||||
*chPtr = (Tcl_UniChar) (((byte & 0x0F) << 12)
|
||||
| ((str[1] & 0x3F) << 6) | (str[2] & 0x3F));
|
||||
return 3;
|
||||
}
|
||||
/*
|
||||
* A three-byte-character lead-byte not followed by
|
||||
* two trail-bytes represents itself.
|
||||
*/
|
||||
|
||||
*chPtr = (Tcl_UniChar) byte;
|
||||
return 1;
|
||||
}
|
||||
#if TCL_UTF_MAX > 3
|
||||
else
|
||||
{
|
||||
int ch, total, trail;
|
||||
|
||||
total = totalBytes[byte];
|
||||
trail = total - 1;
|
||||
if (trail > 0)
|
||||
{
|
||||
ch = byte & (0x3F >> trail);
|
||||
do
|
||||
{
|
||||
str++;
|
||||
if ((*str & 0xC0) != 0x80)
|
||||
{
|
||||
*chPtr = byte;
|
||||
return 1;
|
||||
}
|
||||
ch <<= 6;
|
||||
ch |= (*str & 0x3F);
|
||||
trail--;
|
||||
}
|
||||
while (trail > 0);
|
||||
*chPtr = ch;
|
||||
return total;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
*chPtr = (Tcl_UniChar) byte;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
/* font cache functions */
|
||||
|
||||
static int
|
||||
fontTest (void *element, void *key)
|
||||
{
|
||||
font_t *a = (font_t *) element;
|
||||
fontkey_t *b = (fontkey_t *) key;
|
||||
|
||||
return (strcmp (a->fontlist, b->fontlist) == 0);
|
||||
}
|
||||
|
||||
static void *
|
||||
fontFetch (char **error, void *key)
|
||||
{
|
||||
font_t *a;
|
||||
fontkey_t *b = (fontkey_t *) key;
|
||||
int n;
|
||||
int font_found = 0;
|
||||
unsigned short platform, encoding;
|
||||
char *fontsearchpath, *fontpath, *fontlist;
|
||||
char *fullname = NULL;
|
||||
char *name, *path, *dir;
|
||||
char *strtok_ptr;
|
||||
FT_Error err;
|
||||
FT_CharMap found = 0;
|
||||
FT_CharMap charmap;
|
||||
|
||||
a = (font_t *) gdMalloc (sizeof (font_t));
|
||||
a->fontlist = strdup (b->fontlist);
|
||||
a->library = b->library;
|
||||
|
||||
/*
|
||||
* Search the pathlist for any of a list of font names.
|
||||
*/
|
||||
fontsearchpath = getenv ("GDFONTPATH");
|
||||
if (!fontsearchpath)
|
||||
fontsearchpath = DEFAULT_FONTPATH;
|
||||
path = strdup (fontsearchpath);
|
||||
fontlist = strdup (a->fontlist);
|
||||
|
||||
/*
|
||||
* Must use gd_strtok_r else pointer corrupted by strtok in nested loop.
|
||||
*/
|
||||
for (name = gd_strtok_r (fontlist, LISTSEPARATOR, &strtok_ptr); name;
|
||||
name = gd_strtok_r (0, LISTSEPARATOR, &strtok_ptr))
|
||||
{
|
||||
|
||||
/*
|
||||
* Allocate an oversized buffer that is guaranteed to be
|
||||
* big enough for all paths to be tested.
|
||||
*/
|
||||
fullname = gdRealloc (fullname,
|
||||
strlen (fontsearchpath) + strlen (name) + 6);
|
||||
/* if name is an absolute filename then test directly */
|
||||
if (*name == '/')
|
||||
{
|
||||
sprintf (fullname, "%s", name);
|
||||
if (access (fullname, R_OK) == 0)
|
||||
{
|
||||
font_found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (dir = strtok (path, PATHSEPARATOR); dir;
|
||||
dir = strtok (0, PATHSEPARATOR))
|
||||
{
|
||||
sprintf (fullname, "%s/%s.ttf", dir, name);
|
||||
if (access (fullname, R_OK) == 0)
|
||||
{
|
||||
font_found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (font_found)
|
||||
break;
|
||||
}
|
||||
gdFree (path);
|
||||
gdFree (fontlist);
|
||||
if (!font_found)
|
||||
{
|
||||
*error = "Could not find/open font";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = FT_New_Face (*b->library, fullname, 0, &a->face);
|
||||
if (err)
|
||||
{
|
||||
*error = "Could not read font";
|
||||
return NULL;
|
||||
}
|
||||
gdFree (fullname);
|
||||
|
||||
/* FIXME - This mapping stuff is imcomplete - where is the spec? */
|
||||
|
||||
a->have_char_map_unicode = 0;
|
||||
a->have_char_map_big5 = 0;
|
||||
a->have_char_map_sjis = 0;
|
||||
a->have_char_map_apple_roman = 0;
|
||||
for (n = 0; n < a->face->num_charmaps; n++)
|
||||
{
|
||||
charmap = a->face->charmaps[n];
|
||||
platform = charmap->platform_id;
|
||||
encoding = charmap->encoding_id;
|
||||
if ((platform == 3 && encoding == 1) /* Windows Unicode */
|
||||
|| (platform == 3 && encoding == 0) /* Windows Symbol */
|
||||
|| (platform == 2 && encoding == 1) /* ISO Unicode */
|
||||
|| (platform == 0))
|
||||
{ /* Apple Unicode */
|
||||
a->have_char_map_unicode = 1;
|
||||
found = charmap;
|
||||
}
|
||||
else if (platform == 3 && encoding == 4)
|
||||
{ /* Windows Big5 */
|
||||
a->have_char_map_big5 = 1;
|
||||
found = charmap;
|
||||
}
|
||||
else if (platform == 3 && encoding == 2)
|
||||
{ /* Windows Sjis */
|
||||
a->have_char_map_sjis = 1;
|
||||
found = charmap;
|
||||
}
|
||||
else if ((platform == 1 && encoding == 0) /* Apple Roman */
|
||||
|| (platform == 2 && encoding == 0))
|
||||
{ /* ISO ASCII */
|
||||
a->have_char_map_apple_roman = 1;
|
||||
found = charmap;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
*error = "Unable to find a CharMap that I can handle";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void *) a;
|
||||
}
|
||||
|
||||
static void
|
||||
fontRelease (void *element)
|
||||
{
|
||||
font_t *a = (font_t *) element;
|
||||
|
||||
FT_Done_Face (a->face);
|
||||
gdFree (a->fontlist);
|
||||
gdFree ((char *) element);
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
/* tweencolor cache functions */
|
||||
|
||||
static int
|
||||
tweenColorTest (void *element, void *key)
|
||||
{
|
||||
tweencolor_t *a = (tweencolor_t *) element;
|
||||
tweencolorkey_t *b = (tweencolorkey_t *) key;
|
||||
|
||||
return (a->pixel == b->pixel
|
||||
&& a->bgcolor == b->bgcolor
|
||||
&& a->fgcolor == b->fgcolor
|
||||
&& a->im == b->im);
|
||||
}
|
||||
|
||||
/*
|
||||
* Computes a color in im's color table that is part way between
|
||||
* the background and foreground colors proportional to the gray
|
||||
* pixel value in the range 0-NUMCOLORS. The fg and bg colors must already
|
||||
* be in the color table.
|
||||
*/
|
||||
static void *
|
||||
tweenColorFetch (char **error, void *key)
|
||||
{
|
||||
tweencolor_t *a;
|
||||
tweencolorkey_t *b = (tweencolorkey_t *) key;
|
||||
int pixel, npixel, bg, fg;
|
||||
gdImagePtr im;
|
||||
|
||||
a = (tweencolor_t *) gdMalloc (sizeof (tweencolor_t));
|
||||
pixel = a->pixel = b->pixel;
|
||||
bg = a->bgcolor = b->bgcolor;
|
||||
fg = a->fgcolor = b->fgcolor;
|
||||
im = b->im;
|
||||
|
||||
/* if fg is specified by a negative color idx, then don't antialias */
|
||||
if (fg < 0)
|
||||
{
|
||||
a->tweencolor = -fg;
|
||||
}
|
||||
else
|
||||
{
|
||||
npixel = NUMCOLORS - pixel;
|
||||
if (im->trueColor)
|
||||
{
|
||||
/* 2.0.1: use gdImageSetPixel to do the alpha blending work,
|
||||
or to just store the alpha level. All we have to do here
|
||||
is incorporate our knowledge of the percentage of this
|
||||
pixel that is really "lit" by pushing the alpha value
|
||||
up toward transparency in edge regions. */
|
||||
a->tweencolor = gdTrueColorAlpha (
|
||||
gdTrueColorGetRed (fg),
|
||||
gdTrueColorGetGreen (fg),
|
||||
gdTrueColorGetBlue (fg),
|
||||
gdAlphaMax - (gdTrueColorGetAlpha (fg) * pixel / 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);
|
||||
}
|
||||
}
|
||||
return (void *) a;
|
||||
}
|
||||
|
||||
static void
|
||||
tweenColorRelease (void *element)
|
||||
{
|
||||
gdFree ((char *) 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)
|
||||
{
|
||||
unsigned char *pixel;
|
||||
int *tpixel;
|
||||
int x, y, row, col, pc;
|
||||
|
||||
tweencolor_t *tc_elem;
|
||||
tweencolorkey_t tc_key;
|
||||
|
||||
/* initialize tweenColorCache on first call */
|
||||
static gdCache_head_t *tc_cache;
|
||||
|
||||
if (!tc_cache)
|
||||
{
|
||||
tc_cache = gdCacheCreate (TWEENCOLORCACHESIZE,
|
||||
tweenColorTest, tweenColorFetch, tweenColorRelease);
|
||||
}
|
||||
|
||||
/* copy to image, mapping colors */
|
||||
tc_key.fgcolor = fg;
|
||||
tc_key.im = im;
|
||||
for (row = 0; row < bitmap.rows; row++)
|
||||
{
|
||||
pc = row * bitmap.pitch;
|
||||
y = pen_y + row;
|
||||
|
||||
/* clip if out of bounds */
|
||||
if (y >= im->sy || y < 0)
|
||||
continue;
|
||||
|
||||
for (col = 0; col < bitmap.width; col++, pc++)
|
||||
{
|
||||
if (bitmap.pixel_mode == ft_pixel_mode_grays)
|
||||
{
|
||||
/*
|
||||
* Round to NUMCOLORS levels of antialiasing for
|
||||
* index color images since only 256 colors are
|
||||
* available.
|
||||
*/
|
||||
tc_key.pixel = ((bitmap.buffer[pc] * NUMCOLORS)
|
||||
+ bitmap.num_grays / 2)
|
||||
/ (bitmap.num_grays - 1);
|
||||
}
|
||||
else if (bitmap.pixel_mode == ft_pixel_mode_mono)
|
||||
{
|
||||
tc_key.pixel = ((bitmap.buffer[pc / 8]
|
||||
<< (pc % 8)) & 128) ? NUMCOLORS : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Unsupported ft_pixel_mode";
|
||||
}
|
||||
|
||||
if (tc_key.pixel > 0)
|
||||
{ /* if not background */
|
||||
x = pen_x + col;
|
||||
|
||||
/* clip if out of bounds */
|
||||
if (x >= im->sx || x < 0)
|
||||
continue;
|
||||
/* get pixel location in gd buffer */
|
||||
if (im->trueColor)
|
||||
{
|
||||
tpixel = &im->tpixels[y][x];
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = &im->pixels[y][x];
|
||||
}
|
||||
if (tc_key.pixel == NUMCOLORS)
|
||||
{
|
||||
/* use fg color directly */
|
||||
if (im->trueColor)
|
||||
{
|
||||
*tpixel = fg;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pixel = fg;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* find antialised color */
|
||||
if (im->trueColor)
|
||||
{
|
||||
tc_key.bgcolor = *tpixel;
|
||||
}
|
||||
else
|
||||
{
|
||||
tc_key.bgcolor = *pixel;
|
||||
}
|
||||
tc_elem = (tweencolor_t *) gdCacheGet (
|
||||
tc_cache, &tc_key);
|
||||
if (im->trueColor)
|
||||
{
|
||||
*tpixel = tc_elem->tweencolor;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pixel = tc_elem->tweencolor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (char *) NULL;
|
||||
}
|
||||
|
||||
extern int any2eucjp (char *, char *, unsigned int);
|
||||
|
||||
/********************************************************************/
|
||||
/* gdImageStringFT - render a utf8 string onto a gd image */
|
||||
|
||||
char *
|
||||
gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
|
||||
double ptsize, double angle, int x, int y, char *string)
|
||||
{
|
||||
FT_BBox bbox, glyph_bbox;
|
||||
FT_Matrix matrix;
|
||||
FT_Vector pen, delta, penf;
|
||||
FT_Face face;
|
||||
FT_Glyph image;
|
||||
FT_GlyphSlot slot;
|
||||
FT_Error err;
|
||||
FT_Bool use_kerning;
|
||||
FT_UInt glyph_index, previous;
|
||||
double sin_a = sin (angle);
|
||||
double cos_a = cos (angle);
|
||||
int len, i = 0, ch;
|
||||
int x1 = 0, y1 = 0;
|
||||
font_t *font;
|
||||
fontkey_t fontkey;
|
||||
char *next;
|
||||
char *tmpstr = 0;
|
||||
int render = (im && (im->trueColor || (fg <= 255 && fg >= -255)));
|
||||
FT_BitmapGlyph bm;
|
||||
|
||||
/***** initialize font library and font cache on first call ******/
|
||||
static gdCache_head_t *fontCache;
|
||||
static FT_Library library;
|
||||
|
||||
if (!fontCache)
|
||||
{
|
||||
if (FT_Init_FreeType (&library))
|
||||
{
|
||||
return "Failure to initialize font library";
|
||||
}
|
||||
fontCache = gdCacheCreate (FONTCACHESIZE,
|
||||
fontTest, fontFetch, fontRelease);
|
||||
}
|
||||
/*****/
|
||||
|
||||
/* get the font (via font cache) */
|
||||
fontkey.fontlist = fontlist;
|
||||
fontkey.library = &library;
|
||||
font = (font_t *) gdCacheGet (fontCache, &fontkey);
|
||||
if (!font)
|
||||
{
|
||||
return fontCache->error;
|
||||
}
|
||||
face = font->face; /* shortcut */
|
||||
slot = face->glyph; /* shortcut */
|
||||
|
||||
if (FT_Set_Char_Size (face, 0, (FT_F26Dot6) (ptsize * 64),
|
||||
GD_RESOLUTION, GD_RESOLUTION))
|
||||
{
|
||||
return "Could not set character size";
|
||||
}
|
||||
|
||||
matrix.xx = (FT_Fixed) (cos_a * (1 << 16));
|
||||
matrix.yx = (FT_Fixed) (sin_a * (1 << 16));
|
||||
matrix.xy = -matrix.yx;
|
||||
matrix.yy = matrix.xx;
|
||||
|
||||
penf.x = penf.y = 0; /* running position of non-rotated string */
|
||||
pen.x = pen.y = 0; /* running position of rotated string */
|
||||
bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0;
|
||||
|
||||
use_kerning = FT_HAS_KERNING (face);
|
||||
previous = 0;
|
||||
|
||||
#ifndef JISX0208
|
||||
if (font->have_char_map_sjis)
|
||||
{
|
||||
#endif
|
||||
if (tmpstr = (char *) gdMalloc (BUFSIZ))
|
||||
{
|
||||
any2eucjp (tmpstr, string, BUFSIZ);
|
||||
next = tmpstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
next = string;
|
||||
}
|
||||
#ifndef JISX0208
|
||||
}
|
||||
else
|
||||
{
|
||||
next = string;
|
||||
}
|
||||
#endif
|
||||
while (*next)
|
||||
{
|
||||
ch = *next;
|
||||
|
||||
/* carriage returns */
|
||||
if (ch == '\r')
|
||||
{
|
||||
penf.x = 0;
|
||||
x1 = (penf.x * cos_a - penf.y * sin_a + 32) / 64;
|
||||
y1 = (penf.x * sin_a + penf.y * cos_a + 32) / 64;
|
||||
pen.x = pen.y = 0;
|
||||
previous = 0; /* clear kerning flag */
|
||||
next++;
|
||||
continue;
|
||||
}
|
||||
/* newlines */
|
||||
if (ch == '\n')
|
||||
{
|
||||
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++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (font->have_char_map_unicode)
|
||||
{
|
||||
/* use UTF-8 mapping from ASCII */
|
||||
len = gdTcl_UtfToUniChar (next, &ch);
|
||||
next += len;
|
||||
}
|
||||
else if (font->have_char_map_sjis)
|
||||
{
|
||||
unsigned char c;
|
||||
int jiscode;
|
||||
|
||||
c = *next;
|
||||
if (0xA1 <= c && c <= 0xFE)
|
||||
{
|
||||
next++;
|
||||
jiscode = 0x100 * (c & 0x7F) + ((*next) & 0x7F);
|
||||
|
||||
ch = (jiscode >> 8) & 0xFF;
|
||||
jiscode &= 0xFF;
|
||||
|
||||
if (ch & 1)
|
||||
jiscode += 0x40 - 0x21;
|
||||
else
|
||||
jiscode += 0x9E - 0x21;
|
||||
|
||||
if (jiscode >= 0x7F)
|
||||
jiscode++;
|
||||
ch = (ch - 0x21) / 2 + 0x81;
|
||||
if (ch >= 0xA0)
|
||||
ch += 0x40;
|
||||
|
||||
ch = (ch << 8) + jiscode;
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = c & 0xFF; /* don't extend sign */
|
||||
}
|
||||
next++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Big 5 mapping:
|
||||
* use "JIS-8 half-width katakana" coding from 8-bit characters. Ref:
|
||||
* ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/japan.inf-032092.sjs
|
||||
*/
|
||||
ch = (*next) & 0xFF; /* don't extend sign */
|
||||
next++;
|
||||
if (ch >= 161 /* first code of JIS-8 pair */
|
||||
&& *next)
|
||||
{ /* don't advance past '\0' */
|
||||
/* TBB: Fix from Kwok Wah On: & 255 needed */
|
||||
ch = (ch * 256) + ((*next) & 255);
|
||||
next++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert character code to glyph index */
|
||||
glyph_index = FT_Get_Char_Index (face, ch);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* load glyph image into the slot (erase previous one) */
|
||||
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++;
|
||||
}
|
||||
|
||||
/* transform glyph image */
|
||||
FT_Glyph_Transform (image, &matrix, 0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* record current glyph index for kerning */
|
||||
previous = glyph_index;
|
||||
|
||||
/* increment pen position */
|
||||
pen.x += image->advance.x >> 10;
|
||||
pen.y -= image->advance.y >> 10;
|
||||
|
||||
penf.x += slot->metrics.horiAdvance;
|
||||
|
||||
FT_Done_Glyph (image);
|
||||
}
|
||||
|
||||
if (brect)
|
||||
{ /* only if need brect */
|
||||
/* For perfect rounding, must get sin(a + pi/4) and sin(a - pi/4). */
|
||||
double d1 = sin (angle + 0.78539816339744830962);
|
||||
double d2 = sin (angle - 0.78539816339744830962);
|
||||
|
||||
/* rotate bounding rectangle */
|
||||
brect[0] = (int) (bbox.xMin * cos_a - bbox.yMin * sin_a);
|
||||
brect[1] = (int) (bbox.xMin * sin_a + bbox.yMin * cos_a);
|
||||
brect[2] = (int) (bbox.xMax * cos_a - bbox.yMin * sin_a);
|
||||
brect[3] = (int) (bbox.xMax * sin_a + bbox.yMin * cos_a);
|
||||
brect[4] = (int) (bbox.xMax * cos_a - bbox.yMax * sin_a);
|
||||
brect[5] = (int) (bbox.xMax * sin_a + bbox.yMax * cos_a);
|
||||
brect[6] = (int) (bbox.xMin * cos_a - bbox.yMax * sin_a);
|
||||
brect[7] = (int) (bbox.xMin * sin_a + bbox.yMax * cos_a);
|
||||
|
||||
/* scale, round and offset brect */
|
||||
brect[0] = x + gdroundupdown (brect[0], d2 > 0);
|
||||
brect[1] = y - gdroundupdown (brect[1], d1 < 0);
|
||||
brect[2] = x + gdroundupdown (brect[2], d1 > 0);
|
||||
brect[3] = y - gdroundupdown (brect[3], d2 > 0);
|
||||
brect[4] = x + gdroundupdown (brect[4], d2 < 0);
|
||||
brect[5] = y - gdroundupdown (brect[5], d1 > 0);
|
||||
brect[6] = x + gdroundupdown (brect[6], d1 < 0);
|
||||
brect[7] = y - gdroundupdown (brect[7], d2 < 0);
|
||||
}
|
||||
|
||||
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 */
|
95
ext/gd/libgd/gdhelpers.c
Normal file
95
ext/gd/libgd/gdhelpers.c
Normal file
@ -0,0 +1,95 @@
|
||||
#include "gd.h"
|
||||
#include "gdhelpers.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* TBB: gd_strtok_r is not portable; provide an implementation */
|
||||
|
||||
#define SEP_TEST (separators[*((unsigned char *) s)])
|
||||
|
||||
char *
|
||||
gd_strtok_r (char *s, char *sep, char **state)
|
||||
{
|
||||
char separators[256];
|
||||
char *start;
|
||||
char *result = 0;
|
||||
memset (separators, 0, sizeof (separators));
|
||||
while (*sep)
|
||||
{
|
||||
separators[*((unsigned char *) sep)] = 1;
|
||||
sep++;
|
||||
}
|
||||
if (!s)
|
||||
{
|
||||
/* Pick up where we left off */
|
||||
s = *state;
|
||||
}
|
||||
start = s;
|
||||
/* 1. EOS */
|
||||
if (!(*s))
|
||||
{
|
||||
*state = s;
|
||||
return 0;
|
||||
}
|
||||
/* 2. Leading separators, if any */
|
||||
if (SEP_TEST)
|
||||
{
|
||||
do
|
||||
{
|
||||
s++;
|
||||
}
|
||||
while (SEP_TEST);
|
||||
/* 2a. EOS after separators only */
|
||||
if (!(*s))
|
||||
{
|
||||
*state = s;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* 3. A token */
|
||||
result = s;
|
||||
do
|
||||
{
|
||||
/* 3a. Token at end of string */
|
||||
if (!(*s))
|
||||
{
|
||||
*state = s;
|
||||
return result;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
while (!SEP_TEST);
|
||||
/* 4. Terminate token and skip trailing separators */
|
||||
*s = '\0';
|
||||
do
|
||||
{
|
||||
s++;
|
||||
}
|
||||
while (SEP_TEST);
|
||||
/* 5. Return token */
|
||||
*state = s;
|
||||
return result;
|
||||
}
|
||||
|
||||
void *
|
||||
gdCalloc (size_t nmemb, size_t size)
|
||||
{
|
||||
return calloc (nmemb, size);
|
||||
}
|
||||
|
||||
void *
|
||||
gdMalloc (size_t size)
|
||||
{
|
||||
return malloc (size);
|
||||
}
|
||||
|
||||
void *
|
||||
gdRealloc (void *ptr, size_t size)
|
||||
{
|
||||
return realloc (ptr, size);
|
||||
}
|
||||
|
||||
void
|
||||
gdFree (void *ptr)
|
||||
{
|
||||
free (ptr);
|
||||
}
|
17
ext/gd/libgd/gdhelpers.h
Normal file
17
ext/gd/libgd/gdhelpers.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef GDHELPERS_H
|
||||
#define GDHELPERS_H 1
|
||||
|
||||
/* TBB: strtok_r is not universal; provide an implementation of it. */
|
||||
|
||||
extern char *gd_strtok_r(char *s, char *sep, char **state);
|
||||
|
||||
/* These functions wrap memory management. gdFree is
|
||||
in gd.h, where callers can utilize it to correctly
|
||||
free memory allocated by these functions with the
|
||||
right version of free(). */
|
||||
void *gdCalloc(size_t nmemb, size_t size);
|
||||
void *gdMalloc(size_t size);
|
||||
void *gdRealloc(void *ptr, size_t size);
|
||||
|
||||
#endif /* GDHELPERS_H */
|
||||
|
626
ext/gd/libgd/gdkanji.c
Normal file
626
ext/gd/libgd/gdkanji.c
Normal file
@ -0,0 +1,626 @@
|
||||
|
||||
/* gdkanji.c (Kanji code converter) */
|
||||
/* written by Masahito Yamaga (ma@yama-ga.com) */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "gd.h"
|
||||
#include "gdhelpers.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#if defined(HAVE_ICONV_H) || defined(HAVE_ICONV)
|
||||
#include <iconv.h>
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ICONV_H) && !defined(HAVE_ICONV)
|
||||
#define HAVE_ICONV 1
|
||||
#endif
|
||||
|
||||
#define LIBNAME "any2eucjp()"
|
||||
|
||||
#if defined(__MSC__) || defined(__BORLANDC__) || defined(__TURBOC__) || defined(_Windows) || defined(MSDOS)
|
||||
#ifndef SJISPRE
|
||||
#define SJISPRE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef TRUE
|
||||
#undef TRUE
|
||||
#endif
|
||||
#ifdef FALSE
|
||||
#undef FALSE
|
||||
#endif
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define NEW 1
|
||||
#define OLD 2
|
||||
#define ESCI 3
|
||||
#define NEC 4
|
||||
#define EUC 5
|
||||
#define SJIS 6
|
||||
#define EUCORSJIS 7
|
||||
#define ASCII 8
|
||||
|
||||
#define NEWJISSTR "JIS7"
|
||||
#define OLDJISSTR "jis"
|
||||
#define EUCSTR "eucJP"
|
||||
#define SJISSTR "SJIS"
|
||||
|
||||
#define ESC 27
|
||||
#define SS2 142
|
||||
|
||||
static void
|
||||
debug (const char *format,...)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
fprintf (stdout, "%s: ", LIBNAME);
|
||||
vfprintf (stdout, format, args);
|
||||
fprintf (stdout, "\n");
|
||||
va_end (args);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
error (const char *format,...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
fprintf (stderr, "%s: ", LIBNAME);
|
||||
vfprintf (stderr, format, args);
|
||||
fprintf (stderr, "\n");
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
/* DetectKanjiCode() derived from DetectCodeType() by Ken Lunde. */
|
||||
|
||||
static int
|
||||
DetectKanjiCode (unsigned char *str)
|
||||
{
|
||||
static int whatcode = ASCII;
|
||||
int oldcode = ASCII;
|
||||
int c, i;
|
||||
char *lang = NULL;
|
||||
|
||||
c = '\1';
|
||||
i = 0;
|
||||
|
||||
if (whatcode != EUCORSJIS && whatcode != ASCII)
|
||||
{
|
||||
oldcode = whatcode;
|
||||
whatcode = ASCII;
|
||||
}
|
||||
|
||||
while ((whatcode == EUCORSJIS || whatcode == ASCII) && c != '\0')
|
||||
{
|
||||
if ((c = str[i++]) != '\0')
|
||||
{
|
||||
if (c == ESC)
|
||||
{
|
||||
c = str[i++];
|
||||
if (c == '$')
|
||||
{
|
||||
c = str[i++];
|
||||
if (c == 'B')
|
||||
whatcode = NEW;
|
||||
else if (c == '@')
|
||||
whatcode = OLD;
|
||||
}
|
||||
else if (c == '(')
|
||||
{
|
||||
c = str[i++];
|
||||
if (c == 'I')
|
||||
whatcode = ESCI;
|
||||
}
|
||||
else if (c == 'K')
|
||||
whatcode = NEC;
|
||||
}
|
||||
else if ((c >= 129 && c <= 141) || (c >= 143 && c <= 159))
|
||||
whatcode = SJIS;
|
||||
else if (c == SS2)
|
||||
{
|
||||
c = str[i++];
|
||||
if ((c >= 64 && c <= 126) || (c >= 128 && c <= 160) || (c >= 224 && c <= 252))
|
||||
whatcode = SJIS;
|
||||
else if (c >= 161 && c <= 223)
|
||||
whatcode = EUCORSJIS;
|
||||
}
|
||||
else if (c >= 161 && c <= 223)
|
||||
{
|
||||
c = str[i++];
|
||||
if (c >= 240 && c <= 254)
|
||||
whatcode = EUC;
|
||||
else if (c >= 161 && c <= 223)
|
||||
whatcode = EUCORSJIS;
|
||||
else if (c >= 224 && c <= 239)
|
||||
{
|
||||
whatcode = EUCORSJIS;
|
||||
while (c >= 64 && c != '\0' && whatcode == EUCORSJIS)
|
||||
{
|
||||
if (c >= 129)
|
||||
{
|
||||
if (c <= 141 || (c >= 143 && c <= 159))
|
||||
whatcode = SJIS;
|
||||
else if (c >= 253 && c <= 254)
|
||||
whatcode = EUC;
|
||||
}
|
||||
c = str[i++];
|
||||
}
|
||||
}
|
||||
else if (c <= 159)
|
||||
whatcode = SJIS;
|
||||
}
|
||||
else if (c >= 240 && c <= 254)
|
||||
whatcode = EUC;
|
||||
else if (c >= 224 && c <= 239)
|
||||
{
|
||||
c = str[i++];
|
||||
if ((c >= 64 && c <= 126) || (c >= 128 && c <= 160))
|
||||
whatcode = SJIS;
|
||||
else if (c >= 253 && c <= 254)
|
||||
whatcode = EUC;
|
||||
else if (c >= 161 && c <= 252)
|
||||
whatcode = EUCORSJIS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (whatcode == ASCII)
|
||||
debug ("Kanji code not included.");
|
||||
else if (whatcode == EUCORSJIS)
|
||||
debug ("Kanji code not detected.");
|
||||
else
|
||||
debug ("Kanji code detected at %d byte.", i);
|
||||
#endif
|
||||
|
||||
if (whatcode == EUCORSJIS && oldcode != ASCII)
|
||||
whatcode = oldcode;
|
||||
|
||||
if (whatcode == EUCORSJIS)
|
||||
{
|
||||
if (getenv ("LC_ALL"))
|
||||
lang = getenv ("LC_ALL");
|
||||
else if (getenv ("LC_CTYPE"))
|
||||
lang = getenv ("LC_CTYPE");
|
||||
else if (getenv ("LANG"))
|
||||
lang = getenv ("LANG");
|
||||
|
||||
if (lang)
|
||||
{
|
||||
if (strcmp (lang, "ja_JP.SJIS") == 0 ||
|
||||
#ifdef hpux
|
||||
strcmp (lang, "japanese") == 0 ||
|
||||
#endif
|
||||
strcmp (lang, "ja_JP.mscode") == 0 ||
|
||||
strcmp (lang, "ja_JP.PCK") == 0)
|
||||
whatcode = SJIS;
|
||||
else if (strncmp (lang, "ja", 2) == 0)
|
||||
#ifdef SJISPRE
|
||||
whatcode = SJIS;
|
||||
#else
|
||||
whatcode = EUC;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (whatcode == EUCORSJIS)
|
||||
#ifdef SJISPRE
|
||||
whatcode = SJIS;
|
||||
#else
|
||||
whatcode = EUC;
|
||||
#endif
|
||||
|
||||
return whatcode;
|
||||
}
|
||||
|
||||
/* SJIStoJIS() is sjis2jis() by Ken Lunde. */
|
||||
|
||||
static void
|
||||
SJIStoJIS (int *p1, int *p2)
|
||||
{
|
||||
register unsigned char c1 = *p1;
|
||||
register unsigned char c2 = *p2;
|
||||
register int adjust = c2 < 159;
|
||||
register int rowOffset = c1 < 160 ? 112 : 176;
|
||||
register int cellOffset = adjust ? (31 + (c2 > 127)) : 126;
|
||||
|
||||
*p1 = ((c1 - rowOffset) << 1) - adjust;
|
||||
*p2 -= cellOffset;
|
||||
}
|
||||
|
||||
/* han2zen() was derived from han2zen() written by Ken Lunde. */
|
||||
|
||||
#define IS_DAKU(c) ((c >= 182 && c <= 196) || (c >= 202 && c <= 206) || (c == 179))
|
||||
#define IS_HANDAKU(c) (c >= 202 && c <= 206)
|
||||
|
||||
static void
|
||||
han2zen (int *p1, int *p2)
|
||||
{
|
||||
int c = *p1;
|
||||
int daku = FALSE;
|
||||
int handaku = FALSE;
|
||||
int mtable[][2] =
|
||||
{
|
||||
{129, 66},
|
||||
{129, 117},
|
||||
{129, 118},
|
||||
{129, 65},
|
||||
{129, 69},
|
||||
{131, 146},
|
||||
{131, 64},
|
||||
{131, 66},
|
||||
{131, 68},
|
||||
{131, 70},
|
||||
{131, 72},
|
||||
{131, 131},
|
||||
{131, 133},
|
||||
{131, 135},
|
||||
{131, 98},
|
||||
{129, 91},
|
||||
{131, 65},
|
||||
{131, 67},
|
||||
{131, 69},
|
||||
{131, 71},
|
||||
{131, 73},
|
||||
{131, 74},
|
||||
{131, 76},
|
||||
{131, 78},
|
||||
{131, 80},
|
||||
{131, 82},
|
||||
{131, 84},
|
||||
{131, 86},
|
||||
{131, 88},
|
||||
{131, 90},
|
||||
{131, 92},
|
||||
{131, 94},
|
||||
{131, 96},
|
||||
{131, 99},
|
||||
{131, 101},
|
||||
{131, 103},
|
||||
{131, 105},
|
||||
{131, 106},
|
||||
{131, 107},
|
||||
{131, 108},
|
||||
{131, 109},
|
||||
{131, 110},
|
||||
{131, 113},
|
||||
{131, 116},
|
||||
{131, 119},
|
||||
{131, 122},
|
||||
{131, 125},
|
||||
{131, 126},
|
||||
{131, 128},
|
||||
{131, 129},
|
||||
{131, 130},
|
||||
{131, 132},
|
||||
{131, 134},
|
||||
{131, 136},
|
||||
{131, 137},
|
||||
{131, 138},
|
||||
{131, 139},
|
||||
{131, 140},
|
||||
{131, 141},
|
||||
{131, 143},
|
||||
{131, 147},
|
||||
{129, 74},
|
||||
{129, 75}
|
||||
};
|
||||
|
||||
if (*p2 == 222 && IS_DAKU (*p1))
|
||||
daku = TRUE; /* Daku-ten */
|
||||
else if (*p2 == 223 && IS_HANDAKU (*p1))
|
||||
handaku = TRUE; /* Han-daku-ten */
|
||||
|
||||
*p1 = mtable[c - 161][0];
|
||||
*p2 = mtable[c - 161][1];
|
||||
|
||||
if (daku)
|
||||
{
|
||||
if ((*p2 >= 74 && *p2 <= 103) || (*p2 >= 110 && *p2 <= 122))
|
||||
(*p2)++;
|
||||
else if (*p2 == 131 && *p2 == 69)
|
||||
*p2 = 148;
|
||||
}
|
||||
else if (handaku && *p2 >= 110 && *p2 <= 122)
|
||||
(*p2) += 2;
|
||||
}
|
||||
|
||||
/* Recast strcpy to handle unsigned chars used below. */
|
||||
#define ustrcpy(A,B) (strcpy((char*)(A),(const char*)(B)))
|
||||
|
||||
static void
|
||||
do_convert (unsigned char *to, unsigned char *from, const char *code)
|
||||
{
|
||||
#ifdef HAVE_ICONV
|
||||
iconv_t cd;
|
||||
size_t from_len, to_len;
|
||||
|
||||
if ((cd = iconv_open (EUCSTR, code)) == (iconv_t) - 1)
|
||||
{
|
||||
error ("iconv_open() error");
|
||||
#ifdef HAVE_ERRNO_H
|
||||
if (errno == EINVAL)
|
||||
error ("invalid code specification: \"%s\" or \"%s\"",
|
||||
EUCSTR, code);
|
||||
#endif
|
||||
strcpy ((char *) to, (const char *) from);
|
||||
return;
|
||||
}
|
||||
|
||||
from_len = strlen ((const char *) from) + 1;
|
||||
to_len = BUFSIZ;
|
||||
|
||||
if (iconv (cd, (const char **) &from, &from_len,
|
||||
(char **) &to, &to_len) == -1)
|
||||
{
|
||||
#ifdef HAVE_ERRNO_H
|
||||
if (errno == EINVAL)
|
||||
error ("invalid end of input string");
|
||||
else if (errno == EILSEQ)
|
||||
error ("invalid code in input string");
|
||||
else if (errno == E2BIG)
|
||||
error ("output buffer overflow at do_convert()");
|
||||
else
|
||||
#endif
|
||||
error ("something happen");
|
||||
strcpy ((char *) to, (const char *) from);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iconv_close (cd) != 0)
|
||||
{
|
||||
error ("iconv_close() error");
|
||||
}
|
||||
#else
|
||||
int p1, p2, i, j;
|
||||
int jisx0208 = FALSE;
|
||||
int hankaku = FALSE;
|
||||
|
||||
j = 0;
|
||||
if (strcmp (code, NEWJISSTR) == 0 || strcmp (code, OLDJISSTR) == 0)
|
||||
{
|
||||
for (i = 0; from[i] != '\0' && j < BUFSIZ; i++)
|
||||
{
|
||||
if (from[i] == ESC)
|
||||
{
|
||||
i++;
|
||||
if (from[i] == '$')
|
||||
{
|
||||
jisx0208 = TRUE;
|
||||
hankaku = FALSE;
|
||||
i++;
|
||||
}
|
||||
else if (from[i] == '(')
|
||||
{
|
||||
jisx0208 = FALSE;
|
||||
i++;
|
||||
if (from[i] == 'I') /* Hankaku Kana */
|
||||
hankaku = TRUE;
|
||||
else
|
||||
hankaku = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (jisx0208)
|
||||
to[j++] = from[i] + 128;
|
||||
else if (hankaku)
|
||||
{
|
||||
to[j++] = SS2;
|
||||
to[j++] = from[i] + 128;
|
||||
}
|
||||
else
|
||||
to[j++] = from[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcmp (code, SJISSTR) == 0)
|
||||
{
|
||||
for (i = 0; from[i] != '\0' && j < BUFSIZ; i++)
|
||||
{
|
||||
p1 = from[i];
|
||||
if (p1 < 127)
|
||||
to[j++] = p1;
|
||||
else if ((p1 >= 161) && (p1 <= 223))
|
||||
{ /* Hankaku Kana */
|
||||
to[j++] = SS2;
|
||||
to[j++] = p1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p2 = from[++i];
|
||||
SJIStoJIS (&p1, &p2);
|
||||
to[j++] = p1 + 128;
|
||||
to[j++] = p2 + 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error ("invalid code specification: \"%s\"", code);
|
||||
return;
|
||||
}
|
||||
|
||||
if (j >= BUFSIZ)
|
||||
{
|
||||
error ("output buffer overflow at do_convert()");
|
||||
ustrcpy (to, from);
|
||||
}
|
||||
else
|
||||
to[j] = '\0';
|
||||
#endif /* HAVE_ICONV */
|
||||
}
|
||||
|
||||
static int
|
||||
do_check_and_conv (unsigned char *to, unsigned char *from)
|
||||
{
|
||||
static unsigned char tmp[BUFSIZ];
|
||||
int p1, p2, i, j;
|
||||
int kanji = TRUE;
|
||||
|
||||
switch (DetectKanjiCode (from))
|
||||
{
|
||||
case NEW:
|
||||
debug ("Kanji code is New JIS.");
|
||||
do_convert (tmp, from, NEWJISSTR);
|
||||
break;
|
||||
case OLD:
|
||||
debug ("Kanji code is Old JIS.");
|
||||
do_convert (tmp, from, OLDJISSTR);
|
||||
break;
|
||||
case ESCI:
|
||||
debug ("This string includes Hankaku-Kana (jisx0201) escape sequence [ESC] + ( + I.");
|
||||
do_convert (tmp, from, NEWJISSTR);
|
||||
break;
|
||||
case NEC:
|
||||
debug ("Kanji code is NEC Kanji.");
|
||||
error ("cannot convert NEC Kanji.");
|
||||
ustrcpy (tmp, from);
|
||||
kanji = FALSE;
|
||||
break;
|
||||
case EUC:
|
||||
debug ("Kanji code is EUC.");
|
||||
ustrcpy (tmp, from);
|
||||
break;
|
||||
case SJIS:
|
||||
debug ("Kanji code is SJIS.");
|
||||
do_convert (tmp, from, SJISSTR);
|
||||
break;
|
||||
case EUCORSJIS:
|
||||
debug ("Kanji code is EUC or SJIS.");
|
||||
ustrcpy (tmp, from);
|
||||
kanji = FALSE;
|
||||
break;
|
||||
case ASCII:
|
||||
debug ("This is ASCII string.");
|
||||
ustrcpy (tmp, from);
|
||||
kanji = FALSE;
|
||||
break;
|
||||
default:
|
||||
debug ("This string includes unknown code.");
|
||||
ustrcpy (tmp, from);
|
||||
kanji = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Hankaku Kana ---> Zenkaku Kana */
|
||||
if (kanji)
|
||||
{
|
||||
j = 0;
|
||||
for (i = 0; tmp[i] != '\0' && j < BUFSIZ; i++)
|
||||
{
|
||||
if (tmp[i] == SS2)
|
||||
{
|
||||
p1 = tmp[++i];
|
||||
if (tmp[i + 1] == SS2)
|
||||
{
|
||||
p2 = tmp[i + 2];
|
||||
if (p2 == 222 || p2 == 223)
|
||||
i += 2;
|
||||
else
|
||||
p2 = 0;
|
||||
}
|
||||
else
|
||||
p2 = 0;
|
||||
han2zen (&p1, &p2);
|
||||
SJIStoJIS (&p1, &p2);
|
||||
to[j++] = p1 + 128;
|
||||
to[j++] = p2 + 128;
|
||||
}
|
||||
else
|
||||
to[j++] = tmp[i];
|
||||
}
|
||||
|
||||
if (j >= BUFSIZ)
|
||||
{
|
||||
error ("output buffer overflow at Hankaku --> Zenkaku");
|
||||
ustrcpy (to, tmp);
|
||||
}
|
||||
else
|
||||
to[j] = '\0';
|
||||
}
|
||||
else
|
||||
ustrcpy (to, tmp);
|
||||
|
||||
return kanji;
|
||||
}
|
||||
|
||||
int
|
||||
any2eucjp (unsigned char *dest, unsigned char *src, unsigned int dest_max)
|
||||
{
|
||||
static unsigned char tmp_dest[BUFSIZ];
|
||||
int ret;
|
||||
|
||||
if (strlen ((const char *) src) >= BUFSIZ)
|
||||
{
|
||||
error ("input string too large");
|
||||
return -1;
|
||||
}
|
||||
if (dest_max > BUFSIZ)
|
||||
{
|
||||
error ("invalid maximum size of destination\nit should be less than %d.", BUFSIZ);
|
||||
return -1;
|
||||
}
|
||||
ret = do_check_and_conv (tmp_dest, src);
|
||||
if (strlen ((const char *) tmp_dest) >= dest_max)
|
||||
{
|
||||
error ("output buffer overflow");
|
||||
ustrcpy (dest, src);
|
||||
return -1;
|
||||
}
|
||||
ustrcpy (dest, tmp_dest);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
unsigned int
|
||||
strwidth (unsigned char *s)
|
||||
{
|
||||
unsigned char *t;
|
||||
unsigned int i;
|
||||
|
||||
t = (unsigned char *) gdMalloc (BUFSIZ);
|
||||
any2eucjp (t, s, BUFSIZ);
|
||||
i = strlen (t);
|
||||
gdFree (t);
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
int
|
||||
main ()
|
||||
{
|
||||
unsigned char input[BUFSIZ];
|
||||
unsigned char *output;
|
||||
unsigned char *str;
|
||||
int c, i = 0;
|
||||
|
||||
while ((c = fgetc (stdin)) != '\n' && i < BUFSIZ)
|
||||
input[i++] = c;
|
||||
input[i] = '\0';
|
||||
|
||||
printf ("input : %d bytes\n", strlen ((const char *) input));
|
||||
printf ("output: %d bytes\n", strwidth (input));
|
||||
|
||||
output = (unsigned char *) gdMalloc (BUFSIZ);
|
||||
any2eucjp (output, input, BUFSIZ);
|
||||
str = output;
|
||||
while (*str != '\0')
|
||||
putchar (*(str++));
|
||||
putchar ('\n');
|
||||
gdFree (output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
55
ext/gd/libgd/gdparttopng.c
Normal file
55
ext/gd/libgd/gdparttopng.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* For atoi */
|
||||
#include "gd.h"
|
||||
|
||||
/* A short program which converts a .png file into a .gd file, for
|
||||
your convenience in creating images on the fly from a
|
||||
basis image that must be loaded quickly. The .gd format
|
||||
is not intended to be a general-purpose format. */
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gdImagePtr im;
|
||||
FILE *in, *out;
|
||||
int x, y, w, h;
|
||||
|
||||
if (argc != 7)
|
||||
{
|
||||
fprintf (stderr, "Usage: gdparttopng filename.gd filename.png x y w h\n");
|
||||
exit (1);
|
||||
}
|
||||
in = fopen (argv[1], "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "Input file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
x = atoi (argv[3]);
|
||||
y = atoi (argv[4]);
|
||||
w = atoi (argv[5]);
|
||||
h = atoi (argv[6]);
|
||||
|
||||
printf ("Extracting from (%d, %d), size is %dx%d\n", x, y, w, h);
|
||||
|
||||
im = gdImageCreateFromGd2Part (in, x, y, w, h);
|
||||
fclose (in);
|
||||
if (!im)
|
||||
{
|
||||
fprintf (stderr, "Input is not in PNG format!\n");
|
||||
exit (1);
|
||||
}
|
||||
out = fopen (argv[2], "wb");
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr, "Output file cannot be written to!\n");
|
||||
gdImageDestroy (im);
|
||||
exit (1);
|
||||
}
|
||||
gdImagePng (im, out);
|
||||
fclose (out);
|
||||
gdImageDestroy (im);
|
||||
|
||||
return 0;
|
||||
}
|
728
ext/gd/libgd/gdtables.c
Normal file
728
ext/gd/libgd/gdtables.c
Normal file
@ -0,0 +1,728 @@
|
||||
|
||||
int gdCosT[] =
|
||||
{
|
||||
1024,
|
||||
1023,
|
||||
1023,
|
||||
1022,
|
||||
1021,
|
||||
1020,
|
||||
1018,
|
||||
1016,
|
||||
1014,
|
||||
1011,
|
||||
1008,
|
||||
1005,
|
||||
1001,
|
||||
997,
|
||||
993,
|
||||
989,
|
||||
984,
|
||||
979,
|
||||
973,
|
||||
968,
|
||||
962,
|
||||
955,
|
||||
949,
|
||||
942,
|
||||
935,
|
||||
928,
|
||||
920,
|
||||
912,
|
||||
904,
|
||||
895,
|
||||
886,
|
||||
877,
|
||||
868,
|
||||
858,
|
||||
848,
|
||||
838,
|
||||
828,
|
||||
817,
|
||||
806,
|
||||
795,
|
||||
784,
|
||||
772,
|
||||
760,
|
||||
748,
|
||||
736,
|
||||
724,
|
||||
711,
|
||||
698,
|
||||
685,
|
||||
671,
|
||||
658,
|
||||
644,
|
||||
630,
|
||||
616,
|
||||
601,
|
||||
587,
|
||||
572,
|
||||
557,
|
||||
542,
|
||||
527,
|
||||
512,
|
||||
496,
|
||||
480,
|
||||
464,
|
||||
448,
|
||||
432,
|
||||
416,
|
||||
400,
|
||||
383,
|
||||
366,
|
||||
350,
|
||||
333,
|
||||
316,
|
||||
299,
|
||||
282,
|
||||
265,
|
||||
247,
|
||||
230,
|
||||
212,
|
||||
195,
|
||||
177,
|
||||
160,
|
||||
142,
|
||||
124,
|
||||
107,
|
||||
89,
|
||||
71,
|
||||
53,
|
||||
35,
|
||||
17,
|
||||
0,
|
||||
-17,
|
||||
-35,
|
||||
-53,
|
||||
-71,
|
||||
-89,
|
||||
-107,
|
||||
-124,
|
||||
-142,
|
||||
-160,
|
||||
-177,
|
||||
-195,
|
||||
-212,
|
||||
-230,
|
||||
-247,
|
||||
-265,
|
||||
-282,
|
||||
-299,
|
||||
-316,
|
||||
-333,
|
||||
-350,
|
||||
-366,
|
||||
-383,
|
||||
-400,
|
||||
-416,
|
||||
-432,
|
||||
-448,
|
||||
-464,
|
||||
-480,
|
||||
-496,
|
||||
-512,
|
||||
-527,
|
||||
-542,
|
||||
-557,
|
||||
-572,
|
||||
-587,
|
||||
-601,
|
||||
-616,
|
||||
-630,
|
||||
-644,
|
||||
-658,
|
||||
-671,
|
||||
-685,
|
||||
-698,
|
||||
-711,
|
||||
-724,
|
||||
-736,
|
||||
-748,
|
||||
-760,
|
||||
-772,
|
||||
-784,
|
||||
-795,
|
||||
-806,
|
||||
-817,
|
||||
-828,
|
||||
-838,
|
||||
-848,
|
||||
-858,
|
||||
-868,
|
||||
-877,
|
||||
-886,
|
||||
-895,
|
||||
-904,
|
||||
-912,
|
||||
-920,
|
||||
-928,
|
||||
-935,
|
||||
-942,
|
||||
-949,
|
||||
-955,
|
||||
-962,
|
||||
-968,
|
||||
-973,
|
||||
-979,
|
||||
-984,
|
||||
-989,
|
||||
-993,
|
||||
-997,
|
||||
-1001,
|
||||
-1005,
|
||||
-1008,
|
||||
-1011,
|
||||
-1014,
|
||||
-1016,
|
||||
-1018,
|
||||
-1020,
|
||||
-1021,
|
||||
-1022,
|
||||
-1023,
|
||||
-1023,
|
||||
-1024,
|
||||
-1023,
|
||||
-1023,
|
||||
-1022,
|
||||
-1021,
|
||||
-1020,
|
||||
-1018,
|
||||
-1016,
|
||||
-1014,
|
||||
-1011,
|
||||
-1008,
|
||||
-1005,
|
||||
-1001,
|
||||
-997,
|
||||
-993,
|
||||
-989,
|
||||
-984,
|
||||
-979,
|
||||
-973,
|
||||
-968,
|
||||
-962,
|
||||
-955,
|
||||
-949,
|
||||
-942,
|
||||
-935,
|
||||
-928,
|
||||
-920,
|
||||
-912,
|
||||
-904,
|
||||
-895,
|
||||
-886,
|
||||
-877,
|
||||
-868,
|
||||
-858,
|
||||
-848,
|
||||
-838,
|
||||
-828,
|
||||
-817,
|
||||
-806,
|
||||
-795,
|
||||
-784,
|
||||
-772,
|
||||
-760,
|
||||
-748,
|
||||
-736,
|
||||
-724,
|
||||
-711,
|
||||
-698,
|
||||
-685,
|
||||
-671,
|
||||
-658,
|
||||
-644,
|
||||
-630,
|
||||
-616,
|
||||
-601,
|
||||
-587,
|
||||
-572,
|
||||
-557,
|
||||
-542,
|
||||
-527,
|
||||
-512,
|
||||
-496,
|
||||
-480,
|
||||
-464,
|
||||
-448,
|
||||
-432,
|
||||
-416,
|
||||
-400,
|
||||
-383,
|
||||
-366,
|
||||
-350,
|
||||
-333,
|
||||
-316,
|
||||
-299,
|
||||
-282,
|
||||
-265,
|
||||
-247,
|
||||
-230,
|
||||
-212,
|
||||
-195,
|
||||
-177,
|
||||
-160,
|
||||
-142,
|
||||
-124,
|
||||
-107,
|
||||
-89,
|
||||
-71,
|
||||
-53,
|
||||
-35,
|
||||
-17,
|
||||
0,
|
||||
17,
|
||||
35,
|
||||
53,
|
||||
71,
|
||||
89,
|
||||
107,
|
||||
124,
|
||||
142,
|
||||
160,
|
||||
177,
|
||||
195,
|
||||
212,
|
||||
230,
|
||||
247,
|
||||
265,
|
||||
282,
|
||||
299,
|
||||
316,
|
||||
333,
|
||||
350,
|
||||
366,
|
||||
383,
|
||||
400,
|
||||
416,
|
||||
432,
|
||||
448,
|
||||
464,
|
||||
480,
|
||||
496,
|
||||
512,
|
||||
527,
|
||||
542,
|
||||
557,
|
||||
572,
|
||||
587,
|
||||
601,
|
||||
616,
|
||||
630,
|
||||
644,
|
||||
658,
|
||||
671,
|
||||
685,
|
||||
698,
|
||||
711,
|
||||
724,
|
||||
736,
|
||||
748,
|
||||
760,
|
||||
772,
|
||||
784,
|
||||
795,
|
||||
806,
|
||||
817,
|
||||
828,
|
||||
838,
|
||||
848,
|
||||
858,
|
||||
868,
|
||||
877,
|
||||
886,
|
||||
895,
|
||||
904,
|
||||
912,
|
||||
920,
|
||||
928,
|
||||
935,
|
||||
942,
|
||||
949,
|
||||
955,
|
||||
962,
|
||||
968,
|
||||
973,
|
||||
979,
|
||||
984,
|
||||
989,
|
||||
993,
|
||||
997,
|
||||
1001,
|
||||
1005,
|
||||
1008,
|
||||
1011,
|
||||
1014,
|
||||
1016,
|
||||
1018,
|
||||
1020,
|
||||
1021,
|
||||
1022,
|
||||
1023,
|
||||
1023
|
||||
};
|
||||
|
||||
int gdSinT[] =
|
||||
{
|
||||
0,
|
||||
17,
|
||||
35,
|
||||
53,
|
||||
71,
|
||||
89,
|
||||
107,
|
||||
124,
|
||||
142,
|
||||
160,
|
||||
177,
|
||||
195,
|
||||
212,
|
||||
230,
|
||||
247,
|
||||
265,
|
||||
282,
|
||||
299,
|
||||
316,
|
||||
333,
|
||||
350,
|
||||
366,
|
||||
383,
|
||||
400,
|
||||
416,
|
||||
432,
|
||||
448,
|
||||
464,
|
||||
480,
|
||||
496,
|
||||
512,
|
||||
527,
|
||||
542,
|
||||
557,
|
||||
572,
|
||||
587,
|
||||
601,
|
||||
616,
|
||||
630,
|
||||
644,
|
||||
658,
|
||||
671,
|
||||
685,
|
||||
698,
|
||||
711,
|
||||
724,
|
||||
736,
|
||||
748,
|
||||
760,
|
||||
772,
|
||||
784,
|
||||
795,
|
||||
806,
|
||||
817,
|
||||
828,
|
||||
838,
|
||||
848,
|
||||
858,
|
||||
868,
|
||||
877,
|
||||
886,
|
||||
895,
|
||||
904,
|
||||
912,
|
||||
920,
|
||||
928,
|
||||
935,
|
||||
942,
|
||||
949,
|
||||
955,
|
||||
962,
|
||||
968,
|
||||
973,
|
||||
979,
|
||||
984,
|
||||
989,
|
||||
993,
|
||||
997,
|
||||
1001,
|
||||
1005,
|
||||
1008,
|
||||
1011,
|
||||
1014,
|
||||
1016,
|
||||
1018,
|
||||
1020,
|
||||
1021,
|
||||
1022,
|
||||
1023,
|
||||
1023,
|
||||
1024,
|
||||
1023,
|
||||
1023,
|
||||
1022,
|
||||
1021,
|
||||
1020,
|
||||
1018,
|
||||
1016,
|
||||
1014,
|
||||
1011,
|
||||
1008,
|
||||
1005,
|
||||
1001,
|
||||
997,
|
||||
993,
|
||||
989,
|
||||
984,
|
||||
979,
|
||||
973,
|
||||
968,
|
||||
962,
|
||||
955,
|
||||
949,
|
||||
942,
|
||||
935,
|
||||
928,
|
||||
920,
|
||||
912,
|
||||
904,
|
||||
895,
|
||||
886,
|
||||
877,
|
||||
868,
|
||||
858,
|
||||
848,
|
||||
838,
|
||||
828,
|
||||
817,
|
||||
806,
|
||||
795,
|
||||
784,
|
||||
772,
|
||||
760,
|
||||
748,
|
||||
736,
|
||||
724,
|
||||
711,
|
||||
698,
|
||||
685,
|
||||
671,
|
||||
658,
|
||||
644,
|
||||
630,
|
||||
616,
|
||||
601,
|
||||
587,
|
||||
572,
|
||||
557,
|
||||
542,
|
||||
527,
|
||||
512,
|
||||
496,
|
||||
480,
|
||||
464,
|
||||
448,
|
||||
432,
|
||||
416,
|
||||
400,
|
||||
383,
|
||||
366,
|
||||
350,
|
||||
333,
|
||||
316,
|
||||
299,
|
||||
282,
|
||||
265,
|
||||
247,
|
||||
230,
|
||||
212,
|
||||
195,
|
||||
177,
|
||||
160,
|
||||
142,
|
||||
124,
|
||||
107,
|
||||
89,
|
||||
71,
|
||||
53,
|
||||
35,
|
||||
17,
|
||||
0,
|
||||
-17,
|
||||
-35,
|
||||
-53,
|
||||
-71,
|
||||
-89,
|
||||
-107,
|
||||
-124,
|
||||
-142,
|
||||
-160,
|
||||
-177,
|
||||
-195,
|
||||
-212,
|
||||
-230,
|
||||
-247,
|
||||
-265,
|
||||
-282,
|
||||
-299,
|
||||
-316,
|
||||
-333,
|
||||
-350,
|
||||
-366,
|
||||
-383,
|
||||
-400,
|
||||
-416,
|
||||
-432,
|
||||
-448,
|
||||
-464,
|
||||
-480,
|
||||
-496,
|
||||
-512,
|
||||
-527,
|
||||
-542,
|
||||
-557,
|
||||
-572,
|
||||
-587,
|
||||
-601,
|
||||
-616,
|
||||
-630,
|
||||
-644,
|
||||
-658,
|
||||
-671,
|
||||
-685,
|
||||
-698,
|
||||
-711,
|
||||
-724,
|
||||
-736,
|
||||
-748,
|
||||
-760,
|
||||
-772,
|
||||
-784,
|
||||
-795,
|
||||
-806,
|
||||
-817,
|
||||
-828,
|
||||
-838,
|
||||
-848,
|
||||
-858,
|
||||
-868,
|
||||
-877,
|
||||
-886,
|
||||
-895,
|
||||
-904,
|
||||
-912,
|
||||
-920,
|
||||
-928,
|
||||
-935,
|
||||
-942,
|
||||
-949,
|
||||
-955,
|
||||
-962,
|
||||
-968,
|
||||
-973,
|
||||
-979,
|
||||
-984,
|
||||
-989,
|
||||
-993,
|
||||
-997,
|
||||
-1001,
|
||||
-1005,
|
||||
-1008,
|
||||
-1011,
|
||||
-1014,
|
||||
-1016,
|
||||
-1018,
|
||||
-1020,
|
||||
-1021,
|
||||
-1022,
|
||||
-1023,
|
||||
-1023,
|
||||
-1024,
|
||||
-1023,
|
||||
-1023,
|
||||
-1022,
|
||||
-1021,
|
||||
-1020,
|
||||
-1018,
|
||||
-1016,
|
||||
-1014,
|
||||
-1011,
|
||||
-1008,
|
||||
-1005,
|
||||
-1001,
|
||||
-997,
|
||||
-993,
|
||||
-989,
|
||||
-984,
|
||||
-979,
|
||||
-973,
|
||||
-968,
|
||||
-962,
|
||||
-955,
|
||||
-949,
|
||||
-942,
|
||||
-935,
|
||||
-928,
|
||||
-920,
|
||||
-912,
|
||||
-904,
|
||||
-895,
|
||||
-886,
|
||||
-877,
|
||||
-868,
|
||||
-858,
|
||||
-848,
|
||||
-838,
|
||||
-828,
|
||||
-817,
|
||||
-806,
|
||||
-795,
|
||||
-784,
|
||||
-772,
|
||||
-760,
|
||||
-748,
|
||||
-736,
|
||||
-724,
|
||||
-711,
|
||||
-698,
|
||||
-685,
|
||||
-671,
|
||||
-658,
|
||||
-644,
|
||||
-630,
|
||||
-616,
|
||||
-601,
|
||||
-587,
|
||||
-572,
|
||||
-557,
|
||||
-542,
|
||||
-527,
|
||||
-512,
|
||||
-496,
|
||||
-480,
|
||||
-464,
|
||||
-448,
|
||||
-432,
|
||||
-416,
|
||||
-400,
|
||||
-383,
|
||||
-366,
|
||||
-350,
|
||||
-333,
|
||||
-316,
|
||||
-299,
|
||||
-282,
|
||||
-265,
|
||||
-247,
|
||||
-230,
|
||||
-212,
|
||||
-195,
|
||||
-177,
|
||||
-160,
|
||||
-142,
|
||||
-124,
|
||||
-107,
|
||||
-89,
|
||||
-71,
|
||||
-53,
|
||||
-35,
|
||||
-17
|
||||
};
|
409
ext/gd/libgd/gdtest.c
Normal file
409
ext/gd/libgd/gdtest.c
Normal file
@ -0,0 +1,409 @@
|
||||
#include <stdio.h>
|
||||
#ifdef _WIN32
|
||||
#include <process.h>
|
||||
int
|
||||
unlink (const char *filename)
|
||||
{
|
||||
return _unlink (filename);
|
||||
}
|
||||
#else
|
||||
#include <unistd.h> /* for getpid(), unlink() */
|
||||
#endif
|
||||
#include "gd.h"
|
||||
|
||||
void CompareImages (char *msg, gdImagePtr im1, gdImagePtr im2);
|
||||
|
||||
static int freadWrapper (void *context, char *buf, int len);
|
||||
static int fwriteWrapper (void *context, const char *buffer, int len);
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gdImagePtr im, ref, im2, im3;
|
||||
FILE *in, *out;
|
||||
void *iptr;
|
||||
int sz;
|
||||
gdIOCtxPtr ctx;
|
||||
char of[256];
|
||||
int colRed, colBlu;
|
||||
gdSource imgsrc;
|
||||
gdSink imgsnk;
|
||||
int foreground;
|
||||
int i;
|
||||
if (argc != 2)
|
||||
{
|
||||
fprintf (stderr, "Usage: gdtest filename.png\n");
|
||||
exit (1);
|
||||
}
|
||||
in = fopen (argv[1], "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "Input file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im = gdImageCreateFromPng (in);
|
||||
|
||||
rewind (in);
|
||||
ref = gdImageCreateFromPng (in);
|
||||
|
||||
fclose (in);
|
||||
|
||||
printf ("Reference File has %d Palette entries\n", ref->colorsTotal);
|
||||
|
||||
CompareImages ("Initial Versions", ref, im);
|
||||
|
||||
|
||||
/* */
|
||||
/* Send to PNG File then Ptr */
|
||||
/* */
|
||||
sprintf (of, "%s.png", argv[1]);
|
||||
out = fopen (of, "wb");
|
||||
gdImagePng (im, out);
|
||||
fclose (out);
|
||||
|
||||
in = fopen (of, "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "PNG Output file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im2 = gdImageCreateFromPng (in);
|
||||
fclose (in);
|
||||
|
||||
CompareImages ("GD->PNG File->GD", ref, im2);
|
||||
|
||||
unlink (of);
|
||||
gdImageDestroy (im2);
|
||||
|
||||
iptr = gdImagePngPtr (im, &sz);
|
||||
ctx = gdNewDynamicCtx (sz, iptr);
|
||||
im2 = gdImageCreateFromPngCtx (ctx);
|
||||
|
||||
CompareImages ("GD->PNG ptr->GD", ref, im2);
|
||||
|
||||
gdImageDestroy (im2);
|
||||
ctx->free (ctx);
|
||||
|
||||
|
||||
/* */
|
||||
/* Send to GD2 File then Ptr */
|
||||
/* */
|
||||
sprintf (of, "%s.gd2", argv[1]);
|
||||
out = fopen (of, "wb");
|
||||
gdImageGd2 (im, out, 128, 2);
|
||||
fclose (out);
|
||||
|
||||
in = fopen (of, "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "GD2 Output file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im2 = gdImageCreateFromGd2 (in);
|
||||
fclose (in);
|
||||
|
||||
CompareImages ("GD->GD2 File->GD", ref, im2);
|
||||
|
||||
unlink (of);
|
||||
gdImageDestroy (im2);
|
||||
|
||||
iptr = gdImageGd2Ptr (im, 128, 2, &sz);
|
||||
/*printf("Got ptr %d (size %d)\n",iptr, sz); */
|
||||
ctx = gdNewDynamicCtx (sz, iptr);
|
||||
/*printf("Got ctx %d\n",ctx); */
|
||||
im2 = gdImageCreateFromGd2Ctx (ctx);
|
||||
/*printf("Got img2 %d\n",im2); */
|
||||
|
||||
CompareImages ("GD->GD2 ptr->GD", ref, im2);
|
||||
|
||||
gdImageDestroy (im2);
|
||||
ctx->free (ctx);
|
||||
|
||||
|
||||
/* */
|
||||
/* Send to GD File then Ptr */
|
||||
/* */
|
||||
sprintf (of, "%s.gd", argv[1]);
|
||||
out = fopen (of, "wb");
|
||||
gdImageGd (im, out);
|
||||
fclose (out);
|
||||
|
||||
in = fopen (of, "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "GD Output file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im2 = gdImageCreateFromGd (in);
|
||||
fclose (in);
|
||||
|
||||
CompareImages ("GD->GD File->GD", ref, im2);
|
||||
|
||||
unlink (of);
|
||||
gdImageDestroy (im2);
|
||||
|
||||
iptr = gdImageGdPtr (im, &sz);
|
||||
/*printf("Got ptr %d (size %d)\n",iptr, sz); */
|
||||
ctx = gdNewDynamicCtx (sz, iptr);
|
||||
/*printf("Got ctx %d\n",ctx); */
|
||||
im2 = gdImageCreateFromGdCtx (ctx);
|
||||
/*printf("Got img2 %d\n",im2); */
|
||||
|
||||
CompareImages ("GD->GD ptr->GD", ref, im2);
|
||||
|
||||
gdImageDestroy (im2);
|
||||
ctx->free (ctx);
|
||||
|
||||
/*
|
||||
** Test gdImageCreateFromPngSource'
|
||||
* */
|
||||
|
||||
in = fopen (argv[1], "rb");
|
||||
|
||||
imgsrc.source = freadWrapper;
|
||||
imgsrc.context = in;
|
||||
im2 = gdImageCreateFromPngSource (&imgsrc);
|
||||
fclose (in);
|
||||
|
||||
if (im2 == NULL)
|
||||
{
|
||||
printf ("GD Source: ERROR Null returned by gdImageCreateFromPngSource\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
CompareImages ("GD Source", ref, im2);
|
||||
gdImageDestroy (im2);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Test gdImagePngToSink'
|
||||
* */
|
||||
|
||||
sprintf (of, "%s.snk", argv[1]);
|
||||
out = fopen (of, "wb");
|
||||
imgsnk.sink = fwriteWrapper;
|
||||
imgsnk.context = out;
|
||||
gdImagePngToSink (im, &imgsnk);
|
||||
fclose (out);
|
||||
in = fopen (of, "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "GD Sink: ERROR - GD Sink Output file does not exist!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
im2 = gdImageCreateFromPng (in);
|
||||
fclose (in);
|
||||
|
||||
CompareImages ("GD Sink", ref, im2);
|
||||
gdImageDestroy (im2);
|
||||
};
|
||||
|
||||
unlink (of);
|
||||
|
||||
/* */
|
||||
/* Test Extraction */
|
||||
/* */
|
||||
in = fopen ("test/gdtest_200_300_150_100.png", "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "gdtest_200_300_150_100.png does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im2 = gdImageCreateFromPng (in);
|
||||
fclose (in);
|
||||
|
||||
|
||||
in = fopen ("test/gdtest.gd2", "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "gdtest.gd2 does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im3 = gdImageCreateFromGd2Part (in, 200, 300, 150, 100);
|
||||
fclose (in);
|
||||
|
||||
CompareImages ("GD2Part (gdtest_200_300_150_100.png, gdtest.gd2(part))", im2, im3);
|
||||
|
||||
gdImageDestroy (im2);
|
||||
gdImageDestroy (im3);
|
||||
|
||||
/* */
|
||||
/* Copy Blend */
|
||||
/* */
|
||||
in = fopen ("test/gdtest.png", "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "gdtest.png does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im2 = gdImageCreateFromPng (in);
|
||||
fclose (in);
|
||||
|
||||
im3 = gdImageCreate (100, 60);
|
||||
colRed = gdImageColorAllocate (im3, 255, 0, 0);
|
||||
colBlu = gdImageColorAllocate (im3, 0, 0, 255);
|
||||
gdImageFilledRectangle (im3, 0, 0, 49, 30, colRed);
|
||||
gdImageFilledRectangle (im3, 50, 30, 99, 59, colBlu);
|
||||
|
||||
gdImageCopyMerge (im2, im3, 150, 200, 10, 10, 90, 50, 50);
|
||||
gdImageCopyMerge (im2, im3, 180, 70, 10, 10, 90, 50, 50);
|
||||
|
||||
gdImageCopyMergeGray (im2, im3, 250, 160, 10, 10, 90, 50, 50);
|
||||
gdImageCopyMergeGray (im2, im3, 80, 70, 10, 10, 90, 50, 50);
|
||||
|
||||
gdImageDestroy (im3);
|
||||
|
||||
in = fopen ("test/gdtest_merge.png", "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "gdtest_merge.png does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im3 = gdImageCreateFromPng (in);
|
||||
fclose (in);
|
||||
|
||||
printf ("[Merged Image has %d colours]\n", im2->colorsTotal);
|
||||
CompareImages ("Merged (gdtest.png, gdtest_merge.png)", im2, im3);
|
||||
|
||||
gdImageDestroy (im2);
|
||||
gdImageDestroy (im3);
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
out = fopen ("test/gdtest.jpg", "wb");
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr, "Can't create file test/gdtest.jpg.\n");
|
||||
exit (1);
|
||||
}
|
||||
gdImageJpeg (im, out, -1);
|
||||
fclose (out);
|
||||
in = fopen ("test/gdtest.jpg", "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "Can't open file test/gdtest.jpg.\n");
|
||||
exit (1);
|
||||
}
|
||||
im2 = gdImageCreateFromJpeg (in);
|
||||
fclose (in);
|
||||
if (!im2)
|
||||
{
|
||||
fprintf (stderr, "gdImageCreateFromJpeg failed.\n");
|
||||
exit (1);
|
||||
}
|
||||
gdImageDestroy (im2);
|
||||
printf ("Created test/gdtest.jpg successfully. Compare this image\n"
|
||||
"to the input image manually. Some difference must be\n"
|
||||
"expected as JPEG is a lossy file format.\n");
|
||||
#endif /* HAVE_JPEG */
|
||||
/* Assume the color closest to black is the foreground
|
||||
color for the B&W wbmp image. */
|
||||
fprintf (stderr, "NOTE: the WBMP output image will NOT match the original unless the original\n"
|
||||
"is also black and white. This is OK!\n");
|
||||
foreground = gdImageColorClosest (im, 0, 0, 0);
|
||||
fprintf (stderr, "Foreground index is %d\n", foreground);
|
||||
if (foreground == -1)
|
||||
{
|
||||
fprintf (stderr, "Source image has no colors, skipping wbmp test.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out = fopen ("test/gdtest.wbmp", "wb");
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr, "Can't create file test/gdtest.wbmp.\n");
|
||||
exit (1);
|
||||
}
|
||||
gdImageWBMP (im, foreground, out);
|
||||
fclose (out);
|
||||
in = fopen ("test/gdtest.wbmp", "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "Can't open file test/gdtest.wbmp.\n");
|
||||
exit (1);
|
||||
}
|
||||
im2 = gdImageCreateFromWBMP (in);
|
||||
fprintf (stderr, "WBMP has %d colors\n", gdImageColorsTotal (im2));
|
||||
fprintf (stderr, "WBMP colors are:\n");
|
||||
for (i = 0; (i < gdImageColorsTotal (im2)); i++)
|
||||
{
|
||||
fprintf (stderr, "%02X%02X%02X\n",
|
||||
gdImageRed (im2, i),
|
||||
gdImageGreen (im2, i),
|
||||
gdImageBlue (im2, i));
|
||||
}
|
||||
fclose (in);
|
||||
if (!im2)
|
||||
{
|
||||
fprintf (stderr, "gdImageCreateFromWBMP failed.\n");
|
||||
exit (1);
|
||||
}
|
||||
CompareImages ("WBMP test (gdtest.png, gdtest.wbmp)", ref, im2);
|
||||
out = fopen ("test/gdtest_wbmp_to_png.png", "wb");
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr, "Can't create file test/gdtest_wbmp_to_png.png.\n");
|
||||
exit (1);
|
||||
}
|
||||
gdImagePng (im2, out);
|
||||
fclose (out);
|
||||
gdImageDestroy (im2);
|
||||
}
|
||||
gdImageDestroy (im);
|
||||
gdImageDestroy (ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
CompareImages (char *msg, gdImagePtr im1, gdImagePtr im2)
|
||||
{
|
||||
int cmpRes;
|
||||
|
||||
cmpRes = gdImageCompare (im1, im2);
|
||||
|
||||
if (cmpRes & GD_CMP_IMAGE)
|
||||
{
|
||||
printf ("%%%s: ERROR images differ: BAD\n", msg);
|
||||
}
|
||||
else if (cmpRes != 0)
|
||||
{
|
||||
printf ("%%%s: WARNING images differ: WARNING - Probably OK\n", msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("%%%s: OK\n", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmpRes & (GD_CMP_SIZE_X + GD_CMP_SIZE_Y))
|
||||
{
|
||||
printf ("-%s: INFO image sizes differ\n", msg);
|
||||
}
|
||||
|
||||
if (cmpRes & GD_CMP_NUM_COLORS)
|
||||
{
|
||||
printf ("-%s: INFO number of pallette entries differ %d Vs. %d\n", msg,
|
||||
im1->colorsTotal, im2->colorsTotal);
|
||||
}
|
||||
|
||||
if (cmpRes & GD_CMP_COLOR)
|
||||
{
|
||||
printf ("-%s: INFO actual colours of pixels differ\n", msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
freadWrapper (void *context, char *buf, int len)
|
||||
{
|
||||
int got = fread (buf, 1, len, (FILE *) context);
|
||||
return got;
|
||||
}
|
||||
|
||||
static int
|
||||
fwriteWrapper (void *context, const char *buffer, int len)
|
||||
{
|
||||
return fwrite (buffer, 1, len, (FILE *) context);
|
||||
}
|
108
ext/gd/libgd/gdtestft.c
Normal file
108
ext/gd/libgd/gdtestft.c
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
#include "gd.h"
|
||||
#include <string.h>
|
||||
|
||||
#define PI 3.141592
|
||||
#define DEG2RAD(x) ((x)*PI/180.)
|
||||
|
||||
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
#define MAX4(x,y,z,w) \
|
||||
((MAX((x),(y))) > (MAX((z),(w))) ? (MAX((x),(y))) : (MAX((z),(w))))
|
||||
#define MIN4(x,y,z,w) \
|
||||
((MIN((x),(y))) < (MIN((z),(w))) ? (MIN((x),(y))) : (MIN((z),(w))))
|
||||
|
||||
#define MAXX(x) MAX4(x[0],x[2],x[4],x[6])
|
||||
#define MINX(x) MIN4(x[0],x[2],x[4],x[6])
|
||||
#define MAXY(x) MAX4(x[1],x[3],x[5],x[7])
|
||||
#define MINY(x) MIN4(x[1],x[3],x[5],x[7])
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
#ifndef HAVE_LIBFREETYPE
|
||||
fprintf (stderr, "gd was not compiled with HAVE_LIBFREETYPE defined.\n");
|
||||
fprintf (stderr, "Install the FreeType library, including the\n");
|
||||
fprintf (stderr, "header files. Then edit the gd Makefile, type\n");
|
||||
fprintf (stderr, "make clean, and type make again.\n");
|
||||
return 1;
|
||||
#else
|
||||
gdImagePtr im;
|
||||
int black;
|
||||
int white;
|
||||
int brect[8];
|
||||
int x, y;
|
||||
char *err;
|
||||
FILE *out;
|
||||
#ifdef JISX0208
|
||||
char *s = "Hello. ‚±‚ñ‚É‚¿‚Í Qyjpqg,"; /* String to draw. */
|
||||
#else
|
||||
char *s = "Hello. Qyjpqg,"; /* String to draw. */
|
||||
#endif
|
||||
|
||||
double sz = 40.;
|
||||
|
||||
#if 0
|
||||
double angle = 0.;
|
||||
#else
|
||||
double angle = DEG2RAD (-90);
|
||||
#endif
|
||||
|
||||
#ifdef JISX0208
|
||||
char *f = "/usr/openwin/lib/locale/ja/X11/fonts/TT/HG-MinchoL.ttf"; /* UNICODE */
|
||||
/* char *f = "/usr/local/lib/fonts/truetype/DynaFont/dfpop1.ttf"; *//* SJIS */
|
||||
#else
|
||||
char *f = "times"; /* TrueType font */
|
||||
#endif
|
||||
|
||||
/* obtain brect so that we can size the image */
|
||||
err = gdImageStringFT ((gdImagePtr) NULL, &brect[0], 0, f, sz, angle, 0, 0, s);
|
||||
if (err)
|
||||
{
|
||||
fprintf (stderr, err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* create an image just big enough for the string */
|
||||
x = MAXX (brect) - MINX (brect) + 6;
|
||||
y = MAXY (brect) - MINY (brect) + 6;
|
||||
#if 0
|
||||
im = gdImageCreate (500, 500);
|
||||
#else
|
||||
/* gd 2.0: true color images can use freetype too */
|
||||
im = gdImageCreateTrueColor (x, y);
|
||||
#endif
|
||||
|
||||
/* 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 */
|
||||
x = 0 - MINX (brect) + 3;
|
||||
y = 0 - MINY (brect) + 3;
|
||||
|
||||
err = gdImageStringFT (im, NULL, black, f, sz, angle, x, y, s);
|
||||
if (err)
|
||||
{
|
||||
fprintf (stderr, err);
|
||||
return 1;
|
||||
}
|
||||
/* TBB: Write img to test/fttest.png */
|
||||
out = fopen ("test/fttest.png", "wb");
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr, "Can't create test/fttest.png\n");
|
||||
exit (1);
|
||||
}
|
||||
gdImagePng (im, out);
|
||||
fclose (out);
|
||||
fprintf (stderr, "Test image written to test/fttest.png\n");
|
||||
/* Destroy it */
|
||||
gdImageDestroy (im);
|
||||
|
||||
return 0;
|
||||
#endif /* HAVE_FREETYPE */
|
||||
}
|
44
ext/gd/libgd/gdtopng.c
Normal file
44
ext/gd/libgd/gdtopng.c
Normal file
@ -0,0 +1,44 @@
|
||||
#include <stdio.h>
|
||||
#include "gd.h"
|
||||
|
||||
/* A short program which converts a .png file into a .gd file, for
|
||||
your convenience in creating images on the fly from a
|
||||
basis image that must be loaded quickly. The .gd format
|
||||
is not intended to be a general-purpose format. */
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gdImagePtr im;
|
||||
FILE *in, *out;
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf (stderr, "Usage: gdtopng filename.gd filename.png\n");
|
||||
exit (1);
|
||||
}
|
||||
in = fopen (argv[1], "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "Input file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im = gdImageCreateFromGd (in);
|
||||
fclose (in);
|
||||
if (!im)
|
||||
{
|
||||
fprintf (stderr, "Input is not in PNG format!\n");
|
||||
exit (1);
|
||||
}
|
||||
out = fopen (argv[2], "wb");
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr, "Output file cannot be written to!\n");
|
||||
gdImageDestroy (im);
|
||||
exit (1);
|
||||
}
|
||||
gdImagePng (im, out);
|
||||
fclose (out);
|
||||
gdImageDestroy (im);
|
||||
|
||||
return 0;
|
||||
}
|
148
ext/gd/libgd/gdxpm.c
Normal file
148
ext/gd/libgd/gdxpm.c
Normal file
@ -0,0 +1,148 @@
|
||||
|
||||
/*
|
||||
add ability to load xpm files to gd, requires the xpm
|
||||
library.
|
||||
Caolan.McNamara@ul.ie
|
||||
http://www.csn.ul.ie/~caolan
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "gd.h"
|
||||
#include "gdhelpers.h"
|
||||
|
||||
#ifndef HAVE_XPM
|
||||
gdImagePtr
|
||||
gdImageCreateFromXpm (char *filename)
|
||||
{
|
||||
fprintf (stderr, "libgd was not built with xpm support\n");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "xpm.h"
|
||||
|
||||
gdImagePtr
|
||||
gdImageCreateFromXpm (char *filename)
|
||||
{
|
||||
XpmInfo info;
|
||||
XpmImage image;
|
||||
int i, j, k, number;
|
||||
char buf[5];
|
||||
gdImagePtr im = 0;
|
||||
char *apixel;
|
||||
int *pointer;
|
||||
int red = 0, green = 0, blue = 0, color = 0;
|
||||
int *colors;
|
||||
int ret;
|
||||
|
||||
ret = XpmReadFileToXpmImage (filename, &image, &info);
|
||||
if (ret != XpmSuccess)
|
||||
return 0;
|
||||
|
||||
if (!(im = gdImageCreate (image.width, image.height)))
|
||||
return 0;
|
||||
|
||||
number = image.ncolors;
|
||||
colors = (int *) gdMalloc (sizeof (int) * number);
|
||||
if (colors == NULL)
|
||||
return (0);
|
||||
for (i = 0; i < number; i++)
|
||||
{
|
||||
switch (strlen (image.colorTable[i].c_color))
|
||||
{
|
||||
case 4:
|
||||
buf[1] = '\0';
|
||||
buf[0] = image.colorTable[i].c_color[1];
|
||||
red = strtol (buf, NULL, 16);
|
||||
|
||||
buf[0] = image.colorTable[i].c_color[3];
|
||||
green = strtol (buf, NULL, 16);
|
||||
|
||||
buf[0] = image.colorTable[i].c_color[5];
|
||||
blue = strtol (buf, NULL, 16);
|
||||
break;
|
||||
case 7:
|
||||
buf[2] = '\0';
|
||||
buf[0] = image.colorTable[i].c_color[1];
|
||||
buf[1] = image.colorTable[i].c_color[2];
|
||||
red = strtol (buf, NULL, 16);
|
||||
|
||||
buf[0] = image.colorTable[i].c_color[3];
|
||||
buf[1] = image.colorTable[i].c_color[4];
|
||||
green = strtol (buf, NULL, 16);
|
||||
|
||||
buf[0] = image.colorTable[i].c_color[5];
|
||||
buf[1] = image.colorTable[i].c_color[6];
|
||||
blue = strtol (buf, NULL, 16);
|
||||
break;
|
||||
case 10:
|
||||
buf[3] = '\0';
|
||||
buf[0] = image.colorTable[i].c_color[1];
|
||||
buf[1] = image.colorTable[i].c_color[2];
|
||||
buf[2] = image.colorTable[i].c_color[3];
|
||||
red = strtol (buf, NULL, 16);
|
||||
red /= 64;
|
||||
|
||||
buf[0] = image.colorTable[i].c_color[4];
|
||||
buf[1] = image.colorTable[i].c_color[5];
|
||||
buf[2] = image.colorTable[i].c_color[6];
|
||||
green = strtol (buf, NULL, 16);
|
||||
green /= 64;
|
||||
|
||||
buf[0] = image.colorTable[i].c_color[7];
|
||||
buf[1] = image.colorTable[i].c_color[8];
|
||||
buf[2] = image.colorTable[i].c_color[9];
|
||||
blue = strtol (buf, NULL, 16);
|
||||
blue /= 64;
|
||||
break;
|
||||
case 13:
|
||||
buf[4] = '\0';
|
||||
buf[0] = image.colorTable[i].c_color[1];
|
||||
buf[1] = image.colorTable[i].c_color[2];
|
||||
buf[2] = image.colorTable[i].c_color[3];
|
||||
buf[3] = image.colorTable[i].c_color[4];
|
||||
red = strtol (buf, NULL, 16);
|
||||
red /= 256;
|
||||
|
||||
buf[0] = image.colorTable[i].c_color[5];
|
||||
buf[1] = image.colorTable[i].c_color[6];
|
||||
buf[2] = image.colorTable[i].c_color[7];
|
||||
buf[3] = image.colorTable[i].c_color[8];
|
||||
green = strtol (buf, NULL, 16);
|
||||
green /= 256;
|
||||
|
||||
buf[0] = image.colorTable[i].c_color[9];
|
||||
buf[1] = image.colorTable[i].c_color[10];
|
||||
buf[2] = image.colorTable[i].c_color[11];
|
||||
buf[3] = image.colorTable[i].c_color[12];
|
||||
blue = strtol (buf, NULL, 16);
|
||||
blue /= 256;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
colors[i] = gdImageColorResolve (im, red, green, blue);
|
||||
if (colors[i] == -1)
|
||||
fprintf (stderr, "ARRRGH\n");
|
||||
}
|
||||
|
||||
apixel = (char *) gdMalloc (image.cpp + 1);
|
||||
if (apixel == NULL)
|
||||
return (0);
|
||||
apixel[image.cpp] = '\0';
|
||||
|
||||
pointer = image.data;
|
||||
for (i = 0; i < image.height; i++)
|
||||
{
|
||||
for (j = 0; j < image.width; j++)
|
||||
{
|
||||
k = *pointer++;
|
||||
gdImageSetPixel (im, j, i, colors[k]);
|
||||
}
|
||||
}
|
||||
gdFree (apixel);
|
||||
gdFree (colors);
|
||||
return (im);
|
||||
}
|
||||
#endif
|
1205
ext/gd/libgd/jisx0208.h
Normal file
1205
ext/gd/libgd/jisx0208.h
Normal file
File diff suppressed because it is too large
Load Diff
52
ext/gd/libgd/mathmake.c
Normal file
52
ext/gd/libgd/mathmake.c
Normal file
@ -0,0 +1,52 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#define scale 1024
|
||||
|
||||
int basis[91];
|
||||
int cost[360];
|
||||
|
||||
main (void)
|
||||
{
|
||||
int i;
|
||||
printf ("#define costScale %d\n", scale);
|
||||
printf ("int cost[] = {\n ");
|
||||
for (i = 0; (i <= 90); i++)
|
||||
{
|
||||
basis[i] = cos ((double) i * .0174532925) * scale;
|
||||
}
|
||||
for (i = 0; (i < 90); i++)
|
||||
{
|
||||
printf ("%d,\n ", cost[i] = basis[i]);
|
||||
}
|
||||
for (i = 90; (i < 180); i++)
|
||||
{
|
||||
printf ("%d,\n ", cost[i] = -basis[180 - i]);
|
||||
}
|
||||
for (i = 180; (i < 270); i++)
|
||||
{
|
||||
printf ("%d,\n ", cost[i] = -basis[i - 180]);
|
||||
}
|
||||
for (i = 270; (i < 359); i++)
|
||||
{
|
||||
printf ("%d,\n ", cost[i] = basis[360 - i]);
|
||||
}
|
||||
printf ("%d\n", cost[359] = basis[1]);
|
||||
printf ("};\n");
|
||||
printf ("#define sintScale %d\n", scale);
|
||||
printf ("int sint[] = {\n ");
|
||||
for (i = 0; (i < 360); i++)
|
||||
{
|
||||
int val;
|
||||
val = cost[(i + 270) % 360];
|
||||
if (i != 359)
|
||||
{
|
||||
printf ("%d,\n ", val);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("%d\n", val);
|
||||
}
|
||||
}
|
||||
printf ("};\n");
|
||||
}
|
45
ext/gd/libgd/pngtogd.c
Normal file
45
ext/gd/libgd/pngtogd.c
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include "gd.h"
|
||||
|
||||
/* A short program which converts a .png file into a .gd file, for
|
||||
your convenience in creating images on the fly from a
|
||||
basis image that must be loaded quickly. The .gd format
|
||||
is not intended to be a general-purpose format. */
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gdImagePtr im;
|
||||
FILE *in, *out;
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf (stderr, "Usage: pngtogd filename.png filename.gd\n");
|
||||
exit (1);
|
||||
}
|
||||
in = fopen (argv[1], "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "Input file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im = gdImageCreateFromPng (in);
|
||||
fclose (in);
|
||||
if (!im)
|
||||
{
|
||||
fprintf (stderr, "Input is not in PNG format!\n");
|
||||
exit (1);
|
||||
}
|
||||
out = fopen (argv[2], "wb");
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr, "Output file cannot be written to!\n");
|
||||
gdImageDestroy (im);
|
||||
exit (1);
|
||||
}
|
||||
gdImageGd (im, out);
|
||||
fclose (out);
|
||||
gdImageDestroy (im);
|
||||
|
||||
return 0;
|
||||
}
|
52
ext/gd/libgd/pngtogd2.c
Normal file
52
ext/gd/libgd/pngtogd2.c
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "gd.h"
|
||||
|
||||
/* A short program which converts a .png file into a .gd file, for
|
||||
your convenience in creating images on the fly from a
|
||||
basis image that must be loaded quickly. The .gd format
|
||||
is not intended to be a general-purpose format. */
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gdImagePtr im;
|
||||
FILE *in, *out;
|
||||
int cs, fmt;
|
||||
|
||||
if (argc != 5)
|
||||
{
|
||||
fprintf (stderr, "Usage: pngtogd2 filename.png filename.gd2 cs fmt\n");
|
||||
fprintf (stderr, " where cs is the chunk size\n");
|
||||
fprintf (stderr, " fmt is 1 for raw, 2 for compressed\n");
|
||||
exit (1);
|
||||
}
|
||||
in = fopen (argv[1], "rb");
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr, "Input file does not exist!\n");
|
||||
exit (1);
|
||||
}
|
||||
im = gdImageCreateFromPng (in);
|
||||
fclose (in);
|
||||
if (!im)
|
||||
{
|
||||
fprintf (stderr, "Input is not in PNG format!\n");
|
||||
exit (1);
|
||||
}
|
||||
out = fopen (argv[2], "wb");
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr, "Output file cannot be written to!\n");
|
||||
gdImageDestroy (im);
|
||||
exit (1);
|
||||
}
|
||||
cs = atoi (argv[3]);
|
||||
fmt = atoi (argv[4]);
|
||||
gdImageGd2 (im, out, cs, fmt);
|
||||
fclose (out);
|
||||
gdImageDestroy (im);
|
||||
|
||||
return 0;
|
||||
}
|
129
ext/gd/libgd/testac.c
Normal file
129
ext/gd/libgd/testac.c
Normal file
@ -0,0 +1,129 @@
|
||||
|
||||
#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);
|
||||
}
|
369
ext/gd/libgd/wbmp.c
Normal file
369
ext/gd/libgd/wbmp.c
Normal file
@ -0,0 +1,369 @@
|
||||
|
||||
/* WBMP
|
||||
** ----
|
||||
** WBMP Level 0: B/W, Uncompressed
|
||||
** This implements the WBMP format as specified in WAPSpec 1.1 and 1.2.
|
||||
** It does not support ExtHeaders as defined in the spec. The spec states
|
||||
** that a WAP client does not need to implement ExtHeaders.
|
||||
**
|
||||
** (c) 2000 Johan Van den Brande <johan@vandenbrande.com>
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wbmp.h"
|
||||
#include "gd.h"
|
||||
#include "gdhelpers.h"
|
||||
|
||||
#ifdef NOTDEF
|
||||
#define __TEST /* Compile with main function */
|
||||
#define __DEBUG /* Extra verbose when with __TEST */
|
||||
#define __WRITE /* readwbmp and writewbmp(stdout) */
|
||||
#define __VIEW /* view the wbmp on stdout */
|
||||
#endif
|
||||
|
||||
/* getmbi
|
||||
** ------
|
||||
** Get a multibyte integer from a generic getin function
|
||||
** 'getin' can be getc, with in = NULL
|
||||
** you can find getin as a function just above the main function
|
||||
** This way you gain a lot of flexibilty about how this package
|
||||
** reads a wbmp file.
|
||||
*/
|
||||
int
|
||||
getmbi (int (*getin) (void *in), void *in)
|
||||
{
|
||||
int i, mbi = 0;
|
||||
|
||||
do
|
||||
{
|
||||
i = getin (in);
|
||||
if (i < 0)
|
||||
return (-1);
|
||||
mbi = mbi << 7 | i & 0x7f;
|
||||
}
|
||||
while (i & 0x80);
|
||||
|
||||
return (mbi);
|
||||
}
|
||||
|
||||
|
||||
/* putmbi
|
||||
** ------
|
||||
** Put a multibyte intgerer in some kind of output stream
|
||||
** I work here with a function pointer, to make it as generic
|
||||
** as possible. Look at this function as an iterator on the
|
||||
** mbi integers it spits out.
|
||||
**
|
||||
*/
|
||||
void
|
||||
putmbi (int i, void (*putout) (int c, void *out), void *out)
|
||||
{
|
||||
int cnt, l, accu;
|
||||
|
||||
/* Get number of septets */
|
||||
cnt = 0;
|
||||
accu = 0;
|
||||
while (accu != i)
|
||||
accu += i & 0x7f << 7 * cnt++;
|
||||
|
||||
/* Produce the multibyte output */
|
||||
for (l = cnt - 1; l > 0; l--)
|
||||
putout (0x80 | (i & 0x7f << 7 * l) >> 7 * l, out);
|
||||
|
||||
putout (i & 0x7f, out);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* skipheader
|
||||
** ----------
|
||||
** Skips the ExtHeader. Not needed for the moment
|
||||
**
|
||||
*/
|
||||
int
|
||||
skipheader (int (*getin) (void *in), void *in)
|
||||
{
|
||||
int i;
|
||||
|
||||
do
|
||||
{
|
||||
i = getin (in);
|
||||
if (i < 0)
|
||||
return (-1);
|
||||
}
|
||||
while (i & 0x80);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* create wbmp
|
||||
** -----------
|
||||
** create an empty wbmp
|
||||
**
|
||||
*/
|
||||
Wbmp *
|
||||
createwbmp (int width, int height, int color)
|
||||
{
|
||||
int i;
|
||||
|
||||
Wbmp *wbmp;
|
||||
if ((wbmp = (Wbmp *) gdMalloc (sizeof (Wbmp))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if ((wbmp->bitmap = (int *) gdMalloc (sizeof (int) * width * height)) == NULL)
|
||||
{
|
||||
gdFree (wbmp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
wbmp->width = width;
|
||||
wbmp->height = height;
|
||||
|
||||
for (i = 0; i < width * height; wbmp->bitmap[i++] = color);
|
||||
|
||||
return (wbmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* readwbmp
|
||||
** -------
|
||||
** Actually reads the WBMP format from an open file descriptor
|
||||
** It goes along by returning a pointer to a WBMP struct.
|
||||
**
|
||||
*/
|
||||
int
|
||||
readwbmp (int (*getin) (void *in), void *in, Wbmp ** return_wbmp)
|
||||
{
|
||||
int row, col, byte, pel, pos;
|
||||
Wbmp *wbmp;
|
||||
|
||||
if ((wbmp = (Wbmp *) gdMalloc (sizeof (Wbmp))) == NULL)
|
||||
return (-1);
|
||||
|
||||
wbmp->type = getin (in);
|
||||
if (wbmp->type != 0)
|
||||
{
|
||||
gdFree (wbmp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (skipheader (getin, in))
|
||||
return (-1);
|
||||
|
||||
|
||||
wbmp->width = getmbi (getin, in);
|
||||
if (wbmp->width == -1)
|
||||
{
|
||||
gdFree (wbmp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
wbmp->height = getmbi (getin, in);
|
||||
if (wbmp->height == -1)
|
||||
{
|
||||
gdFree (wbmp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#ifdef __DEBUG
|
||||
printf ("W: %d, H: %d\n", wbmp->width, wbmp->height);
|
||||
#endif
|
||||
|
||||
if ((wbmp->bitmap = (int *) gdMalloc (sizeof (int) * wbmp->width * wbmp->height)) == NULL)
|
||||
{
|
||||
gdFree (wbmp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#ifdef __DEBUG
|
||||
printf ("DATA CONSTRUCTED\n");
|
||||
#endif
|
||||
|
||||
pos = 0;
|
||||
for (row = 0; row < wbmp->height; row++)
|
||||
{
|
||||
for (col = 0; col < wbmp->width;)
|
||||
{
|
||||
byte = getin (in);
|
||||
|
||||
for (pel = 7; pel >= 0; pel--)
|
||||
{
|
||||
if (col++ < wbmp->width)
|
||||
{
|
||||
if (byte & 1 << pel)
|
||||
{
|
||||
wbmp->bitmap[pos] = WBMP_WHITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
wbmp->bitmap[pos] = WBMP_BLACK;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*return_wbmp = wbmp;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* writewbmp
|
||||
** ---------
|
||||
** Write a wbmp to a file descriptor
|
||||
**
|
||||
** Why not just giving a filedescriptor to this function?
|
||||
** Well, the incentive to write this function was the complete
|
||||
** integration in gd library from www.boutell.com. They use
|
||||
** their own io functions, so the passing of a function seemed to be
|
||||
** a logic(?) decision ...
|
||||
**
|
||||
*/
|
||||
int
|
||||
writewbmp (Wbmp * wbmp, void (*putout) (int c, void *out), void *out)
|
||||
{
|
||||
int row, col;
|
||||
int bitpos, octet;
|
||||
|
||||
/* Generate the header */
|
||||
putout (0, out); /* WBMP Type 0: B/W, Uncompressed bitmap */
|
||||
putout (0, out); /* FixHeaderField */
|
||||
|
||||
|
||||
|
||||
/* Size of the image */
|
||||
putmbi (wbmp->width, putout, out); /* width */
|
||||
putmbi (wbmp->height, putout, out); /* height */
|
||||
|
||||
|
||||
/* Image data */
|
||||
for (row = 0; row < wbmp->height; row++)
|
||||
{
|
||||
bitpos = 8;
|
||||
octet = 0;
|
||||
for (col = 0; col < wbmp->width; col++)
|
||||
{
|
||||
octet |= ((wbmp->bitmap[row * wbmp->width + col] == 1) ? WBMP_WHITE : WBMP_BLACK) << --bitpos;
|
||||
if (bitpos == 0)
|
||||
{
|
||||
bitpos = 8;
|
||||
putout (octet, out);
|
||||
octet = 0;
|
||||
}
|
||||
}
|
||||
if (bitpos != 8)
|
||||
putout (octet, out);
|
||||
|
||||
}
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* freewbmp
|
||||
** --------
|
||||
** gdFrees up memory occupied by a WBMP structure
|
||||
**
|
||||
*/
|
||||
void
|
||||
freewbmp (Wbmp * wbmp)
|
||||
{
|
||||
gdFree (wbmp->bitmap);
|
||||
gdFree (wbmp);
|
||||
}
|
||||
|
||||
|
||||
/* printwbmp
|
||||
** ---------
|
||||
** print a WBMP to stdout for visualisation
|
||||
**
|
||||
*/
|
||||
void
|
||||
printwbmp (Wbmp * wbmp)
|
||||
{
|
||||
int row, col;
|
||||
for (row = 0; row < wbmp->height; row++)
|
||||
{
|
||||
for (col = 0; col < wbmp->width; col++)
|
||||
{
|
||||
if (wbmp->bitmap[wbmp->width * row + col] == WBMP_BLACK)
|
||||
{
|
||||
putchar ('#');
|
||||
}
|
||||
else
|
||||
{
|
||||
putchar (' ');
|
||||
}
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __TEST
|
||||
|
||||
/* putout to file descriptor
|
||||
** -------------------------
|
||||
*/
|
||||
int
|
||||
putout (int c, void *out)
|
||||
{
|
||||
return (putc (c, (FILE *) out));
|
||||
}
|
||||
|
||||
/* getin from file descriptor
|
||||
** --------------------------
|
||||
*/
|
||||
int
|
||||
getin (void *in)
|
||||
{
|
||||
return (getc ((FILE *) in));
|
||||
}
|
||||
|
||||
|
||||
/* Main function
|
||||
** -------------
|
||||
**
|
||||
*/
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
FILE *wbmp_file;
|
||||
Wbmp *wbmp;
|
||||
|
||||
wbmp_file = fopen (argv[1], "rb");
|
||||
if (wbmp_file)
|
||||
{
|
||||
readwbmp (&getin, wbmp_file, &wbmp);
|
||||
|
||||
#ifdef __VIEW
|
||||
|
||||
#ifdef __DEBUG
|
||||
printf ("\nVIEWING IMAGE\n");
|
||||
#endif
|
||||
|
||||
printwbmp (wbmp);
|
||||
#endif
|
||||
|
||||
#ifdef __WRITE
|
||||
|
||||
#ifdef __DEBUG
|
||||
printf ("\nDUMPING WBMP to STDOUT\n");
|
||||
#endif
|
||||
|
||||
writewbmp (wbmp, &putout, stdout);
|
||||
#endif
|
||||
|
||||
freewbmp (wbmp);
|
||||
fclose (wbmp_file);
|
||||
}
|
||||
}
|
||||
#endif
|
47
ext/gd/libgd/wbmp.h
Normal file
47
ext/gd/libgd/wbmp.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* WBMP
|
||||
** ----
|
||||
** WBMP Level 0: B/W, Uncompressed
|
||||
** This implements the WBMP format as specified in WAPSpec 1.1 and 1.2.
|
||||
** It does not support ExtHeaders as defined in the spec. The spec states
|
||||
** that a WAP client does not need to implement ExtHeaders.
|
||||
**
|
||||
** (c) 2000 Johan Van den Brande <johan@vandenbrande.com>
|
||||
**
|
||||
** Header file
|
||||
*/
|
||||
#ifndef __WBMP_H
|
||||
#define __WBMP_H 1
|
||||
|
||||
|
||||
/* WBMP struct
|
||||
** -----------
|
||||
** A Wireless bitmap structure
|
||||
**
|
||||
*/
|
||||
|
||||
typedef struct Wbmp_
|
||||
{
|
||||
int type; /* type of the wbmp */
|
||||
int width; /* width of the image */
|
||||
int height; /* height of the image */
|
||||
int *bitmap; /* pointer to data: 0 = WHITE , 1 = BLACK */
|
||||
} Wbmp;
|
||||
|
||||
#define WBMP_WHITE 1
|
||||
#define WBMP_BLACK 0
|
||||
|
||||
|
||||
/* Proto's
|
||||
** -------
|
||||
**
|
||||
*/
|
||||
void putmbi( int i, void (*putout)(int c, void *out), void *out);
|
||||
int getmbi ( int (*getin)(void *in), void *in );
|
||||
int skipheader( int (*getin)(void *in), void *in );
|
||||
Wbmp *createwbmp( int width, int height, int color );
|
||||
int readwbmp( int (*getin)(void *in), void *in, Wbmp **wbmp );
|
||||
int writewbmp( Wbmp *wbmp, void (*putout)( int c, void *out), void *out);
|
||||
void freewbmp( Wbmp *wbmp );
|
||||
void printwbmp( Wbmp *wbmp );
|
||||
|
||||
#endif
|
254
ext/gd/libgd/webpng.c
Normal file
254
ext/gd/libgd/webpng.c
Normal file
@ -0,0 +1,254 @@
|
||||
/* Bring in the gd library functions */
|
||||
#include "gd.h"
|
||||
|
||||
/* Bring in standard I/O and string manipulation functions */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for atoi() */
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <process.h>
|
||||
int
|
||||
getpid ()
|
||||
{
|
||||
return _getpid ();
|
||||
}
|
||||
#else
|
||||
#include <unistd.h> /* for getpid(), unlink() */
|
||||
#endif
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
FILE *in;
|
||||
FILE *out;
|
||||
char outFn[20];
|
||||
int useStdinStdout = 0;
|
||||
|
||||
/* Declare our image pointer */
|
||||
gdImagePtr im = 0;
|
||||
int i;
|
||||
/* We'll clear 'no' once we know the user has made a
|
||||
reasonable request. */
|
||||
int no = 1;
|
||||
/* We'll set 'write' once we know the user's request
|
||||
requires that the image be written back to disk. */
|
||||
int write = 0;
|
||||
/* C programs always get at least one argument; we want at
|
||||
least one more (the image), more in practice. */
|
||||
if (argc < 2 || !strcmp (argv[1], "--help"))
|
||||
{
|
||||
no = 1;
|
||||
goto usage;
|
||||
}
|
||||
|
||||
/* The last argument should be the image. Open the file. */
|
||||
if (strcmp ("-", argv[argc - 1]) == 0)
|
||||
{ /* - is synonymous with STDIN */
|
||||
useStdinStdout = 1;
|
||||
in = stdin;
|
||||
}
|
||||
else
|
||||
{
|
||||
in = fopen (argv[argc - 1], "rb");
|
||||
}
|
||||
if (!in)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Error: can't open file %s.\n", argv[argc - 1]);
|
||||
exit (1);
|
||||
}
|
||||
/* Now load the image. */
|
||||
im = gdImageCreateFromPng (in);
|
||||
fclose (in);
|
||||
/* If the load failed, it must not be a PNG file. */
|
||||
if (!im)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Error: %s is not a valid PNG file.\n", argv[argc - 1]);
|
||||
exit (1);
|
||||
}
|
||||
/* Consider each argument in turn. */
|
||||
for (i = 1; (i < (argc - 1)); i++)
|
||||
{
|
||||
/* -i turns on and off interlacing. */
|
||||
if (!strcmp (argv[i], "--help"))
|
||||
{
|
||||
/* Every program should use this for help! :) */
|
||||
no = 1;
|
||||
goto usage;
|
||||
}
|
||||
else if (!strcmp (argv[i], "-i"))
|
||||
{
|
||||
if (i == (argc - 2))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Error: -i specified without y or n.\n");
|
||||
no = 1;
|
||||
goto usage;
|
||||
}
|
||||
if (!strcmp (argv[i + 1], "y"))
|
||||
{
|
||||
/* Set interlace. */
|
||||
gdImageInterlace (im, 1);
|
||||
}
|
||||
else if (!strcmp (argv[i + 1], "n"))
|
||||
{
|
||||
/* Clear interlace. */
|
||||
gdImageInterlace (im, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Error: -i specified without y or n.\n");
|
||||
no = 1;
|
||||
goto usage;
|
||||
}
|
||||
i++;
|
||||
no = 0;
|
||||
write = 1;
|
||||
}
|
||||
else if (!strcmp (argv[i], "-t"))
|
||||
{
|
||||
/* Set transparent index (or none). */
|
||||
int index;
|
||||
if (i == (argc - 2))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Error: -t specified without a color table index.\n");
|
||||
no = 1;
|
||||
goto usage;
|
||||
}
|
||||
if (!strcmp (argv[i + 1], "none"))
|
||||
{
|
||||
/* -1 means not transparent. */
|
||||
gdImageColorTransparent (im, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* OK, get an integer and set the index. */
|
||||
index = atoi (argv[i + 1]);
|
||||
gdImageColorTransparent (im, index);
|
||||
}
|
||||
i++;
|
||||
write = 1;
|
||||
no = 0;
|
||||
}
|
||||
else if (!strcmp (argv[i], "-l"))
|
||||
{
|
||||
/* List the colors in the color table. */
|
||||
int 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"))
|
||||
{
|
||||
/* Output dimensions, etc. */
|
||||
int t;
|
||||
printf ("Width: %d Height: %d Colors: %d\n",
|
||||
gdImageSX (im), gdImageSY (im),
|
||||
gdImageColorsTotal (im));
|
||||
t = gdImageGetTransparent (im);
|
||||
if (t != (-1))
|
||||
{
|
||||
printf ("First 100% transparent index: %d\n", t);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* -1 means the image is not transparent. */
|
||||
printf ("First 100% transparent index: none\n");
|
||||
}
|
||||
if (gdImageGetInterlaced (im))
|
||||
{
|
||||
printf ("Interlaced: yes\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Interlaced: no\n");
|
||||
}
|
||||
no = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Unknown argument: %s\n", argv[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
usage:
|
||||
if (no)
|
||||
{
|
||||
/* If the command failed, output an explanation. */
|
||||
fprintf (stderr,
|
||||
"Usage: webpng [-i y|n ] [-l] [-t index|none ] [-d] pngname.png\n"
|
||||
|
||||
" -i [y|n] Turns on/off interlace\n"
|
||||
" -l Prints the table of color indexes\n"
|
||||
" -t [index] Set the transparent color to the specified index (0-255 or \"none\")\n"
|
||||
" -d Reports the dimensions and other characteristics of the image.\n"
|
||||
"\n"
|
||||
"If you specify '-' as the input file, stdin/stdout will be used input/output.\n"
|
||||
);
|
||||
}
|
||||
if (write)
|
||||
{
|
||||
if (useStdinStdout)
|
||||
{
|
||||
out = stdout;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Open a temporary file. */
|
||||
|
||||
/* "temp.tmp" is not good temporary filename. */
|
||||
sprintf (outFn, "webpng.tmp%d", getpid ());
|
||||
out = fopen (outFn, "wb");
|
||||
|
||||
if (!out)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Unable to write to %s -- exiting\n", outFn);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the new PNG. */
|
||||
gdImagePng (im, out);
|
||||
|
||||
if (!useStdinStdout)
|
||||
{
|
||||
fclose (out);
|
||||
/* Erase the old PNG. */
|
||||
unlink (argv[argc - 1]);
|
||||
/* Rename the new to the old. */
|
||||
if (rename (outFn, argv[argc - 1]) != 0)
|
||||
{
|
||||
perror ("rename");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Delete the image from memory. */
|
||||
if (im)
|
||||
{
|
||||
gdImageDestroy (im);
|
||||
}
|
||||
/* All's well that ends well. */
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user