Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ext/gd/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ if test "$PHP_GD" != "no"; then
libgd/gd_io.c
libgd/gd_jpeg.c
libgd/gd_matrix.c
libgd/gd_nnquant.c
libgd/gd_pixelate.c
libgd/gd_png.c
libgd/gd_rotate.c
Expand Down
2 changes: 1 addition & 1 deletion ext/gd/config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ if (PHP_GD != "no") {
gd_io_file.c gd_io_ss.c gd_jpeg.c gdkanji.c gd_png.c gd_ss.c \
gdtables.c gd_topal.c gd_wbmp.c gdxpm.c wbmp.c gd_xbm.c gd_security.c gd_transform.c \
gd_filter.c gd_pixelate.c gd_rotate.c gd_color_match.c gd_webp.c gd_avif.c \
gd_crop.c gd_interpolation.c gd_matrix.c gd_bmp.c gd_tga.c", "gd");
gd_crop.c gd_interpolation.c gd_matrix.c gd_bmp.c gd_tga.c gd_nnquant.c", "gd");
AC_DEFINE('HAVE_GD_BUNDLED', 1, "Define to 1 if gd extension uses GD library bundled in PHP.");
AC_DEFINE('HAVE_GD_PNG', 1, "Define to 1 if gd extension has PNG support.");
AC_DEFINE('HAVE_GD_BMP', 1, "Define to 1 if gd extension has BMP support.");
Expand Down
62 changes: 62 additions & 0 deletions ext/gd/gd.c
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,68 @@ PHP_FUNCTION(imagecolormatch)
}
/* }}} */

PHP_FUNCTION(imagetruecolortopalettesetmethod)
{
zval *IM;
zend_long method;
zend_long speed = 0;
gdImagePtr im;

ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(method)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(speed)
ZEND_PARSE_PARAMETERS_END();

im = php_gd_libgdimageptr_from_zval_p(IM);

if (method <= GD_QUANT_DEFAULT || method >= GD_QUANT_LIQ) {
zend_argument_value_error(2, "must be one of the GD_QUANT_* constants");
RETURN_THROWS();
}

if (speed < 0 || speed > 10) {
zend_argument_value_error(3, "must be between 0 and 10");
RETURN_THROWS();
}

if (gdImageTrueColorToPaletteSetMethod(im, method, speed)) {
RETURN_TRUE;
} else {
php_error_docref(NULL, E_WARNING, "Couldn't set quantization method");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question you know better gd than I do, seems to me the only failure case left is when the method is not available correct ? so always will be unavailable then. dunno if we should raise an exception and this call only returns true.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I agree, but we should add info about the available quantization methods first.

RETURN_FALSE;
}
}

PHP_FUNCTION(imagetruecolortopalettesetquality)
{
zval *IM;
zend_long min_quality;
zend_long max_quality;
gdImagePtr im;

ZEND_PARSE_PARAMETERS_START(3, 3)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(min_quality)
Z_PARAM_LONG(max_quality)
ZEND_PARSE_PARAMETERS_END();

im = php_gd_libgdimageptr_from_zval_p(IM);

if (min_quality < 1 || min_quality > 100) {
zend_argument_value_error(2, "must be between 1 and 100");
RETURN_THROWS();
}

if (max_quality < 1 || max_quality > 100) {
zend_argument_value_error(3, "must be between 1 and 100");
RETURN_THROWS();
}

gdImageTrueColorToPaletteSetQuality (im, min_quality, max_quality);
}

/* {{{ Set line thickness for drawing lines, ellipses, rectangles, polygons etc. */
PHP_FUNCTION(imagesetthickness)
{
Expand Down
28 changes: 28 additions & 0 deletions ext/gd/gd.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,30 @@
const IMG_EFFECT_MULTIPLY = UNKNOWN;
#endif

/**
* @var int
* @cvalue GD_QUANT_DEFAULT
*/
const IMG_QUANT_DEFAULT = UNKNOWN;

/**
* @var int
* @cvalue GD_QUANT_JQUANT
*/
const IMG_QUANT_JQUANT = UNKNOWN;

/**
* @var int
* @cvalue GD_QUANT_NEUQUANT
*/
const IMG_QUANT_NEUQUANT = UNKNOWN;

/**
* @var int
* @cvalue GD_QUANT_LIQ
*/
const IMG_QUANT_LIQ = UNKNOWN;

/**
* @var int
* @cvalue GD_CROP_DEFAULT
Expand Down Expand Up @@ -498,6 +522,10 @@ function imagepalettetotruecolor(GdImage $image): bool {}

function imagecolormatch(GdImage $image1, GdImage $image2): bool {}

function imagetruecolortopalettesetmethod(GdImage $image, int $method, int $speed = 0): bool {}

function imagetruecolortopalettesetquality(GdImage $image, int $min_quality, int $max_quality): void {}

function imagesetthickness(GdImage $image, int $thickness): bool {}

function imagefilledellipse(GdImage $image, int $center_x, int $center_y, int $width, int $height, int $color): bool {}
Expand Down
22 changes: 21 additions & 1 deletion ext/gd/gd_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions ext/gd/libgd/gd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,11 @@ gdImagePtr gdImageClone (gdImagePtr src) {
dst->res_x = src->res_x;
dst->res_y = src->res_y;

dst->paletteQuantizationMethod = src->paletteQuantizationMethod;
dst->paletteQuantizationSpeed = src->paletteQuantizationSpeed;
dst->paletteQuantizationMinQuality = src->paletteQuantizationMinQuality;
dst->paletteQuantizationMaxQuality = src->paletteQuantizationMaxQuality;

dst->interpolation_id = src->interpolation_id;
dst->interpolation = src->interpolation;

Expand Down
59 changes: 59 additions & 0 deletions ext/gd/libgd/gd.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,33 @@ int gdAlphaBlend(int dest, int src);
int gdLayerOverlay(int dst, int src);
int gdLayerMultiply(int dest, int src);

/**
* Group: Color Quantization
*
* Enum: gdPaletteQuantizationMethod
*
* Constants:
* GD_QUANT_DEFAULT - GD_QUANT_LIQ if libimagequant is available,
* GD_QUANT_JQUANT otherwise.
* GD_QUANT_JQUANT - libjpeg's old median cut. Fast, but only uses 16-bit
* color.
* GD_QUANT_NEUQUANT - NeuQuant - approximation using Kohonen neural network.
* GD_QUANT_LIQ - A combination of algorithms used in libimagequant
* aiming for the highest quality at cost of speed.
*
* Note that GD_QUANT_JQUANT does not retain the alpha channel, and
* GD_QUANT_NEUQUANT does not support dithering.
*
* See also:
* - <gdImageTrueColorToPaletteSetMethod>
*/
enum gdPaletteQuantizationMethod {
GD_QUANT_DEFAULT = 0,
GD_QUANT_JQUANT = 1,
GD_QUANT_NEUQUANT = 2,
GD_QUANT_LIQ = 3
};

/**
* Group: Transform
*
Expand Down Expand Up @@ -241,6 +268,18 @@ typedef struct gdImageStruct {
int cy2;
unsigned int res_x;
unsigned int res_y;

/* Selects quantization method, see gdImageTrueColorToPaletteSetMethod() and gdPaletteQuantizationMethod enum. */
int paletteQuantizationMethod;
/* speed/quality trade-off. 1 = best quality, 10 = best speed. 0 = method-specific default.
Applicable to GD_QUANT_LIQ and GD_QUANT_NEUQUANT. */
int paletteQuantizationSpeed;
/* Image will remain true-color if conversion to palette cannot achieve given quality.
Value from 1 to 100, 1 = ugly, 100 = perfect. Applicable to GD_QUANT_LIQ.*/
int paletteQuantizationMinQuality;
/* Image will use minimum number of palette colors needed to achieve given quality. Must be higher than paletteQuantizationMinQuality
Value from 1 to 100, 1 = ugly, 100 = perfect. Applicable to GD_QUANT_LIQ.*/
int paletteQuantizationMaxQuality;
gdInterpolationMethod interpolation_id;
interpolation_method interpolation;
} gdImage;
Expand Down Expand Up @@ -575,6 +614,24 @@ int gdImagePaletteToTrueColor(gdImagePtr src);
and im2 is the palette version */
int gdImageColorMatch(gdImagePtr im1, gdImagePtr im2);

/* Selects quantization method used for subsequent gdImageTrueColorToPalette calls.
See gdPaletteQuantizationMethod enum (e.g. GD_QUANT_NEUQUANT, GD_QUANT_LIQ).
Speed is from 1 (highest quality) to 10 (fastest).
Speed 0 selects method-specific default (recommended).

Returns FALSE if the given method is invalid or not available.
*/
int gdImageTrueColorToPaletteSetMethod (gdImagePtr im, int method, int speed);

/*
Chooses quality range that subsequent call to gdImageTrueColorToPalette will aim for.
Min and max quality is in range 1-100 (1 = ugly, 100 = perfect). Max must be higher than min.
If palette cannot represent image with at least min_quality, then image will remain true-color.
If palette can represent image with quality better than max_quality, then lower number of colors will be used.
This function has effect only when GD_QUANT_LIQ method has been selected and the source image is true-color.
*/
void gdImageTrueColorToPaletteSetQuality (gdImagePtr im, int min_quality, int max_quality);

/* 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,
Expand Down Expand Up @@ -739,6 +796,8 @@ void gdImageAlphaBlending(gdImagePtr im, int alphaBlendingArg);
void gdImageAntialias(gdImagePtr im, int antialias);
void gdImageSaveAlpha(gdImagePtr im, int saveAlphaArg);

gdImagePtr gdImageNeuQuant(gdImagePtr im, const int max_color, int sample_factor);

enum gdPixelateMode {
GD_PIXELATE_UPPERLEFT,
GD_PIXELATE_AVERAGE
Expand Down
Loading
Loading