summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/generators.c322
-rw-r--r--src/items.c19
-rw-r--r--src/items.h5
-rw-r--r--src/jpeg-utils.cpp8
-rw-r--r--src/jpeg-utils.h1
-rw-r--r--src/setup.c17
-rw-r--r--src/setup.h8
-rw-r--r--templates/classic/default.xml99
-rw-r--r--templates/fluid/fluid.xml6
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>