imlib2: added loader for HEIF files (uses libheif), implemented just `load2` for now

Summary: Implemented a loader for HEIF images. Uses libheif, and implemented the `load2` function as of now

Reviewers: raster

Subscribers: Colocasian, eworm, kwo

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D12267
This commit is contained in:
Rishvic Pushpakaran 2022-01-26 00:31:17 +05:30 committed by Kim Woelders
parent 5261da4a6e
commit b9668a0851
3 changed files with 197 additions and 0 deletions

View File

@ -199,6 +199,7 @@ EC_LOADER_CHECK(PNG, auto, libpng)
EC_LOADER_CHECK(SVG, auto, librsvg-2.0)
EC_LOADER_CHECK(TIFF, auto, libtiff-4)
EC_LOADER_CHECK(WEBP, auto, libwebpdemux)
EC_LOADER_CHECK(HEIF, auto, libheif)
loader_check_bz2() {
AC_CHECK_LIB(bz2, BZ2_bzRead, bz2_ok=yes, bz2_ok=no)
@ -278,6 +279,7 @@ echo " PNG.....................: $png_ok"
echo " SVG.....................: $svg_ok"
echo " TIFF....................: $tiff_ok"
echo " WEBP....................: $webp_ok"
echo " HEIF....................: $heif_ok"
echo " Decompressors"
echo " BZIP2...................: $bz2_ok"
echo " LZMA(XZ)................: $lzma_ok"

View File

@ -32,6 +32,9 @@ endif
if BUILD_WEBP_LOADER
pkg_LTLIBRARIES += webp.la
endif
if BUILD_HEIF_LOADER
pkg_LTLIBRARIES += heif.la
endif
if BUILD_BZ2_LOADER
pkg_LTLIBRARIES += bz2.la
@ -119,6 +122,12 @@ webp_la_LDFLAGS = -module -avoid-version
webp_la_LIBADD = $(WEBP_LIBS) $(top_builddir)/src/lib/libImlib2.la
webp_la_LIBTOOLFLAGS = --tag=disable-static
heif_la_SOURCES = loader_heif.c
heif_la_CPPFLAGS = $(HEIF_CFLAGS) $(AM_CPPFLAGS)
heif_la_LDFLAGS = -module -avoid-version
heif_la_LIBADD = $(HEIF_LIBS) $(top_builddir)/src/lib/libImlib2.la
heif_la_LIBTOOLFLAGS = --tag=disable-static
xbm_la_SOURCES = loader_xbm.c
xbm_la_LDFLAGS = -module -avoid-version
xbm_la_LIBADD = $(top_builddir)/src/lib/libImlib2.la

View File

@ -0,0 +1,186 @@
/*
* Loader for HEIF images.
*
* Only loads the primary image for any file, whether it be a still image or an
* image sequence.
*/
#include "loader_common.h"
#include <libheif/heif.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#define HEIF_BYTES_TO_CHECK 12L
#define HEIF_8BIT_TO_PIXEL_ARGB(plane, has_alpha) \
PIXEL_ARGB((has_alpha) ? (plane)[3] : 0xff, (plane)[0], (plane)[1], (plane)[2])
int
load2(ImlibImage * im, int load_data)
{
int rc;
int encoded_fd;
struct stat stats;
void *address = MAP_FAILED;
uint8_t *encoded_data = NULL;
int img_has_alpha;
int stride = 0;
int bytes_per_px;
int y, x;
struct heif_error error;
struct heif_context *ctx = NULL;
struct heif_image_handle *img_handle = NULL;
struct heif_image *img_data = NULL;
struct heif_decoding_options *decode_opts = NULL;
DATA32 *ptr;
const uint8_t *img_plane = NULL;
rc = LOAD_FAIL;
encoded_fd = fileno(im->fp);
if (encoded_fd == -1)
goto quit;
if (fstat(encoded_fd, &stats) == -1)
goto quit;
/* input data needs to be atleast 12 bytes */
if (stats.st_size < HEIF_BYTES_TO_CHECK)
goto quit;
address = mmap(0, stats.st_size, PROT_READ, MAP_PRIVATE, encoded_fd, 0);
if (address == MAP_FAILED)
goto quit;
/* Convert address to array of uint8_t. */
encoded_data = (uint8_t *) address;
/* check signature */
switch (heif_check_filetype(encoded_data, stats.st_size))
{
case heif_filetype_no:
case heif_filetype_yes_unsupported:
goto quit;
/* Have to let heif_filetype_maybe through because mif1 brand gives
* heif_filetype_maybe on check */
case heif_filetype_maybe:
case heif_filetype_yes_supported:
break;
}
ctx = heif_context_alloc();
if (!ctx)
goto quit;
error =
heif_context_read_from_memory_without_copy(ctx, encoded_data,
stats.st_size, NULL);
if (error.code != heif_error_Ok)
goto quit;
error = heif_context_get_primary_image_handle(ctx, &img_handle);
if (error.code != heif_error_Ok)
goto quit;
/* Freeing heif_context, since we got primary image handle */
heif_context_free(ctx);
ctx = NULL;
im->w = heif_image_handle_get_width(img_handle);
im->h = heif_image_handle_get_height(img_handle);
if (!IMAGE_DIMENSIONS_OK(im->w, im->h))
goto quit;
img_has_alpha = heif_image_handle_has_alpha_channel(img_handle);
if (img_has_alpha)
SET_FLAG(im->flags, F_HAS_ALPHA);
else
UNSET_FLAG(im->flags, F_HAS_ALPHA);
if (!load_data)
{
rc = LOAD_SUCCESS;
goto quit;
}
/* load data */
/* Set decoding option to convert HDR to 8-bit if libheif>=1.7.0 and
* successful allocation of heif_decoding_options */
#if LIBHEIF_HAVE_VERSION(1, 7, 0)
decode_opts = heif_decoding_options_alloc();
if (decode_opts)
decode_opts->convert_hdr_to_8bit = 1;
#endif
error =
heif_decode_image(img_handle, &img_data, heif_colorspace_RGB,
img_has_alpha ? heif_chroma_interleaved_RGBA :
heif_chroma_interleaved_RGB, decode_opts);
heif_decoding_options_free(decode_opts);
decode_opts = NULL;
if (error.code != heif_error_Ok)
goto quit;
im->w = heif_image_get_width(img_data, heif_channel_interleaved);
im->h = heif_image_get_height(img_data, heif_channel_interleaved);
if (!IMAGE_DIMENSIONS_OK(im->w, im->h))
goto quit;
ptr = __imlib_AllocateData(im);
if (!ptr)
goto quit;
img_plane =
heif_image_get_plane_readonly(img_data, heif_channel_interleaved,
&stride);
if (!img_plane)
goto quit;
/* Divide the number of bits per pixel by 8, always rounding up */
bytes_per_px =
(heif_image_get_bits_per_pixel(img_data, heif_channel_interleaved) +
7) >> 3;
/* If somehow bytes_per_pixel < 1, set it to 1 */
bytes_per_px = bytes_per_px < 1 ? 1 : bytes_per_px;
/* Correct the stride, since img_plane will be incremented after each pixel */
stride -= im->w * bytes_per_px;
for (y = 0; y != im->h; y++, img_plane += stride)
{
for (x = 0; x != im->w; x++, img_plane += bytes_per_px)
*(ptr++) = HEIF_8BIT_TO_PIXEL_ARGB(img_plane, img_has_alpha);
/* Report progress of each row. */
if (im->lc && __imlib_LoadProgressRows(im, y, 1))
{
rc = LOAD_BREAK;
goto quit;
}
}
rc = LOAD_SUCCESS;
quit:
/* Remove mapping if address is not MAP_FAILED. */
if (address != MAP_FAILED)
munmap(address, stats.st_size);
/* Free memory if it is still allocated.
* Working this way means explicitly setting pointers to NULL if they were
* freed beforehand to avoid freeing twice. */
/* decode_opts was freed as soon as decoding was complete */
heif_image_release(img_data);
heif_image_handle_release(img_handle);
heif_context_free(ctx);
heif_decoding_options_free(decode_opts);
return rc;
}
void
formats(ImlibLoader * l)
{
static const char *const list_formats[] =
{ "heif", "heifs", "heic", "heics", "avci", "avcs", "avif", "avifs" };
__imlib_LoaderSetFormats(l, list_formats,
sizeof(list_formats) / sizeof(char *));
}