diff options
author | Přemysl Eric Janouch <p@janouch.name> | 2023-03-15 03:31:30 +0100 |
---|---|---|
committer | Přemysl Eric Janouch <p@janouch.name> | 2023-03-15 05:52:32 +0100 |
commit | 796b05c9a5f04aba87e26c5a8384d84edee20b77 (patch) | |
tree | 74b1dbda5521bb39bcf9215c3e884499fca215d2 /fiv-io.c | |
parent | 9286858573ef5e430ac2fb24c274a6fcd41a1edd (diff) | |
download | fiv-796b05c9a5f04aba87e26c5a8384d84edee20b77.tar.gz fiv-796b05c9a5f04aba87e26c5a8384d84edee20b77.tar.xz fiv-796b05c9a5f04aba87e26c5a8384d84edee20b77.zip |
Integrate online reverse image search
This makes use of our image processing capabilities in order to
turn arbitrary image files into normalized thumbnails,
upload them to a temporary host, and pass the resulting URI
to a search provider.
In future, fiv should ideally run the upload itself,
so that its status and any errors are obvious to the user,
as well as to get rid of the script's dependency on jq.
Diffstat (limited to 'fiv-io.c')
-rw-r--r-- | fiv-io.c | 84 |
1 files changed, 83 insertions, 1 deletions
@@ -1,7 +1,7 @@ // // fiv-io.c: image operations // -// Copyright (c) 2021 - 2022, Přemysl Eric Janouch <p@janouch.name> +// Copyright (c) 2021 - 2023, Přemysl Eric Janouch <p@janouch.name> // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted. @@ -2958,6 +2958,88 @@ fiv_io_deserialize(GBytes *bytes, guint64 *user_data) return surface; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static cairo_status_t +write_to_byte_array( + void *closure, const unsigned char *data, unsigned int length) +{ + g_byte_array_append(closure, data, length); + return CAIRO_STATUS_SUCCESS; +} + +GBytes * +fiv_io_serialize_for_search(cairo_surface_t *surface, GError **error) +{ + g_return_val_if_fail( + surface && cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE, + NULL); + + cairo_format_t format = cairo_image_surface_get_format(surface); + if (format == CAIRO_FORMAT_ARGB32) { + const uint32_t *data = + (const uint32_t *) cairo_image_surface_get_data(surface); + + bool all_solid = true; + for (size_t len = cairo_image_surface_get_width(surface) * + cairo_image_surface_get_height(surface); len--; ) { + if ((data[len] >> 24) != 0xFF) + all_solid = false; + } + if (all_solid) + format = CAIRO_FORMAT_RGB24; + } + + if (format != CAIRO_FORMAT_RGB24) { +#if CAIRO_HAS_PNG_FUNCTIONS + GByteArray *ba = g_byte_array_new(); + cairo_status_t status = + cairo_surface_write_to_png_stream(surface, write_to_byte_array, ba); + if (status == CAIRO_STATUS_SUCCESS) + return g_byte_array_free_to_bytes(ba); + g_byte_array_unref(ba); +#endif + + // Last resort: remove transparency by painting over black. + cairo_surface_t *converted = + cairo_image_surface_create(CAIRO_FORMAT_RGB24, + cairo_image_surface_get_width(surface), + cairo_image_surface_get_height(surface)); + cairo_t *cr = cairo_create(converted); + cairo_set_source_surface(cr, surface, 0, 0); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_paint(cr); + cairo_destroy(cr); + GBytes *result = fiv_io_serialize_for_search(converted, error); + cairo_surface_destroy(converted); + return result; + } + + tjhandle enc = tjInitCompress(); + if (!enc) { + set_error(error, tjGetErrorStr2(enc)); + return NULL; + } + + unsigned char *jpeg = NULL; + unsigned long length = 0; + if (tjCompress2(enc, cairo_image_surface_get_data(surface), + cairo_image_surface_get_width(surface), + cairo_image_surface_get_stride(surface), + cairo_image_surface_get_height(surface), + (G_BYTE_ORDER == G_LITTLE_ENDIAN ? TJPF_BGRX : TJPF_XRGB), + &jpeg, &length, TJSAMP_444, 90, 0)) { + set_error(error, tjGetErrorStr2(enc)); + tjFree(jpeg); + tjDestroy(enc); + return NULL; + } + + tjDestroy(enc); + return g_bytes_new_with_free_func( + jpeg, length, (GDestroyNotify) tjFree, jpeg); +} + // --- Filesystem -------------------------------------------------------------- #include "xdg.h" |