Skip to content

Commit

Permalink
Merge pull request #107 from ohwgiles/feature/gdk-pixbuf
Browse files Browse the repository at this point in the history
Implement gdk-pixbuf loader
  • Loading branch information
fancycode committed Feb 6, 2019
2 parents e70e4b6 + 034e3c4 commit 9d96532
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 1 deletion.
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -63,3 +63,4 @@ endif()

add_subdirectory (examples)
add_subdirectory (libheif)
add_subdirectory (gdk-pixbuf)
1 change: 1 addition & 0 deletions Makefile.am
Expand Up @@ -5,6 +5,7 @@ SUBDIRS = \
examples \
extra \
fuzzing \
gdk-pixbuf \
gnome \
go \
scripts
Expand Down
26 changes: 26 additions & 0 deletions configure.ac
Expand Up @@ -131,6 +131,31 @@ PKG_CHECK_MODULES([libpng], [libpng], [
], [have_libpng="no"])
AM_CONDITIONAL([HAVE_LIBPNG], [test "x$have_libpng" = "xyes"])

AC_ARG_ENABLE([gdk-pixbuf], AS_HELP_STRING([--disable-gdk-pixbuf],
[Disable building of gdk-pixbuf plugin.]))
if eval "test x$enable_gdk_pixbuf = x" ; then enable_gdk_pixbuf=yes ; fi
if eval "test x$enable_gdk_pixbuf != xno"; then
PKG_CHECK_MODULES([gdkpixbuf], [gdk-pixbuf-2.0], [
AC_DEFINE([HAVE_GDKPIXBUF2], [1], [Whether gdk-pixbuf-2.0 was found.])
AC_SUBST(gdkpixbuf_CFLAGS)
AC_SUBST(gdkpixbuf_LIBS)
have_gdkpixbuf2="yes"
], [have_gdkpixbuf2="no"])
fi
AM_CONDITIONAL([HAVE_GDKPIXBUF2], [test "x$have_gdkpixbuf2" = "xyes"])

if eval "test x$have_gdkpixbuf2 = xyes"; then
gdk_pixbuf_binary_version="`$PKG_CONFIG --variable=gdk_pixbuf_binary_version gdk-pixbuf-2.0`"
gdk_pixbuf_binarydir="`$PKG_CONFIG --variable=gdk_pixbuf_binarydir gdk-pixbuf-2.0`"
gdk_pixbuf_moduledir=`$PKG_CONFIG --variable gdk_pixbuf_moduledir gdk-pixbuf-2.0`
gdk_pixbuf_cache_file=`$PKG_CONFIG --variable gdk_pixbuf_cache_file gdk-pixbuf-2.0`

AC_SUBST([gdk_pixbuf_binary_version])
AC_SUBST([gdk_pixbuf_binarydir])
AC_SUBST([gdk_pixbuf_moduledir])
AC_SUBST([gdk_pixbuf_cache_file])
fi

AC_ARG_ENABLE([libfuzzer], AS_HELP_STRING([--enable-libfuzzer],
[Enable fuzzing with libFuzzer.]))
if eval "test x$enable_libfuzzer = xyes"; then
Expand Down Expand Up @@ -168,6 +193,7 @@ AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([examples/Makefile])
AC_CONFIG_FILES([extra/Makefile])
AC_CONFIG_FILES([fuzzing/Makefile])
AC_CONFIG_FILES([gdk-pixbuf/Makefile])
AC_CONFIG_FILES([go/Makefile])
AC_CONFIG_FILES([gnome/Makefile])
AC_CONFIG_FILES([scripts/Makefile])
Expand Down
15 changes: 15 additions & 0 deletions gdk-pixbuf/CMakeLists.txt
@@ -0,0 +1,15 @@
if(UNIX)
include (${CMAKE_ROOT}/Modules/FindPkgConfig.cmake)
pkg_check_modules (GDKPIXBUF2 gdk-pixbuf-2.0)

if(GDKPIXBUF2_FOUND)
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} gdk-pixbuf-2.0 --variable gdk_pixbuf_moduledir OUTPUT_VARIABLE GDKPIXBUF2_MODULE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)

add_library(pixbufloader-heif MODULE pixbufloader-heif.c)

target_include_directories(pixbufloader-heif PRIVATE ${GDKPIXBUF2_INCLUDE_DIRS})
target_link_libraries(pixbufloader-heif PUBLIC ${GDKPIXBUF2_LIBRARIES} ${LIBHEIF_LIBRARY_NAME})

install(TARGETS pixbufloader-heif LIBRARY DESTINATION ${GDKPIXBUF2_MODULE_DIR})
endif()
endif()
13 changes: 13 additions & 0 deletions gdk-pixbuf/Makefile.am
@@ -0,0 +1,13 @@
AUTOMAKE_OPTIONS = subdir-objects

gdk_pixbuf_module_LTLIBRARIES =

if HAVE_GDKPIXBUF2
gdk_pixbuf_module_LTLIBRARIES += libpixbufloader-heif.la
libpixbufloader_heif_la_DEPENDENCIES = ../libheif/libheif.la
libpixbufloader_heif_la_CFLAGS = -I$(top_srcdir) -I$(top_builddir) $(gdkpixbuf_CFLAGS)
libpixbufloader_heif_la_LIBADD = ../libheif/libheif.la $(gdkpixbuf_LIBS)
libpixbufloader_heif_la_SOURCES = pixbufloader-heif.c
endif

EXTRA_DIST = CMakeLists.txt
172 changes: 172 additions & 0 deletions gdk-pixbuf/pixbufloader-heif.c
@@ -0,0 +1,172 @@
/*
* gdk-pixbuf loader module for libheif
* Copyright (c) 2019 Oliver Giles <ohw.giles@gmail.com>
*
* This file is part of libheif.
*
* libheif is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libheif is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libheif. If not, see <http://www.gnu.org/licenses/>.
*/

#define GDK_PIXBUF_ENABLE_BACKEND

#include <gdk-pixbuf/gdk-pixbuf-io.h>
#include <libheif/heif.h>

G_MODULE_EXPORT void fill_vtable (GdkPixbufModule* module);
G_MODULE_EXPORT void fill_info (GdkPixbufFormat* info);

typedef struct {
GdkPixbufModuleUpdatedFunc update_func;
GdkPixbufModulePreparedFunc prepare_func;
GdkPixbufModuleSizeFunc size_func;
gpointer user_data;
GByteArray* data;
} HeifPixbufCtx;

static gpointer begin_load(GdkPixbufModuleSizeFunc size_func, GdkPixbufModulePreparedFunc prepare_func, GdkPixbufModuleUpdatedFunc update_func, gpointer user_data, GError** error)
{
HeifPixbufCtx* hpc;

hpc = g_new0(HeifPixbufCtx, 1);
hpc->data = g_byte_array_new();
hpc->size_func = size_func;
hpc->prepare_func = prepare_func;
hpc->update_func = update_func;
hpc->user_data = user_data;
return hpc;
}

static void cleanup_heif_context(guchar* pixels, gpointer data)
{
heif_context_free((struct heif_context*) data);
}

static gboolean stop_load(gpointer context, GError** error)
{
HeifPixbufCtx* hpc;
struct heif_error err;
struct heif_context* hc;
struct heif_image_handle* hdl;
struct heif_image* img;
int width, height, stride;
int requested_width, requested_height;
const uint8_t* data;
GdkPixbuf* pixbuf;
gboolean result;

result = FALSE;
hpc = (HeifPixbufCtx*) context;

hc = heif_context_alloc();

err = heif_context_read_from_memory_without_copy(hc, hpc->data->data, hpc->data->len, NULL);
if(err.code != heif_error_Ok) {
g_warning("%s", err.message);
goto cleanup;
}

err = heif_context_get_primary_image_handle(hc, &hdl);
if(err.code != heif_error_Ok) {
g_warning("%s", err.message);
goto cleanup;
}

err = heif_decode_image(hdl, &img, heif_colorspace_RGB, heif_chroma_interleaved_RGBA, NULL);
if(err.code != heif_error_Ok) {
g_warning("%s", err.message);
goto cleanup;
}

width = heif_image_get_width(img, heif_channel_interleaved);
height = heif_image_get_height(img, heif_channel_interleaved);
requested_width = 0;
requested_height = 0;
if(hpc->size_func)
(*hpc->size_func)(&requested_width, &requested_height, hpc->user_data);

if(requested_width == 0 || requested_height == 0) {
width = heif_image_get_width(img, heif_channel_interleaved);
height = heif_image_get_height(img, heif_channel_interleaved);
} else {
struct heif_image* resized;
heif_image_scale_image(img, &resized, requested_width, requested_height, NULL);
heif_image_release(img);
img = resized;
}

data = heif_image_get_plane_readonly(img, heif_channel_interleaved, &stride);

pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, TRUE, 8, width, height, stride, cleanup_heif_context, hc);

if(hpc->prepare_func)
(*hpc->prepare_func)(pixbuf, NULL, hpc->user_data);

if(hpc->update_func != NULL)
(*hpc->update_func)(pixbuf, 0, 0, gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), hpc->user_data);

result = TRUE;

cleanup:
if(!result)
heif_context_free(hc);

g_byte_array_free(hpc->data, TRUE);
g_free(hpc);

return result;
}

static gboolean load_increment(gpointer context, const guchar* buf, guint size, GError** error)
{
HeifPixbufCtx* ctx = (HeifPixbufCtx*) context;
g_byte_array_append(ctx->data, buf, size);
return TRUE;
}

void fill_vtable(GdkPixbufModule* module)
{
module->begin_load = begin_load;
module->stop_load = stop_load;
module->load_increment = load_increment;
}

void fill_info(GdkPixbufFormat* info)
{
static GdkPixbufModulePattern signature[] = {
{ " ftyp", "xxxx ", 100 },
{ NULL, NULL, 0 }
};

static gchar *mime_types[] = {
"image/heif",
"image/heic",
NULL
};

static gchar *extensions[] = {
"heif",
"heic",
NULL
};

info->name = "heif";
info->signature = signature;
info->domain = "pixbufloader-heif";
info->description = "HEIF Image";
info->mime_types = mime_types;
info->extensions = extensions;
info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
info->disabled = FALSE;
info->license = "LGPL3";
}
1 change: 1 addition & 0 deletions scripts/install-ci-linux.sh
Expand Up @@ -74,6 +74,7 @@ fi

if [ ! -z "$WITH_GRAPHICS" ]; then
INSTALL_PACKAGES="$INSTALL_PACKAGES \
libgdk-pixbuf2.0-dev \
libjpeg-dev \
libpng-dev \
"
Expand Down
2 changes: 1 addition & 1 deletion scripts/prepare-ci.sh
Expand Up @@ -49,7 +49,7 @@ if [ -z "$CHECK_LICENSES" ] && [ -z "$CPPLINT" ] && [ -z "$CMAKE" ]; then
CONFIGURE_ARGS="$CONFIGURE_ARGS --host=$CONFIGURE_HOST"
fi
if [ ! -z "$GO" ]; then
CONFIGURE_ARGS="$CONFIGURE_ARGS --prefix=$BUILD_ROOT/dist"
CONFIGURE_ARGS="$CONFIGURE_ARGS --prefix=$BUILD_ROOT/dist --disable-gdk-pixbuf"
else
CONFIGURE_ARGS="$CONFIGURE_ARGS --disable-go"
fi
Expand Down

0 comments on commit 9d96532

Please sign in to comment.