summaryrefslogtreecommitdiff
path: root/src/generators.c
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@users.sourceforge.net>2016-09-18 19:34:56 +0200
committerTomas Bzatek <tbzatek@users.sourceforge.net>2016-09-18 19:54:08 +0200
commitaeefd1959aad3b80a0fe02083edbd5ebfb09510b (patch)
tree4da69339f39f55c3a70e7f54a4eafe95ea9fd972 /src/generators.c
parent6b853ad4312763d50f1e843d4e7168ccd023530a (diff)
downloadcataract-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.
Diffstat (limited to 'src/generators.c')
-rw-r--r--src/generators.c322
1 files changed, 198 insertions, 124 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 */