summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Reboredo <39890836+YakoYakoYokuYoku@users.noreply.github.com>2021-03-02 14:32:03 -0300
committerGitHub <noreply@github.com>2021-03-02 12:32:03 -0500
commit39c4644fa01f6b9f002119e4109e252bc665b8f1 (patch)
tree852d151b50717219ebff215b4b6f65a945ebf9f3
parentd6a061850d40110a98364766f654030f929ec0ed (diff)
downloadlibgd-39c4644fa01f6b9f002119e4109e252bc665b8f1.tar.gz
HEIF support through libheif (#670)
With the adoption of AVIF by Firefox and Chromium based browsers (still in experimental phase), the newer incorporation of HEIF by Canon and Sony in their cameras and the newer support of both of them in modern software like ImageMagick, GIMP and Krita, `gd` haven't seen any endorsement for the formats up until this PR. Reading and writing is done by `libheif`, with functionality for chroma subsampling (for now `4:2:0`, `4:2:2` and `4:4:4`), quality (with new `200` for lossless) and compression (whether `HEVC` or `AV1`) selection. This was tested with `libheif` version `1.11.0` in my Solus machine. Also, fixes both #395 and #557.
-rw-r--r--CMakeLists.txt10
-rw-r--r--CONTRIBUTORS1
-rw-r--r--README.md2
-rw-r--r--cmake/modules/FindHEIF.cmake82
-rw-r--r--configure.ac9
-rw-r--r--docs/naturaldocs/project/Menu.txt1
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/Makefile.am1
-rw-r--r--src/config.h.cmake3
-rw-r--r--src/gd.h50
-rw-r--r--src/gd_filename.c7
-rw-r--r--src/gd_heif.c582
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/heif/CMakeLists.txt11
-rw-r--r--tests/heif/Makemodule.am11
-rw-r--r--tests/heif/avif_ptr_double_free.c31
-rw-r--r--tests/heif/heif_im2im.c49
-rw-r--r--tests/heif/heif_null.c20
-rw-r--r--tests/heif/heif_ptr_double_free.c31
-rw-r--r--tests/heif/heif_read.c23
-rw-r--r--tests/heif/label.avifbin0 -> 602 bytes
-rw-r--r--tests/heif/label.heicbin0 -> 1170 bytes
-rwxr-xr-xtests/source/run.sh2
-rw-r--r--windows/Makefile.vc7
-rw-r--r--windows/msys/Makefile2
26 files changed, 937 insertions, 3 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bf7836f..b13767d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,7 @@ OPTION(ENABLE_XPM "Enable XPM support" 0)
OPTION(ENABLE_FREETYPE "Enable Freetype2 support" 0)
OPTION(ENABLE_FONTCONFIG "Enable FontConfig support" 0)
OPTION(ENABLE_WEBP "Enable WebP support" 0)
+OPTION(ENABLE_HEIF "Enable HEIF support" 0)
OPTION(ENABLE_RAQM "Enable RAQM support" 0)
if (BUILD_TEST)
@@ -119,6 +120,10 @@ else (USE_EXT_GD)
FIND_PACKAGE(WEBP REQUIRED)
ENDIF (ENABLE_WEBP)
+ IF (ENABLE_HEIF)
+ FIND_PACKAGE(HEIF REQUIRED)
+ ENDIF (ENABLE_HEIF)
+
IF (ENABLE_LIQ)
FIND_PACKAGE(LIQ REQUIRED)
ENDIF (ENABLE_LIQ)
@@ -171,6 +176,11 @@ else (USE_EXT_GD)
SET(HAVE_LIBWEBP 1)
ENDIF(WEBP_FOUND)
+ IF(HEIF_FOUND)
+ INCLUDE_DIRECTORIES(${HEIF_INCLUDE_DIR})
+ SET(HAVE_LIBHEIF 1)
+ ENDIF(HEIF_FOUND)
+
IF(PNG_FOUND)
INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR})
SET(HAVE_LIBPNG 1)
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 8cf0bdd..55f386f 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -11,6 +11,7 @@ Kornel LesiƄski
kshepherd
lhecking
Marcin Wojdyr
+Martin Reboredo (YakoYakoYokuYoku)
mattias
Mike Frysinger
Mateusz Loskot (mloskot)
diff --git a/README.md b/README.md
index 44e7cdd..96268ea 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,8 @@ GD has builtin support for:
It also has optional support for more formats via external libraries:
+* [HEIF](https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format) via [libheif](https://github.com/strukturag/libheif/)
+ * Also it includes [AVIF](https://en.wikipedia.org/wiki/AV1#AV1_Image_File_Format_%28AVIF%29) read support if your system's `libheif` has AV1 decoding.
* [JPEG](https://en.wikipedia.org/wiki/JPEG) via [IJG/libjpeg](http://www.ijg.org/) or [libjpeg-turbo](http://libjpeg-turbo.virtualgl.org/)
* Does not include [JPEG 2000](https://en.wikipedia.org/wiki/JPEG_2000)
* [PNG](https://en.wikipedia.org/wiki/Portable_Network_Graphics) via [libpng](http://www.libpng.org/)
diff --git a/cmake/modules/FindHEIF.cmake b/cmake/modules/FindHEIF.cmake
new file mode 100644
index 0000000..adc5cce
--- /dev/null
+++ b/cmake/modules/FindHEIF.cmake
@@ -0,0 +1,82 @@
+# - Find the native HEIF includes and library
+#
+
+# This module defines
+# HEIF_INCLUDE_DIR, where to find heif.h, etc.
+# HEIF_LIBRARIES, the libraries to link against to use HEIF.
+# HEIF_FOUND, If false, do not try to use HEIF.
+# Also defined, but not for general use are
+# HEIF_LIBRARY, where to find the HEIF library.
+
+# Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * The names of Kitware, Inc., the Insight Consortium, or the names of
+# any consortium members, or of any contributors, may not be used to
+# endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+SET(HEIF_FOUND "NO")
+
+# use pkg-config to get the directories and then use these values
+# in the FIND_PATH() and FIND_LIBRARY() calls
+if( NOT WIN32 )
+ find_package(PkgConfig)
+
+ pkg_check_modules(HEIF_PKG QUIET fontconfig)
+endif( NOT WIN32 )
+
+FIND_PATH(HEIF_INCLUDE_DIR NAMES libheif/heif.h
+ PATHS
+ /usr/local/include
+ /usr/include
+ HINTS
+ ${HEIF_PKG_INCLUDE_DIRS} # Generated by pkg-config
+)
+
+SET(HEIF_NAMES ${HEIF_NAMES} heif ${HEIF_PKG_LIBRARY})
+FIND_LIBRARY(HEIF_LIBRARY
+ NAMES ${HEIF_NAMES}
+ PATH /usr/local/lib /usr/lib
+ PATH_SUFFIXES lib64 lib
+ HINTS ${HEIF_PKG_LIBRARY_DIRS} # Generated by pkg-config
+)
+
+IF (HEIF_LIBRARY AND HEIF_INCLUDE_DIR)
+ SET(HEIF_FOUND "YES")
+ SET(HAVE_LIBHEIF 1)
+ SET(HEIF_LIBRARIES ${HEIF_LIBRARY})
+ENDIF (HEIF_LIBRARY AND HEIF_INCLUDE_DIR)
+
+IF (HEIF_FOUND)
+ IF (NOT HEIF_FIND_QUIETLY)
+ MESSAGE(STATUS "Find HEIF: ${HEIF_LIBRARY}")
+ ENDIF (NOT HEIF_FIND_QUIETLY)
+ELSE (HEIF_FOUND)
+ IF (HEIF_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find HEIF library")
+ ENDIF (HEIF_FIND_REQUIRED)
+ENDIF (HEIF_FOUND)
+
+MARK_AS_ADVANCED(HEIF_INCLUDE_DIR HEIF_LIBRARY)
diff --git a/configure.ac b/configure.ac
index a2b6f18..5a4c357 100644
--- a/configure.ac
+++ b/configure.ac
@@ -285,6 +285,14 @@ GD_LIB_PKG_CHECK([LIBWEBP], [WEBP], [webp], [libwebp], [
])
])
+dnl Check for heif support.
+GD_LIB_PKG_CHECK([LIBHEIF], [HEIF], [heif], [libheif >= 1.7.0], [
+ AC_CHECK_LIB([heif], [heif_get_version], [dnl
+ AS_VAR_APPEND([LIBHEIF_LIBS], [" -lheif"])
+ gd_found_lib=yes
+ ])
+])
+
gl_VISIBILITY()
CFLAGS="$CFLAGS $CFLAG_VISIBILITY"
@@ -314,6 +322,7 @@ AC_MSG_RESULT([
Support for PNG library: $gd_with_LIBPNG
Support for JPEG library: $gd_with_LIBJPEG
Support for WebP library: $gd_with_LIBWEBP
+ Support for HEIF library: $gd_with_LIBHEIF
Support for TIFF library: $gd_with_LIBTIFF
Support for Freetype 2.x library: $gd_with_LIBFREETYPE
Support for Fontconfig library: $gd_with_LIBFONTCONFIG
diff --git a/docs/naturaldocs/project/Menu.txt b/docs/naturaldocs/project/Menu.txt
index 2ce9748..250d988 100644
--- a/docs/naturaldocs/project/Menu.txt
+++ b/docs/naturaldocs/project/Menu.txt
@@ -55,6 +55,7 @@ Group: Image Formats {
File: GD2 IO (no auto-title, gd_gd2.c)
File: GIF Input (no auto-title, gd_gif_in.c)
File: GIF Output (no auto-title, gd_gif_out.c)
+ File: HEIF IO (no auto-title, gd_heif.c)
File: JPEG IO (no auto-title, gd_jpeg.c)
File: PNG IO (no auto-title, gd_png.c)
File: TGA Input (no auto-title, gd_tga.c)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6bc2e4e..ccd76e9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -15,6 +15,7 @@ SET (LIBGD_SRC_FILES
gd_gd2.c
gd_gif_in.c
gd_gif_out.c
+ gd_heif.c
gd_intern.h
gd_interpolation.c
gd_io.c
@@ -130,6 +131,7 @@ SET(LIBGD_DEP_LIBS
${FONTCONFIG_LIBRARY}
${WEBP_LIBRARIES}
${RAQM_LIBRARIES}
+ ${HEIF_LIBRARIES}
)
if (BUILD_SHARED_LIBS)
target_link_libraries(${GD_LIB} ${LIBGD_DEP_LIBS})
diff --git a/src/Makefile.am b/src/Makefile.am
index 38322ae..69a5c18 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -73,6 +73,7 @@ libgd_la_SOURCES = \
gd_gd2.c \
gd_gif_in.c \
gd_gif_out.c \
+ gd_heif.c \
gd_intern.h \
gd_interpolation.c \
gd_io.c \
diff --git a/src/config.h.cmake b/src/config.h.cmake
index 06408c1..fb86f3c 100644
--- a/src/config.h.cmake
+++ b/src/config.h.cmake
@@ -54,6 +54,9 @@
/* Define if you have webp */
#cmakedefine HAVE_LIBWEBP
+/* Define if you have heif */
+#cmakedefine HAVE_LIBHEIF
+
/* Define if you have xpm */
#cmakedefine HAVE_LIBXPM
diff --git a/src/gd.h b/src/gd.h
index 4c43106..55fa5b3 100644
--- a/src/gd.h
+++ b/src/gd.h
@@ -330,6 +330,46 @@ typedef enum {
GD_METHOD_COUNT = 23
} gdInterpolationMethod;
+/**
+ * Group: HEIF Coding Format
+ *
+ * Values that select the HEIF coding format.
+ *
+ * Constants: gdHeifCodec
+ *
+ * GD_HEIF_CODEC_UNKNOWN
+ * GD_HEIF_CODEC_HEVC
+ * GD_HEIF_CODEC_AV1
+ *
+ * See also:
+ * - <gdImageHeif>
+ */
+typedef enum {
+ GD_HEIF_CODEC_UNKNOWN = 0,
+ GD_HEIF_CODEC_HEVC,
+ GD_HEIF_CODEC_AV1 = 4,
+} gdHeifCodec;
+
+/**
+ * Group: HEIF Chroma Subsampling
+ *
+ * Values that select the HEIF chroma subsampling.
+ *
+ * Constants: gdHeifCompression
+ *
+ * GD_HEIF_CHROMA_420
+ * GD_HEIF_CHROMA_422
+ * GD_HEIF_CHROMA_444
+ *
+ * See also:
+ * - <gdImageHeif>
+ */
+typedef const char *gdHeifChroma;
+
+#define GD_HEIF_CHROMA_420 "420"
+#define GD_HEIF_CHROMA_422 "422"
+#define GD_HEIF_CHROMA_444 "444"
+
/* define struct with name and func ptr and add it to gdImageStruct gdInterpolationMethod interpolation; */
/* Interpolation function ptr */
@@ -624,6 +664,10 @@ BGD_DECLARE(gdImagePtr) gdImageCreateFromWebp (FILE * inFile);
BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpPtr (int size, void *data);
BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpCtx (gdIOCtx * infile);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromHeif(FILE *inFile);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromHeifPtr(int size, void *data);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromHeifCtx(gdIOCtx *infile);
+
BGD_DECLARE(gdImagePtr) gdImageCreateFromTiff(FILE *inFile);
BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffCtx(gdIOCtx *infile);
BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffPtr(int size, void *data);
@@ -1081,6 +1125,12 @@ BGD_DECLARE(void *) gdImageWebpPtr (gdImagePtr im, int *size);
BGD_DECLARE(void *) gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization);
BGD_DECLARE(void) gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization);
+BGD_DECLARE(void) gdImageHeifEx(gdImagePtr im, FILE *outFile, int quality, gdHeifCodec codec, gdHeifChroma chroma);
+BGD_DECLARE(void) gdImageHeif(gdImagePtr im, FILE *outFile);
+BGD_DECLARE(void *) gdImageHeifPtr(gdImagePtr im, int *size);
+BGD_DECLARE(void *) gdImageHeifPtrEx(gdImagePtr im, int *size, int quality, gdHeifCodec codec, gdHeifChroma chroma);
+BGD_DECLARE(void) gdImageHeifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, gdHeifCodec codec, gdHeifChroma chroma);
+
/**
* Group: GifAnim
diff --git a/src/gd_filename.c b/src/gd_filename.c
index 077f870..6b67c3a 100644
--- a/src/gd_filename.c
+++ b/src/gd_filename.c
@@ -60,6 +60,11 @@ static const struct FileType {
{".jpeg", gdImageCreateFromJpeg, writejpeg, NULL},
#endif
+#ifdef HAVE_LIBHEIF
+ {".heic", gdImageCreateFromHeif, gdImageHeif, NULL},
+ {".heix", gdImageCreateFromHeif, NULL, NULL},
+#endif
+
#ifdef HAVE_LIBTIFF
{".tiff", gdImageCreateFromTiff, gdImageTiff, NULL},
{".tif" , gdImageCreateFromTiff, gdImageTiff, NULL},
@@ -128,6 +133,8 @@ ftype(const char *filename) {
- .tga
- .png
- .jpg, .jpeg
+ - .heif, .heix
+ - .avif
- .tiff, .tif
- .webp
- .xpm
diff --git a/src/gd_heif.c b/src/gd_heif.c
new file mode 100644
index 0000000..3b00a6c
--- /dev/null
+++ b/src/gd_heif.c
@@ -0,0 +1,582 @@
+/**
+ * File: HEIF IO
+ *
+ * Read and write HEIF images.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "gd.h"
+#include "gd_errors.h"
+#include "gdhelpers.h"
+
+#ifdef HAVE_LIBHEIF
+#include <libheif/heif.h>
+
+#define GD_HEIF_ALLOC_STEP (4*1024)
+#define GD_HEIF_HEADER 12
+
+typedef enum gd_heif_brand {
+ GD_HEIF_BRAND_AVIF = 1,
+ GD_HEIF_BRAND_MIF1 = 2,
+ GD_HEIF_BRAND_HEIC = 4,
+ GD_HEIF_BRAND_HEIX = 8,
+} gd_heif_brand;
+
+/*
+ Function: gdImageCreateFromHeif
+
+ <gdImageCreateFromHeif> is called to load truecolor images from
+ HEIF format files. Invoke <gdImageCreateFromHeif> with an
+ already opened pointer to a file containing the desired
+ image. <gdImageCreateFromHeif> returns a <gdImagePtr> to the new
+ truecolor image, or NULL if unable to load the image (most often
+ because the file is corrupt or does not contain a HEIF
+ image). <gdImageCreateFromHeif> does not close the file.
+
+ You can inspect the sx and sy members of the image to determine
+ its size. The image must eventually be destroyed using
+ <gdImageDestroy>.
+
+ *The returned image is always a truecolor image.*
+
+ Parameters:
+
+ infile - The input FILE pointer.
+
+ Returns:
+
+ A pointer to the new *truecolor* image. This will need to be
+ destroyed with <gdImageDestroy> once it is no longer needed.
+
+ On error, returns NULL.
+*/
+BGD_DECLARE(gdImagePtr) gdImageCreateFromHeif(FILE *inFile)
+{
+ gdImagePtr im;
+ gdIOCtx *in = gdNewFileCtx(inFile);
+
+ if (!in)
+ return NULL;
+ im = gdImageCreateFromHeifCtx(in);
+ in->gd_free(in);
+
+ return im;
+}
+
+/*
+ Function: gdImageCreateFromHeifPtr
+
+ See <gdImageCreateFromHeif>.
+
+ Parameters:
+
+ size - size of HEIF data in bytes.
+ data - pointer to HEIF data.
+*/
+BGD_DECLARE(gdImagePtr) gdImageCreateFromHeifPtr(int size, void *data)
+{
+ gdImagePtr im;
+ gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
+
+ if (!in)
+ return NULL;
+ im = gdImageCreateFromHeifCtx(in);
+ in->gd_free(in);
+
+ return im;
+}
+
+static int _gdHeifCheckBrand(unsigned char *magic, gd_heif_brand expected_brand)
+{
+ if (memcmp(magic + 4, "ftyp", 4) != 0)
+ return GD_FALSE;
+ if (memcmp(magic + 8, "avif", 4) == 0 && expected_brand & GD_HEIF_BRAND_AVIF)
+ return GD_TRUE;
+ if (memcmp(magic + 8, "heic", 4) == 0 && expected_brand & GD_HEIF_BRAND_HEIC)
+ return GD_TRUE;
+ if (memcmp(magic + 8, "heix", 4) == 0 && expected_brand & GD_HEIF_BRAND_HEIX)
+ return GD_TRUE;
+ if (memcmp(magic + 8, "mif1", 4) == 0 && expected_brand & GD_HEIF_BRAND_MIF1)
+ return GD_TRUE;
+
+ return GD_FALSE;
+}
+
+static gdImagePtr _gdImageCreateFromHeifCtx(gdIOCtx *infile, gd_heif_brand expected_brand)
+{
+ struct heif_context *heif_ctx;
+ struct heif_decoding_options *heif_dec_opts;
+ struct heif_image_handle *heif_imhandle;
+ struct heif_image *heif_im;
+ struct heif_error err;
+ int width, height;
+ uint8_t *filedata = NULL;
+ uint8_t *rgba = NULL;
+ unsigned char *read, *temp, magic[GD_HEIF_HEADER];
+ int magic_len;
+ size_t size = 0, n = GD_HEIF_ALLOC_STEP;
+ gdImagePtr im;
+ int x, y;
+ uint8_t *p;
+
+ magic_len = gdGetBuf(magic, GD_HEIF_HEADER, infile);
+ if (magic_len != GD_HEIF_HEADER || !_gdHeifCheckBrand(magic, expected_brand)) {
+ gd_error("gd-heif incorrect type of file\n");
+ return NULL;
+ }
+ gdSeek(infile, 0);
+
+ while (n == GD_HEIF_ALLOC_STEP) {
+ temp = gdRealloc(filedata, size + GD_HEIF_ALLOC_STEP);
+ if (temp) {
+ filedata = temp;
+ read = temp + size;
+ } else {
+ gdFree(filedata);
+ gd_error("gd-heif decode realloc failed\n");
+ return NULL;
+ }
+
+ n = gdGetBuf(read, GD_HEIF_ALLOC_STEP, infile);
+ if (n > 0) {
+ size += n;
+ }
+ }
+
+ heif_ctx = heif_context_alloc();
+ if (heif_ctx == NULL) {
+ gd_error("gd-heif could not allocate context\n");
+ gdFree(filedata);
+ return NULL;
+ }
+ err = heif_context_read_from_memory_without_copy(heif_ctx, filedata, size, NULL);
+ if (err.code != heif_error_Ok) {
+ gd_error("gd-heif context creation failed\n");
+ gdFree(filedata);
+ heif_context_free(heif_ctx);
+ return NULL;
+ }
+
+ heif_imhandle = NULL;
+ err = heif_context_get_primary_image_handle(heif_ctx, &heif_imhandle);
+ if (err.code != heif_error_Ok) {
+ gd_error("gd-heif cannot retreive handle\n");
+ gdFree(filedata);
+ heif_context_free(heif_ctx);
+ return NULL;
+ }
+
+ heif_im = NULL;
+ heif_dec_opts = heif_decoding_options_alloc();
+ if (heif_dec_opts == NULL) {
+ gd_error("gd-heif could not allocate decode options\n");
+ gdFree(filedata);
+ heif_image_handle_release(heif_imhandle);
+ heif_context_free(heif_ctx);
+ return NULL;
+ }
+
+ heif_dec_opts->convert_hdr_to_8bit = GD_TRUE;
+ heif_dec_opts->ignore_transformations = GD_TRUE;
+ err = heif_decode_image(heif_imhandle, &heif_im, heif_colorspace_RGB, heif_chroma_interleaved_RGBA, heif_dec_opts);
+ heif_decoding_options_free(heif_dec_opts);
+ if (err.code != heif_error_Ok) {
+ gd_error("gd-heif decoding failed\n");
+ gdFree(filedata);
+ heif_image_handle_release(heif_imhandle);
+ heif_context_free(heif_ctx);
+ return NULL;
+ }
+
+ width = heif_image_get_width(heif_im, heif_channel_interleaved);
+ height = heif_image_get_height(heif_im, heif_channel_interleaved);
+
+ im = gdImageCreateTrueColor(width, height);
+ if (!im) {
+ gdFree(filedata);
+ heif_image_release(heif_im);
+ heif_image_handle_release(heif_imhandle);
+ heif_context_free(heif_ctx);
+ return NULL;
+ }
+ rgba = (uint8_t *)heif_image_get_plane_readonly(heif_im, heif_channel_interleaved, NULL);
+ if (!rgba) {
+ gd_error("gd-heif cannot get image plane\n");
+ gdFree(filedata);
+ heif_image_release(heif_im);
+ heif_image_handle_release(heif_imhandle);
+ heif_context_free(heif_ctx);
+ gdImageDestroy(im);
+ return NULL;
+ }
+ for (y = 0, p = rgba; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ uint8_t r = *(p++);
+ uint8_t g = *(p++);
+ uint8_t b = *(p++);
+ uint8_t a = gdAlphaMax - (*(p++) >> 1);
+ im->tpixels[y][x] = gdTrueColorAlpha(r, g, b, a);
+ }
+ }
+ gdFree(filedata);
+ heif_image_release(heif_im);
+ heif_image_handle_release(heif_imhandle);
+ heif_context_free(heif_ctx);
+
+ return im;
+}
+
+/*
+ Function: gdImageCreateFromHeifCtx
+
+ See <gdImageCreateFromHeif>.
+*/
+BGD_DECLARE(gdImagePtr) gdImageCreateFromHeifCtx(gdIOCtx *infile)
+{
+ return _gdImageCreateFromHeifCtx(infile, GD_HEIF_BRAND_AVIF | GD_HEIF_BRAND_MIF1 | GD_HEIF_BRAND_HEIC | GD_HEIF_BRAND_HEIX);
+}
+
+
+static struct heif_error _gdImageWriteHeif(struct heif_context *heif_ctx, const void *data, size_t size, void *userdata)
+{
+ gdIOCtx *outfile;
+ struct heif_error err;
+
+ outfile = (gdIOCtx *)userdata;
+
+ gdPutBuf(data, size, outfile);
+
+ err.code = heif_error_Ok;
+ err.subcode = heif_suberror_Unspecified;
+ err.message = "";
+
+ return err;
+}
+
+/* returns GD_TRUE on success, GD_FALSE on failure */
+static int _gdImageHeifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, gdHeifCodec codec, gdHeifChroma chroma)
+{
+ struct heif_context *heif_ctx;
+ struct heif_encoder *heif_enc;
+ struct heif_image *heif_im;
+ struct heif_writer heif_wr;
+ struct heif_error err;
+ uint8_t *rgba;
+ int x, y;
+ uint8_t *p;
+
+ if (im == NULL) {
+ return GD_FALSE;
+ }
+
+ if (codec != GD_HEIF_CODEC_HEVC && codec != GD_HEIF_CODEC_AV1) {
+ gd_error("Unsupported format by heif");
+ return GD_FALSE;
+ }
+
+ if (!gdImageTrueColor(im)) {
+ gd_error("Palette image not supported by heif\n");
+ return GD_FALSE;
+ }
+
+ if (overflow2(gdImageSX(im), 4)) {
+ return GD_FALSE;
+ }
+
+ if (overflow2(gdImageSX(im) * 4, gdImageSY(im))) {
+ return GD_FALSE;
+ }
+
+ heif_ctx = heif_context_alloc();
+ if (heif_ctx == NULL) {
+ gd_error("gd-heif could not allocate context\n");
+ return GD_FALSE;
+ }
+ err = heif_context_get_encoder_for_format(heif_ctx, (enum heif_compression_format)codec, &heif_enc);
+ if (err.code != heif_error_Ok) {
+ gd_error("gd-heif encoder acquisition failed (missing codec support?)\n");
+ heif_context_free(heif_ctx);
+ return GD_FALSE;
+ }
+
+ if (quality == 200) {
+ err = heif_encoder_set_lossless(heif_enc, GD_TRUE);
+ } else if (quality == -1) {
+ err = heif_encoder_set_lossy_quality(heif_enc, 80);
+ } else {
+ err = heif_encoder_set_lossy_quality(heif_enc, quality);
+ }
+ if (err.code != heif_error_Ok) {
+ gd_error("gd-heif invalid quality number\n");
+ heif_encoder_release(heif_enc);
+ heif_context_free(heif_ctx);
+ return GD_FALSE;
+ }
+
+ err = heif_encoder_set_parameter_string(heif_enc, "chroma", chroma);
+ if (err.code != heif_error_Ok) {
+ gd_error("gd-heif invalid chroma subsampling parameter\n");
+ heif_encoder_release(heif_enc);
+ heif_context_free(heif_ctx);
+ return GD_FALSE;
+ }
+
+ err = heif_image_create(gdImageSX(im), gdImageSY(im), heif_colorspace_RGB, heif_chroma_interleaved_RGBA, &heif_im);
+ if (err.code != heif_error_Ok) {
+ gd_error("gd-heif image creation failed");
+ heif_encoder_release(heif_enc);
+ heif_context_free(heif_ctx);
+ return GD_FALSE;
+ }
+
+ err = heif_image_add_plane(heif_im, heif_channel_interleaved, gdImageSX(im), gdImageSY(im), 32);
+ if (err.code != heif_error_Ok) {
+ gd_error("gd-heif cannot add image plane\n");
+ heif_image_release(heif_im);
+ heif_encoder_release(heif_enc);
+ heif_context_free(heif_ctx);
+ return GD_FALSE;
+ }
+
+ rgba = (uint8_t *)heif_image_get_plane_readonly(heif_im, heif_channel_interleaved, NULL);
+ if (!rgba) {
+ gd_error("gd-heif cannot get image plane\n");
+ heif_image_release(heif_im);
+ heif_encoder_release(heif_enc);
+ heif_context_free(heif_ctx);
+ return GD_FALSE;
+ }
+ p = rgba;
+ for (y = 0; y < gdImageSY(im); y++) {
+ for (x = 0; x < gdImageSX(im); x++) {
+ int c;
+ char a;
+ c = im->tpixels[y][x];
+ a = gdTrueColorGetAlpha(c);
+ if (a == 127) {
+ a = 0;
+ } else {
+ a = 255 - ((a << 1) + (a >> 6));
+ }
+ *(p++) = gdTrueColorGetRed(c);
+ *(p++) = gdTrueColorGetGreen(c);
+ *(p++) = gdTrueColorGetBlue(c);
+ *(p++) = a;
+ }
+ }
+ err = heif_context_encode_image(heif_ctx, heif_im, heif_enc, NULL, NULL);
+ heif_encoder_release(heif_enc);
+ if (err.code != heif_error_Ok) {
+ gd_error("gd-heif encoding failed\n");
+ heif_image_release(heif_im);
+ heif_context_free(heif_ctx);
+ return GD_FALSE;
+ }
+ heif_wr.write = _gdImageWriteHeif;
+ heif_wr.writer_api_version = 1;
+ err = heif_context_write(heif_ctx, &heif_wr, (void *)outfile);
+
+ heif_image_release(heif_im);
+ heif_context_free(heif_ctx);
+
+ return GD_TRUE;
+}
+
+
+/*
+ Function: gdImageHeifCtx
+
+ Write the image as HEIF data via a <gdIOCtx>. See <gdImageHeifEx>
+ for more details.
+
+ Parameters:
+
+ im - The image to write.
+ outfile - The output sink.
+ quality - Image quality.
+ codec - The output coding format.
+ chroma - The output chroma subsampling format.
+
+ Returns:
+
+ Nothing.
+*/
+BGD_DECLARE(void) gdImageHeifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, gdHeifCodec codec, gdHeifChroma chroma)
+{
+ _gdImageHeifCtx(im, outfile, quality, codec, chroma);
+}
+
+/*
+ Function: gdImageHeifEx
+
+ <gdImageHeifEx> outputs the specified image to the specified file in
+ HEIF format. The file must be open for writing. Under MSDOS and
+ all versions of Windows, it is important to use "wb" as opposed to
+ simply "w" as the mode when opening the file, and under Unix there
+ is no penalty for doing so. <gdImageHeifEx> does not close the file;
+ your code must do so.
+
+ If _quality_ is -1, a reasonable quality value (which should yield a
+ good general quality / size tradeoff for most situations) is used. Otherwise
+ _quality_ should be a value in the range 0-100, higher quality values
+ usually implying both higher quality and larger image sizes or 200, for
+ lossless codec.
+
+ Variants:
+
+ <gdImageHeifCtx> stores the image using a <gdIOCtx> struct.
+
+ <gdImageHeifPtrEx> stores the image to RAM.
+
+ Parameters:
+
+ im - The image to save.
+ outFile - The FILE pointer to write to.
+ quality - Codec quality (0-100).
+ codec - The output coding format.
+ chroma - The output chroma subsampling format.
+
+ Returns:
+
+ Nothing.
+*/
+BGD_DECLARE(void) gdImageHeifEx(gdImagePtr im, FILE *outFile, int quality, gdHeifCodec codec, gdHeifChroma chroma)
+{
+ gdIOCtx *out = gdNewFileCtx(outFile);
+ if (out == NULL) {
+ return;
+ }
+ _gdImageHeifCtx(im, out, quality, codec, chroma);
+ out->gd_free(out);
+}
+
+/*
+ Function: gdImageHeif
+
+ Variant of <gdImageHeifEx> which uses the default quality (-1), the
+ default codec (GD_HEIF_Codec_HEVC) and the default chroma
+ subsampling (GD_HEIF_CHROMA_444).
+
+ Parameters:
+
+ im - The image to save
+ outFile - The FILE pointer to write to.
+
+ Returns:
+
+ Nothing.
+*/
+BGD_DECLARE(void) gdImageHeif(gdImagePtr im, FILE *outFile)
+{
+ gdIOCtx *out = gdNewFileCtx(outFile);
+ if (out == NULL) {
+ return;
+ }
+ _gdImageHeifCtx(im, out, -1, GD_HEIF_CODEC_HEVC, GD_HEIF_CHROMA_444);
+ out->gd_free(out);
+}
+
+/*
+ Function: gdImageHeifPtr
+
+ See <gdImageHeifEx>.
+*/
+BGD_DECLARE(void *) gdImageHeifPtr(gdImagePtr im, int *size)
+{
+ void *rv;
+ gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
+ if (out == NULL) {
+ return NULL;
+ }
+ if (_gdImageHeifCtx(im, out, -1, GD_HEIF_CODEC_HEVC, GD_HEIF_CHROMA_444)) {
+ rv = gdDPExtractData(out, size);
+ } else {
+ rv = NULL;
+ }
+ out->gd_free(out);
+
+ return rv;
+}
+
+/*
+ Function: gdImageHeifPtrEx
+
+ See <gdImageHeifEx>.
+*/
+BGD_DECLARE(void *) gdImageHeifPtrEx(gdImagePtr im, int *size, int quality, gdHeifCodec codec, gdHeifChroma chroma)
+{
+ void *rv;
+ gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
+ if (out == NULL) {
+ return NULL;
+ }
+ if (_gdImageHeifCtx(im, out, quality, codec, chroma)) {
+ rv = gdDPExtractData(out, size);
+ } else {
+ rv = NULL;
+ }
+ out->gd_free(out);
+ return rv;
+}
+
+#else /* HAVE_LIBHEIF */
+
+static void _noHeifError(void)
+{
+ gd_error("HEIF image support has been disabled\n");
+}
+
+BGD_DECLARE(gdImagePtr) gdImageCreateFromHeif(FILE *inFile)
+{
+ _noHeifError();
+ return NULL;
+}
+
+BGD_DECLARE(gdImagePtr) gdImageCreateFromHeifPtr(int size, void *data)
+{
+ _noHeifError();
+ return NULL;
+}
+
+BGD_DECLARE(gdImagePtr) gdImageCreateFromHeifCtx(gdIOCtx *infile)
+{
+ _noHeifError();
+ return NULL;
+}
+
+BGD_DECLARE(void) gdImageHeifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, gdHeifCodec codec, gdHeifChroma chroma)
+{
+ _noHeifError();
+}
+
+BGD_DECLARE(void) gdImageHeifEx(gdImagePtr im, FILE *outFile, int quality, gdHeifCodec codec, gdHeifChroma chroma)
+{
+ _noHeifError();
+}
+
+BGD_DECLARE(void) gdImageHeif(gdImagePtr im, FILE *outFile)
+{
+ _noHeifError();
+}
+
+BGD_DECLARE(void *) gdImageHeifPtr(gdImagePtr im, int *size)
+{
+ _noHeifError();
+ return NULL;
+}
+
+BGD_DECLARE(void *) gdImageHeifPtrEx(gdImagePtr im, int *size, int quality, gdHeifCodec codec, gdHeifChroma chroma)
+{
+ _noHeifError();
+ return NULL;
+}
+
+#endif /* HAVE_LIBHEIF */
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index c99fe21..6775948 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -82,6 +82,7 @@ if (BUILD_TEST)
gdtransformaffineboundingbox
gdtransformaffinecopy
gif
+ heif
jpeg
png
tga
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f342ceb..efbe26a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -78,6 +78,7 @@ include gdtiled/Makemodule.am
include gdtransformaffineboundingbox/Makemodule.am
include gdtransformaffinecopy/Makemodule.am
include gif/Makemodule.am
+include heif/Makemodule.am
include jpeg/Makemodule.am
include png/Makemodule.am
include tga/Makemodule.am
@@ -102,6 +103,7 @@ CLEANFILES += \
*.gd \
*.gd2 \
*.gif \
+ *.heif \
*.jpeg \
*.jpg \
*.png \
diff --git a/tests/heif/CMakeLists.txt b/tests/heif/CMakeLists.txt
new file mode 100644
index 0000000..4a41528
--- /dev/null
+++ b/tests/heif/CMakeLists.txt
@@ -0,0 +1,11 @@
+IF(HEIF_FOUND)
+LIST(APPEND TESTS_FILES
+ avif_ptr_double_free
+ heif_im2im
+ heif_null
+ heif_ptr_double_free
+ heif_read
+)
+ENDIF(HEIF_FOUND)
+
+ADD_GD_TESTS()
diff --git a/tests/heif/Makemodule.am b/tests/heif/Makemodule.am
new file mode 100644
index 0000000..675e8a9
--- /dev/null
+++ b/tests/heif/Makemodule.am
@@ -0,0 +1,11 @@
+if HAVE_LIBHEIF
+libgd_test_programs += \
+ heif/avif_ptr_double_free \
+ heif/heif_im2im \
+ heif/heif_null \
+ heif/heif_ptr_double_free \
+ heif/heif_read
+endif
+
+EXTRA_DIST += \
+ heif/CMakeLists.txt
diff --git a/tests/heif/avif_ptr_double_free.c b/tests/heif/avif_ptr_double_free.c
new file mode 100644
index 0000000..f294929
--- /dev/null
+++ b/tests/heif/avif_ptr_double_free.c
@@ -0,0 +1,31 @@
+/**
+ * Test that failure to convert to AVIF returns NULL
+ *
+ * We are creating an image, set its width to zero, and pass this image to
+ * `gdImageAvifPtr()` which is supposed to fail, and as such should return NULL.
+ *
+ * See also <https://github.com/libgd/libgd/issues/381>
+ */
+
+
+#include "gd.h"
+#include "gdtest.h"
+
+
+int main()
+{
+ gdImagePtr src, dst;
+ int size;
+
+ src = gdImageCreateTrueColor(1, 10);
+ gdTestAssert(src != NULL);
+
+ src->sx = 0;
+
+ dst = gdImageHeifPtrEx(src, &size, 100, GD_HEIF_CODEC_AV1, GD_HEIF_CHROMA_444);
+ gdTestAssert(dst == NULL);
+
+ gdImageDestroy(src);
+
+ return gdNumFailures();
+}
diff --git a/tests/heif/heif_im2im.c b/tests/heif/heif_im2im.c
new file mode 100644
index 0000000..6ab9cf6
--- /dev/null
+++ b/tests/heif/heif_im2im.c
@@ -0,0 +1,49 @@
+/**
+ * Check if it's any difference between the original bitmap and a encoded and
+ * decoded `4:4:4` HEIF lossless image.
+ */
+
+
+#include "gd.h"
+#include "gdtest.h"
+
+int main()
+{
+ gdImagePtr src, dst;
+ int r, g, b;
+ void *p;
+ int size = 0;
+ CuTestImageResult result = {0, 0};
+
+ src = gdImageCreateTrueColor(100, 100);
+ gdTestAssertMsg(src != NULL, "could not create src\n");
+ /* libheif seems to have some rounding issues */
+ r = gdImageColorAllocate(src, 0xFE, 0, 0);
+ g = gdImageColorAllocate(src, 0, 0xFE, 0);
+ b = gdImageColorAllocate(src, 0, 0, 0xFE);
+ gdImageFilledRectangle(src, 0, 0, 99, 99, r);
+ gdImageRectangle(src, 20, 20, 79, 79, g);
+ gdImageEllipse(src, 70, 25, 30, 20, b);
+
+ p = gdImageHeifPtrEx(src, &size, 200, GD_HEIF_CODEC_HEVC, GD_HEIF_CHROMA_444);
+ gdTestAssertMsg(p != NULL, "return value of gdImageHeifPtrEx() is null\n");
+ gdTestAssertMsg(size > 0, "gdImageHeifPtrEx() output size is non-positive\n");
+
+ dst = gdImageCreateFromHeifPtr(size, p);
+ gdTestAssertMsg(dst != NULL, "return value of gdImageCreateFromHeifPtr() is null\n");
+
+ if (gdTestAssertMsg(src != NULL && dst != NULL, "cannot compare with NULL buffer"))
+ gdTestImageDiff(src, dst, NULL, &result);
+ else
+ result.pixels_changed = 0;
+ gdTestAssertMsg(result.pixels_changed == 0, "pixels changed: %d\n", result.pixels_changed);
+
+ if (dst != NULL)
+ gdImageDestroy(dst);
+ if (p != NULL)
+ gdFree(p);
+ if (src != NULL)
+ gdImageDestroy(src);
+
+ return gdNumFailures();
+}
diff --git a/tests/heif/heif_null.c b/tests/heif/heif_null.c
new file mode 100644
index 0000000..0b5eac5
--- /dev/null
+++ b/tests/heif/heif_null.c
@@ -0,0 +1,20 @@
+/**
+ * Simple test case that confirms the failure of using `gdImageCreateFromHeif`
+ * with a NULL pointer.
+ */
+
+
+#include "gd.h"
+#include "gdtest.h"
+
+int main()
+{
+ gdImagePtr im;
+
+ im = gdImageCreateFromHeif(NULL);
+ if (!gdTestAssert(im == NULL))
+ gdImageDestroy(im);
+ gdImageHeif(im, NULL); /* noop safely */
+
+ return gdNumFailures();
+}
diff --git a/tests/heif/heif_ptr_double_free.c b/tests/heif/heif_ptr_double_free.c
new file mode 100644
index 0000000..14f1d25
--- /dev/null
+++ b/tests/heif/heif_ptr_double_free.c
@@ -0,0 +1,31 @@
+/**
+ * Test that failure to convert to HEIF returns NULL
+ *
+ * We are creating an image, set its width to zero, and pass this image to
+ * `gdImageHeifPtr()` which is supposed to fail, and as such should return NULL.
+ *
+ * See also <https://github.com/libgd/libgd/issues/381>
+ */
+
+
+#include "gd.h"
+#include "gdtest.h"
+
+
+int main()
+{
+ gdImagePtr src, dst;
+ int size;
+
+ src = gdImageCreateTrueColor(1, 10);
+ gdTestAssert(src != NULL);
+
+ src->sx = 0;
+
+ dst = gdImageHeifPtrEx(src, &size, 0, GD_HEIF_CODEC_HEVC, GD_HEIF_CHROMA_444);
+ gdTestAssert(dst == NULL);
+
+ gdImageDestroy(src);
+
+ return gdNumFailures();
+}
diff --git a/tests/heif/heif_read.c b/tests/heif/heif_read.c
new file mode 100644
index 0000000..469ea31
--- /dev/null
+++ b/tests/heif/heif_read.c
@@ -0,0 +1,23 @@
+/**
+ * Simple test case that confirms the failure of using `gdImageCreateFromHeif`
+ * with a NULL pointer.
+ */
+
+
+#include "gd.h"
+#include "gdtest.h"
+
+int main()
+{
+ gdImagePtr im;
+ FILE *fp;
+
+ fp = gdTestFileOpen2("heif", "label.heic");
+ gdTestAssert(fp != NULL);
+ im = gdImageCreateFromHeif(fp);
+ if (gdTestAssert(im != NULL))
+ gdImageDestroy(im);
+ fclose(fp);
+
+ return gdNumFailures();
+}
diff --git a/tests/heif/label.avif b/tests/heif/label.avif
new file mode 100644
index 0000000..2e84362
--- /dev/null
+++ b/tests/heif/label.avif
Binary files differ
diff --git a/tests/heif/label.heic b/tests/heif/label.heic
new file mode 100644
index 0000000..12814f7
--- /dev/null
+++ b/tests/heif/label.heic
Binary files differ
diff --git a/tests/source/run.sh b/tests/source/run.sh
index 1945ae1..8d7f9c3 100755
--- a/tests/source/run.sh
+++ b/tests/source/run.sh
@@ -17,7 +17,7 @@ export LC_ALL=C
# List all the non-binary files we know about in the tree.
read -r -d'\n' -a files < <(
git ls-tree -r --name-only HEAD | \
- grep -Ev '\.(bin|bmp|gd|gd2|gif|jpg|jpeg|png|pic|sgi|tga|tiff|ttf|xbm|xpm)$'
+ grep -Ev '\.(avif|bin|bmp|gd|gd2|gif|heic|jpg|jpeg|png|pic|sgi|tga|tiff|ttf|xbm|xpm)$'
) || :
banner() {
diff --git a/windows/Makefile.vc b/windows/Makefile.vc
index 67a8014..d97b22f 100644
--- a/windows/Makefile.vc
+++ b/windows/Makefile.vc
@@ -94,10 +94,11 @@ LIB_OBJS= \
$(LIBGD_OBJ_DIR)\gd_version.obj \
$(LIBGD_OBJ_DIR)\gd_crop.obj \
$(LIBGD_OBJ_DIR)\gd_color_map.obj \
+ $(LIBGD_OBJ_DIR)\gd_heif.obj \
$(LIBGD_OBJ_DIR)\gd_webp.obj
LIBS=kernel32.lib ole32.lib user32.lib advapi32.lib shell32.lib ws2_32.lib Dnsapi.lib Gdi32.Lib
-LIBS_GD=libjpeg_a.lib freetype_a.lib libpng_a.lib libiconv_a.lib zlib_a.lib libwebp_a.lib libxpm_a.lib libtiff.lib
+LIBS_GD=libjpeg_a.lib freetype_a.lib libpng_a.lib libiconv_a.lib zlib_a.lib libheif_a.lib libwebp_a.lib libxpm_a.lib libtiff.lib
PROG_EXES= \
$(LIBGD_OBJ_DIR)\gdcmpgif.exe \
@@ -138,6 +139,7 @@ CFLAGS= $(CFLAGS) \
/DHAVE_LIBJPEG=1\
/DHAVE_LIBPNG=1\
/DHAVE_LIBWEBP=1\
+ /DHAVE_LIBHEIF=1\
/DHAVE_LIBZ=1\
/DHAVE_LIBXPM=1\
/DHAVE_LIBTIFF=1\
@@ -196,6 +198,9 @@ make_dirs:
@echo #ifndef HAVE_LIBWEBP>> $(GD_CONFIG_H)
@echo #define HAVE_LIBWEBP>> $(GD_CONFIG_H)
@echo #endif>> $(GD_CONFIG_H)
+ @echo #ifndef HAVE_LIBHEIF>> $(GD_CONFIG_H)
+ @echo #define HAVE_LIBHEIF>> $(GD_CONFIG_H)
+ @echo #endif>> $(GD_CONFIG_H)
@echo #ifndef HAVE_LIBZ>> $(GD_CONFIG_H)
@echo #define HAVE_LIBZ>> $(GD_CONFIG_H)
@echo #endif>> $(GD_CONFIG_H)
diff --git a/windows/msys/Makefile b/windows/msys/Makefile
index d4acaaf..8c5d380 100644
--- a/windows/msys/Makefile
+++ b/windows/msys/Makefile
@@ -97,7 +97,7 @@ gd_gif_out.c gd_io_file.c gd_io_ss.c gd_jpeg.c gd_png.c gd_ss.c \
gd_topal.c gd_wbmp.c gdcache.c gdfontg.c gdfontl.c gdfontmb.c \
gdfonts.c gdfontt.c gdft.c gdhelpers.c gdkanji.c gdtables.c gdxpm.c \
wbmp.c gd_filter.c gd_nnquant.c gd_rotate.c gd_matrix.c \
-gd_interpolation.c gd_crop.c gd_webp.c gd_tiff.c gd_tga.c \
+gd_interpolation.c gd_crop.c gd_webp.c gd_heif.c gd_tiff.c gd_tga.c \
gd_bmp.c gd_xbm.c gd_color_match.c gd_version.c gd_filename.c
OBJ=$(SRC:.c=.o)