1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

ext/gd: de-factorize image output functions (#14523)

The image output functions imagegif/imagepng/imagewebp/imageavif/imagejpeg
were all calling the static function _php_image_output_ctx which was basically
a big switch statement between each image type which also have different
parameters.

The only identical part was the call to create_stream_context_from_zval that
is now merged with create_output_context.
This commit is contained in:
Giovanni Giacobbi
2024-06-13 10:46:47 +02:00
committed by GitHub
parent 1e7aac315e
commit 592d899462

View File

@@ -121,14 +121,10 @@ static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS);
static gdImagePtr _php_image_create_from_string(zend_string *Data, char *tn, gdImagePtr (*ioctx_func_p)(gdIOCtxPtr));
static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(FILE *), gdImagePtr (*ioctx_func_p)(gdIOCtxPtr));
static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn);
static gdIOCtx *create_stream_context_from_zval(zval *to_zval);
static gdIOCtx *create_stream_context(php_stream *stream, int close_stream);
static gdIOCtx *create_output_context(void);
static gdIOCtx *create_output_context(zval *to_zval, uint32_t arg_num);
static int _php_image_type(zend_string *data);
/* output streaming (formerly gd_ctx.c) */
static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn);
/*********************************************************
*
* GD Object Representation
@@ -1888,11 +1884,11 @@ PHP_FUNCTION(imagexbm)
ctx = create_stream_context(stream, 1);
} else {
ctx = create_output_context();
ctx = create_output_context(NULL, 0);
}
if (foreground_color_is_null) {
for (i=0; i < gdImageColorsTotal(im); i++) {
for (i = 0; i < gdImageColorsTotal(im); i++) {
if (!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) {
break;
}
@@ -1912,7 +1908,27 @@ PHP_FUNCTION(imagexbm)
/* {{{ Output GIF image to browser or file */
PHP_FUNCTION(imagegif)
{
_php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIF, "GIF");
zval *imgind;
gdImagePtr im;
gdIOCtx *ctx;
zval *to_zval = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!", &imgind, gd_image_ce, &to_zval) == FAILURE) {
RETURN_THROWS();
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
gdImageGifCtx(im, ctx);
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
@@ -1920,7 +1936,38 @@ PHP_FUNCTION(imagegif)
/* {{{ Output PNG image to browser or file */
PHP_FUNCTION(imagepng)
{
_php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_PNG, "PNG");
zval *imgind;
zend_long quality = -1, basefilter = -1;
gdImagePtr im;
gdIOCtx *ctx;
zval *to_zval = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &basefilter) == FAILURE) {
RETURN_THROWS();
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
if (quality < -1 || quality > 9) {
zend_argument_value_error(3, "must be between -1 and 9");
ctx->gd_free(ctx);
RETURN_THROWS();
}
#ifdef HAVE_GD_BUNDLED
gdImagePngCtxEx(im, ctx, (int) quality, (int) basefilter);
#else
gdImagePngCtxEx(im, ctx, (int) quality);
#endif
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
#endif /* HAVE_GD_PNG */
@@ -1929,7 +1976,34 @@ PHP_FUNCTION(imagepng)
/* {{{ Output WEBP image to browser or file */
PHP_FUNCTION(imagewebp)
{
_php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WEBP, "WEBP");
zval *imgind;
zend_long quality = -1;
gdImagePtr im;
gdIOCtx *ctx;
zval *to_zval = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!l", &imgind, gd_image_ce, &to_zval, &quality) == FAILURE) {
RETURN_THROWS();
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
if (quality < -1) {
zend_argument_value_error(3, "must be greater than or equal to -1");
ctx->gd_free(ctx);
RETURN_THROWS();
}
gdImageWebpCtx(im, ctx, (int) quality);
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
#endif /* HAVE_GD_WEBP */
@@ -1938,7 +2012,42 @@ PHP_FUNCTION(imagewebp)
/* {{{ Output AVIF image to browser or file */
PHP_FUNCTION(imageavif)
{
_php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_AVIF, "AVIF");
zval *imgind;
zend_long quality = -1, speed = -1;
gdImagePtr im;
gdIOCtx *ctx;
zval *to_zval = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &speed) == FAILURE) {
RETURN_THROWS();
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
if (quality < -1 || quality > 100) {
zend_argument_value_error(3, "must be between -1 and 100");
ctx->gd_free(ctx);
RETURN_THROWS();
}
if (speed < -1 || speed > 10) {
zend_argument_value_error(4, "must be between -1 and 10");
ctx->gd_free(ctx);
RETURN_THROWS();
} else if (speed == -1) {
speed = 6;
}
gdImageAvifCtx(im, ctx, (int) quality, (int) speed);
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
#endif /* HAVE_GD_AVIF */
@@ -1947,7 +2056,34 @@ PHP_FUNCTION(imageavif)
/* {{{ Output JPEG image to browser or file */
PHP_FUNCTION(imagejpeg)
{
_php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_JPG, "JPEG");
zval *imgind;
zend_long quality = -1;
gdImagePtr im;
gdIOCtx *ctx;
zval *to_zval = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!l", &imgind, gd_image_ce, &to_zval, &quality) == FAILURE) {
RETURN_THROWS();
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
if (quality < -1 || quality > 100) {
zend_argument_value_error(3, "must be at between -1 and 100");
ctx->gd_free(ctx);
RETURN_THROWS();
}
gdImageJpegCtx(im, ctx, (int) quality);
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
#endif /* HAVE_GD_JPG */
@@ -1960,7 +2096,7 @@ PHP_FUNCTION(imagewbmp)
bool foreground_color_is_null = true;
gdImagePtr im;
int i;
gdIOCtx *ctx = NULL;
gdIOCtx *ctx;
zval *to_zval = NULL;
ZEND_PARSE_PARAMETERS_START(1, 3)
@@ -1972,17 +2108,13 @@ PHP_FUNCTION(imagewbmp)
im = php_gd_libgdimageptr_from_zval_p(imgind);
if (to_zval != NULL) {
ctx = create_stream_context_from_zval(to_zval);
if (!ctx) {
RETURN_FALSE;
}
} else {
ctx = create_output_context();
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
if (foreground_color_is_null) {
for (i=0; i < gdImageColorsTotal(im); i++) {
for (i = 0; i < gdImageColorsTotal(im); i++) {
if (!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) {
break;
}
@@ -2020,7 +2152,7 @@ PHP_FUNCTION(imagebmp)
zval *imgind;
bool compressed = true;
gdImagePtr im;
gdIOCtx *ctx = NULL;
gdIOCtx *ctx;
zval *to_zval = NULL;
ZEND_PARSE_PARAMETERS_START(1, 3)
@@ -2032,13 +2164,9 @@ PHP_FUNCTION(imagebmp)
im = php_gd_libgdimageptr_from_zval_p(imgind);
if (to_zval != NULL) {
ctx = create_stream_context_from_zval(to_zval);
if (!ctx) {
RETURN_FALSE;
}
} else {
ctx = create_output_context();
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
gdImageBmpCtx(im, ctx, (int) compressed);
@@ -4230,34 +4358,6 @@ static void _php_image_stream_ctxfreeandclose(struct gdIOCtx *ctx) /* {{{ */
efree(ctx);
} /* }}} */
static gdIOCtx *create_stream_context_from_zval(zval *to_zval) {
php_stream *stream;
int close_stream = 1;
if (Z_TYPE_P(to_zval) == IS_RESOURCE) {
php_stream_from_zval_no_verify(stream, to_zval);
if (stream == NULL) {
return NULL;
}
close_stream = 0;
} else if (Z_TYPE_P(to_zval) == IS_STRING) {
if (CHECK_ZVAL_NULL_PATH(to_zval)) {
zend_argument_type_error(2, "must not contain null bytes");
return NULL;
}
stream = php_stream_open_wrapper(Z_STRVAL_P(to_zval), "wb", REPORT_ERRORS|IGNORE_PATH, NULL);
if (stream == NULL) {
return NULL;
}
} else {
zend_argument_type_error(2, "must be a file name or a stream resource, %s given", zend_zval_value_name(to_zval));
return NULL;
}
return create_stream_context(stream, close_stream);
}
static gdIOCtx *create_stream_context(php_stream *stream, int close_stream) {
gdIOCtx *ctx = ecalloc(1, sizeof(gdIOCtx));
@@ -4273,114 +4373,46 @@ static gdIOCtx *create_stream_context(php_stream *stream, int close_stream) {
return ctx;
}
static gdIOCtx *create_output_context(void) {
gdIOCtx *ctx = ecalloc(1, sizeof(gdIOCtx));
static gdIOCtx *create_output_context(zval *to_zval, uint32_t arg_num) {
gdIOCtx *ctx;
ctx->putC = _php_image_output_putc;
ctx->putBuf = _php_image_output_putbuf;
ctx->gd_free = _php_image_output_ctxfree;
if (to_zval != NULL) {
php_stream *stream;
int close_stream = 1;
ZEND_ASSERT(arg_num > 0);
if (Z_TYPE_P(to_zval) == IS_RESOURCE) {
php_stream_from_zval_no_verify(stream, to_zval);
if (stream == NULL) {
return NULL;
}
close_stream = 0;
} else if (Z_TYPE_P(to_zval) == IS_STRING) {
if (CHECK_ZVAL_NULL_PATH(to_zval)) {
zend_argument_type_error(arg_num, "must not contain null bytes");
return NULL;
}
stream = php_stream_open_wrapper(Z_STRVAL_P(to_zval), "wb", REPORT_ERRORS|IGNORE_PATH, NULL);
if (stream == NULL) {
return NULL;
}
} else {
zend_argument_type_error(arg_num, "must be a file name or a stream resource, %s given", zend_zval_value_name(to_zval));
return NULL;
}
ctx = create_stream_context(stream, close_stream);
} else {
ctx = ecalloc(1, sizeof(gdIOCtx));
ctx->putC = _php_image_output_putc;
ctx->putBuf = _php_image_output_putbuf;
ctx->gd_free = _php_image_output_ctxfree;
}
return ctx;
}
static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn)
{
zval *imgind;
zend_long quality = -1, basefilter = -1, speed = -1;
gdImagePtr im;
gdIOCtx *ctx = NULL;
zval *to_zval = NULL;
if (image_type == PHP_GDIMG_TYPE_GIF) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!", &imgind, gd_image_ce, &to_zval) == FAILURE) {
RETURN_THROWS();
}
} else if (image_type == PHP_GDIMG_TYPE_PNG) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &basefilter) == FAILURE) {
RETURN_THROWS();
}
} else if (image_type == PHP_GDIMG_TYPE_AVIF) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &speed) == FAILURE) {
RETURN_THROWS();
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!l", &imgind, gd_image_ce, &to_zval, &quality) == FAILURE) {
RETURN_THROWS();
}
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
if (to_zval != NULL) {
ctx = create_stream_context_from_zval(to_zval);
if (!ctx) {
RETURN_FALSE;
}
} else {
ctx = create_output_context();
}
switch (image_type) {
#ifdef HAVE_GD_JPG
case PHP_GDIMG_TYPE_JPG:
if (quality < -1 || quality > 100) {
zend_argument_value_error(3, "must be at between -1 and 100");
ctx->gd_free(ctx);
RETURN_THROWS();
}
gdImageJpegCtx(im, ctx, (int) quality);
break;
#endif
#ifdef HAVE_GD_WEBP
case PHP_GDIMG_TYPE_WEBP:
if (quality < -1) {
zend_argument_value_error(3, "must be greater than or equal to -1");
ctx->gd_free(ctx);
RETURN_THROWS();
}
gdImageWebpCtx(im, ctx, (int) quality);
break;
#endif
#ifdef HAVE_GD_AVIF
case PHP_GDIMG_TYPE_AVIF:
if (quality < -1 || quality > 100) {
zend_argument_value_error(3, "must be between -1 and 100");
ctx->gd_free(ctx);
RETURN_THROWS();
}
if (speed < -1 || speed > 10) {
zend_argument_value_error(4, "must be between -1 and 10");
ctx->gd_free(ctx);
RETURN_THROWS();
} else if (speed == -1) {
speed = 6;
}
gdImageAvifCtx(im, ctx, (int) quality, (int) speed);
break;
#endif
#ifdef HAVE_GD_PNG
case PHP_GDIMG_TYPE_PNG:
if (quality < -1 || quality > 9) {
zend_argument_value_error(3, "must be between -1 and 9");
ctx->gd_free(ctx);
RETURN_THROWS();
}
#ifdef HAVE_GD_BUNDLED
gdImagePngCtxEx(im, ctx, (int) quality, (int) basefilter);
#else
gdImagePngCtxEx(im, ctx, (int) quality);
#endif
break;
#endif
case PHP_GDIMG_TYPE_GIF:
gdImageGifCtx(im, ctx);
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */