diff options
| author | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2016-09-18 19:34:56 +0200 |
|---|---|---|
| committer | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2016-09-18 19:54:08 +0200 |
| commit | aeefd1959aad3b80a0fe02083edbd5ebfb09510b (patch) | |
| tree | 4da69339f39f55c3a70e7f54a4eafe95ea9fd972 | |
| parent | 6b853ad4312763d50f1e843d4e7168ccd023530a (diff) | |
| download | cataract-aeefd1959aad3b80a0fe02083edbd5ebfb09510b.tar.xz | |
Introduce resizing thresholds
This commit brings deeper changes to the image sizes concept. The goal
was to allow more flexible input in resizing vs. supplied files mixed
mode. Instead of hard <noresize> flags the decision whether to resize
or copy an image is now based on threshold. While not 100% universal,
it brings more control regarding image size bounds. Also brings a level
of tolerance for specific errors (off-by-one exports).
Image sizes' rules are a bit simpler, hopefully easier to understand.
A lot can be achieved by combination of thresholds.
| -rw-r--r-- | src/generators.c | 322 | ||||
| -rw-r--r-- | src/items.c | 19 | ||||
| -rw-r--r-- | src/items.h | 5 | ||||
| -rw-r--r-- | src/jpeg-utils.cpp | 8 | ||||
| -rw-r--r-- | src/jpeg-utils.h | 1 | ||||
| -rw-r--r-- | src/setup.c | 17 | ||||
| -rw-r--r-- | src/setup.h | 8 | ||||
| -rw-r--r-- | templates/classic/default.xml | 99 | ||||
| -rw-r--r-- | templates/fluid/fluid.xml | 6 |
9 files changed, 301 insertions, 184 deletions
diff --git a/src/generators.c b/src/generators.c index 1ecb3c6..b9df04c 100644 --- a/src/generators.c +++ b/src/generators.c @@ -186,80 +186,107 @@ get_item_titles (TGallerySetup *setup, *title_desc = g_strstrip (*title_desc); } -static void -get_image_paths (TGallerySetup *setup, - TAlbum *items, - TIndexItem *item, - TPathInfo *path_info, - TImageSize *image_size, - gchar **full_img_src, - gchar **full_img_dst, - gchar **page_img_dst) +static gchar * +get_image_source_path (TGallerySetup *setup, + TAlbum *items, + TIndexItem *item, + TPathInfo *path_info, + TImageSize *image_size) { - gchar *s1, *s2, *s3; - gchar *target_image_dir; - - if (full_img_src) - *full_img_src = NULL; - if (full_img_dst) - *full_img_dst = NULL; - if (page_img_dst) - *page_img_dst = NULL; - - if (full_img_src == NULL && image_size == NULL) - return; + const gchar *s; - s1 = NULL; + s = NULL; /* image_size == NULL means return real image source path */ if (image_size) { /* ignore combinations that are not valid */ if ((items->type == GALLERY_TYPE_INDEX && ! image_size->is_thumbnail) || (image_size->is_thumbnail && item->hidden) || (image_size->is_thumbnail && items->type == GALLERY_TYPE_INDEX && (item->thumbnail == NULL || strlen (item->thumbnail) == 0))) - return; + return NULL; if (image_size->is_thumbnail && items->type == GALLERY_TYPE_INDEX) - s1 = item->thumbnail; + s = item->thumbnail; - if (s1 == NULL && item->image_sizes != NULL) - s1 = g_hash_table_lookup (item->image_sizes, image_size->name); - - /* go through the fallback */ - while (s1 == NULL && image_size->fallback_size != NULL) { - image_size = lookup_image_size_for_name (setup, image_size->fallback_size); - s1 = item->image_sizes ? g_hash_table_lookup (item->image_sizes, image_size->name) : NULL; - } + if (s == NULL && item->image_sizes != NULL) + s = g_hash_table_lookup (item->image_sizes, image_size->name); } - /* we have reached our target image size, s1 == NULL means the image should be resized from the source image */ - if (s1 == NULL) - s1 = item->path; + /* we have reached our target image size, s == NULL means the image should be resized from the source image */ + if (s == NULL) + s = item->path; - if (s1 == NULL) { + if (s == NULL) { log_error ("Unable to find image source for item #%d (\"%s\") for image size \"%s\"\n", get_item_index (items, item), item->title, image_size->name); - return; + return NULL; } - if (full_img_src) - *full_img_src = g_build_filename (path_info->src_dir, s1, NULL); + return g_build_filename (path_info->src_dir, s, NULL); +} - if (image_size) { - target_image_dir = g_strdup_printf ("%s%s", TARGET_IMAGE_DIR_PREFIX, image_size->name); - s2 = g_path_get_basename (s1); - if (image_size->is_thumbnail) { - s3 = g_strdup_printf (THUMBNAIL_NAME_FORMAT, get_item_index (items, item), s2); - g_free (s2); - s2 = s3; - } - if (full_img_dst) - *full_img_dst = g_build_filename (path_info->dest_dir, target_image_dir, s2, NULL); - if (page_img_dst) - *page_img_dst = g_build_filename (target_image_dir, s2, NULL); - g_free (s2); - g_free (target_image_dir); +static gchar * +get_image_dest_path (TGallerySetup *setup, + TAlbum *items, + TIndexItem *item, + TPathInfo *path_info, + TImageSize *image_size, + gboolean page_link) +{ + gchar *src; + gchar *dst; + gchar *s, *s2; + gchar *target_image_dir; + + g_assert (image_size != NULL); + + src = get_image_source_path (setup, items, item, path_info, image_size); + + target_image_dir = g_strdup_printf ("%s%s", TARGET_IMAGE_DIR_PREFIX, image_size->name); + s = g_path_get_basename (src); + if (image_size->is_thumbnail) { + s2 = g_strdup_printf (THUMBNAIL_NAME_FORMAT, get_item_index (items, item), s); + g_free (s); + s = s2; } + if (page_link) + dst = g_build_filename (target_image_dir, s, NULL); + else + dst = g_build_filename (path_info->dest_dir, target_image_dir, s, NULL); + + g_free (s); + g_free (target_image_dir); + g_free (src); + + return dst; } +static gchar * +get_image_dest_path_with_fallback (TGallerySetup *setup, + TAlbum *items, + TIndexItem *item, + TPathInfo *path_info, + TImageSize *image_size, + gboolean page_link) +{ + gchar *dst; + TImageSize *tmp_image_size; + + if (image_size->fallback_size == NULL) + return get_image_dest_path (setup, items, item, path_info, image_size, page_link); + + 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) { + g_free (dst); + tmp_image_size = lookup_image_size_for_name (setup, tmp_image_size->fallback_size); + } + + if (page_link) { + g_free (dst); + dst = get_image_dest_path (setup, items, item, path_info, tmp_image_size, page_link); + } + + return dst; +} static void metadata_apply_overrides (ExifData *exif_data, @@ -330,40 +357,61 @@ struct HaveImageSizeData { TGallerySetup *setup; TAlbum *items; TIndexItem *item; + TPathInfo *path_info; }; static gboolean +have_generated_image (TGallerySetup *setup, + TAlbum *items, + TIndexItem *item, + TPathInfo *path_info, + TImageSize *image_size) +{ + gchar *img_dst; + int res; + + img_dst = get_image_dest_path (setup, items, item, path_info, image_size, FALSE); + if (img_dst == NULL) + return FALSE; + res = g_access (img_dst, R_OK); + g_free (img_dst); + + return (res == 0); +} + +static gboolean have_image_size_cb (gchar **args, gpointer user_data) { struct HaveImageSizeData *data = user_data; + TImageSize *image_size; g_return_val_if_fail (g_strv_length (args) != 2, FALSE); /* incl. trailing NULL */ /* no image size of that name available */ - if (! lookup_image_size_for_name (data->setup, *args)) + image_size = lookup_image_size_for_name (data->setup, *args); + if (image_size == NULL) return FALSE; if (data->item->image_sizes && g_hash_table_lookup (data->item->image_sizes, *args)) return TRUE; - /* FIXME: rework this */ -/* if (data->item->path) - return TRUE; */ - - return FALSE; + /* check for generated image */ + return have_generated_image (data->setup, data->items, data->item, data->path_info, image_size); } static gboolean have_album_image_size_cb (gchar **args, gpointer user_data) { struct HaveImageSizeData *data = user_data; + TImageSize *image_size; TIndexItem *iter_item; int i; g_return_val_if_fail (g_strv_length (args) != 2, FALSE); /* incl. trailing NULL */ /* no image size of that name available */ - if (! lookup_image_size_for_name (data->setup, *args)) + image_size = lookup_image_size_for_name (data->setup, *args); + if (image_size == NULL) return FALSE; for (i = 0; i < data->items->items->len; i++) { @@ -374,9 +422,9 @@ have_album_image_size_cb (gchar **args, gpointer user_data) if (iter_item->image_sizes && g_hash_table_lookup (iter_item->image_sizes, *args)) return TRUE; - /* FIXME: rework this */ -/* if (iter_item->path) - return TRUE; */ + /* check for generated image */ + if (have_generated_image (data->setup, data->items, iter_item, data->path_info, image_size)) + return TRUE; } return FALSE; @@ -399,6 +447,7 @@ generate_image (TGallerySetup *setup, unsigned long img_w, img_h; unsigned long src_img_w, src_img_h; unsigned long tmpw, tmph; + int src_img_quality, img_quality; GList *l; TImageSize *image_size; ExifData *exif_data; @@ -408,19 +457,20 @@ generate_image (TGallerySetup *setup, for (l = g_list_first (setup->design->image_sizes); l; l = g_list_next (l)) { image_size = l->data; - /* fallback mode, don't generate any image and use different image size */ - if (image_size->fallback_size != NULL && (item->image_sizes == NULL || g_hash_table_lookup (item->image_sizes, image_size->name) == NULL)) + img_src = get_image_source_path (setup, items, item, path_info, image_size); + if (img_src == NULL) continue; - - get_image_paths (setup, items, item, path_info, image_size, &img_src, &img_dst, NULL); - if (img_src == NULL || img_dst == 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; + } exif_data = exif_data_new_empty (); metadata_apply_overrides (exif_data, setup, path_info, items, item, image_size); @@ -428,17 +478,16 @@ generate_image (TGallerySetup *setup, /* Do something when required */ res = res || needs_update (img_src, img_dst); if (! query_update) { - /* Determine whether to perform file copy or resize */ - if (! image_size->is_thumbnail && image_size->no_resize && (! item->image_sizes || (item->image_sizes && g_hash_table_lookup (item->image_sizes, image_size->name)))) { + /* 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, setup->autorotate); + 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) { - stats_images_inc (); - + img_quality = image_size->quality; if (image_size->is_thumbnail && image_size->thumb_crop_style != CROP_STYLE_NORMAL) { switch (image_size->thumb_crop_style) { case CROP_STYLE_SQUARED: @@ -463,14 +512,41 @@ generate_image (TGallerySetup *setup, tmpw = image_size->portrait_width; tmph = image_size->portrait_height; } - calculate_sizes (tmpw, tmph, &img_w, &img_h); + /* Check for image size suitability */ + if (! image_size->is_thumbnail && src_img_w + image_size->availability_threshold < tmpw && src_img_h + image_size->availability_threshold < tmph) { +/* 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; + } + /* Calculate dimensions */ + if (src_img_w < tmpw + image_size->no_resize_threshold && src_img_h < tmph + image_size->no_resize_threshold) { +/* printf (" Note: image %s dimensions (%lux%lu) are within bounds (%lux%lu..%lux%lu), passing by...\n", + img_src, src_img_w, src_img_h, tmpw - image_size->availability_threshold, tmph - image_size->availability_threshold, + tmpw + image_size->no_resize_threshold, tmph + image_size->no_resize_threshold); */ + } else { + calculate_sizes (tmpw, tmph, &img_w, &img_h); + if (setup->warn_resize) + printf (" Warning: resizing image %s from %lux%lu to %lux%lu\n", img_src, src_img_w, src_img_h, img_w, img_h); + } + /* Calculate compression quality */ + if (src_img_quality >= image_size->quality + image_size->quality_threshold) { + if (setup->warn_resize) + printf (" Warning: lowering compression quality of %s from %d to %d\n", img_src, src_img_quality, img_quality); + } else { + img_quality = src_img_quality; + } } /* Perform resize and strip */ - if (setup->warn_resize && ! image_size->is_thumbnail) - printf (" Warning: resizing image %s from %lux%lu to %lux%lu\n", img_src, src_img_w, src_img_h, img_w, img_h); - if (! resize_image (img_src, img_dst, img_w, img_h, image_size->quality, image_size->is_thumbnail, setup->autorotate, exif_data)) - log_error (" Error resizing image %s\n", img_src); + 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)) + log_error (" Error resizing image %s\n", img_src); + } } else { log_error ("generate_image: image %s sizes are %lux%lu\n", img_src, src_img_w, src_img_h); } @@ -671,7 +747,6 @@ add_next_prev_links (TGallerySetup *setup, int item_index; int i; gchar *s; - gchar *preload_imgname; item_index = get_item_index (items, item); for (i = item_index - 2; i >= 0; i--) { @@ -705,10 +780,11 @@ add_next_prev_links (TGallerySetup *setup, else replace_table_add_key (replace_table, "LINK_PREV", get_index_filename (items, theme, NULL, NULL)); - if (next_item != NULL && setup->preload && image_size != NULL) { - get_image_paths (setup, items, next_item, path_info, image_size, NULL, NULL, &preload_imgname); - } - replace_table_add_key (replace_table, "IMG_SRC_PRELOAD", preload_imgname ? preload_imgname : ""); + s = NULL; + if (next_item != NULL && setup->preload && image_size != NULL) + s = get_image_dest_path_with_fallback (setup, items, next_item, path_info, image_size, TRUE); + replace_table_add_key (replace_table, "IMG_SRC_PRELOAD", s ? s : ""); + g_free (s); } static ExifData * @@ -719,7 +795,7 @@ get_img_exif_data (TGallerySetup *setup, TImageSize *image_size) { ExifData *exif; - gchar *img_orig_src; + gchar *img_src; gchar *img_dst; gchar *s; @@ -735,31 +811,29 @@ get_img_exif_data (TGallerySetup *setup, /* Get EXIF data from the source image */ if (exif == NULL) { - img_orig_src = NULL; - get_image_paths (setup, items, item, path_info, NULL, &img_orig_src, NULL, NULL); - if (img_orig_src != NULL && g_access (img_orig_src, R_OK) == 0) - exif = read_exif (img_orig_src); + img_src = get_image_source_path (setup, items, item, path_info, NULL); + if (img_src != NULL && g_access (img_src, R_OK) == 0) + exif = read_exif (img_src); /* -- silently succeed if (exif == NULL) log_error ("write_html_image: error getting exif data from file \"%s\"\n", img_orig_src); */ - g_free (img_orig_src); + g_free (img_src); } + /* Try supplied image file */ + if (exif == NULL && item->image_sizes != NULL) { + img_src = get_image_source_path (setup, items, item, path_info, image_size); + if (img_src != NULL && g_access (img_src, R_OK) == 0) + exif = read_exif (img_src); + g_free (img_src); + } /* Try destination image size instead, though it might have the metadata stripped */ if (exif == NULL) { - img_orig_src = img_dst = NULL; - get_image_paths (setup, items, item, path_info, image_size, &img_orig_src, &img_dst, NULL); - if (img_orig_src != NULL && g_access (img_orig_src, R_OK) == 0) - exif = read_exif (img_orig_src); - if (exif == NULL && img_dst != NULL && g_access (img_dst, R_OK) == 0) + img_dst = get_image_dest_path (setup, items, item, path_info, image_size, FALSE); + if (img_dst != NULL && g_access (img_dst, R_OK) == 0) exif = read_exif (img_dst); - /* -- silently succeed - if (exif == NULL) - log_error ("write_html_image: error getting exif data from file \"%s\"\n", img_dst); - */ g_free (img_dst); - g_free (img_orig_src); } if (exif != NULL) @@ -790,10 +864,8 @@ process_img_item (TGallerySetup *setup, gchar *s1, *s2, *s3, *s4; gchar *img_dst; gchar *img_dst_page; - gchar *img_orig_dst; - gchar *img_orig_dst_page; gchar *title, *title_desc; - TImageSize *orig_image_size; + TImageSize *tmp_image_size; ExifData *exif = NULL; struct HaveImageSizeData *img_size_data; @@ -822,12 +894,13 @@ process_img_item (TGallerySetup *setup, g_free (s1); } else { - get_image_paths (setup, items, item, path_info, thumb_image_size, NULL, &s2, &s3); + s2 = get_image_dest_path (setup, items, item, path_info, thumb_image_size, FALSE); + s3 = get_image_dest_path (setup, items, item, path_info, thumb_image_size, TRUE); } img_thumb_w = img_thumb_h = 0; if (s2 != NULL) - get_image_sizes (s2, &img_thumb_w, &img_thumb_h, setup->autorotate); + get_image_sizes (s2, &img_thumb_w, &img_thumb_h, NULL, setup->autorotate); if (img_thumb_w == img_thumb_h) replace_table_add_key (replace_table, "THUMB_ORIENTATION", "squared"); @@ -856,36 +929,35 @@ process_img_item (TGallerySetup *setup, /* Image stuff */ if (image_size != NULL) { /* First calculate image paths */ - img_dst = img_dst_page = NULL; - get_image_paths (setup, items, item, path_info, image_size, NULL, &img_dst, &img_dst_page); + img_dst = get_image_dest_path_with_fallback (setup, items, item, path_info, image_size, FALSE); + img_dst_page = get_image_dest_path_with_fallback (setup, items, item, path_info, image_size, TRUE); /* Retrieve image sizes */ - get_image_sizes (img_dst, &img_w, &img_h, setup->autorotate); + get_image_sizes (img_dst, &img_w, &img_h, NULL, setup->autorotate); + exif = get_img_exif_data (setup, path_info, items, item, image_size); replace_table_add_key_int (replace_table, "IMG_SIZE_W", img_w); replace_table_add_key_int (replace_table, "IMG_SIZE_H", img_h); replace_table_add_key (replace_table, "IMG_SRC", img_dst_page); - exif = get_img_exif_data (setup, path_info, items, item, image_size); + g_free (img_dst); + g_free (img_dst_page); - /* TODO: legacy stuff, subject to removal */ - orig_image_size = NULL; + /* Legacy stuff, subject to removal */ + tmp_image_size = NULL; /* Take the last image size from the sorted list */ if (g_list_length (setup->design->image_sizes) > 0) - orig_image_size = (TImageSize *) g_list_last (setup->design->image_sizes); - if (orig_image_size != NULL) { - img_orig_dst = img_orig_dst_page = NULL; - get_image_paths (setup, items, item, path_info, orig_image_size, NULL, &img_orig_dst, &img_orig_dst_page); - get_image_sizes (img_orig_dst, &img_orig_w, &img_orig_h, setup->autorotate); + tmp_image_size = (TImageSize *) (g_list_last (setup->design->image_sizes))->data; + if (tmp_image_size != NULL && tmp_image_size != image_size) { + img_dst = get_image_dest_path_with_fallback (setup, items, item, path_info, tmp_image_size, FALSE); + img_dst_page = get_image_dest_path_with_fallback (setup, items, item, path_info, tmp_image_size, TRUE); + get_image_sizes (img_dst, &img_orig_w, &img_orig_h, NULL, setup->autorotate); g_hash_table_replace (defines, g_strdup ("HAVE_FULLSIZE"), g_strdup ("")); replace_table_add_key_int (replace_table, "IMG_SIZE_FULLSIZE_W", img_orig_w); replace_table_add_key_int (replace_table, "IMG_SIZE_FULLSIZE_H", img_orig_h); - replace_table_add_key (replace_table, "IMG_SRC_FULLSIZE", img_orig_dst_page); - g_free (img_orig_dst); - g_free (img_orig_dst_page); + replace_table_add_key (replace_table, "IMG_SRC_FULLSIZE", img_dst_page); + g_free (img_dst); + g_free (img_dst_page); } - - g_free (img_dst); - g_free (img_dst_page); } /* Get title and description from IPTC/EXIF/JPEG if not defined */ @@ -928,8 +1000,9 @@ process_img_item (TGallerySetup *setup, /* Single image size callback */ img_size_data = g_new0 (struct HaveImageSizeData, 1); img_size_data->setup = setup; - img_size_data->item = item; img_size_data->items = items; + img_size_data->item = item; + img_size_data->path_info = path_info; block_parser_register_function (block_parser, "have_image_size", have_image_size_cb, img_size_data, g_free); } @@ -1048,6 +1121,7 @@ write_html_page (TGallerySetup *setup, img_size_data = g_new0 (struct HaveImageSizeData, 1); img_size_data->setup = setup; img_size_data->items = items; + img_size_data->path_info = path_info; block_parser_register_function (block_parser, "have_album_image_size", have_album_image_size_cb, img_size_data, g_free); /* Picture page tags */ diff --git a/src/items.c b/src/items.c index d475f91..0ddc3b1 100644 --- a/src/items.c +++ b/src/items.c @@ -551,6 +551,25 @@ get_child_gallery_type (const gchar *filename) } /* + * dup_path_info: duplicate pathinfo data + */ +TPathInfo * +dup_path_info (TPathInfo *path_info) +{ + TPathInfo *info; + + info = g_malloc0 (sizeof (TPathInfo)); + info->album_path = g_strdup (path_info->album_path); + info->dest_dir = g_strdup (path_info->dest_dir); + info->dest_root = g_strdup (path_info->dest_root); + info->source_root = g_strdup (path_info->source_root); + info->src_dir = g_strdup (path_info->src_dir); + info->templates_root = g_strdup (path_info->templates_root); + + return info; +} + +/* * free_path_info: free allocated pathinfo data */ void diff --git a/src/items.h b/src/items.h index 2d0df59..24a521f 100644 --- a/src/items.h +++ b/src/items.h @@ -127,6 +127,11 @@ void get_album_titles (const gchar *filename, gchar **title, gchar **description TGalleryType get_child_gallery_type (const gchar *filename); /* + * dup_path_info: duplicate pathinfo data + */ +TPathInfo * dup_path_info (TPathInfo *path_info); + +/* * free_path_info: free allocated pathinfo data */ void free_path_info (TPathInfo *path_info); diff --git a/src/jpeg-utils.cpp b/src/jpeg-utils.cpp index ddac2c7..11d2c4e 100644 --- a/src/jpeg-utils.cpp +++ b/src/jpeg-utils.cpp @@ -556,7 +556,8 @@ resize_image (const gchar *src, const gchar *dst, MagickResizeImage (magick_wand, size_x, size_y, LanczosFilter, 1.0); } - MagickSetImageCompressionQuality (magick_wand, quality); + if ((int) MagickGetImageCompressionQuality (magick_wand) != quality) + MagickSetImageCompressionQuality (magick_wand, quality); /* Write the image and destroy it. */ if (MagickWriteImage (magick_wand, dst) == MagickFalse) { @@ -578,6 +579,7 @@ resize_image (const gchar *src, const gchar *dst, void get_image_sizes (const gchar *img, unsigned long *width, unsigned long *height, + int *quality, gboolean autorotate) { MagickWand *magick_wand; @@ -587,6 +589,8 @@ get_image_sizes (const gchar *img, *width = -1; *height = -1; + if (quality) + *quality = -1; g_assert (img != NULL); @@ -610,6 +614,8 @@ get_image_sizes (const gchar *img, *width = MagickGetImageWidth (magick_wand); *height = MagickGetImageHeight (magick_wand); + if (quality) + *quality = (int) MagickGetImageCompressionQuality (magick_wand); magick_wand = DestroyMagickWand (magick_wand); } diff --git a/src/jpeg-utils.h b/src/jpeg-utils.h index 3c56eaf..405d9b0 100644 --- a/src/jpeg-utils.h +++ b/src/jpeg-utils.h @@ -107,6 +107,7 @@ gboolean resize_image (const gchar *src, const gchar *dst, */ void get_image_sizes (const gchar *img, unsigned long *width, unsigned long *height, + int *quality, gboolean autorotate); /* diff --git a/src/setup.c b/src/setup.c index b2cd800..7b59030 100644 --- a/src/setup.c +++ b/src/setup.c @@ -152,7 +152,7 @@ image_sizes_compare_func (TImageSize *a, TImageSize *b) sa = a->landscape_width + a->landscape_height + a->portrait_width + a->portrait_height + a->square_size; sb = b->landscape_width + b->landscape_height + b->portrait_width + b->portrait_height + b->square_size; - return sb - sa; + return sa - sb; } /* @@ -218,10 +218,6 @@ parse_design_setup_xml (const gchar *filename) } g_free (s); - s = g_strdup_printf ("/design_setup/image_sizes/size[%d]/no_resize", i + 1); - image_size->no_resize = xml_file_get_node_present (xml, s); - g_free (s); - s = g_strdup_printf ("/design_setup/image_sizes/size[%d]/landscape", i + 1); image_size->landscape_width = xml_file_get_node_attribute_long_with_default (xml, s, "w", 0); image_size->landscape_height = xml_file_get_node_attribute_long_with_default (xml, s, "h", 0); @@ -248,6 +244,13 @@ parse_design_setup_xml (const gchar *filename) s = g_strdup_printf ("/design_setup/image_sizes/size[%d]/fallback", i + 1); image_size->fallback_size = xml_file_get_node_attribute (xml, s, "size"); g_free (s); + + s = g_strdup_printf ("/design_setup/image_sizes/size[%d]/threshold", i + 1); + image_size->no_resize_threshold = xml_file_get_node_attribute_long_with_default (xml, s, "no_resize", DEFAULT_NO_RESIZE_THRESHOLD); + image_size->availability_threshold = xml_file_get_node_attribute_long_with_default (xml, s, "availability", DEFAULT_AVAILABILITY_THRESHOLD); + image_size->quality_threshold = xml_file_get_node_attribute_long_with_default (xml, s, "quality", DEFAULT_QUALITY_THRESHOLD); + g_free (s); + } design->image_sizes = g_list_sort (design->image_sizes, (GCompareFunc) image_sizes_compare_func); @@ -368,7 +371,9 @@ makeup_legacy_design (const gchar *filename) image_size->portrait_height = xml_file_get_node_attribute_long_with_default (xml, s, "portrait_h", 0); image_size->square_size = xml_file_get_node_attribute_long_with_default (xml, s, "square", 0); image_size->quality = xml_file_get_node_attribute_long_with_default (xml, s, "quality", -1); - image_size->no_resize = (i != 0); + image_size->no_resize_threshold = DEFAULT_NO_RESIZE_THRESHOLD; + image_size->availability_threshold = DEFAULT_AVAILABILITY_THRESHOLD; + image_size->quality_threshold = DEFAULT_QUALITY_THRESHOLD; image_size->is_thumbnail = (i == 0); image_size->thumb_crop_style = ((i == 0) && squared_thumbs) ? CROP_STYLE_SQUARED : CROP_STYLE_NORMAL; g_free (s); diff --git a/src/setup.h b/src/setup.h index faf02f6..54b89b2 100644 --- a/src/setup.h +++ b/src/setup.h @@ -27,6 +27,10 @@ G_BEGIN_DECLS #define THUMBNAIL_NAME_FORMAT "%.3d_%s" #define TARGET_IMAGE_DIR_PREFIX "_" +#define DEFAULT_NO_RESIZE_THRESHOLD 1 +#define DEFAULT_AVAILABILITY_THRESHOLD 1 +#define DEFAULT_QUALITY_THRESHOLD 5 + #define SETUP_XML "setup.xml" #define SETUP_V2_XML "setup2.xml" #define SETUP_NATIVE_VERSION 200 /* 2.0 */ @@ -104,8 +108,10 @@ typedef struct { int crop_width; int crop_height; int quality; - gboolean no_resize; gchar *fallback_size; + int no_resize_threshold; + int availability_threshold; + int quality_threshold; TCropStyle thumb_crop_style; } TImageSize; diff --git a/templates/classic/default.xml b/templates/classic/default.xml index 8cf709e..6db84ee 100644 --- a/templates/classic/default.xml +++ b/templates/classic/default.xml @@ -3,59 +3,69 @@ <!-- image size definitions --> <image_sizes> - <!-- Every image size automatically corresponds to the <item> tag parameter - of the same name in album source files. E.g. image size named "hires" - would correspond to <item hires=".."> tags. Use the image size parameter - "tagname" to override that. --> + <!-- Every item in an album may carry multiple sizes for the particular image. + The base and source image file is specified by the <item src> tag and + should point to the largest available size. This attribute is mandatory + and serves as a source of metadata (e.g. EXIF). Defined image sizes are + then resized from this source image unless a custom image file is supplied. + Custom image may be supplied from the album XML file in form of an extra + attribute of the <item> tag. Image size names are matched automatically + with these attributes. I.e. image size named "hires" would correspond + to <item hires=".."> attribute. Use the image size parameter "tagname" + to override that name. --> + + <!-- Not all image sizes are always available for every album item and themes + should handle that gracefully. Unless a custom image file is supplied + the image is resized from the base image file pointed to by the <item src> + tag given that its dimensions are larger than desired size. Should the + base image dimensions be smaller, the image size is marked as unavailable + for the particular album item. In case of a custom image file is supplied + for the particular image size, no resizing or size checking is performed + at all and the file is simply copied to destination. --> - <!-- "original", "preview" and "thumbnail" sizes are somewhat special here - in order to keep compatibility with previous versions. --> + <!-- The "preview" size is considered default and should be displayed + on a first visit. --> + <size name="preview" tagname="preview"> + <landscape w="1067" h="600" /> + <portrait w="800" h="800" /> + <quality value="95" /> + </size> <!-- Meaning of "original" is shifted here from previous versions; - it's considered more like a bigger preview size for large screens now. - However it still serves the purpose of supplying metadata (EXIF etc.). --> - <!-- Corresponds with mandatory <item src> tag in album source file. --> - <!-- Note that the series of legacy <nofullsize> and <fullsize> tags control - this image size availability on the page. --> + it's independent now and considered more like a bigger image size for + large screens. --> <size name="original"> <landscape w="1200" h="800" /> <portrait w="1024" h="1024" /> <quality value="97" /> - <!-- With the presence of the "no_resize" tag, no resizing will be done and - image file will be copied as is (this is a default for backwards - compatibility). --> - <no_resize /> - <!-- Normally an image is resized to the given dimensions from the original - image when an image is not supplied from the album XML file for the - particular image size. This tag tells the generator to use the fallback - image size instead when an image has not been supplied. Can be freely - combined with the <no_resize /> tags, in that case it only applies - to supplied images. --> - <!-- In case when the "original" size is not available due to the legacy - <nofullsize> tag present, the "preview" size will be used instead. --> + <!-- Thresholds affect resizing and availability. Value units are pixels + or percent (quality only). --> + <!-- The "no_resize" threshold brings size tolerance before performing + resizing. Only applicable when custom image file is not supplied, + source image whose dimensions are larger than defined image size bounds + yet whose difference is smaller than the "no_resize" threshold is + considered usable and no resizing is performed. This is useful to + prevent resizing similarly sized images which brings nasty pixel + distortion effects. --> + <!-- Similarly, the "availability" threshold specifies how much smaller + image can still be considered usable for the particular image size. + No resizing is peformed either case. This is useful mostly for legacy + reasons for images that have not been exported precisely to the + requested dimensions. --> + <!-- The "quality" threshold indicates how much higher JPEG quality value + is tolerated (in percents). --> + <threshold no_resize="10" availability="100" quality="5" /> + <!-- In case no custom image has been supplied and dimensions of the source + image are smaller than required dimensions, a fallback image size might + be used instead. This is useful to prevent missing images on a page, + with the cost of uneven image sizes displayed. --> <fallback size="preview" /> </size> - <!-- The "preview" size is considered default and should be displayed - on a first visit. --> - <size name="preview" tagname="preview"> - <!-- Note that "preview" sizes can be further overriden by album legacy - <images> tag and also per-image by "width"/"height" <item> tag - attributes. Same goes for quality. --> - <landscape w="1067" h="600" /> - <portrait w="800" h="800" /> - <quality value="95" /> - <!-- Similar to the "original" size where the image has to be always supplied, - the image won't get resized only when an image file is supplied by the - <item preview="..."> tag. Otherwise this tag is ignored and image will - be resized from the "original" size (backwards compatibility). - This rule applies also for any other optional image sizes. --> - <no_resize /> - </size> <!-- Thumbnail section is mandatory. --> <!-- The "type" attribute has to be set to "thumbnail" to be treated as such. --> - <!-- Note that thumbnail images are always resized even for custom supplied files. --> + <!-- Note that thumbnail images are always resized even for custom supplied image. --> <!-- An optional "style" attribute affects cropping: * normal - image is resized to fit the dimension limits, maintaining aspect ratio without any crop (default) @@ -70,15 +80,6 @@ <crop w="180" h="120" /> <!-- valid only for the "fixed" crop style --> <quality value="80" /> </size> - - <!-- Here you can define custom sizes which will be generated from the file - defined in <item src> tag. Currently, there's no way how to supply custom - sized images from album source file (might be changed in the future). --> - <size name="mobile"> - <landscape w="320" h="240" /> - <portrait w="240" h="320" /> - <quality value="90" /> - </size> </image_sizes> <!-- Global support files, common files used by several themes. --> diff --git a/templates/fluid/fluid.xml b/templates/fluid/fluid.xml index b4e528b..49e8547 100644 --- a/templates/fluid/fluid.xml +++ b/templates/fluid/fluid.xml @@ -6,15 +6,15 @@ <landscape w="1423" h="800" /> <portrait w="1000" h="1000" /> <quality value="95" /> - <no_resize /> <fallback size="preview" /> + <threshold no_resize="25" availability="155" quality="5" /> </size> <size name="preview" tagname="preview"> <landscape w="1067" h="600" /> <portrait w="800" h="800" /> <quality value="95" /> - <no_resize /> + <threshold no_resize="10" availability="10" quality="5" /> </size> <size name="thumbnail" type="thumbnail" style="fixed"> @@ -26,8 +26,8 @@ <landscape w="1897" h="1067" /> <portrait w="1200" h="1200" /> <quality value="95" /> - <no_resize /> <fallback size="original" /> + <threshold no_resize="20" availability="20" quality="5" /> </size> </image_sizes> |
