From: farindk Date: Fri, 27 Apr 2018 08:26:21 +0000 (+0200) Subject: added HEIF writer and replaced HEIF reader with a more complete HEIF implementation... X-Git-Tag: 7.0.7-29~35 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4179457e953287f49876efc90af2388fee1933f8;p=imagemagick added HEIF writer and replaced HEIF reader with a more complete HEIF implementation (#1099) * first implementation of HEIC writer based on libheif * new HEIC reader based on libheif * rename HEIC image type * adapt to changed encoder API * read Exif data from HEIC * remove check for libde265 from autoconf as we are now depending only on libheif instead * check in autoconf files (note: these should not be in git) * support 'ping' for reading image attributes without decoding * variable HEIF compression quality setting * show proper error messages * use image_info->quality instead of image->quality * restore all files generated by autotools to their original state from master branch --- diff --git a/coders/Makefile.am b/coders/Makefile.am index bb21ad8af..dc23ea6d9 100644 --- a/coders/Makefile.am +++ b/coders/Makefile.am @@ -574,7 +574,7 @@ coders_hdr_la_LIBADD = $(MAGICKCORE_LIBS) $(GOMP_LIBS) $(MATH_LIBS) coders_heic_la_SOURCES = coders/heic.c coders_heic_la_CPPFLAGS = $(MODULE_CODER_CPPFLAGS) coders_heic_la_LDFLAGS = $(MODULECOMMONFLAGS) -coders_heic_la_LIBADD = $(MAGICKCORE_LIBS) $(HEIC_LIBS) +coders_heic_la_LIBADD = $(MAGICKCORE_LIBS) $(HEIF_LIBS) # HRZ coder module coders_hrz_la_SOURCES = coders/hrz.c @@ -623,7 +623,7 @@ coders_jpeg_la_SOURCES = coders/jpeg.c coders_jpeg_la_CPPFLAGS = $(MAGICK_CODER_CPPFLAGS) coders_jpeg_la_LDFLAGS = $(MODULECOMMONFLAGS) coders_jpeg_la_LIBADD = $(MAGICKCORE_LIBS) $(JPEG_LIBS) $(MATH_LIBS) - + # JPEG 2000 coder module coders_jp2_la_SOURCES = coders/jp2.c coders_jp2_la_CPPFLAGS = $(MAGICK_CODER_CPPFLAGS) $(LIBOPENJP2_CFLAGS) diff --git a/coders/heic.c b/coders/heic.c index 2a51712a4..d259d40c2 100644 --- a/coders/heic.c +++ b/coders/heic.c @@ -10,1050 +10,82 @@ % H H EEEEE IIIII CCCC % % % % % -% Read/Write Heic Image Format % % % -% Software Design % -% Anton Kortunov % -% December 2017 % -% % -% % -% Copyright 2017-2018 YANDEX LLC. % -% % -% You may not use this file except in compliance with the License. You may % -% obtain a copy of the License at % -% % -% https://www.imagemagick.org/script/license.php % -% % -% Unless required by applicable law or agreed to in writing, software % -% distributed under the License is distributed on an "AS IS" BASIS, % -% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % -% See the License for the specific language governing permissions and % -% limitations under the License. % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% -*/ - -/* - Include declarations. -*/ -#include "MagickCore/studio.h" -#include "MagickCore/artifact.h" -#include "MagickCore/blob.h" -#include "MagickCore/blob-private.h" -#include "MagickCore/client.h" -#include "MagickCore/colorspace-private.h" -#include "MagickCore/property.h" -#include "MagickCore/display.h" -#include "MagickCore/exception.h" -#include "MagickCore/exception-private.h" -#include "MagickCore/image.h" -#include "MagickCore/image-private.h" -#include "MagickCore/list.h" -#include "MagickCore/magick.h" -#include "MagickCore/monitor.h" -#include "MagickCore/monitor-private.h" -#include "MagickCore/montage.h" -#include "MagickCore/transform.h" -#include "MagickCore/memory_.h" -#include "MagickCore/memory-private.h" -#include "MagickCore/option.h" -#include "MagickCore/pixel-accessor.h" -#include "MagickCore/quantum-private.h" -#include "MagickCore/static.h" -#include "MagickCore/string_.h" -#include "MagickCore/string-private.h" -#include "MagickCore/module.h" -#include "MagickCore/utility.h" -#if defined(MAGICKCORE_HEIC_DELEGATE) -#include -#endif - -/* - Typedef declarations. -*/ -#if defined(MAGICKCORE_HEIC_DELEGATE) - -#define MAX_ASSOCS_COUNT 10 -#define MAX_ITEM_PROPS 100 -#define MAX_HVCC_ATOM_SIZE 1024 -#define MAX_ATOMS_IN_BOX 100 -#define BUFFER_SIZE 100 - -typedef struct _HEICItemInfo -{ - unsigned int - type; - - unsigned int - assocsCount; - - uint8_t - assocs[MAX_ASSOCS_COUNT]; - - unsigned int - dataSource; - - unsigned int - offset; - - unsigned int - size; -} HEICItemInfo; - -typedef struct _HEICItemProp -{ - unsigned int - type; - - unsigned int - size; - - uint8_t - *data; -} HEICItemProp; - -typedef struct _HEICGrid -{ - unsigned int - id; - - unsigned int - rowsMinusOne; - - unsigned int - columnsMinusOne; - - unsigned int - imageWidth; - - unsigned int - imageHeight; -} HEICGrid; - -typedef struct _HEICImageContext -{ - MagickBooleanType - finished; - - int - idsCount; - - HEICItemInfo - *itemInfo; - - int - itemPropsCount; - - HEICItemProp - itemProps[MAX_ITEM_PROPS]; - - unsigned int - idatSize; - - uint8_t - *idat; - - HEICGrid - grid; - - de265_decoder_context - *h265Ctx; - - Image - *tmp; -} HEICImageContext; - -typedef struct _DataBuffer { - unsigned char - *data; - - off_t - pos; - - size_t - size; -} DataBuffer; - - -#define ATOM(a,b,c,d) ((a << 24) + (b << 16) + (c << 8) + d) -#define ThrowImproperImageHeader(msg) { \ - (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError, \ - "ImproperImageHeader","`%s'",msg); \ -} -#define ThrowAndReturn(msg) { \ - ThrowImproperImageHeader(msg) \ - return(MagickFalse); \ -} - -inline static unsigned int readInt(const unsigned char* data) -{ - unsigned int val = 0; - - val=(unsigned int)(data[0]) << 24; - val|=(unsigned int)(data[1]) << 16; - val|=(unsigned int)(data[2]) << 8; - val|=(unsigned int)(data[3]); - - return val; -} - -inline static MagickSizeType DBChop(DataBuffer *head, DataBuffer *db, size_t size) -{ - if (size > (db->size - db->pos)) { - return MagickFalse; - } - - head->data = db->data + db->pos; - head->pos = 0; - head->size = size; - - db->pos += size; - - return MagickTrue; -} - -inline static uint32_t DBReadUInt(DataBuffer *db) -{ - uint32_t val = 0; - - if (db->size - db->pos < 4) { - db->pos = db->size; - return 0; - } - - val=(uint32_t) db->data[db->pos+0] << 24; - val|=(uint32_t) db->data[db->pos+1] << 16; - val|=(uint32_t) db->data[db->pos+2] << 8; - val|=(uint32_t) db->data[db->pos+3]; - - db->pos += 4; - - return val; -} - -inline static uint16_t DBReadUShort(DataBuffer *db) -{ - uint16_t val = 0; - - if (db->size - db->pos < 2) { - db->pos = db->size; - return 0; - } - - val=(uint16_t) db->data[db->pos+0] << 8; - val|=(uint16_t) db->data[db->pos+1]; - - db->pos += 2; - - return val; -} - -inline static uint8_t DBReadUChar(DataBuffer *db) -{ - uint8_t val; - - if (db->size - db->pos < 2) { - db->pos = db->size; - return 0; - } - - val=(uint8_t) db->data[db->pos]; - db->pos += 1; - - return val; -} - -inline static size_t DBGetSize(DataBuffer *db) -{ - return db->size - db->pos; -} - -inline static void DBSkip(DataBuffer *db, size_t skip) -{ - if (db->pos + skip > db->size) - { - db->pos = db->size; - } else { - db->pos += skip; - } -} - -static MagickBooleanType ParseAtom(Image *image, DataBuffer *db, - HEICImageContext *ctx, ExceptionInfo *exception); - -static MagickBooleanType ParseFullBox(Image *image, DataBuffer *db, - unsigned int atom, HEICImageContext *ctx, ExceptionInfo *exception) -{ - unsigned int - version, flags, i; - - flags = DBReadUInt(db); - version = flags >> 24; - flags &= 0xffffff; - - (void) flags; - (void) version; - - if (DBGetSize(db) < 4) { - ThrowAndReturn("atom is too short"); - } - - for (i = 0; i < MAX_ATOMS_IN_BOX && DBGetSize(db) > 0; i++) { - if (ParseAtom(image, db, ctx, exception) == MagickFalse) - return MagickFalse; - } - - return MagickTrue; -} - -static MagickBooleanType ParseBox(Image *image, DataBuffer *db, - unsigned int atom, HEICImageContext *ctx, ExceptionInfo *exception) -{ - unsigned int - i; - - for (i = 0; i < MAX_ATOMS_IN_BOX && DBGetSize(db) > 0; i++) { - if (ParseAtom(image, db, ctx, exception) == MagickFalse) - return MagickFalse; - } - - return MagickTrue; -} - -static MagickBooleanType ParseHvcCAtom(HEICItemProp *prop, ExceptionInfo *exception) -{ - size_t - size, pos, count, i; - - uint8_t - buffer[MAX_HVCC_ATOM_SIZE]; - - uint8_t - *p; - - p = prop->data; - - size = prop->size; - if (size >= MAX_HVCC_ATOM_SIZE) - ThrowAndReturn("hvcC atom is too long"); - memcpy(buffer, prop->data, size); - - pos = 22; - if (pos >= size) { - ThrowAndReturn("hvcC atom is too short"); - } - - count = buffer[pos++]; - - for (i = 0; i < count && pos < size-3; i++) { - size_t - naluType, num, j; - - naluType = buffer[pos++] & 0x3f; - (void) naluType; - num = buffer[pos++] << 8; - num += buffer[pos++]; - - for (j = 0; j < num && pos < size-2; j++) { - size_t - naluSize; - - naluSize = buffer[pos++] << 8; - naluSize += buffer[pos++]; - - if ((pos + naluSize > size) || - (p + naluSize > prop->data + prop->size)) { - ThrowAndReturn("hvcC atom is too short"); - } - - /* AnnexB NALU header */ - *p++ = 0; - *p++ = 0; - *p++ = 0; - *p++ = 1; - - memcpy(p, buffer + pos, naluSize); - p += naluSize; - pos += naluSize; - } - } - - prop->size = p - prop->data; - return MagickTrue; -} - -static MagickBooleanType ParseIpcoAtom(Image *image, DataBuffer *db, - HEICImageContext *ctx, ExceptionInfo *exception) -{ - unsigned int - length, atom; - - HEICItemProp - *prop; - - /* - property indicies starts from 1 - */ - for (ctx->itemPropsCount = 1; ctx->itemPropsCount < MAX_ITEM_PROPS && DBGetSize(db) > 8; ctx->itemPropsCount++) { - DataBuffer - propDb; - - length = DBReadUInt(db); - atom = DBReadUInt(db); - - if (ctx->itemPropsCount == MAX_ITEM_PROPS) { - ThrowAndReturn("too many item properties"); - } - - prop = &(ctx->itemProps[ctx->itemPropsCount]); - prop->type = atom; - prop->size = length - 8; - if (prop->size > DBGetSize(db)) - ThrowAndReturn("insufficient data"); - if (prop->data != (uint8_t *) NULL) - prop->data=(uint8_t *) RelinquishMagickMemory(prop->data); - prop->data = (uint8_t *) AcquireCriticalMemory(prop->size+4); - (void) memset(prop->data, 0, prop->size+4); - if (DBChop(&propDb, db, prop->size) != MagickTrue) { - ThrowAndReturn("incorrect read size"); - } - memcpy(prop->data, propDb.data, prop->size); - - switch (prop->type) { - case ATOM('h', 'v', 'c', 'C'): - ParseHvcCAtom(prop, exception); - break; - default: - break; - } - } - - return MagickTrue; -} - -static MagickBooleanType ParseIinfAtom(Image *image, DataBuffer *db, - HEICImageContext *ctx, ExceptionInfo *exception) -{ - unsigned int - version, flags, count, i; - - if (DBGetSize(db) < 4) { - ThrowAndReturn("atom is too short"); - } - - flags = DBReadUInt(db); - version = flags >> 24; - flags = 0xffffff; - - if (version == 0) { - count = DBReadUShort(db); - } else { - count = DBReadUInt(db); - } - - /* - item indicies starts from 1 - */ - ctx->idsCount = count; - if (ctx->itemInfo != (HEICItemInfo *) NULL) - ctx->itemInfo=(HEICItemInfo *) RelinquishMagickMemory(ctx->itemInfo); - if ((8.0*count) > (double)DBGetSize(db)) - ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile", - image->filename); - ctx->itemInfo = (HEICItemInfo *)AcquireMagickMemory(sizeof(HEICItemInfo)*(count+1)); - if (ctx->itemInfo == (HEICItemInfo *) NULL) - ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", - image->filename); - - memset(ctx->itemInfo, 0, sizeof(HEICItemInfo)*(count+1)); - - for (i = 0; i < count && DBGetSize(db) > 0; i++) - { - (void) ParseAtom(image, db, ctx, exception); - } - - return MagickTrue; -} - -static MagickBooleanType ParseInfeAtom(Image *image, DataBuffer *db, - HEICImageContext *ctx, ExceptionInfo *exception) -{ - unsigned int - version, flags, id, type; - - if (DBGetSize(db) < 9) { - ThrowAndReturn("atom is too short"); - } - - flags = DBReadUInt(db); - version = flags >> 24; - flags = 0xffffff; - - if (version != 2) { - ThrowAndReturn("unsupported infe atom version"); - } - - id = DBReadUShort(db); - DBSkip(db, 2); /* item protection index */ - type = DBReadUInt(db); - - /* - item indicies starts from 1 - */ - if ((id > (ssize_t) ctx->idsCount) || - (ctx->itemInfo == (HEICItemInfo *) NULL)) - ThrowAndReturn("item id is incorrect"); - - ctx->itemInfo[id].type = type; - - return MagickTrue; -} - -static MagickBooleanType ParseIpmaAtom(Image *image, DataBuffer *db, - HEICImageContext *ctx, ExceptionInfo *exception) -{ - unsigned int - version, flags, count, i; - - if (DBGetSize(db) < 9) { - ThrowAndReturn("atom is too short"); - } - - flags = DBReadUInt(db); - version = flags >> 24; - flags = 0xffffff; - - count = DBReadUInt(db); - - for (i = 0; i < count && DBGetSize(db) > 2; i++) { - unsigned int - id, assoc_count, j; - - if (version < 1) { - id = DBReadUShort(db); - } else { - id = DBReadUInt(db); - } - - /* - item indicies starts from 1 - */ - if ((id > (ssize_t) ctx->idsCount) || - (ctx->itemInfo == (HEICItemInfo *) NULL)) - ThrowAndReturn("item id is incorrect"); - - assoc_count = DBReadUChar(db); - - if (assoc_count >= MAX_ASSOCS_COUNT) { - ThrowAndReturn("too many associations"); - } - - for (j = 0; j < assoc_count && DBGetSize(db) > 0; j++) { - ctx->itemInfo[id].assocs[j] = DBReadUChar(db); - } - - ctx->itemInfo[id].assocsCount = j; - } - - return MagickTrue; -} - -static MagickBooleanType ParseIlocAtom(Image *image, DataBuffer *db, - HEICImageContext *ctx, ExceptionInfo *exception) -{ - unsigned int - version, flags, tmp, count, i; - - if (DBGetSize(db) < 9) { - ThrowAndReturn("atom is too short"); - } - - flags = DBReadUInt(db); - version = flags >> 24; - flags = 0xffffff; - - tmp = DBReadUChar(db); - if (tmp != 0x44) { - ThrowAndReturn("only offset_size=4 and length_size=4 are supported"); - } - tmp = DBReadUChar(db); - if (tmp != 0x00) { - ThrowAndReturn("only base_offset_size=0 and index_size=0 are supported"); - } - - if (version < 2) { - count = DBReadUShort(db); - } else { - count = DBReadUInt(db); - } - - for (i = 0; i < count && DBGetSize(db) > 2; i++) { - unsigned int - id, ext_count; - - HEICItemInfo - *item; - - id = DBReadUShort(db); - - /* - item indicies starts from 1 - */ - if ((id > (ssize_t) ctx->idsCount) || - (ctx->itemInfo == (HEICItemInfo *) NULL)) - ThrowAndReturn("item id is incorrect"); - - item = &ctx->itemInfo[id]; - - if (version == 1 || version == 2) { - item->dataSource = DBReadUShort(db); - } - - /* - * data ref index - */ - DBSkip(db, 2); - ext_count = DBReadUShort(db); - - if (ext_count != 1) { - ThrowAndReturn("only one excention per item is supported"); - } - - item->offset = DBReadUInt(db); - item->size = DBReadUInt(db); - } - - return MagickTrue; -} - -static MagickBooleanType ParseAtom(Image *image, DataBuffer *db, - HEICImageContext *ctx, ExceptionInfo *exception) -{ - DataBuffer - atomDb; - - MagickBooleanType - status; - - MagickSizeType - atom_size; - - unsigned int - atom; - - if (DBGetSize(db) < 8) - { - ThrowAndReturn("atom is too short"); - } - - atom_size = DBReadUInt(db); - atom = DBReadUInt(db); - - if (atom_size == 1) { - /* Only 32 bit atom size are supported */ - DBReadUInt(db); - atom_size = DBReadUInt(db); - } - - if (atom_size - 8 > DBGetSize(db)) - { - ThrowAndReturn("atom is too short"); - } - - if (DBChop(&atomDb, db, atom_size - 8) != MagickTrue) - { - ThrowAndReturn("unable to read atom"); - } - - status = MagickTrue; - - switch (atom) - { - case ATOM('i', 'r', 'e', 'f'): - status = ParseFullBox(image, &atomDb, atom, ctx, exception); - break; - case ATOM('i', 'p', 'r', 'p'): - status = ParseBox(image, &atomDb, atom, ctx, exception); - break; - case ATOM('i', 'i', 'n', 'f'): - status = ParseIinfAtom(image, &atomDb, ctx, exception); - break; - case ATOM('i', 'n', 'f', 'e'): - status = ParseInfeAtom(image, &atomDb, ctx, exception); - break; - case ATOM('i', 'p', 'c', 'o'): - status = ParseIpcoAtom(image, &atomDb, ctx, exception); - break; - case ATOM('i', 'p', 'm', 'a'): - status = ParseIpmaAtom(image, &atomDb, ctx, exception); - break; - case ATOM('i', 'l', 'o', 'c'): - status = ParseIlocAtom(image, &atomDb, ctx, exception); - break; - case ATOM('i', 'd', 'a', 't'): - { - ctx->idatSize = atom_size - 8; - if (ctx->idat != (uint8_t *) NULL) - ctx->idat = (uint8_t *) RelinquishMagickMemory(ctx->idat); - ctx->idat = (uint8_t *) AcquireMagickMemory(ctx->idatSize); - if (ctx->idat == (uint8_t *) NULL) - ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", - image->filename); - - memcpy(ctx->idat, atomDb.data, ctx->idatSize); - } - break; - default: - break; - } - - return status; -} - - -static MagickBooleanType ParseRootAtom(Image *image,MagickSizeType *size, - HEICImageContext *ctx,ExceptionInfo *exception) -{ - MagickBooleanType - status; - - MagickSizeType - atom_size; - - unsigned int - atom; - - if (*size < 8) - ThrowAndReturn("atom is too short"); - - atom_size = ReadBlobMSBLong(image); - atom = ReadBlobMSBLong(image); - - if (atom_size == 1) { - ReadBlobMSBLong(image); - atom_size = ReadBlobMSBLong(image); - } - - - if (atom_size > *size) - ThrowAndReturn("atom is too short"); - - status = MagickTrue; - - switch (atom) - { - case ATOM('f', 't', 'y', 'p'): - DiscardBlobBytes(image, atom_size-8); - break; - case ATOM('m', 'e', 't', 'a'): - { - DataBuffer - db; - - size_t - count; - - db.pos = 0; - db.size = atom_size - 8; - db.data = (unsigned char *) AcquireMagickMemory(db.size); - if (db.data == NULL) - ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", - image->filename); - - count = ReadBlob(image, db.size, db.data); - if (count != db.size) { - RelinquishMagickMemory((void *)db.data); - ThrowAndReturn("unable to read data"); - } - - /* - * Meta flags and version - */ - /* DBSkip(&db, 4); */ - status = ParseFullBox(image, &db, atom, ctx, exception); - RelinquishMagickMemory((void *)db.data); - } - break; - case ATOM('m', 'd', 'a', 't'): - ctx->finished = MagickTrue; - break; - default: - DiscardBlobBytes(image, atom_size-8); - break; - } - *size=*size-atom_size; - return(status); -} - -static MagickBooleanType decodeGrid(HEICImageContext *ctx, - ExceptionInfo *exception) -{ - unsigned int - i, flags; - - if (ctx->itemInfo == (HEICItemInfo *) NULL) - ThrowAndReturn("no atoms defined"); - for (i = 1; i <= (ssize_t) ctx->idsCount; i++) { - HEICItemInfo - *info = &ctx->itemInfo[i]; - if (info->type != ATOM('g','r','i','d')) - continue; - if (info->dataSource != 1) { - ThrowAndReturn("unsupport data source type"); - } - - if (ctx->idatSize < 8) { - ThrowAndReturn("idat is too small"); - } - - flags = ctx->idat[1]; - - ctx->grid.rowsMinusOne = ctx->idat[2]; - ctx->grid.columnsMinusOne = ctx->idat[3]; - - if (flags & 1) { - ThrowAndReturn("Only 16 bits sizes are supported"); - } - - ctx->grid.imageWidth = (ctx->idat[4] << 8) + ctx->idat[5]; - ctx->grid.imageHeight = (ctx->idat[6] << 8) + ctx->idat[7]; - - ctx->grid.id = i; - - return MagickTrue; - } - return MagickFalse; -} - -static MagickBooleanType decodeH265Image(Image *image, HEICImageContext *ctx, unsigned int id, ExceptionInfo *exception) -{ - unsigned char - *buffer = NULL; - - unsigned char - *p; - - size_t - count, pos, nal_unit_size; - - int - more, i; - - unsigned int - x_offset, y_offset; - - de265_error - err; - - pos = 0; - de265_reset(ctx->h265Ctx); - - x_offset = 512 * ((id-1) % (ctx->grid.columnsMinusOne + 1)); - y_offset = 512 * ((id-1) / (ctx->grid.columnsMinusOne + 1)); - - for (i = 0; i < (ssize_t) ctx->itemInfo[id].assocsCount; i++) { - ssize_t - assoc; - - assoc = ctx->itemInfo[id].assocs[i] & 0x7f; - if (assoc > ctx->itemPropsCount) { - ThrowImproperImageHeader("incorrect item property index"); - goto err_out_free; - } - - switch (ctx->itemProps[assoc].type) { - case ATOM('h', 'v', 'c', 'C'): - err = de265_push_data(ctx->h265Ctx, ctx->itemProps[assoc].data, ctx->itemProps[assoc].size, pos, (void*)2); - if (err != DE265_OK) { - ThrowImproperImageHeader("unable to push data"); - goto err_out_free; - } - - pos += ctx->itemProps[assoc].size; - break; - case ATOM('c', 'o', 'l', 'r'): - { - StringInfo - *profile; - - if (ctx->itemProps[assoc].size < 16) - continue; - - profile=BlobToStringInfo(ctx->itemProps[assoc].data + 4, ctx->itemProps[assoc].size - 4); - (void) SetImageProfile(image, "icc", profile, exception); - profile=DestroyStringInfo(profile); - break; - } - } - } - - buffer = (unsigned char *) AcquireMagickMemory(ctx->itemInfo[id].size); - if (buffer == NULL) { - (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError, - "MemoryAllocationFailed","`%s'",image->filename); - goto err_out_free; - } - - SeekBlob(image, ctx->itemInfo[id].offset, SEEK_SET); - count = ReadBlob(image, ctx->itemInfo[id].size, buffer); - if (count != ctx->itemInfo[id].size) { - ThrowImproperImageHeader("unable to read data"); - goto err_out_free; - } - - /* - * AVCC to AnnexB - */ - for (p = buffer; p < buffer + ctx->itemInfo[id].size; /* void */) { - nal_unit_size = readInt(p); - p[0] = 0; - p[1] = 0; - p[2] = 0; - p[3] = 1; - p += nal_unit_size + 4; - } - - err = de265_push_data(ctx->h265Ctx, buffer, ctx->itemInfo[id].size, pos, (void*)2); - if (err != DE265_OK) { - ThrowImproperImageHeader("unable to push data"); - goto err_out_free; - } - - err = de265_flush_data(ctx->h265Ctx); - if (err != DE265_OK) { - ThrowImproperImageHeader("unable to flush data"); - goto err_out_free; - } - - more = 0; - - do { - err = de265_decode(ctx->h265Ctx, &more); - if (err != DE265_OK) { - ThrowImproperImageHeader("unable to decode data"); - goto err_out_free; - } - - while (1) { - de265_error warning = de265_get_warning(ctx->h265Ctx); - if (warning==DE265_OK) { - break; - } - buffer = (unsigned char *) RelinquishMagickMemory(buffer); - ThrowBinaryException(CoderWarning,(const char *)NULL, - de265_get_error_text(warning)); - } - - const struct de265_image* img = de265_get_next_picture(ctx->h265Ctx); - if (img) { - const uint8_t *planes[3]; - int dims[3][2]; - int strides[3]; - - int c; - for (c = 0; c < 3; c++) { - planes[c] = de265_get_image_plane(img, c, &(strides[c])); - dims[c][0] = de265_get_image_width(img, c); - dims[c][1] = de265_get_image_height(img, c); - } - - - assert(dims[0][0] == 512); - assert(dims[0][1] == 512); - assert(dims[1][0] == 256); - assert(dims[1][1] == 256); - assert(dims[2][0] == 256); - assert(dims[2][1] == 256); - - Image* chroma; - - chroma = ctx->tmp; - - int x, y; - - for (y = 0; y < 256; y++) { - register Quantum *q; - register const uint8_t *p1 = planes[1] + y * strides[1]; - register const uint8_t *p2 = planes[2] + y * strides[2]; - - q = QueueAuthenticPixels(chroma, 0, y, 256, 1, exception); - if (q == NULL) { - goto err_out_free; - } - - for (x = 0; x < 256; x++) { - SetPixelGreen(chroma, ScaleCharToQuantum(*p1++), q); - SetPixelBlue(chroma, ScaleCharToQuantum(*p2++), q); - q+=GetPixelChannels(chroma); - } - - if (SyncAuthenticPixels(chroma, exception) == MagickFalse) { - goto err_out_free; - } - } - - Image* resized_chroma = ResizeImage(chroma, 512, 512, TriangleFilter, exception); - if (resized_chroma == NULL) { - goto err_out_free; - } - - for (y = 0; y < 512; y++) { - register Quantum *q; - register const Quantum *p; - register const uint8_t *l = planes[0] + y * strides[0]; - - q = QueueAuthenticPixels(image, x_offset, y_offset + y, 512, 1, exception); - if (q == NULL) { - goto err_loop_free; - } - - p = GetVirtualPixels(resized_chroma, 0, y, 512, 1, exception); - if (p == NULL) { - goto err_loop_free; - } - - for (x = 0; x < 512; x++) { - SetPixelRed(image, ScaleCharToQuantum(*l), q); - SetPixelGreen(image, GetPixelGreen(resized_chroma, p), q); - SetPixelBlue(image, GetPixelBlue(resized_chroma, p), q); - l++; - q+=GetPixelChannels(image); - p+=GetPixelChannels(resized_chroma); - } - - if (SyncAuthenticPixels(image, exception) == MagickFalse) { - goto err_loop_free; - } - } +% Read/Write Heic Image Format % +% % +% Dirk Farin % +% April 2018 % +% % +% Copyright 2018 Struktur AG % +% % +% Anton Kortunov % +% December 2017 % +% % +% Copyright 2017-2018 YANDEX LLC. % +% % +% You may not use this file except in compliance with the License. You may % +% obtain a copy of the License at % +% % +% https://www.imagemagick.org/script/license.php % +% % +% Unless required by applicable law or agreed to in writing, software % +% distributed under the License is distributed on an "AS IS" BASIS, % +% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % +% See the License for the specific language governing permissions and % +% limitations under the License. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% +*/ - if (resized_chroma) - resized_chroma = DestroyImage(resized_chroma); +/* + Include declarations. +*/ +#include "MagickCore/studio.h" +#include "MagickCore/artifact.h" +#include "MagickCore/blob.h" +#include "MagickCore/blob-private.h" +#include "MagickCore/client.h" +#include "MagickCore/colorspace-private.h" +#include "MagickCore/property.h" +#include "MagickCore/display.h" +#include "MagickCore/exception.h" +#include "MagickCore/exception-private.h" +#include "MagickCore/image.h" +#include "MagickCore/image-private.h" +#include "MagickCore/list.h" +#include "MagickCore/magick.h" +#include "MagickCore/monitor.h" +#include "MagickCore/monitor-private.h" +#include "MagickCore/montage.h" +#include "MagickCore/transform.h" +#include "MagickCore/memory_.h" +#include "MagickCore/memory-private.h" +#include "MagickCore/option.h" +#include "MagickCore/pixel-accessor.h" +#include "MagickCore/quantum-private.h" +#include "MagickCore/static.h" +#include "MagickCore/string_.h" +#include "MagickCore/string-private.h" +#include "MagickCore/module.h" +#include "MagickCore/utility.h" +#if defined(MAGICKCORE_HEIC_DELEGATE) +#include +#include +#endif - more = 0; - de265_release_next_picture(ctx->h265Ctx); - break; -err_loop_free: - if (resized_chroma) - resized_chroma = DestroyImage(resized_chroma); +static MagickBooleanType + WriteHEICImage(const ImageInfo *,Image *,ExceptionInfo *); - de265_release_next_picture(ctx->h265Ctx); - goto err_out_free; - } - } while (more); +/* + Typedef declarations. +*/ +#if defined(MAGICKCORE_HEIC_DELEGATE) - de265_reset(ctx->h265Ctx); - buffer = (unsigned char *) RelinquishMagickMemory(buffer); - return MagickTrue; -err_out_free: - de265_reset(ctx->h265Ctx); - buffer = (unsigned char *) RelinquishMagickMemory(buffer); - return MagickFalse; -} /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1083,31 +115,20 @@ err_out_free: % */ static Image *ReadHEICImage(const ImageInfo *image_info, - ExceptionInfo *exception) + ExceptionInfo *exception) { Image *image; - Image - *cropped = NULL; - MagickBooleanType status; - RectangleInfo - crop_info; - MagickSizeType length; ssize_t - count, - i; + count; - HEICImageContext - ctx; - - memset(&ctx, 0, sizeof(ctx)); /* Open image file. @@ -1116,190 +137,158 @@ static Image *ReadHEICImage(const ImageInfo *image_info, assert(image_info->signature == MagickCoreSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", - image_info->filename); + image_info->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickCoreSignature); image=AcquireImage(image_info,exception); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) - { - image=DestroyImageList(image); - return((Image *) NULL); - } - cropped=(Image *) NULL; + { + image=DestroyImageList(image); + return((Image *) NULL); + } length=GetBlobSize(image); - count = MAX_ATOMS_IN_BOX; - while (length && ctx.finished == MagickFalse && count--) - { - if (ParseRootAtom(image, &length, &ctx, exception) == MagickFalse) - goto cleanup; + + + uint8_t* filedata = (unsigned char *) AcquireMagickMemory(length); + if (filedata == NULL) + ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", + image->filename); + + count = ReadBlob(image, length, filedata); + if (count != length) { + RelinquishMagickMemory((void *)filedata); + + (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError, + "ImproperImageHeader","`%s'", "unable to read data"); + return(MagickFalse); } - if (ctx.finished != MagickTrue) - goto cleanup; /* - Initialize h265 decoder + Decode HEIF file */ - ctx.h265Ctx = de265_new_decoder(); - if (ctx.h265Ctx == NULL) { - ThrowImproperImageHeader("unable to initialize decode"); - goto cleanup; + + struct heif_context* heif_context = heif_context_alloc(); + struct heif_error error; + + error = heif_context_read_from_memory(heif_context, filedata,length, NULL); + if (error.code) { } - if (decodeGrid(&ctx, exception) != MagickTrue) - goto cleanup; + RelinquishMagickMemory((void *)filedata); + - count = (ctx.grid.rowsMinusOne + 1) * (ctx.grid.columnsMinusOne + 1); + struct heif_image_handle* image_handle = NULL; + error = heif_context_get_primary_image_handle(heif_context, &image_handle); + if (error.code) { + } + + + + /* + Set image size + */ - image->columns = 512 * (ctx.grid.columnsMinusOne + 1); - image->rows = 512 * (ctx.grid.rowsMinusOne + 1); - image->depth=8; + int width = heif_image_handle_get_width(image_handle); + int height = heif_image_handle_get_height(image_handle); - status=SetImageExtent(image,image->columns,image->rows,exception); + + status=SetImageExtent(image,width,height,exception); if (status == MagickFalse) goto cleanup; - if (image_info->ping == MagickFalse) - { - ctx.tmp = CloneImage(image, 256, 256, MagickTrue, exception); - if (ctx.tmp == NULL) { - (void) ThrowMagickException(exception,GetMagickModule(), - ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); - goto cleanup; - } - - DuplicateBlob(ctx.tmp, image); + image->depth = 8; - for (i = 0; i < count; i++) { - decodeH265Image(image, &ctx, i+1, exception); - } - } - crop_info.x = 0; - crop_info.y = 0; + struct heif_image* heif_image = NULL; - for (i = 0; i < ctx.itemInfo[ctx.grid.id].assocsCount; i++) { - ssize_t - assoc; + if (image_info->ping == MagickFalse) + { + /* + Copy HEIF image into ImageMagick data structures + */ - assoc = ctx.itemInfo[ctx.grid.id].assocs[i] & 0x7f; - if (assoc > ctx.itemPropsCount) { - ThrowImproperImageHeader("incorrect item property index"); - goto cleanup; - } + error = heif_decode_image(image_handle, + &heif_image, + heif_colorspace_YCbCr, + heif_chroma_420, + NULL); - switch (ctx.itemProps[assoc].type) { - case ATOM('i', 's', 'p', 'e'): - if (ctx.itemProps[assoc].size < 12) { - ThrowImproperImageHeader("ispe atom is too short"); - goto cleanup; - } - crop_info.width = readInt(ctx.itemProps[assoc].data+4); - crop_info.height = readInt(ctx.itemProps[assoc].data+8); - break; + uint8_t* p_y; + uint8_t* p_cb; + uint8_t* p_cr; + int stride_y, stride_cb, stride_cr; - case ATOM('i', 'r', 'o', 't'): - { - const char *value; + p_y = heif_image_get_plane(heif_image, heif_channel_Y, &stride_y); + p_cb = heif_image_get_plane(heif_image, heif_channel_Cb, &stride_cb); + p_cr = heif_image_get_plane(heif_image, heif_channel_Cr, &stride_cr); - if (ctx.itemProps[assoc].size < 1) { - ThrowImproperImageHeader("irot atom is too short"); - goto cleanup; - } - switch (ctx.itemProps[assoc].data[0]) - { - case 0: - image->orientation = TopLeftOrientation; - value = "1"; - break; - case 1: - image->orientation = RightTopOrientation; - value = "8"; - break; - case 2: - image->orientation = BottomRightOrientation; - value = "3"; - break; - case 3: - image->orientation = LeftTopOrientation; - value = "6"; - break; - default: - value = "1"; - } + int x,y; + Quantum* q; - SetImageProperty(image, "exif:Orientation", value, exception); + for (y=0; y < (long) height; y++) + { + q=QueueAuthenticPixels(image,0,y,width,1,exception); + if (q == (Quantum *) NULL) + break; + + for (x=0; x < (long) width; x++) + { + SetPixelRed(image,ScaleCharToQuantum(p_y[y*stride_y + x]),q); + SetPixelGreen(image,ScaleCharToQuantum(p_cb[(y/2)*stride_cb + x/2]),q); + SetPixelBlue(image,ScaleCharToQuantum(p_cr[(y/2)*stride_cr + x/2]),q); + q+=GetPixelChannels(image); + } + + if (SyncAuthenticPixels(image,exception) == MagickFalse) + break; } - break; + + SetImageColorspace(image,YCbCrColorspace,exception); } - } - for (i = 1; i <= ctx.idsCount; i++) { - unsigned char - *buffer = NULL; + /* + Read Exif data from HEIC file + */ - StringInfo - *profile; + heif_item_id exif_id; + int nMetadata = heif_image_handle_get_list_of_metadata_block_IDs(image_handle, + "Exif", + &exif_id, 1); - HEICItemInfo - *info = &ctx.itemInfo[i]; + if (nMetadata > 0) { + size_t exif_size = heif_image_handle_get_metadata_size(image_handle, + exif_id); - if (info->type != ATOM('E','x','i','f')) - continue; - if (info->size <= 4) - continue; + uint8_t* exif_buffer = (unsigned char *) AcquireMagickMemory(exif_size); - buffer = (unsigned char *) AcquireMagickMemory(info->size); - if (buffer == NULL) { - (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError, - "MemoryAllocationFailed","`%s'",image->filename); - goto cleanup; - } + error = heif_image_handle_get_metadata(image_handle, + exif_id, + exif_buffer); - SeekBlob(image, info->offset+4, SEEK_SET); - count = ReadBlob(image, info->size-4, buffer); - profile=BlobToStringInfo(buffer, count); + StringInfo* profile = BlobToStringInfo(exif_buffer, exif_size); SetImageProfile(image, "exif", profile, exception); profile = DestroyStringInfo(profile); - RelinquishMagickMemory(buffer); + RelinquishMagickMemory(exif_buffer); } - cropped = CropImage(image, &crop_info, exception); - image = DestroyImage(image); - if (cropped != NULL) - { - if (image_info->ping != MagickFalse) - cropped->colorspace=YCbCrColorspace; - else - SetImageColorspace(cropped,YCbCrColorspace,exception); - } -cleanup: - if (image) { - image = DestroyImage(image); - } - if (ctx.h265Ctx) { - de265_free_decoder(ctx.h265Ctx); - } - if (ctx.tmp) { - ctx.tmp = DestroyImage(ctx.tmp); - } - if (ctx.idat) { - ctx.idat = (uint8_t *) RelinquishMagickMemory(ctx.idat); - } - if (ctx.itemInfo) { - ctx.itemInfo = (HEICItemInfo *) RelinquishMagickMemory(ctx.itemInfo); - } - for (i = 1; i <= ctx.itemPropsCount; i++) { - if (ctx.itemProps[i].data) { - ctx.itemProps[i].data = (uint8_t *) RelinquishMagickMemory(ctx.itemProps[i].data); - } - } - return cropped; + cleanup: + + if (heif_image) + heif_image_release(heif_image); + + if (image_handle) + heif_image_handle_release(image_handle); + + if (heif_context) + heif_context_free(heif_context); + + return image; } #endif @@ -1364,9 +353,10 @@ ModuleExport size_t RegisterHEICImage(void) MagickInfo *entry; - entry=AcquireMagickInfo("HEIC","HEIC","Apple High efficiency Image Format"); + entry=AcquireMagickInfo("HEIC","HEIC","High Efficiency Image Format"); #if defined(MAGICKCORE_HEIC_DELEGATE) entry->decoder=(DecodeImageHandler *) ReadHEICImage; + entry->encoder=(EncodeImageHandler *) WriteHEICImage; #endif entry->magick=(IsImageFormatHandler *) IsHEIC; entry->mime_type=ConstantString("image/x-heic"); @@ -1399,3 +389,276 @@ ModuleExport void UnregisterHEICImage(void) { (void) UnregisterMagickInfo("HEIC"); } + + + +static struct heif_error heif_write_func(struct heif_context* ctx, + const void* data, + size_t size, + void* userdata) +{ + Image* image = (Image*)userdata; + (void) WriteBlob(image, size, data); + + struct heif_error error_ok; + error_ok.code = heif_error_Ok; + error_ok.subcode = heif_suberror_Unspecified; + error_ok.message = "ok"; + return error_ok; +} + + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% W r i t e H E I C I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% WriteHEICImage() writes an HEIF image using the libheif library. +% +% The format of the WriteHEICImage method is: +% +% MagickBooleanType WriteHEICImage(const ImageInfo *image_info, +% Image *image) +% +% A description of each parameter follows. +% +% o image_info: the image info. +% +% o image: The image. +% +% o exception: return any errors or warnings in this structure. +% +*/ +#if defined(MAGICKCORE_HEIC_DELEGATE) +static MagickBooleanType WriteHEICImage(const ImageInfo *image_info,Image *image, + ExceptionInfo *exception) +{ + long + y; + + MagickBooleanType + status; + + MagickOffsetType + scene; + + const Quantum + *src; + + long + x; + + /* + Open output image file. + */ + assert(image_info != (const ImageInfo *) NULL); + assert(image_info->signature == MagickCoreSignature); + assert(image != (Image *) NULL); + assert(image->signature == MagickCoreSignature); + if (image->debug != MagickFalse) + (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); + status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); + if (status == MagickFalse) + return(status); + scene=0; + + + struct heif_context* heif_context = heif_context_alloc(); + struct heif_image* heif_image = NULL; + struct heif_encoder* heif_encoder = NULL; + + do + { + /* Initialize HEIF encoder context + */ + + struct heif_error error; + error = heif_image_create(image->columns, image->rows, + heif_colorspace_YCbCr, + heif_chroma_420, + &heif_image); + if (error.code) { + (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning, + error.message,"`%s'",image->filename); + goto error_cleanup; + } + + error = heif_image_add_plane(heif_image, + heif_channel_Y, + image->columns, image->rows, 8); + if (error.code) { + (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning, + error.message,"`%s'",image->filename); + goto error_cleanup; + } + + error = heif_image_add_plane(heif_image, + heif_channel_Cb, + (image->columns+1)/2, (image->rows+1)/2, 8); + if (error.code) { + (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning, + error.message,"`%s'",image->filename); + goto error_cleanup; + } + + error = heif_image_add_plane(heif_image, + heif_channel_Cr, + (image->columns+1)/2, (image->rows+1)/2, 8); + if (error.code) { + (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning, + error.message,"`%s'",image->filename); + goto error_cleanup; + } + + + uint8_t* p_y; + uint8_t* p_cb; + uint8_t* p_cr; + int stride_y, stride_cb, stride_cr; + + p_y = heif_image_get_plane(heif_image, heif_channel_Y, &stride_y); + p_cb = heif_image_get_plane(heif_image, heif_channel_Cb, &stride_cb); + p_cr = heif_image_get_plane(heif_image, heif_channel_Cr, &stride_cr); + + /* + Transform colorspace to YCbCr. + */ + if (image->colorspace != YCbCrColorspace) { + (void) TransformImageColorspace(image,YCbCrColorspace,exception); + } + + + /* + Copy image to heif_image + */ + + for (y=0; y < (long) image->rows; y++) + { + src=GetVirtualPixels(image,0,y,image->columns,1,exception); + if (src == (const Quantum *) NULL) + break; + + if ((y & 1)==0) + { + for (x=0; x < (long) image->columns; x+=2) + { + p_y[y*stride_y + x] = ScaleQuantumToChar(GetPixelRed(image,src)); + p_cb[y/2*stride_cb + x/2] = ScaleQuantumToChar(GetPixelGreen(image,src)); + p_cr[y/2*stride_cr + x/2] = ScaleQuantumToChar(GetPixelBlue(image,src)); + src+=GetPixelChannels(image); + + if (x+1 < image->columns) { + p_y[y*stride_y + x+1] = ScaleQuantumToChar(GetPixelRed(image,src)); + src+=GetPixelChannels(image); + } + } + } + else + { + for (x=0; x < (long) image->columns; x++) + { + p_y[y*stride_y + x] = ScaleQuantumToChar(GetPixelRed(image,src)); + src+=GetPixelChannels(image); + } + } + + + if (image->previous == (Image *) NULL) + if ((image->progress_monitor != (MagickProgressMonitor) NULL) && + (QuantumTick(y,image->rows) != MagickFalse)) + { + status=image->progress_monitor(SaveImageTag,y,image->rows, + image->client_data); + if (status == MagickFalse) + break; + } + } + + + /* + Code and actually write the HEIC image + */ + + error = heif_context_get_encoder_for_format(heif_context, + heif_compression_HEVC, + &heif_encoder); + if (error.code) { + (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning, + error.message,"`%s'",image->filename); + goto error_cleanup; + } + + + if (image_info->quality != UndefinedCompressionQuality) { + error = heif_encoder_set_lossy_quality(heif_encoder, + image_info->quality); + if (error.code) { + (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning, + error.message,"`quality=%zu'",image_info->quality); + + goto error_cleanup; + } + } + + error = heif_context_encode_image(heif_context, + heif_image, + heif_encoder, + NULL, + NULL); + if (error.code) { + (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning, + error.message,"`%s'",image->filename); + goto error_cleanup; + } + + struct heif_writer writer; + writer.writer_api_version = 1; + writer.write = heif_write_func; + + error = heif_context_write(heif_context, &writer, image); + if (error.code) { + (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning, + error.message,"`%s'",image->filename); + goto error_cleanup; + } + + + heif_image_release(heif_image); + heif_image = NULL; + + heif_encoder_release(heif_encoder); + heif_encoder = NULL; + + + if (GetNextImageInList(image) == (Image *) NULL) + break; + + image=SyncNextImageInList(image); + status=SetImageProgress(image,SaveImagesTag,scene, + GetImageListLength(image)); + if (status == MagickFalse) + break; + scene++; + } while (image_info->adjoin != MagickFalse); + + + if (heif_context) { + heif_context_free(heif_context); + } + + (void) CloseBlob(image); + return(MagickTrue); + + +error_cleanup: + heif_image_release(heif_image); + heif_encoder_release(heif_encoder); + return MagickFalse; +} +#endif diff --git a/configure.ac b/configure.ac index abfe1e11e..6d1d5aa42 100644 --- a/configure.ac +++ b/configure.ac @@ -2263,23 +2263,23 @@ if test "$with_heic" != 'yes'; then fi have_heic='no' -HEIC_CFLAGS="" -HEIC_LIBS="" -HEIC_PKG="" +HEIF_CFLAGS="" +HEIF_LIBS="" +HEIF_PKG="" if test "x$with_heic" = "xyes"; then AC_MSG_RESULT([-------------------------------------------------------------]) - PKG_CHECK_MODULES(HEIC,[libde265], have_heic=yes, have_heic=no) + PKG_CHECK_MODULES(HEIF,[libheif], have_heic=yes, have_heic=no) AC_MSG_RESULT([]) fi if test "$have_heic" = 'yes'; then - AC_DEFINE(HEIC_DELEGATE,1,Define if you have HEIC library) - CFLAGS="$HEIC_CFLAGS $CFLAGS" + AC_DEFINE(HEIC_DELEGATE,1,Define if you have libheif library) + CFLAGS="$HEIF_CFLAGS $CFLAGS" fi AM_CONDITIONAL(HEIC_DELEGATE, test "$have_heic" = 'yes') -AC_SUBST(HEIC_CFLAGS) -AC_SUBST(HEIC_LIBS) +AC_SUBST(HEIF_CFLAGS) +AC_SUBST(HEIF_LIBS) dnl =========================================================================== @@ -3884,7 +3884,7 @@ fi if test "$build_modules" != 'no'; then MAGICK_DEP_LIBS="$USER_LIBS $LCMS_LIBS $FREETYPE_LIBS $RAQM_LIBS $LQR_LIBS $FFTW_LIBS $XML_LIBS $FLIF_LIBS $FONTCONFIG_LIBS $XEXT_LIBS $IPC_LIBS $X11_LIBS $XT_LIBS $LZMA_LIBS $BZLIB_LIBS $ZLIB_LIBS $LTDL_LIBS $GDI32_LIBS $MATH_LIBS $GOMP_LIBS $CL_LIBS $UMEM_LIBS $JEMALLOC_LIBS $THREAD_LIBS" else - MAGICK_DEP_LIBS="$USER_LIBS $JBIG_LIBS $LCMS_LIBS $TIFF_LIBS $FREETYPE_LIBS $RAQM_LIBS $JPEG_LIBS $GS_LIBS $LQR_LIBS $PNG_LIBS $AUTOTRACE_LIBS $DJVU_LIBS $FFTW_LIBS $FLIF_LIBS $FPX_LIBS $FONTCONFIG_LIBS $HEIC_LIBS $WEBPMUX_LIBS $WEBP_LIBS $WMF_LIBS $DPS_LIBS $XEXT_LIBS $XT_LIBS $IPC_LIBS $X11_LIBS $LZMA_LIBS $BZLIB_LIBS $OPENEXR_LIBS $LIBOPENJP2_LIBS $PANGO_LIBS $RAW_R_LIBS $RSVG_LIBS $XML_LIBS $GVC_LIBS $ZLIB_LIBS $LTDL_LIBS $GDI32_LIBS $MATH_LIBS $GOMP_LIBS $CL_LIBS $UMEM_LIBS $JEMALLOC_LIBS $THREAD_LIBS" + MAGICK_DEP_LIBS="$USER_LIBS $JBIG_LIBS $LCMS_LIBS $TIFF_LIBS $FREETYPE_LIBS $RAQM_LIBS $JPEG_LIBS $GS_LIBS $LQR_LIBS $PNG_LIBS $AUTOTRACE_LIBS $DJVU_LIBS $FFTW_LIBS $FLIF_LIBS $FPX_LIBS $FONTCONFIG_LIBS $HEIF_LIBS $WEBPMUX_LIBS $WEBP_LIBS $WMF_LIBS $DPS_LIBS $XEXT_LIBS $XT_LIBS $IPC_LIBS $X11_LIBS $LZMA_LIBS $BZLIB_LIBS $OPENEXR_LIBS $LIBOPENJP2_LIBS $PANGO_LIBS $RAW_R_LIBS $RSVG_LIBS $XML_LIBS $GVC_LIBS $ZLIB_LIBS $LTDL_LIBS $GDI32_LIBS $MATH_LIBS $GOMP_LIBS $CL_LIBS $UMEM_LIBS $JEMALLOC_LIBS $THREAD_LIBS" fi AC_SUBST(MAGICK_DEP_LIBS) @@ -4033,7 +4033,7 @@ matches your expectations. FreeType --with-freetype=$with_freetype $have_freetype Ghostscript lib --with-gslib=$with_gslib $have_gslib Graphviz --with-gvc=$with_gvc $have_gvc - HEIC --with-heic=$with_heic $have_heic + HEIC --with-heic=$with_heic $have_heic JBIG --with-jbig=$with_jbig $have_jbig JPEG v1 --with-jpeg=$with_jpeg $have_jpeg LCMS --with-lcms=$with_lcms $have_lcms