Check wide thumbnail metadata

This commit is contained in:
Přemysl Eric Janouch 2021-12-29 01:54:40 +01:00
parent c49e58a0ba
commit 0110e0a5d2
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 70 additions and 12 deletions

View File

@ -15,6 +15,8 @@
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// //
#include "config.h"
#include <spng.h> #include <spng.h>
#include <webp/encode.h> #include <webp/encode.h>
#include <webp/mux.h> #include <webp/mux.h>
@ -73,6 +75,14 @@ FivThumbnailSizeInfo
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define THUMB_URI "Thumb::URI"
#define THUMB_MTIME "Thumb::MTime"
#define THUMB_SIZE "Thumb::Size"
#define THUMB_IMAGE_WIDTH "Thumb::Image::Width"
#define THUMB_IMAGE_HEIGHT "Thumb::Image::Height"
#define THUMB_COLORSPACE "Thumb::ColorSpace"
#define THUMB_COLORSPACE_SRGB "sRGB"
cairo_user_data_key_t fiv_thumbnail_key_lq; cairo_user_data_key_t fiv_thumbnail_key_lq;
static void static void
@ -250,20 +260,20 @@ fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size, GError **error)
GString *thum = g_string_new(""); GString *thum = g_string_new("");
g_string_append_printf( g_string_append_printf(
thum, "%s%c%s%c", "Thumb::URI", 0, uri, 0); thum, "%s%c%s%c", THUMB_URI, 0, uri, 0);
g_string_append_printf( g_string_append_printf(
thum, "%s%c%ld%c", "Thumb::Mtime", 0, (long) st.st_mtim.tv_sec, 0); thum, "%s%c%ld%c", THUMB_MTIME, 0, (long) st.st_mtim.tv_sec, 0);
g_string_append_printf( g_string_append_printf(
thum, "%s%c%ld%c", "Thumb::Size", 0, (long) filesize, 0); thum, "%s%c%ld%c", THUMB_SIZE, 0, (long) filesize, 0);
g_string_append_printf(thum, "%s%c%d%c", "Thumb::Image::Width", 0, g_string_append_printf(thum, "%s%c%d%c", THUMB_IMAGE_WIDTH, 0,
cairo_image_surface_get_width(surface), 0); cairo_image_surface_get_width(surface), 0);
g_string_append_printf(thum, "%s%c%d%c", "Thumb::Image::Height", 0, g_string_append_printf(thum, "%s%c%d%c", THUMB_IMAGE_HEIGHT, 0,
cairo_image_surface_get_height(surface), 0); cairo_image_surface_get_height(surface), 0);
// Without a CMM, no conversion is attempted. // Without a CMM, no conversion is attempted.
if (sRGB) { if (sRGB) {
g_string_append_printf( g_string_append_printf(
thum, "%s%c%s%c", "Thumb::ColorSpace", 0, "sRGB", 0); thum, "%s%c%s%c", THUMB_COLORSPACE, 0, THUMB_COLORSPACE_SRGB, 0);
} }
for (int use = max_size; use >= FIV_THUMBNAIL_SIZE_MIN; use--) { for (int use = max_size; use >= FIV_THUMBNAIL_SIZE_MIN; use--) {
@ -285,14 +295,62 @@ fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size, GError **error)
return TRUE; return TRUE;
} }
static bool
check_wide_thumbnail_texts(GBytes *thum, const gchar *target, time_t mtime,
bool *sRGB)
{
gsize len = 0;
const gchar *s = g_bytes_get_data(thum, &len), *end = s + len;
// Similar to PNG below, but we're following our own specification.
const gchar *key = NULL, *nul = NULL;
bool have_uri = false, have_mtime = false;
for (; (nul = memchr(s, '\0', end - s)); s = ++nul) {
if (!key) {
key = s;
continue;
} else if (!strcmp(key, THUMB_URI)) {
have_uri = true;
if (strcmp(target, s))
return false;
} else if (!strcmp(key, THUMB_MTIME)) {
have_mtime = true;
if (atol(s) != mtime)
return false;
} else if (!strcmp(key, THUMB_COLORSPACE))
*sRGB = !strcmp(s, THUMB_COLORSPACE_SRGB);
key = NULL;
}
return have_uri && have_mtime;
}
static cairo_surface_t * static cairo_surface_t *
read_wide_thumbnail( read_wide_thumbnail(
const gchar *path, const gchar *uri, time_t mtime, GError **error) const gchar *path, const gchar *uri, time_t mtime, GError **error)
{ {
// TODO(p): Validate fiv_io_key_thum. cairo_surface_t *surface = fiv_io_open(path, NULL, FALSE, error);
(void) uri; if (!surface)
(void) mtime; return NULL;
return fiv_io_open(path, NULL, FALSE, error);
bool sRGB = false;
GBytes *thum = cairo_surface_get_user_data(surface, &fiv_io_key_thum);
if (!thum) {
set_error(error, "not a thumbnail");
} else if (!check_wide_thumbnail_texts(thum, uri, mtime, &sRGB)) {
set_error(error, "mismatch");
} else {
// TODO(p): Add a function or a non-valueless define to check
// for CMM presence, then remove this ifdef.
#ifdef HAVE_LCMS2
if (!sRGB)
mark_thumbnail_lq(surface);
#endif // HAVE_LCMS2
return surface;
}
cairo_surface_destroy(surface);
return NULL;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -306,12 +364,12 @@ check_spng_thumbnail_texts(struct spng_text *texts, uint32_t texts_len,
bool need_uri = true, need_mtime = true; bool need_uri = true, need_mtime = true;
for (uint32_t i = 0; i < texts_len; i++) { for (uint32_t i = 0; i < texts_len; i++) {
struct spng_text *text = texts + i; struct spng_text *text = texts + i;
if (!strcmp(text->keyword, "Thumb::URI")) { if (!strcmp(text->keyword, THUMB_URI)) {
need_uri = false; need_uri = false;
if (strcmp(target, text->text)) if (strcmp(target, text->text))
return false; return false;
} }
if (!strcmp(text->keyword, "Thumb::MTime")) { if (!strcmp(text->keyword, THUMB_MTIME)) {
need_mtime = false; need_mtime = false;
if (atol(text->text) != mtime) if (atol(text->text) != mtime)
return false; return false;