|
Packit Service |
df60bb |
#ifdef HAVE_CONFIG_H
|
|
Packit Service |
df60bb |
#include "config.h"
|
|
Packit Service |
df60bb |
#endif /* HAVE_CONFIG_H */
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
#include "gd.h"
|
|
Packit Service |
df60bb |
#include "gd_errors.h"
|
|
Packit Service |
df60bb |
#include <math.h>
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* In tests this is sufficient to prevent obvious artifacts */
|
|
Packit Service |
df60bb |
#define MAG 4
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
#define PI 3.141592
|
|
Packit Service |
df60bb |
#define DEG2RAD(x) ((x)*PI/180.)
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
|
Packit Service |
df60bb |
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
#define MAX4(x,y,z,w) \
|
|
Packit Service |
df60bb |
((MAX((x),(y))) > (MAX((z),(w))) ? (MAX((x),(y))) : (MAX((z),(w))))
|
|
Packit Service |
df60bb |
#define MIN4(x,y,z,w) \
|
|
Packit Service |
df60bb |
((MIN((x),(y))) < (MIN((z),(w))) ? (MIN((x),(y))) : (MIN((z),(w))))
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
#define MAXX(x) MAX4(x[0],x[2],x[4],x[6])
|
|
Packit Service |
df60bb |
#define MINX(x) MIN4(x[0],x[2],x[4],x[6])
|
|
Packit Service |
df60bb |
#define MAXY(x) MAX4(x[1],x[3],x[5],x[7])
|
|
Packit Service |
df60bb |
#define MINY(x) MIN4(x[1],x[3],x[5],x[7])
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/**
|
|
Packit Service |
df60bb |
* Function: gdImageStringFTCircle
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* Draw text curved along the top and bottom of a circular area of an image.
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* Parameters:
|
|
Packit Service |
df60bb |
* im - The image to draw onto.
|
|
Packit Service |
df60bb |
* cx - The x-coordinate of the center of the circular area.
|
|
Packit Service |
df60bb |
* cy - The y-coordinate of the center of the circular area.
|
|
Packit Service |
df60bb |
* radius - The radius of the circular area.
|
|
Packit Service |
df60bb |
* textRadius - The height of each character; if textRadius is 1/2 of radius,
|
|
Packit Service |
df60bb |
* characters extend halfway from the edge to the center.
|
|
Packit Service |
df60bb |
* fillPortion - The percentage of the 180 degrees of the circular area
|
|
Packit Service |
df60bb |
* assigned to each section of text, that is actually occupied
|
|
Packit Service |
df60bb |
* by text. The value has to be in range 0.0 to 1.0, with useful
|
|
Packit Service |
df60bb |
* values from about 0.4 to 0.9; 0.9 looks better than 1.0 which
|
|
Packit Service |
df60bb |
* is rather crowded.
|
|
Packit Service |
df60bb |
* font - The fontlist that is passed to <gdImageStringFT>.
|
|
Packit Service |
df60bb |
* points - The point size, which functions as a hint. Although the size
|
|
Packit Service |
df60bb |
* of the text is determined by radius, textRadius and
|
|
Packit Service |
df60bb |
* fillPortion, a point size that 'hints' appropriately should be
|
|
Packit Service |
df60bb |
* passed. If it's known that the text will be large, a large
|
|
Packit Service |
df60bb |
* point size such as 24.0 should be passed to get the best
|
|
Packit Service |
df60bb |
* results.
|
|
Packit Service |
df60bb |
* top - The text to draw clockwise at the top of the circular area.
|
|
Packit Service |
df60bb |
* bottom - The text to draw counterclockwise at the bottom of the
|
|
Packit Service |
df60bb |
* circular area.
|
|
Packit Service |
df60bb |
* fgcolor - The font color.
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* Returns:
|
|
Packit Service |
df60bb |
* NULL on success, or an error string on failure.
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
BGD_DECLARE(char*)
|
|
Packit Service |
df60bb |
gdImageStringFTCircle (gdImagePtr im,
|
|
Packit Service |
df60bb |
int cx,
|
|
Packit Service |
df60bb |
int cy,
|
|
Packit Service |
df60bb |
double radius,
|
|
Packit Service |
df60bb |
double textRadius,
|
|
Packit Service |
df60bb |
double fillPortion,
|
|
Packit Service |
df60bb |
char *font,
|
|
Packit Service |
df60bb |
double points, char *top, char *bottom, int fgcolor)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
char *err;
|
|
Packit Service |
df60bb |
int w;
|
|
Packit Service |
df60bb |
int brect[8];
|
|
Packit Service |
df60bb |
int sx1, sx2, sy1, sy2, sx, sy;
|
|
Packit Service |
df60bb |
int x, y;
|
|
Packit Service |
df60bb |
int fr, fg, fb, fa;
|
|
Packit Service |
df60bb |
int ox, oy;
|
|
Packit Service |
df60bb |
double prop;
|
|
Packit Service |
df60bb |
gdImagePtr im1;
|
|
Packit Service |
df60bb |
gdImagePtr im2;
|
|
Packit Service |
df60bb |
gdImagePtr im3;
|
|
Packit Service |
df60bb |
/* obtain brect so that we can size the image */
|
|
Packit Service |
df60bb |
err = gdImageStringFT ((gdImagePtr) NULL,
|
|
Packit Service |
df60bb |
&brect[0], 0, font, points * MAG, 0, 0, 0, bottom);
|
|
Packit Service |
df60bb |
if (err) {
|
|
Packit Service |
df60bb |
return err;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
sx1 = MAXX (brect) - MINX (brect) + 6;
|
|
Packit Service |
df60bb |
sy1 = MAXY (brect) - MINY (brect) + 6;
|
|
Packit Service |
df60bb |
err = gdImageStringFT ((gdImagePtr) NULL,
|
|
Packit Service |
df60bb |
&brect[0], 0, font, points * MAG, 0, 0, 0, top);
|
|
Packit Service |
df60bb |
if (err) {
|
|
Packit Service |
df60bb |
return err;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
sx2 = MAXX (brect) - MINX (brect) + 6;
|
|
Packit Service |
df60bb |
sy2 = MAXY (brect) - MINY (brect) + 6;
|
|
Packit Service |
df60bb |
/* Pad by 4 pixels to allow for slight errors
|
|
Packit Service |
df60bb |
observed in the bounding box returned by freetype */
|
|
Packit Service |
df60bb |
if (sx1 > sx2) {
|
|
Packit Service |
df60bb |
sx = sx1 * 2 + 4;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
sx = sx2 * 2 + 4;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
if (sy1 > sy2) {
|
|
Packit Service |
df60bb |
sy = sy1;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
sy = sy2;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
im1 = gdImageCreateTrueColor (sx, sy);
|
|
Packit Service |
df60bb |
if (!im1) {
|
|
Packit Service |
df60bb |
return "could not create first image";
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
err = gdImageStringFT (im1, 0, gdTrueColor (255, 255, 255),
|
|
Packit Service |
df60bb |
font, points * MAG,
|
|
Packit Service |
df60bb |
0, ((sx / 2) - sx1) / 2, points * MAG, bottom);
|
|
Packit Service |
df60bb |
if (err) {
|
|
Packit Service |
df60bb |
gdImageDestroy (im1);
|
|
Packit Service |
df60bb |
return err;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
/* We don't know the descent, which would be needed to do this
|
|
Packit Service |
df60bb |
with the angle parameter. Instead, implement a simple
|
|
Packit Service |
df60bb |
flip operation ourselves. */
|
|
Packit Service |
df60bb |
err = gdImageStringFT (im1, 0, gdTrueColor (255, 255, 255),
|
|
Packit Service |
df60bb |
font, points * MAG,
|
|
Packit Service |
df60bb |
0, sx / 2 + ((sx / 2) - sx2) / 2, points * MAG, top);
|
|
Packit Service |
df60bb |
if (err) {
|
|
Packit Service |
df60bb |
gdImageDestroy (im1);
|
|
Packit Service |
df60bb |
return err;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
/* Flip in place is tricky, be careful not to double-swap things */
|
|
Packit Service |
df60bb |
if (sy & 1) {
|
|
Packit Service |
df60bb |
for (y = 0; (y <= (sy / 2)); y++) {
|
|
Packit Service |
df60bb |
int xlimit = sx - 2;
|
|
Packit Service |
df60bb |
if (y == (sy / 2)) {
|
|
Packit Service |
df60bb |
/* If there is a "middle" row, be careful
|
|
Packit Service |
df60bb |
not to swap twice! */
|
|
Packit Service |
df60bb |
xlimit -= (sx / 4);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
for (x = (sx / 2) + 2; (x < xlimit); x++) {
|
|
Packit Service |
df60bb |
int t;
|
|
Packit Service |
df60bb |
int ox = sx - x + (sx / 2) - 1;
|
|
Packit Service |
df60bb |
int oy = sy - y - 1;
|
|
Packit Service |
df60bb |
t = im1->tpixels[oy][ox];
|
|
Packit Service |
df60bb |
im1->tpixels[oy][ox] = im1->tpixels[y][x];
|
|
Packit Service |
df60bb |
im1->tpixels[y][x] = t;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
for (y = 0; (y < (sy / 2)); y++) {
|
|
Packit Service |
df60bb |
int xlimit = sx - 2;
|
|
Packit Service |
df60bb |
for (x = (sx / 2) + 2; (x < xlimit); x++) {
|
|
Packit Service |
df60bb |
int t;
|
|
Packit Service |
df60bb |
int ox = sx - x + (sx / 2) - 1;
|
|
Packit Service |
df60bb |
int oy = sy - y - 1;
|
|
Packit Service |
df60bb |
t = im1->tpixels[oy][ox];
|
|
Packit Service |
df60bb |
im1->tpixels[oy][ox] = im1->tpixels[y][x];
|
|
Packit Service |
df60bb |
im1->tpixels[y][x] = t;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
#if STEP_PNGS
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
FILE *out = fopen ("gdfx1.png", "wb");
|
|
Packit Service |
df60bb |
gdImagePng (im1, out);
|
|
Packit Service |
df60bb |
fclose (out);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
#endif /* STEP_PNGS */
|
|
Packit Service |
df60bb |
/* Resample taller; the exact proportions of the text depend on the
|
|
Packit Service |
df60bb |
ratio of textRadius to radius, and the value of fillPortion */
|
|
Packit Service |
df60bb |
if (sx > sy * 10) {
|
|
Packit Service |
df60bb |
w = sx;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
w = sy * 10;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
im2 = gdImageCreateTrueColor (w, w);
|
|
Packit Service |
df60bb |
if (!im2) {
|
|
Packit Service |
df60bb |
gdImageDestroy (im1);
|
|
Packit Service |
df60bb |
return "could not create resampled image";
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
prop = textRadius / radius;
|
|
Packit Service |
df60bb |
gdImageCopyResampled (im2, im1,
|
|
Packit Service |
df60bb |
gdImageSX (im2) * (1.0 - fillPortion) / 4,
|
|
Packit Service |
df60bb |
sy * 10 * (1.0 - prop),
|
|
Packit Service |
df60bb |
0, 0,
|
|
Packit Service |
df60bb |
gdImageSX (im2) * fillPortion / 2, sy * 10 * prop,
|
|
Packit Service |
df60bb |
gdImageSX (im1) / 2, gdImageSY (im1));
|
|
Packit Service |
df60bb |
gdImageCopyResampled (im2, im1,
|
|
Packit Service |
df60bb |
(gdImageSX (im2) / 2) +
|
|
Packit Service |
df60bb |
gdImageSX (im2) * (1.0 - fillPortion) / 4,
|
|
Packit Service |
df60bb |
sy * 10 * (1.0 - prop),
|
|
Packit Service |
df60bb |
gdImageSX (im1) / 2, 0,
|
|
Packit Service |
df60bb |
gdImageSX (im2) * fillPortion / 2, sy * 10 * prop,
|
|
Packit Service |
df60bb |
gdImageSX (im1) / 2, gdImageSY (im1));
|
|
Packit Service |
df60bb |
#if STEP_PNGS
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
FILE *out = fopen ("gdfx2.png", "wb");
|
|
Packit Service |
df60bb |
gdImagePng (im2, out);
|
|
Packit Service |
df60bb |
fclose (out);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
#endif /* STEP_PNGS */
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
gdImageDestroy (im1);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Ready to produce a circle */
|
|
Packit Service |
df60bb |
im3 = gdImageSquareToCircle (im2, radius);
|
|
Packit Service |
df60bb |
if (im3 == NULL) {
|
|
Packit Service |
df60bb |
gdImageDestroy(im2);
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdImageDestroy (im2);
|
|
Packit Service |
df60bb |
/* Now blend im3 with the destination. Cheat a little. The
|
|
Packit Service |
df60bb |
source (im3) is white-on-black, so we can use the
|
|
Packit Service |
df60bb |
red component as a basis for alpha as long as we're
|
|
Packit Service |
df60bb |
careful to shift off the extra bit and invert
|
|
Packit Service |
df60bb |
(alpha ranges from 0 to 127 where 0 is OPAQUE).
|
|
Packit Service |
df60bb |
Also be careful to allow for an alpha component
|
|
Packit Service |
df60bb |
in the fgcolor parameter itself (gug!) */
|
|
Packit Service |
df60bb |
fr = gdTrueColorGetRed (fgcolor);
|
|
Packit Service |
df60bb |
fg = gdTrueColorGetGreen (fgcolor);
|
|
Packit Service |
df60bb |
fb = gdTrueColorGetBlue (fgcolor);
|
|
Packit Service |
df60bb |
fa = gdTrueColorGetAlpha (fgcolor);
|
|
Packit Service |
df60bb |
ox = cx - (im3->sx / 2);
|
|
Packit Service |
df60bb |
oy = cy - (im3->sy / 2);
|
|
Packit Service |
df60bb |
for (y = 0; (y < im3->sy); y++) {
|
|
Packit Service |
df60bb |
for (x = 0; (x < im3->sx); x++) {
|
|
Packit Service |
df60bb |
int a = gdTrueColorGetRed (im3->tpixels[y][x]) >> 1;
|
|
Packit Service |
df60bb |
a *= (127 - fa);
|
|
Packit Service |
df60bb |
a /= 127;
|
|
Packit Service |
df60bb |
a = 127 - a;
|
|
Packit Service |
df60bb |
gdImageSetPixel (im, x + ox, y + oy,
|
|
Packit Service |
df60bb |
gdTrueColorAlpha (fr, fg, fb, a));
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdImageDestroy (im3);
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
#if GDFX_MAIN
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
int
|
|
Packit Service |
df60bb |
main (int argc, char *argv[])
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
FILE *in;
|
|
Packit Service |
df60bb |
FILE *out;
|
|
Packit Service |
df60bb |
gdImagePtr im;
|
|
Packit Service |
df60bb |
int radius;
|
|
Packit Service |
df60bb |
/* Create an image of text on a circle, with an
|
|
Packit Service |
df60bb |
alpha channel so that we can copy it onto a
|
|
Packit Service |
df60bb |
background */
|
|
Packit Service |
df60bb |
in = fopen ("eleanor.jpg", "rb");
|
|
Packit Service |
df60bb |
if (!in) {
|
|
Packit Service |
df60bb |
im = gdImageCreateTrueColor (300, 300);
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
im = gdImageCreateFromJpeg (in);
|
|
Packit Service |
df60bb |
fclose (in);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
if (gdImageSX (im) < gdImageSY (im)) {
|
|
Packit Service |
df60bb |
radius = gdImageSX (im) / 2;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
radius = gdImageSY (im) / 2;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdImageStringFTCircle (im,
|
|
Packit Service |
df60bb |
gdImageSX (im) / 2,
|
|
Packit Service |
df60bb |
gdImageSY (im) / 2,
|
|
Packit Service |
df60bb |
radius,
|
|
Packit Service |
df60bb |
radius / 2,
|
|
Packit Service |
df60bb |
0.8,
|
|
Packit Service |
df60bb |
"arial",
|
|
Packit Service |
df60bb |
24,
|
|
Packit Service |
df60bb |
"top text",
|
|
Packit Service |
df60bb |
"bottom text", gdTrueColorAlpha (240, 240, 255, 32));
|
|
Packit Service |
df60bb |
out = fopen ("gdfx.png", "wb");
|
|
Packit Service |
df60bb |
if (!out) {
|
|
Packit Service |
df60bb |
gd_error("Can't create gdfx.png\n");
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdImagePng (im, out);
|
|
Packit Service |
df60bb |
fclose (out);
|
|
Packit Service |
df60bb |
gdImageDestroy (im);
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
#endif /* GDFX_MAIN */
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Note: don't change these */
|
|
Packit Service |
df60bb |
#define SUPER 2
|
|
Packit Service |
df60bb |
#define SUPERBITS1 1
|
|
Packit Service |
df60bb |
#define SUPERBITS2 2
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/**
|
|
Packit Service |
df60bb |
* Function: gdImageSquareToCircle
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* Apply polar coordinate transformation to an image.
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* The X axis of the original will be remapped to theta (angle) and the Y axis
|
|
Packit Service |
df60bb |
* of the original will be remapped to rho (distance from center).
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* Parameters:
|
|
Packit Service |
df60bb |
* im - The image, which must be square, i.e. width == height.
|
|
Packit Service |
df60bb |
* radius - The radius of the new image, i.e. width == height == radius * 2.
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* Returns:
|
|
Packit Service |
df60bb |
* The transformed image, or NULL on failure.
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
BGD_DECLARE(gdImagePtr)
|
|
Packit Service |
df60bb |
gdImageSquareToCircle (gdImagePtr im, int radius)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
int x, y;
|
|
Packit Service |
df60bb |
double c;
|
|
Packit Service |
df60bb |
gdImagePtr im2;
|
|
Packit Service |
df60bb |
if (im->sx != im->sy) {
|
|
Packit Service |
df60bb |
/* Source image must be square */
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
im2 = gdImageCreateTrueColor (radius * 2, radius * 2);
|
|
Packit Service |
df60bb |
if (!im2) {
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
/* Supersampling for a nicer result */
|
|
Packit Service |
df60bb |
c = (im2->sx / 2) * SUPER;
|
|
Packit Service |
df60bb |
for (y = 0; (y < im2->sy * SUPER); y++) {
|
|
Packit Service |
df60bb |
for (x = 0; (x < im2->sx * SUPER); x++) {
|
|
Packit Service |
df60bb |
double rho = sqrt ((x - c) * (x - c) + (y - c) * (y - c));
|
|
Packit Service |
df60bb |
int pix;
|
|
Packit Service |
df60bb |
int cpix;
|
|
Packit Service |
df60bb |
double theta;
|
|
Packit Service |
df60bb |
double ox;
|
|
Packit Service |
df60bb |
double oy;
|
|
Packit Service |
df60bb |
int red, green, blue, alpha;
|
|
Packit Service |
df60bb |
if (rho > c) {
|
|
Packit Service |
df60bb |
continue;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
theta = atan2 (x - c, y - c) + PI / 2;
|
|
Packit Service |
df60bb |
if (theta < 0) {
|
|
Packit Service |
df60bb |
theta += 2 * PI;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
/* Undo supersampling */
|
|
Packit Service |
df60bb |
oy = (rho * im->sx) / (im2->sx * SUPER / 2);
|
|
Packit Service |
df60bb |
ox = theta * im->sx / (3.141592653 * 2);
|
|
Packit Service |
df60bb |
pix = gdImageGetPixel (im, ox, oy);
|
|
Packit Service |
df60bb |
cpix = im2->tpixels[y >> SUPERBITS1][x >> SUPERBITS1];
|
|
Packit Service |
df60bb |
red =
|
|
Packit Service |
df60bb |
(gdImageRed (im, pix) >> SUPERBITS2) + gdTrueColorGetRed (cpix);
|
|
Packit Service |
df60bb |
green =
|
|
Packit Service |
df60bb |
(gdImageGreen (im, pix) >> SUPERBITS2) +
|
|
Packit Service |
df60bb |
gdTrueColorGetGreen (cpix);
|
|
Packit Service |
df60bb |
blue =
|
|
Packit Service |
df60bb |
(gdImageBlue (im, pix) >> SUPERBITS2) + gdTrueColorGetBlue (cpix);
|
|
Packit Service |
df60bb |
alpha =
|
|
Packit Service |
df60bb |
(gdImageAlpha (im, pix) >> SUPERBITS2) +
|
|
Packit Service |
df60bb |
gdTrueColorGetAlpha (cpix);
|
|
Packit Service |
df60bb |
im2->tpixels[y >> SUPERBITS1][x >> SUPERBITS1] =
|
|
Packit Service |
df60bb |
gdTrueColorAlpha (red, green, blue, alpha);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
/* Restore full dynamic range, 0-63 yields 0-252. Replication of
|
|
Packit Service |
df60bb |
first 2 bits in last 2 bits has the desired effect. Note
|
|
Packit Service |
df60bb |
slightly different arithmetic for alpha which is 7-bit.
|
|
Packit Service |
df60bb |
NOTE: only correct for SUPER == 2 */
|
|
Packit Service |
df60bb |
for (y = 0; (y < im2->sy); y++) {
|
|
Packit Service |
df60bb |
for (x = 0; (x < im2->sx); x++) {
|
|
Packit Service |
df60bb |
/* Copy first 2 bits to last 2 bits, matching the
|
|
Packit Service |
df60bb |
dynamic range of the original cheaply */
|
|
Packit Service |
df60bb |
int cpix = im2->tpixels[y][x];
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
im2->tpixels[y][x] = gdTrueColorAlpha ((gdTrueColorGetRed (cpix) &
|
|
Packit Service |
df60bb |
0xFC) +
|
|
Packit Service |
df60bb |
((gdTrueColorGetRed (cpix) &
|
|
Packit Service |
df60bb |
0xC0) >> 6),
|
|
Packit Service |
df60bb |
(gdTrueColorGetGreen (cpix) &
|
|
Packit Service |
df60bb |
0xFC) +
|
|
Packit Service |
df60bb |
((gdTrueColorGetGreen (cpix)
|
|
Packit Service |
df60bb |
& 0xC0) >> 6),
|
|
Packit Service |
df60bb |
(gdTrueColorGetBlue (cpix) &
|
|
Packit Service |
df60bb |
0xFC) +
|
|
Packit Service |
df60bb |
((gdTrueColorGetBlue (cpix) &
|
|
Packit Service |
df60bb |
0xC0) >> 6),
|
|
Packit Service |
df60bb |
(gdTrueColorGetAlpha (cpix) &
|
|
Packit Service |
df60bb |
0x7C) +
|
|
Packit Service |
df60bb |
((gdTrueColorGetAlpha (cpix)
|
|
Packit Service |
df60bb |
& 0x60) >> 6));
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
return im2;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* 2.0.16: Called by gdImageSharpen to avoid excessive code repetition
|
|
Packit Service |
df60bb |
Added on 2003-11-19 by
|
|
Packit Service |
df60bb |
Paul Troughton (paul<dot>troughton<at>ieee<dot>org)
|
|
Packit Service |
df60bb |
Given filter coefficents and colours of three adjacent pixels,
|
|
Packit Service |
df60bb |
returns new colour for centre pixel
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
int
|
|
Packit Service |
df60bb |
gdImageSubSharpen (int pc, int c, int nc, float inner_coeff, float
|
|
Packit Service |
df60bb |
outer_coeff)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
float red, green, blue, alpha;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
red = inner_coeff * gdTrueColorGetRed (c) + outer_coeff *
|
|
Packit Service |
df60bb |
(gdTrueColorGetRed (pc) + gdTrueColorGetRed (nc));
|
|
Packit Service |
df60bb |
green = inner_coeff * gdTrueColorGetGreen (c) + outer_coeff *
|
|
Packit Service |
df60bb |
(gdTrueColorGetGreen (pc) + gdTrueColorGetGreen (nc));
|
|
Packit Service |
df60bb |
blue = inner_coeff * gdTrueColorGetBlue (c) + outer_coeff *
|
|
Packit Service |
df60bb |
(gdTrueColorGetBlue (pc) + gdTrueColorGetBlue (nc));
|
|
Packit Service |
df60bb |
alpha = gdTrueColorGetAlpha (c);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Clamping, as can overshoot bounds in either direction */
|
|
Packit Service |
df60bb |
if (red > 255.0f) {
|
|
Packit Service |
df60bb |
red = 255.0f;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
if (green > 255.0f) {
|
|
Packit Service |
df60bb |
green = 255.0f;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
if (blue > 255.0f) {
|
|
Packit Service |
df60bb |
blue = 255.0f;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
if (red < 0.0f) {
|
|
Packit Service |
df60bb |
red = 0.0f;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
if (green < 0.0f) {
|
|
Packit Service |
df60bb |
green = 0.0f;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
if (blue < 0.0f) {
|
|
Packit Service |
df60bb |
blue = 0.0f;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
return gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/**
|
|
Packit Service |
df60bb |
* Function: gdImageSharpen
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* Sharpen an image.
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* Uses a simple 3x3 convolution kernel and makes use of separability.
|
|
Packit Service |
df60bb |
* It's faster, but less flexible, than full-blown unsharp masking.
|
|
Packit Service |
df60bb |
* Silently does nothing to non-truecolor images and for pct<0, as it's not a useful blurring function.
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* Parameters:
|
|
Packit Service |
df60bb |
* pct - The sharpening percentage, which can be greater than 100.
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* Author:
|
|
Packit Service |
df60bb |
* Paul Troughton (paul<dot>troughton<at>ieee<dot>org)
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
BGD_DECLARE(void)
|
|
Packit Service |
df60bb |
gdImageSharpen (gdImagePtr im, int pct)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
int x, y;
|
|
Packit Service |
df60bb |
int sx, sy;
|
|
Packit Service |
df60bb |
float inner_coeff, outer_coeff;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
sx = im->sx;
|
|
Packit Service |
df60bb |
sy = im->sy;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Must sum to 1 to avoid overall change in brightness.
|
|
Packit Service |
df60bb |
* Scaling chosen so that pct=100 gives 1-D filter [-1 6 -1]/4,
|
|
Packit Service |
df60bb |
* resulting in a 2-D filter [1 -6 1; -6 36 -6; 1 -6 1]/16,
|
|
Packit Service |
df60bb |
* which gives noticeable, but not excessive, sharpening
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
outer_coeff = -pct / 400.0;
|
|
Packit Service |
df60bb |
inner_coeff = 1 - 2 * outer_coeff;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Don't try to do anything with non-truecolor images, as
|
|
Packit Service |
df60bb |
pointless,
|
|
Packit Service |
df60bb |
* nor for pct<=0, as small kernel size leads to nasty
|
|
Packit Service |
df60bb |
artefacts when blurring
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
if ((im->trueColor) && (pct > 0)) {
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* First pass, 1-D convolution column-wise */
|
|
Packit Service |
df60bb |
for (x = 0; x < sx; x++) {
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* pc is colour of previous pixel; c of the
|
|
Packit Service |
df60bb |
current pixel and nc of the next */
|
|
Packit Service |
df60bb |
int pc, c, nc;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Replicate edge pixel at image boundary */
|
|
Packit Service |
df60bb |
pc = gdImageGetPixel (im, x, 0);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Stop looping before last pixel to avoid
|
|
Packit Service |
df60bb |
conditional within loop */
|
|
Packit Service |
df60bb |
for (y = 0; y < sy - 1; y++) {
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
c = gdImageGetPixel (im, x, y);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
nc = gdImageGetTrueColorPixel (im, x, y + 1);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Update centre pixel to new colour */
|
|
Packit Service |
df60bb |
gdImageSetPixel (im, x, y,
|
|
Packit Service |
df60bb |
gdImageSubSharpen (pc, c, nc, inner_coeff,
|
|
Packit Service |
df60bb |
outer_coeff));
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Save original colour of current
|
|
Packit Service |
df60bb |
pixel for next time round */
|
|
Packit Service |
df60bb |
pc = c;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Deal with last pixel, replicating current
|
|
Packit Service |
df60bb |
pixel at image boundary */
|
|
Packit Service |
df60bb |
c = gdImageGetPixel (im, x, y);
|
|
Packit Service |
df60bb |
gdImageSetPixel (im, x, y, gdImageSubSharpen
|
|
Packit Service |
df60bb |
(pc, c, c, inner_coeff, outer_coeff));
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Second pass, 1-D convolution row-wise */
|
|
Packit Service |
df60bb |
for (y = 0; y < sy; y++) {
|
|
Packit Service |
df60bb |
int pc, c;
|
|
Packit Service |
df60bb |
pc = gdImageGetPixel (im, 0, y);
|
|
Packit Service |
df60bb |
for (x = 0; x < sx - 1; x++) {
|
|
Packit Service |
df60bb |
int c, nc;
|
|
Packit Service |
df60bb |
c = gdImageGetPixel (im, x, y);
|
|
Packit Service |
df60bb |
nc = gdImageGetTrueColorPixel (im, x + 1, y);
|
|
Packit Service |
df60bb |
gdImageSetPixel (im, x, y,
|
|
Packit Service |
df60bb |
gdImageSubSharpen (pc, c, nc, inner_coeff,
|
|
Packit Service |
df60bb |
outer_coeff));
|
|
Packit Service |
df60bb |
pc = c;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
c = gdImageGetPixel (im, x, y);
|
|
Packit Service |
df60bb |
gdImageSetPixel (im, x, y, gdImageSubSharpen
|
|
Packit Service |
df60bb |
(pc, c, c, inner_coeff, outer_coeff));
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|