diff options
| author | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2016-10-02 16:58:27 +0200 |
|---|---|---|
| committer | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2016-10-02 17:32:43 +0200 |
| commit | ddd9556689af055355a07cf2766fe95eaed4e38e (patch) | |
| tree | b6de3e57a5cfbd0d855277c3b8c93f16549f0bf2 /src/generators.c | |
| parent | 56ff7bc45505b3e39b2f9be70e7bee3f80ec4f70 (diff) | |
| download | cataract-ddd9556689af055355a07cf2766fe95eaed4e38e.tar.xz | |
Add support for HiDPI images
This works by creating corresponding hidpi image sizes on startup and
letting the machinery generate high resolution images from the source
images (no way to use supplied images). However since browsers expect
exact image dimension multiples for the particular scale factor,
a reference image size (scale factor 1.0x) must be read first, then
cropped to match reference aspect ratio and resized to exact dimensions.
That way pixel-perfect results can be achieved for the chosen scale
factor.
TODO: the CSS background-image: image-set() tags are not supported
on Firefox.
TODO: try the 1.5x scale factor
Diffstat (limited to 'src/generators.c')
| -rw-r--r-- | src/generators.c | 194 |
1 files changed, 129 insertions, 65 deletions
diff --git a/src/generators.c b/src/generators.c index 72c51fb..d6984be 100644 --- a/src/generators.c +++ b/src/generators.c @@ -21,6 +21,7 @@ #include <errno.h> #include <sys/stat.h> #include <unistd.h> +#include <math.h> #include <glib.h> #include <glib/gstdio.h> @@ -207,7 +208,7 @@ get_image_source_path (TGallerySetup *setup, if (image_size->is_thumbnail && items->type == GALLERY_TYPE_INDEX) s = item->thumbnail; - if (s == NULL && item->image_sizes != NULL) + if (s == NULL && ! image_size->is_hidpi && item->image_sizes != NULL) s = g_hash_table_lookup (item->image_sizes, image_size->name); } @@ -239,6 +240,8 @@ get_image_dest_path (TGallerySetup *setup, g_assert (image_size != NULL); src = get_image_source_path (setup, items, item, path_info, image_size); + if (src == NULL) + return NULL; target_image_dir = g_strdup_printf ("%s%s", TARGET_IMAGE_DIR_PREFIX, image_size->name); s = g_path_get_basename (src); @@ -275,7 +278,7 @@ get_image_dest_path_with_fallback (TGallerySetup *setup, tmp_image_size = image_size; while ((dst = get_image_dest_path (setup, items, item, path_info, tmp_image_size, FALSE)), - tmp_image_size->fallback_size && g_access (dst, R_OK) != 0) { + tmp_image_size->fallback_size && dst != NULL && g_access (dst, R_OK) != 0) { g_free (dst); tmp_image_size = lookup_image_size_for_name (setup, tmp_image_size->fallback_size); } @@ -431,63 +434,87 @@ have_album_image_size_cb (gchar **args, gpointer user_data) } -/* - * generate_image: generate needed image sizes - */ -gboolean -generate_image (TGallerySetup *setup, - TAlbum *items, - TIndexItem *item, - TPathInfo *path_info, - gboolean query_update) +static gboolean +generate_image_for_size (TGallerySetup *setup, + TAlbum *items, + TIndexItem *item, + TPathInfo *path_info, + TImageSize *image_size, + gboolean query_update) { gboolean res; gchar *img_src; gchar *img_dst; + gchar *img_ref_dst; unsigned long img_w, img_h; unsigned long src_img_w, src_img_h; unsigned long tmpw, tmph; + unsigned long ref_img_w, ref_img_h; int src_img_quality, img_quality; - GList *l; - TImageSize *image_size; ExifData *exif_data; - res = ! query_update; - for (l = g_list_first (setup->design->image_sizes); l; l = g_list_next (l)) { - image_size = l->data; - img_src = get_image_source_path (setup, items, item, path_info, image_size); - if (img_src == NULL) - continue; - if (g_access (img_src, R_OK) != 0) { - log_error (" Error opening image %s for size \"%s\": %s\n", img_src, image_size->name, g_strerror (errno)); - g_free (img_src); - res = TRUE; - continue; - } - img_dst = get_image_dest_path (setup, items, item, path_info, image_size, FALSE); - if (img_dst == NULL) { - g_free (img_src); - continue; - } + img_src = get_image_source_path (setup, items, item, path_info, image_size); + if (img_src == NULL) + return res; + if (g_access (img_src, R_OK) != 0) { + log_error (" Error opening image %s for size \"%s\": %s\n", img_src, image_size->name, g_strerror (errno)); + g_free (img_src); + return query_update; + } + img_dst = get_image_dest_path (setup, items, item, path_info, image_size, FALSE); + if (img_dst == NULL) { + g_free (img_src); + return res; + } - exif_data = exif_data_new_empty (); - metadata_apply_overrides (exif_data, setup, path_info, items, item, image_size); + exif_data = exif_data_new_empty (); + metadata_apply_overrides (exif_data, setup, path_info, items, item, image_size); - /* Do something when required */ - res = res || needs_update (img_src, img_dst); - if (! query_update) { - /* Always copy supplied image size */ - if (! image_size->is_thumbnail && item->image_sizes && g_hash_table_lookup (item->image_sizes, image_size->name)) { - if (! copy_file (img_src, img_dst)) - log_error (" Error copying image %s to %s\n", img_src, img_dst); - } - /* Resize image */ - else { - get_image_sizes (img_src, &src_img_w, &src_img_h, &src_img_quality, setup->autorotate); - if (src_img_w > 0 && src_img_h > 0) { - img_quality = image_size->quality; + /* Do something when required */ + res = res || needs_update (img_src, img_dst); + if (! query_update) { + /* Always copy supplied image size */ + if (! image_size->is_thumbnail && ! image_size->is_hidpi && item->image_sizes && g_hash_table_lookup (item->image_sizes, image_size->name)) { + if (! copy_file (img_src, img_dst)) + log_error (" Error copying image %s to %s\n", img_src, img_dst); + } + /* Resize image */ + else { + get_image_sizes (img_src, &src_img_w, &src_img_h, &src_img_quality, setup->autorotate); + if (src_img_w > 0 && src_img_h > 0) { + img_quality = image_size->quality; + if (image_size->is_hidpi) { + /* Get reference regular size image dimensions */ + img_ref_dst = get_image_dest_path (setup, items, item, path_info, image_size->hidpi_ref_size, FALSE); + if (! img_ref_dst) { + g_free (img_src); + g_free (img_dst); + return res; + } + ref_img_w = ref_img_h = 0; + get_image_sizes (img_ref_dst, &ref_img_w, &ref_img_h, NULL, FALSE); + g_free (img_ref_dst); + if (ref_img_w <= 0 || ref_img_h <= 0) { + g_free (img_src); + g_free (img_dst); + return res; + } + /* Browsers need exactly n-factor of the original size */ + img_w = lround ((gdouble) ref_img_w * image_size->hidpi_scale_factor); + img_h = lround ((gdouble) ref_img_h * image_size->hidpi_scale_factor); + if ((gdouble) img_w * (100 - setup->design->hidpi_upscale_threshold) / 100 > src_img_w || (gdouble) img_h * (100 - setup->design->hidpi_upscale_threshold) / 100 > src_img_h) { +/* g_print (" Warning: source image %s (%lux%lu) is not large enough for the \"%s\" image size (need %lux%lu)\n", img_src, src_img_w, src_img_h, image_size->name, img_w, img_h); */ + g_free (img_src); + g_free (img_dst); + return res; + } + if (setup->warn_resize && (img_w > src_img_w || img_h > src_img_h)) + printf (" Warning: upscaling image %s from %lux%lu to %lux%lu\n", img_src, src_img_w, src_img_h, img_w, img_h); + + } else { + /* Not a HiDPI image size */ if (image_size->is_thumbnail && image_size->thumb_crop_style != CROP_STYLE_NORMAL) { switch (image_size->thumb_crop_style) { case CROP_STYLE_SQUARED: @@ -517,7 +544,7 @@ generate_image (TGallerySetup *setup, /* printf (" Warning: source image %s (%lux%lu) is not large enough for the \"%s\" image size (need %lux%lu)\n", img_src, src_img_w, src_img_h, image_size->name, tmpw, tmph); */ g_free (img_src); g_free (img_dst); - continue; + return res; } /* Calculate dimensions */ if (src_img_w < tmpw + image_size->no_resize_threshold && src_img_h < tmph + image_size->no_resize_threshold) { @@ -537,29 +564,66 @@ generate_image (TGallerySetup *setup, img_quality = src_img_quality; } } + } - /* Perform resize and strip */ - stats_images_inc (); - if (src_img_w == img_w && src_img_h == img_h && src_img_quality == img_quality) { - if (! copy_file (img_src, img_dst)) - log_error (" Error copying image %s to %s\n", img_src, img_dst); - } else { - if (! resize_image (img_src, img_dst, img_w, img_h, img_quality, image_size->is_thumbnail, setup->autorotate, exif_data, - image_size->is_thumbnail ? setup->design->imgmagick_thumb_opts : setup->design->imgmagick_resize_opts)) - log_error (" Error resizing image %s\n", img_src); - } + + /* Perform resize and strip */ + stats_images_inc (); + if (src_img_w == img_w && src_img_h == img_h && src_img_quality == img_quality) { + if (! copy_file (img_src, img_dst)) + log_error (" Error copying image %s to %s\n", img_src, img_dst); } else { - log_error ("generate_image: image %s sizes are %lux%lu\n", img_src, src_img_w, src_img_h); + if (! resize_image (img_src, img_dst, img_w, img_h, img_quality, image_size->is_thumbnail, setup->autorotate, image_size->is_hidpi, exif_data, + image_size->is_thumbnail ? setup->design->imgmagick_thumb_opts : setup->design->imgmagick_resize_opts)) + log_error (" Error resizing image %s\n", img_src); + } + + if (setup->warn_resize && image_size->is_hidpi) { + get_image_sizes (img_dst, &tmpw, &tmph, NULL, FALSE); + if (img_w != tmpw || img_h != tmph) + g_print (" Warning: generated image '%s' doesn't have required dimensions: need %lux%lu, got %lux%lu\n", img_dst, img_w, img_h, tmpw, tmph); } + } else { + log_error ("generate_image: image %s sizes are %lux%lu\n", img_src, src_img_w, src_img_h); } } - if (! image_size->is_thumbnail) { - modify_exif (img_dst, exif_data, setup->erase_exif_thumbnail, setup->strip_xmp); - } + } + if (! image_size->is_thumbnail) { + modify_exif (img_dst, exif_data, setup->erase_exif_thumbnail, setup->strip_xmp); + } - exif_data_free (exif_data); - g_free (img_src); - g_free (img_dst); + exif_data_free (exif_data); + g_free (img_src); + g_free (img_dst); + + return res; +} + +/* + * generate_image: generate needed image sizes + */ +gboolean +generate_image (TGallerySetup *setup, + TAlbum *items, + TIndexItem *item, + TPathInfo *path_info, + gboolean query_update) +{ + gboolean res; + GList *l; + TImageSize *image_size; + int i; + + res = ! query_update; + for (i = 0; i < 2; i++) { + /* process regular sizes first and then hidpi sizes in the second round */ + for (l = g_list_first (setup->design->image_sizes); l; l = g_list_next (l)) { + image_size = l->data; + if ((i == 0 && image_size->is_hidpi) || (i == 1 && ! image_size->is_hidpi)) + continue; + + res = (query_update && res) || generate_image_for_size (setup, items, item, path_info, image_size, query_update); + } } return res; } @@ -872,9 +936,9 @@ process_img_item (TGallerySetup *setup, struct HaveImageSizeData *img_size_data; GList *l; + album_protected = FALSE; if (list_mode) { /* Index stuff */ - album_protected = FALSE; if (items->type == GALLERY_TYPE_INDEX) { album_objects_count = 0; s1 = g_build_filename (path_info->src_dir, item->path, "index.xml", NULL); @@ -934,7 +998,7 @@ process_img_item (TGallerySetup *setup, tmp_image_size = l->data; if (! all_image_sizes && tmp_image_size != image_size) continue; - if (tmp_image_size->is_thumbnail) + if ((items->type == GALLERY_TYPE_ALBUM && tmp_image_size->is_thumbnail) || (items->type == GALLERY_TYPE_INDEX && ! tmp_image_size->is_thumbnail) || album_protected) continue; /* First calculate image paths */ if (all_image_sizes) { |
