From ddd9556689af055355a07cf2766fe95eaed4e38e Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Sun, 2 Oct 2016 16:58:27 +0200 Subject: 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 --- src/generators.c | 194 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 129 insertions(+), 65 deletions(-) (limited to 'src/generators.c') 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 #include #include +#include #include #include @@ -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) { -- cgit v1.2.3