Compare commits

...

8 Commits

Author SHA1 Message Date
cc59e537da
Update meson invocation to avoid warnings 2023-06-04 17:15:37 +02:00
338ae69121
Add support for the Little CMS fast float plugin
On a sample of JPEGs, it improved loading speed from ~0.26s to ~0.15s.

Unfortunately, it isn't normally installed.
2023-06-04 16:16:52 +02:00
1c61fcc5bc
Move git submodules to a subdirectory 2023-06-04 12:57:47 +02:00
dd1d6647dc
Shuffle code around 2023-06-04 12:10:36 +02:00
abf4f1a792
Convert to strictly non-unique GtkApplication
It's not pretty, but it works.
2023-06-04 12:10:36 +02:00
6a7c86a41b
Remove a macOS rendering bug workaround
Most important Cairo bugs seem to have been fixed recently.
2023-06-04 12:10:35 +02:00
6277a32fe6
Avoid invisible browser entries 2023-06-04 10:36:42 +02:00
8f0576d6bc
Update runtime dependencies 2023-06-03 21:36:45 +02:00
10 changed files with 252 additions and 193 deletions

4
.gitmodules vendored
View File

@ -1,6 +1,6 @@
[submodule "wuffs-mirror-release-c"] [submodule "wuffs-mirror-release-c"]
path = wuffs-mirror-release-c path = submodules/wuffs-mirror-release-c
url = https://github.com/google/wuffs-mirror-release-c url = https://github.com/google/wuffs-mirror-release-c
[submodule "liberty"] [submodule "liberty"]
path = liberty path = submodules/liberty
url = https://git.janouch.name/p/liberty.git url = https://git.janouch.name/p/liberty.git

View File

@ -2,7 +2,7 @@ fiv
=== ===
'fiv' is a slightly unconventional, general-purpose image browser and viewer 'fiv' is a slightly unconventional, general-purpose image browser and viewer
for Linux (that said, macOS and Windows ports are possible). for Linux (as well as macOS and Windows, though these have known issues).
image::docs/fiv.webp["Screenshot of both the browser and the viewer"] image::docs/fiv.webp["Screenshot of both the browser and the viewer"]
@ -40,15 +40,16 @@ Building and Running
-------------------- --------------------
Build-only dependencies: Build-only dependencies:
Meson, pkg-config, asciidoctor or asciidoc (recommended but optional) + Meson, pkg-config, asciidoctor or asciidoc (recommended but optional) +
Runtime dependencies: Runtime dependencies: gtk+-3.0, glib>=2.64, pixman-1, shared-mime-info,
gtk+-3.0, glib>=2.64, pixman-1, shared-mime-info, libturbojpeg, libwebp + libturbojpeg, libwebp, librsvg-2.0 (for icons) +
Optional dependencies: lcms2, LibRaw, librsvg-2.0, xcursor, libheif, libtiff, Optional dependencies: lcms2, Little CMS fast float plugin,
ExifTool, resvg (unstable API, needs to be requested explicitly) + LibRaw, librsvg-2.0, xcursor, libheif, libtiff, ExifTool,
resvg (unstable API, needs to be requested explicitly) +
Runtime dependencies for reverse image search: Runtime dependencies for reverse image search:
xdg-utils, cURL, jq xdg-utils, cURL, jq
$ git clone --recursive https://git.janouch.name/p/fiv.git $ git clone --recursive https://git.janouch.name/p/fiv.git
$ meson builddir $ meson setup builddir
$ cd builddir $ cd builddir
$ meson compile $ meson compile

View File

@ -640,11 +640,15 @@ materialize_icon(FivBrowser *self, Entry *entry)
// of using GLib to look up icons for us, derive a list from a guessed // of using GLib to look up icons for us, derive a list from a guessed
// MIME type, with "-symbolic" prefixes and fallbacks, // MIME type, with "-symbolic" prefixes and fallbacks,
// and use gtk_icon_theme_choose_icon() instead. // and use gtk_icon_theme_choose_icon() instead.
// TODO(p): Make sure we have /some/ icon for every entry.
// TODO(p): We might want to populate these on an as-needed basis. // TODO(p): We might want to populate these on an as-needed basis.
GtkIconInfo *icon_info = gtk_icon_theme_lookup_by_gicon( GtkIconTheme *theme = gtk_icon_theme_get_default();
gtk_icon_theme_get_default(), entry->icon, self->item_height / 2, GtkIconInfo *icon_info = gtk_icon_theme_lookup_by_gicon(theme, entry->icon,
GTK_ICON_LOOKUP_FORCE_SYMBOLIC); self->item_height / 2, GTK_ICON_LOOKUP_FORCE_SYMBOLIC);
if (!icon_info) {
// This icon is included within GTK+.
icon_info = gtk_icon_theme_lookup_icon(theme, "text-x-generic",
self->item_height / 2, GTK_ICON_LOOKUP_FORCE_SYMBOLIC);
}
if (!icon_info) if (!icon_info)
return; return;

View File

@ -84,7 +84,7 @@
#define WUFFS_CONFIG__MODULE__PNG #define WUFFS_CONFIG__MODULE__PNG
#define WUFFS_CONFIG__MODULE__TGA #define WUFFS_CONFIG__MODULE__TGA
#define WUFFS_CONFIG__MODULE__ZLIB #define WUFFS_CONFIG__MODULE__ZLIB
#include "wuffs-mirror-release-c/release/c/wuffs-v0.3.c" #include "submodules/wuffs-mirror-release-c/release/c/wuffs-v0.3.c"
#include "fiv-io.h" #include "fiv-io.h"

385
fiv.c
View File

@ -43,6 +43,11 @@
#include "fiv-thumbnail.h" #include "fiv-thumbnail.h"
#include "fiv-view.h" #include "fiv-view.h"
#ifdef HAVE_LCMS2_FAST_FLOAT
#include <lcms2.h>
#include <lcms2_fast_float.h>
#endif // HAVE_LCMS2_FAST_FLOAT
// --- Utilities --------------------------------------------------------------- // --- Utilities ---------------------------------------------------------------
static void exit_fatal(const char *format, ...) G_GNUC_PRINTF(1, 2); static void exit_fatal(const char *format, ...) G_GNUC_PRINTF(1, 2);
@ -388,12 +393,6 @@ on_about_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
GtkStyleContext *style = gtk_widget_get_style_context(widget); GtkStyleContext *style = gtk_widget_get_style_context(widget);
gtk_render_background(style, cr, 0, 0, allocation.width, allocation.height); gtk_render_background(style, cr, 0, 0, allocation.width, allocation.height);
// The transformation matrix turns out/is applied wrongly on Quartz.
gboolean broken_backend = cairo_surface_get_type(cairo_get_target(cr)) ==
CAIRO_SURFACE_TYPE_QUARTZ;
if (broken_backend)
cairo_push_group(cr);
cairo_translate(cr, (allocation.width - ABOUT_SIZE * ABOUT_SCALE) / 2, cairo_translate(cr, (allocation.width - ABOUT_SIZE * ABOUT_SCALE) / 2,
ABOUT_SIZE * ABOUT_SCALE / 4); ABOUT_SIZE * ABOUT_SCALE / 4);
cairo_scale(cr, ABOUT_SCALE, ABOUT_SCALE); cairo_scale(cr, ABOUT_SCALE, ABOUT_SCALE);
@ -419,11 +418,6 @@ on_about_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
cairo_restore(cr); cairo_restore(cr);
draw_ligature(cr); draw_ligature(cr);
if (broken_backend) {
cairo_pop_group_to_source(cr);
cairo_paint(cr);
}
return TRUE; return TRUE;
} }
@ -2098,163 +2092,12 @@ static const char stylesheet[] = "@define-color fiv-tile @content_view_bg; \
} \ } \
.fiv-information label { padding: 0 4px; }"; .fiv-information label { padding: 0 4px; }";
static FivThumbnailSize
output_thumbnail_prologue(gchar **uris, const char *size_arg)
{
if (!uris)
exit_fatal("No path given");
if (uris[1])
exit_fatal("Only one thumbnail at a time may be produced");
FivThumbnailSize size = FIV_THUMBNAIL_SIZE_COUNT;
if (size_arg) {
for (size = 0; size < FIV_THUMBNAIL_SIZE_COUNT; size++) {
if (!strcmp(
fiv_thumbnail_sizes[size].thumbnail_spec_name, size_arg))
break;
}
if (size >= FIV_THUMBNAIL_SIZE_COUNT)
exit_fatal("unknown thumbnail size: %s", size_arg);
}
#ifdef G_OS_WIN32
_setmode(fileno(stdout), _O_BINARY);
#endif
return size;
}
static void static void
output_thumbnail_for_search(gchar **uris, const char *size_arg) on_app_startup(GApplication *app, G_GNUC_UNUSED gpointer user_data)
{ {
FivThumbnailSize size = output_thumbnail_prologue(uris, size_arg); // We can't prevent GApplication from adding --gapplication-service.
if (g_application_get_flags(app) & G_APPLICATION_IS_SERVICE)
GError *error = NULL; exit(EXIT_FAILURE);
GFile *file = g_file_new_for_uri(uris[0]);
cairo_surface_t *surface = NULL;
GBytes *bytes = NULL;
if ((surface = fiv_thumbnail_produce(file, size, &error)) &&
(bytes = fiv_io_serialize_for_search(surface, &error))) {
fwrite(
g_bytes_get_data(bytes, NULL), 1, g_bytes_get_size(bytes), stdout);
g_bytes_unref(bytes);
} else {
g_assert(error != NULL);
}
g_object_unref(file);
if (error)
exit_fatal("%s", error->message);
cairo_surface_destroy(surface);
}
static void
output_thumbnail(gchar **uris, gboolean extract, const char *size_arg)
{
FivThumbnailSize size = output_thumbnail_prologue(uris, size_arg);
GError *error = NULL;
GFile *file = g_file_new_for_uri(uris[0]);
cairo_surface_t *surface = NULL;
if (extract && (surface = fiv_thumbnail_extract(file, size, &error)))
fiv_io_serialize_to_stdout(surface, FIV_IO_SERIALIZE_LOW_QUALITY);
else if (size_arg &&
(g_clear_error(&error),
(surface = fiv_thumbnail_produce(file, size, &error))))
fiv_io_serialize_to_stdout(surface, 0);
else
g_assert(error != NULL);
g_object_unref(file);
if (error)
exit_fatal("%s", error->message);
cairo_surface_destroy(surface);
}
int
main(int argc, char *argv[])
{
gboolean show_version = FALSE, show_supported_media_types = FALSE,
invalidate_cache = FALSE, browse = FALSE, extract_thumbnail = FALSE;
gchar **args = NULL, *thumbnail_size = NULL, *thumbnail_size_search = NULL;
const GOptionEntry options[] = {
{G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args,
NULL, "[PATH | URI]..."},
{"browse", 0, G_OPTION_FLAG_IN_MAIN,
G_OPTION_ARG_NONE, &browse,
"Start in filesystem browsing mode", NULL},
{"invalidate-cache", 0, G_OPTION_FLAG_IN_MAIN,
G_OPTION_ARG_NONE, &invalidate_cache,
"Invalidate the wide thumbnail cache", NULL},
{"list-supported-media-types", 0, G_OPTION_FLAG_IN_MAIN,
G_OPTION_ARG_NONE, &show_supported_media_types,
"Output supported media types and exit", NULL},
{"version", 'V', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
&show_version, "Output version information and exit", NULL},
{},
};
const GOptionEntry options_internal[] = {
{"extract-thumbnail", 0, 0,
G_OPTION_ARG_NONE, &extract_thumbnail,
"Output any embedded thumbnail (superseding --thumbnail)", NULL},
{"thumbnail", 0, 0,
G_OPTION_ARG_STRING, &thumbnail_size,
"Generate thumbnails, up to SIZE, and output that size", "SIZE"},
{"thumbnail-for-search", 0, 0,
G_OPTION_ARG_STRING, &thumbnail_size_search,
"Output an image file suitable for searching by content", "SIZE"},
{},
};
GOptionContext *context =
g_option_context_new(" - Image browser and viewer");
g_option_context_add_group(context, gtk_get_option_group(TRUE));
g_option_context_add_main_entries(context, options, NULL);
GOptionGroup *internals = g_option_group_new(
"internal", "Internal Options:", "Show internal options", NULL, NULL);
g_option_group_add_entries(internals, options_internal);
g_option_context_add_group(context, internals);
GError *error = NULL;
gboolean initialized =
g_option_context_parse(context, &argc, &argv, &error);
g_option_context_free(context);
if (show_version) {
const char *version = PROJECT_VERSION;
printf("%s %s\n", PROJECT_NAME, &version[*version == 'v']);
return 0;
}
if (show_supported_media_types) {
char **types = fiv_io_all_supported_media_types();
for (char **p = types; *p; p++)
g_print("%s\n", *p);
g_strfreev(types);
return 0;
}
if (invalidate_cache) {
fiv_thumbnail_invalidate();
return 0;
}
if (!initialized)
exit_fatal("%s", error->message);
// Normalize all arguments to URIs.
for (gsize i = 0; args && args[i]; i++) {
GFile *resolved = g_file_new_for_commandline_arg(args[i]);
g_free(args[i]);
args[i] = g_file_get_uri(resolved);
g_object_unref(resolved);
}
if (thumbnail_size_search) {
output_thumbnail_for_search(args, thumbnail_size_search);
return 0;
}
if (extract_thumbnail || thumbnail_size) {
output_thumbnail(args, extract_thumbnail, thumbnail_size);
return 0;
}
// It doesn't make much sense to have command line arguments able to // It doesn't make much sense to have command line arguments able to
// resolve to the VFS they may end up being contained within. // resolve to the VFS they may end up being contained within.
@ -2357,9 +2200,9 @@ main(int argc, char *argv[])
gtk_container_add(GTK_CONTAINER(g.stack), g.view_box); gtk_container_add(GTK_CONTAINER(g.stack), g.view_box);
gtk_container_add(GTK_CONTAINER(g.stack), g.browser_paned); gtk_container_add(GTK_CONTAINER(g.stack), g.browser_paned);
g.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g.window = gtk_application_window_new(GTK_APPLICATION(app));
g_signal_connect(g.window, "destroy", g_signal_connect_swapped(g.window, "destroy",
G_CALLBACK(gtk_main_quit), NULL); G_CALLBACK(g_application_quit), app);
g_signal_connect(g.window, "key-press-event", g_signal_connect(g.window, "key-press-event",
G_CALLBACK(on_key_press), NULL); G_CALLBACK(on_key_press), NULL);
g_signal_connect(g.window, "window-state-event", g_signal_connect(g.window, "window-state-event",
@ -2410,24 +2253,34 @@ main(int argc, char *argv[])
// XXX: The widget wants to read the display's profile. The realize is ugly. // XXX: The widget wants to read the display's profile. The realize is ugly.
gtk_widget_realize(g.view); gtk_widget_realize(g.view);
}
static struct {
gboolean browse, extract_thumbnail;
gchar **args, *thumbnail_size, *thumbnail_size_search;
} o;
static void
on_app_activate(
G_GNUC_UNUSED GApplication *app, G_GNUC_UNUSED gpointer user_data)
{
// XXX: We follow the behaviour of Firefox and Eye of GNOME, which both // XXX: We follow the behaviour of Firefox and Eye of GNOME, which both
// interpret multiple command line arguments differently, as a collection. // interpret multiple command line arguments differently, as a collection.
// However, single-element collections are unrepresentable this way. // However, single-element collections are unrepresentable this way.
// Should we allow multiple targets only in a special new mode? // Should we allow multiple targets only in a special new mode?
g.files_index = -1; g.files_index = -1;
if (args) { if (o.args) {
const gchar *target = *args; const gchar *target = *o.args;
if (args[1]) { if (o.args[1]) {
fiv_collection_reload(args); fiv_collection_reload(o.args);
target = FIV_COLLECTION_SCHEME ":/"; target = FIV_COLLECTION_SCHEME ":/";
} }
GFile *file = g_file_new_for_uri(target); GFile *file = g_file_new_for_uri(target);
open_any_file(file, browse); open_any_file(file, o.browse);
g_object_unref(file); g_object_unref(file);
g_strfreev(args);
} }
if (!g.directory) { if (!g.directory) {
GFile *file = g_file_new_for_path("."); GFile *file = g_file_new_for_path(".");
open_any_file(file, FALSE); open_any_file(file, FALSE);
@ -2435,6 +2288,184 @@ main(int argc, char *argv[])
} }
gtk_widget_show(g.window); gtk_widget_show(g.window);
gtk_main(); }
return 0;
// --- Plumbing ----------------------------------------------------------------
static FivThumbnailSize
output_thumbnail_prologue(gchar **uris, const char *size_arg)
{
if (!uris)
exit_fatal("No path given");
if (uris[1])
exit_fatal("Only one thumbnail at a time may be produced");
FivThumbnailSize size = FIV_THUMBNAIL_SIZE_COUNT;
if (size_arg) {
for (size = 0; size < FIV_THUMBNAIL_SIZE_COUNT; size++) {
if (!strcmp(
fiv_thumbnail_sizes[size].thumbnail_spec_name, size_arg))
break;
}
if (size >= FIV_THUMBNAIL_SIZE_COUNT)
exit_fatal("unknown thumbnail size: %s", size_arg);
}
#ifdef G_OS_WIN32
_setmode(fileno(stdout), _O_BINARY);
#endif
return size;
}
static void
output_thumbnail_for_search(gchar **uris, const char *size_arg)
{
FivThumbnailSize size = output_thumbnail_prologue(uris, size_arg);
GError *error = NULL;
GFile *file = g_file_new_for_uri(uris[0]);
cairo_surface_t *surface = NULL;
GBytes *bytes = NULL;
if ((surface = fiv_thumbnail_produce(file, size, &error)) &&
(bytes = fiv_io_serialize_for_search(surface, &error))) {
fwrite(
g_bytes_get_data(bytes, NULL), 1, g_bytes_get_size(bytes), stdout);
g_bytes_unref(bytes);
} else {
g_assert(error != NULL);
}
g_object_unref(file);
if (error)
exit_fatal("%s", error->message);
cairo_surface_destroy(surface);
}
static void
output_thumbnail(gchar **uris, gboolean extract, const char *size_arg)
{
FivThumbnailSize size = output_thumbnail_prologue(uris, size_arg);
GError *error = NULL;
GFile *file = g_file_new_for_uri(uris[0]);
cairo_surface_t *surface = NULL;
if (extract && (surface = fiv_thumbnail_extract(file, size, &error)))
fiv_io_serialize_to_stdout(surface, FIV_IO_SERIALIZE_LOW_QUALITY);
else if (size_arg &&
(g_clear_error(&error),
(surface = fiv_thumbnail_produce(file, size, &error))))
fiv_io_serialize_to_stdout(surface, 0);
else
g_assert(error != NULL);
g_object_unref(file);
if (error)
exit_fatal("%s", error->message);
cairo_surface_destroy(surface);
}
static gint
on_app_handle_local_options(G_GNUC_UNUSED GApplication *app,
GVariantDict *options, G_GNUC_UNUSED gpointer user_data)
{
if (g_variant_dict_contains(options, "version")) {
const char *version = PROJECT_VERSION;
printf("%s %s\n", PROJECT_NAME, &version[*version == 'v']);
return 0;
}
if (g_variant_dict_contains(options, "list-supported-media-types")) {
char **types = fiv_io_all_supported_media_types();
for (char **p = types; *p; p++)
g_print("%s\n", *p);
g_strfreev(types);
return 0;
}
if (g_variant_dict_contains(options, "invalidate-cache")) {
fiv_thumbnail_invalidate();
return 0;
}
// TODO(p): Use Little CMS with contexts instead.
#ifdef HAVE_LCMS2_FAST_FLOAT
cmsPlugin(cmsFastFloatExtensions());
#endif // HAVE_LCMS2_FAST_FLOAT
// Normalize all arguments to URIs, and run thumbnailing modes first.
for (gsize i = 0; o.args && o.args[i]; i++) {
GFile *resolved = g_file_new_for_commandline_arg(o.args[i]);
g_free(o.args[i]);
o.args[i] = g_file_get_uri(resolved);
g_object_unref(resolved);
}
// These come from an option group that doesn't get copied to "options".
if (o.thumbnail_size_search) {
output_thumbnail_for_search(o.args, o.thumbnail_size_search);
return 0;
}
if (o.extract_thumbnail || o.thumbnail_size) {
output_thumbnail(o.args, o.extract_thumbnail, o.thumbnail_size);
return 0;
}
return -1;
}
int
main(int argc, char *argv[])
{
const GOptionEntry options[] = {
{G_OPTION_REMAINING, 0, 0,
G_OPTION_ARG_FILENAME_ARRAY, &o.args,
NULL, "[PATH | URI]..."},
{"browse", 0, G_OPTION_FLAG_IN_MAIN,
G_OPTION_ARG_NONE, &o.browse,
"Start in filesystem browsing mode", NULL},
{"invalidate-cache", 0, G_OPTION_FLAG_IN_MAIN,
G_OPTION_ARG_NONE, NULL,
"Invalidate the wide thumbnail cache", NULL},
{"list-supported-media-types", 0, G_OPTION_FLAG_IN_MAIN,
G_OPTION_ARG_NONE, NULL,
"Output supported media types and exit", NULL},
{"version", 'V', G_OPTION_FLAG_IN_MAIN,
G_OPTION_ARG_NONE, NULL,
"Output version information and exit", NULL},
{},
};
const GOptionEntry options_internal[] = {
{"extract-thumbnail", 0, 0,
G_OPTION_ARG_NONE, &o.extract_thumbnail,
"Output any embedded thumbnail (superseding --thumbnail)", NULL},
{"thumbnail", 0, 0,
G_OPTION_ARG_STRING, &o.thumbnail_size,
"Generate thumbnails, up to SIZE, and output that size", "SIZE"},
{"thumbnail-for-search", 0, 0,
G_OPTION_ARG_STRING, &o.thumbnail_size_search,
"Output an image file suitable for searching by content", "SIZE"},
{},
};
// We never get the ::open signal, thanks to G_OPTION_ARG_FILENAME_ARRAY.
GtkApplication *app = gtk_application_new(NULL, G_APPLICATION_NON_UNIQUE);
g_application_set_option_context_parameter_string(
G_APPLICATION(app), " - Image browser and viewer");
g_application_add_main_option_entries(G_APPLICATION(app), options);
GOptionGroup *internals = g_option_group_new(
"internal", "Internal Options:", "Show internal options", NULL, NULL);
g_option_group_add_entries(internals, options_internal);
g_application_add_option_group(G_APPLICATION(app), internals);
g_signal_connect(app, "handle-local-options",
G_CALLBACK(on_app_handle_local_options), NULL);
g_signal_connect(app, "startup",
G_CALLBACK(on_app_startup), NULL);
g_signal_connect(app, "activate",
G_CALLBACK(on_app_activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
g_strfreev(o.args);
return status;
} }

View File

@ -25,11 +25,12 @@ libjpegqs = dependency('libjpegqs', required : get_option('libjpegqs'),
lcms2 = dependency('lcms2', required : get_option('lcms2')) lcms2 = dependency('lcms2', required : get_option('lcms2'))
# Note that only libraw_r is thread-safe, but we'll just run it out-of process. # Note that only libraw_r is thread-safe, but we'll just run it out-of process.
libraw = dependency('libraw', required : get_option('libraw')) libraw = dependency('libraw', required : get_option('libraw'))
# This is a direct runtime dependency, but its usage may be disabled for images.
librsvg = dependency('librsvg-2.0', required : get_option('librsvg')) librsvg = dependency('librsvg-2.0', required : get_option('librsvg'))
xcursor = dependency('xcursor', required : get_option('xcursor')) xcursor = dependency('xcursor', required : get_option('xcursor'))
libheif = dependency('libheif', required : get_option('libheif')) libheif = dependency('libheif', required : get_option('libheif'))
libtiff = dependency('libtiff-4', required : get_option('libtiff')) libtiff = dependency('libtiff-4', required : get_option('libtiff'))
# This is a direct dependency of GTK+, but its usage may be disabled. # This is a direct dependency of GTK+, but its usage may be disabled for images.
gdkpixbuf = dependency('gdk-pixbuf-2.0', required : get_option('gdk-pixbuf')) gdkpixbuf = dependency('gdk-pixbuf-2.0', required : get_option('gdk-pixbuf'))
dependencies = [ dependencies = [
dependency('gtk+-3.0'), dependency('gtk+-3.0'),
@ -53,6 +54,24 @@ dependencies = [
cc.find_library('m', required : false), cc.find_library('m', required : false),
] ]
# As of writing, no pkg-config file is produced, and the plugin is not installed
# by default. The library can be built statically, but it's a bit of a hassle.
have_lcms2_fast_float = false
if not get_option('lcms2fastfloat').disabled()
lcms2ff = dependency('lcms2_fast_float', required : false)
if not lcms2ff.found()
lcms2ff = cc.find_library(
'lcms2_fast_float', required : get_option('lcms2fastfloat'))
if lcms2ff.found() and not cc.has_header('lcms2_fast_float.h')
error('lcms2_fast_float.h not found')
endif
endif
if lcms2ff.found()
dependencies += lcms2ff
have_lcms2_fast_float = true
endif
endif
# As of writing, the API is unstable, and no pkg-config file is produced. # As of writing, the API is unstable, and no pkg-config file is produced.
# Trying to wrap Cargo in Meson is a recipe for pain, so no version pinning. # Trying to wrap Cargo in Meson is a recipe for pain, so no version pinning.
have_resvg = false have_resvg = false
@ -85,6 +104,7 @@ endif
conf.set('HAVE_JPEG_QS', libjpegqs.found()) conf.set('HAVE_JPEG_QS', libjpegqs.found())
conf.set('HAVE_LCMS2', lcms2.found()) conf.set('HAVE_LCMS2', lcms2.found())
conf.set('HAVE_LCMS2_FAST_FLOAT', have_lcms2_fast_float)
conf.set('HAVE_LIBRAW', libraw.found()) conf.set('HAVE_LIBRAW', libraw.found())
conf.set('HAVE_RESVG', have_resvg) conf.set('HAVE_RESVG', have_resvg)
conf.set('HAVE_LIBRSVG', librsvg.found()) conf.set('HAVE_LIBRSVG', librsvg.found())
@ -236,7 +256,8 @@ if not win32
else else
command = ['env', 'LC_ALL=C', command = ['env', 'LC_ALL=C',
'asciidoc-release-version=' + meson.project_version(), 'asciidoc-release-version=' + meson.project_version(),
'awk', '-f', files('liberty/tools/asciiman.awk'), '@INPUT@'] 'awk', '-f', files('submodules/liberty/tools/asciiman.awk'),
'@INPUT@']
man_capture = true man_capture = true
endif endif
custom_target('manpage for ' + page, custom_target('manpage for ' + page,

View File

@ -3,6 +3,8 @@ option('tools', type : 'feature', value : 'disabled',
option('lcms2', type : 'feature', value : 'auto', option('lcms2', type : 'feature', value : 'auto',
description : 'Build with Little CMS colour management') description : 'Build with Little CMS colour management')
option('lcms2fastfloat', type : 'feature', value : 'auto',
description : 'Build with Little CMS fast float plugin support')
option('libjpegqs', type : 'feature', value : 'auto', option('libjpegqs', type : 'feature', value : 'auto',
description : 'Build with JPEG Quant Smooth integration') description : 'Build with JPEG Quant Smooth integration')
option('libraw', type : 'feature', value : 'auto', option('libraw', type : 'feature', value : 'auto',

View File

@ -97,7 +97,7 @@ setup() {
endian = 'little' endian = 'little'
EOF EOF
meson --buildtype=debugoptimized --prefix="$packagedir" \ meson setup --buildtype=debugoptimized --prefix="$packagedir" \
--bindir . --libdir . --cross-file="$toolchain" "$builddir" "$sourcedir" --bindir . --libdir . --cross-file="$toolchain" "$builddir" "$sourcedir"
} }