forked from old/legacy-imlib2
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:
parent
5261da4a6e
commit
b9668a0851
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *));
|
||||
}
|
Loading…
Reference in New Issue