Skip to content

Commit

Permalink
ext/gd: bug #80828 HEIF support.
Browse files Browse the repository at this point in the history
  • Loading branch information
devnexen committed Jun 8, 2024
1 parent 5a03ff4 commit c50263f
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 4 deletions.
1 change: 1 addition & 0 deletions ext/gd/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ AC_DEFUN([PHP_GD_CHECK_VERSION],[
PHP_GD_CHECK_FORMAT([Xpm], [HAVE_GD_XPM])
PHP_GD_CHECK_FORMAT([Bmp], [HAVE_GD_BMP])
PHP_GD_CHECK_FORMAT([Tga], [HAVE_GD_TGA])
PHP_GD_CHECK_FORMAT([Heif], [HAVE_GD_HEIF])
PHP_CHECK_LIBRARY(gd, gdFontCacheShutdown, [AC_DEFINE(HAVE_GD_FREETYPE, 1, [ ])], [], [ $GD_SHARED_LIBADD ])
PHP_CHECK_LIBRARY(gd, gdVersionString, [AC_DEFINE(HAVE_GD_LIBVERSION, 1, [ ])], [], [ $GD_SHARED_LIBADD ])
PHP_CHECK_LIBRARY(gd, gdImageGetInterpolationMethod, [AC_DEFINE(HAVE_GD_GET_INTERPOLATION, 1, [ ])], [], [ $GD_SHARED_LIBADD ])
Expand Down
72 changes: 70 additions & 2 deletions ext/gd/gd.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,9 @@ PHP_MINFO_FUNCTION(gd)
#endif
#ifdef HAVE_GD_TGA
php_info_print_table_row(2, "TGA Read Support", "enabled");
#endif
#ifdef HAVE_GD_HEIF
php_info_print_table_row(2, "HEIF Support", "enabled");
#endif
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
Expand Down Expand Up @@ -520,6 +523,11 @@ PHP_FUNCTION(gd_info)
#else
add_assoc_bool(return_value, "TGA Read Support", 0);
#endif
#ifdef HAVE_GD_HEIF
add_assoc_bool(return_value, "HEIF Support", 1);
#else
add_assoc_bool(return_value, "HEIF Support", 0);
#endif
#ifdef USE_GD_JISX0208
add_assoc_bool(return_value, "JIS-mapped Japanese Font Support", 1);
#else
Expand Down Expand Up @@ -1300,6 +1308,9 @@ PHP_FUNCTION(imagetypes)
#ifdef HAVE_GD_AVIF
ret |= PHP_IMG_AVIF;
#endif
#ifdef HAVE_GD_HEIF
ret |= PHP_IMG_HEIF;
#endif

if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
Expand Down Expand Up @@ -1351,6 +1362,11 @@ static int _php_image_type(zend_string *data)
return PHP_GDIMG_TYPE_BMP;
} else if(!memcmp(ZSTR_VAL(data), php_sig_riff, sizeof(php_sig_riff)) && !memcmp(ZSTR_VAL(data) + sizeof(php_sig_riff) + sizeof(uint32_t), php_sig_webp, sizeof(php_sig_webp))) {
return PHP_GDIMG_TYPE_WEBP;
} else if (!memcmp(ZSTR_VAL(data), php_sig_heifheic, sizeof(php_sig_heifheic)) ||
!memcmp(ZSTR_VAL(data), php_sig_heifheix, sizeof(php_sig_heifheix)) ||
!memcmp(ZSTR_VAL(data), php_sig_heifmif1, sizeof(php_sig_heifmif1)) ||
!memcmp(ZSTR_VAL(data), php_sig_heifmsf1, sizeof(php_sig_heifmsf1))) {
return PHP_GDIMG_TYPE_HEIF;
}

php_stream *image_stream = php_stream_memory_open(TEMP_STREAM_READONLY, data);
Expand Down Expand Up @@ -1469,7 +1485,13 @@ PHP_FUNCTION(imagecreatefromstring)
php_error_docref(NULL, E_WARNING, "No AVIF support in this PHP build");
RETURN_FALSE;
#endif

#ifdef HAVE_GD_HEIF
im = _php_image_create_from_string(data, "HEIF", gdImageCreateFromHeifCtx);
break;
#else
php_error_docref(NULL, E_WARNING, "No HEIF support in this PHP build");
RETURN_FALSE;
#endif
default:
php_error_docref(NULL, E_WARNING, "Data is not in a recognized format");
RETURN_FALSE;
Expand Down Expand Up @@ -1674,6 +1696,12 @@ PHP_FUNCTION(imagecreatefromwbmp)
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WBM, "WBMP", gdImageCreateFromWBMP, gdImageCreateFromWBMPCtx);
}
/* }}} */
#ifdef HAVE_GD_HEIF
PHP_FUNCTION(imagecreatefromheif)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_HEIF, "HEIF", gdImageCreateFromHeif, gdImageCreateFromHeifCtx);
}
#endif

/* {{{ Create a new image from GD file or URL */
PHP_FUNCTION(imagecreatefromgd)
Expand Down Expand Up @@ -1900,6 +1928,12 @@ PHP_FUNCTION(imagejpeg)
}
/* }}} */
#endif /* HAVE_GD_JPG */
#ifdef HAVE_GD_HEIF
PHP_FUNCTION(imageheif)
{
_php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_HEIF, "HEIF");
}
#endif

/* {{{ Output WBMP image to browser or file */
PHP_FUNCTION(imagewbmp)
Expand Down Expand Up @@ -4071,10 +4105,12 @@ static gdIOCtx *create_output_context(void) {
static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn)
{
zval *imgind;
zend_long quality = -1, basefilter = -1, speed = -1;
zend_long quality = -1, basefilter = -1, speed = -1, codec = (zend_long)GD_HEIF_CODEC_HEVC;
gdImagePtr im;
gdIOCtx *ctx = NULL;
zval *to_zval = NULL;
char *chroma = NULL;
size_t chroma_len;

if (image_type == PHP_GDIMG_TYPE_GIF) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!", &imgind, gd_image_ce, &to_zval) == FAILURE) {
Expand All @@ -4088,6 +4124,10 @@ static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type,
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &speed) == FAILURE) {
RETURN_THROWS();
}
} else if (image_type == PHP_GDIMG_TYPE_HEIF) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!lls", &imgind, gd_image_ce, &to_zval, &quality, &codec, &chroma, &chroma_len) == FAILURE) {
RETURN_THROWS();
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!l", &imgind, gd_image_ce, &to_zval, &quality) == FAILURE) {
RETURN_THROWS();
Expand Down Expand Up @@ -4143,6 +4183,34 @@ static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type,
gdImageAvifCtx(im, ctx, (int) quality, (int) speed);
break;
#endif
#ifdef HAVE_GD_HEIF
case PHP_GDIMG_TYPE_HEIF:
if (quality < -1) {
zend_argument_value_error(3, "must be greater than or equal to -1");
ctx->gd_free(ctx);
RETURN_THROWS();
}
if (codec < GD_HEIF_CODEC_HEVC || codec > GD_HEIF_CODEC_AV1) {
zend_argument_value_error(4, "must be between HEIF_CODEC_HEVC or HEIF_CODEC_AV1");
ctx->gd_free(ctx);
RETURN_THROWS();
}
if (chroma == NULL) {
chroma = GD_HEIF_CHROMA_420;
chroma_len = strlen(chroma);
}
if (chroma_len != 3 ||
(strcmp(chroma, GD_HEIF_CHROMA_420) &&
strcmp(chroma, GD_HEIF_CHROMA_422) &&
strcmp(chroma, GD_HEIF_CHROMA_444))) {
zend_argument_value_error(5, "must be between HEIF_CHROMA_420, HEIF_CHROMA_422 or HEIF_CHROMA_444");
ctx->gd_free(ctx);
RETURN_THROWS();
}

gdImageHeifCtx(im, ctx, (int) quality, (gdHeifCodec)codec, chroma);
break;
#endif
#ifdef HAVE_GD_PNG
case PHP_GDIMG_TYPE_PNG:
if (quality < -1 || quality > 9) {
Expand Down
48 changes: 48 additions & 0 deletions ext/gd/gd.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@
*/
const IMG_TGA = UNKNOWN;

/**
* @var int
* @cvalue PHP_IMG_HEIF
*/
const IMG_HEIF = UNKNOWN;
/* constant for webp encoding */

#ifdef gdWebpLossless
Expand Down Expand Up @@ -412,6 +417,39 @@
*/
const IMG_FILTER_SCATTER = UNKNOWN;

#ifdef HAVE_GD_HEIF
/**
* @var string
* @cvalue GD_HEIF_CHROMA_420
*/
const HEIF_CHROMA_420 = UNKNOWN;
/**
* @var string
* @cvalue GD_HEIF_CHROMA_422
*/
const HEIF_CHROMA_422 = UNKNOWN;
/**
* @var string
* @cvalue GD_HEIF_CHROMA_444
*/
const HEIF_CHROMA_444 = UNKNOWN;
/**
* @var int
* @cvalue GD_HEIF_CODEC_UNKNOWN
*/
const HEIF_CODEC_UNKNOWN = UNKNOWN;
/**
* @var int
* @cvalue GD_HEIF_CODEC_HEVC
*/
const HEIF_CODEC_HEVC = UNKNOWN;
/**
* @var int
* @cvalue GD_HEIF_CODEC_AV1
*/
const HEIF_CODEC_AV1 = UNKNOWN;
#endif

#ifdef GD_VERSION_STRING
/**
* @var string
Expand Down Expand Up @@ -569,6 +607,11 @@ function imagecreatefrompng(string $filename): GdImage|false {}
function imagecreatefromwebp(string $filename): GdImage|false {}
#endif

#ifdef HAVE_GD_HEIF
/** @refcount 1 */
function imagecreatefromheif(string $filename): GdImage|false {}
#endif

/** @refcount 1 */
function imagecreatefromxbm(string $filename): GdImage|false {}

Expand Down Expand Up @@ -626,6 +669,11 @@ function imagejpeg(GdImage $image, $file = null, int $quality = -1): bool {}
/** @param resource|string|null $file */
function imagewbmp(GdImage $image, $file = null, ?int $foreground_color = null): bool {}

#ifdef HAVE_GD_HEIF
/** @param resource|string|null $file */
function imageheif(GdImage $image, $file = null, int $quality = -1, int $codec = HEIF_CODEC_HEVC, ?string $chroma = null): bool {}
#endif

function imagegd(GdImage $image, ?string $file = null): bool {}

function imagegd2(GdImage $image, ?string $file = null, int $chunk_size = 128, int $mode = IMG_GD2_RAW): bool {}
Expand Down
49 changes: 48 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.

6 changes: 6 additions & 0 deletions ext/gd/php_gd.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#define PHP_GDIMG_TYPE_BMP 12
#define PHP_GDIMG_TYPE_TGA 13
#define PHP_GDIMG_TYPE_AVIF 14
#define PHP_GDIMG_TYPE_HEIF 15

#define PHP_IMG_GIF 1
#define PHP_IMG_JPG 2
Expand All @@ -54,6 +55,7 @@
#define PHP_IMG_BMP 64
#define PHP_IMG_TGA 128
#define PHP_IMG_AVIF 256
#define PHP_IMG_HEIF 384

/* Section Filters Declarations */
/* IMPORTANT NOTE FOR NEW FILTER
Expand Down Expand Up @@ -103,6 +105,10 @@ PHPAPI extern const char php_sig_bmp[2];
PHPAPI extern const char php_sig_riff[4];
PHPAPI extern const char php_sig_webp[4];
PHPAPI extern const char php_sig_avif[4];
PHPAPI extern const char php_sig_heifheic[12];
PHPAPI extern const char php_sig_heifheix[12];
PHPAPI extern const char php_sig_heifmif1[12];
PHPAPI extern const char php_sig_heifmsf1[12];

extern zend_module_entry gd_module_entry;
#define phpext_gd_ptr &gd_module_entry
Expand Down
28 changes: 28 additions & 0 deletions ext/gd/tests/imageheif.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
heif support
--EXTENSIONS--
gd
--SKIPIF--
<?php
if (!function_exists("imagecreatefromheif") || !function_exists("imageheif")) {
die("skip HEIF support unavailable");
}
?>
--FILE--
<?php

require_once __DIR__ . '/similarity.inc';

$infile = __DIR__ . '/imageheif_basic.heif';
$outfile = __DIR__ . '/imageheif_out.heif';

$img = imagecreatefromheif($infile);
var_dump($img);
var_dump(imageheif($img, $outfile));
unlink($outfile);
?>

--EXPECT--
object(GdImage)#1 (0) {
}
bool(true)
Binary file added ext/gd/tests/imageheif_basic.heif
Binary file not shown.
Loading

0 comments on commit c50263f

Please sign in to comment.