/* Cataract - Static web photo gallery generator * Copyright (C) 2008 Tomas Bzatek * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include "setup.h" #include "items.h" #include "jpeg-utils.h" #include "gallery-utils.h" #include "replace-table.h" #include "block-parser.h" #include "stats.h" #define IS_NOFULLSIZE(item,parent_items,setup) \ (! item->force_fullsize && ! setup->override_nofullsize && \ (! parent_items->fullsize || item->force_nofullsize) && \ (item->force_nofullsize || parent_items->nofullsize || setup->nofullsize)) static void get_image_paths (TGallerySetup *setup, TAlbum *items, TIndexItem *item, unsigned int item_index, TPathInfo *path_info, TImageSize *image_size, gchar **full_img_src, gchar **full_img_dst, gchar **page_img_dst) { gboolean nofullsize; gboolean is_thumbnail; gboolean is_preview; gboolean is_original; 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; /* ignore combinations that are not valid */ nofullsize = IS_NOFULLSIZE (item, items, setup); is_thumbnail = g_ascii_strcasecmp ("thumbnail", image_size->name) == 0; is_preview = g_ascii_strcasecmp ("preview", image_size->name) == 0; is_original = g_ascii_strcasecmp ("original", image_size->name) == 0; if ((items->type == GALLERY_TYPE_INDEX && ! is_thumbnail) || (is_thumbnail && item->hidden) || (is_thumbnail && items->type == GALLERY_TYPE_INDEX && (item->thumbnail == NULL || strlen (item->thumbnail) == 0)) /* || -- in several cases we need to get path to the source image, e.g. to retrieve EXIF metadata; disabling the check for now (is_original && nofullsize) */ ) return; target_image_dir = g_strdup_printf ("%s%s", TARGET_IMAGE_DIR_PREFIX, image_size->name); /* Thumbnail special case */ if (is_thumbnail) { s1 = NULL; if (items->type == GALLERY_TYPE_INDEX) { s1 = item->thumbnail; } else if (items->type == GALLERY_TYPE_ALBUM) { s1 = (item->path == NULL && item->preview) ? item->preview : item->path; s1 = (item->thumbnail) ? item->thumbnail : s1; } s2 = g_path_get_basename (s1); if (full_img_src) *full_img_src = g_build_filename (path_info->src_dir, s1, NULL); s3 = g_strdup_printf (THUMBNAIL_NAME_FORMAT, item_index, s2); g_free (s2); if (full_img_dst) *full_img_dst = g_build_filename (path_info->dest_dir, target_image_dir, s3, NULL); if (page_img_dst) *page_img_dst = g_build_filename (target_image_dir, s3, NULL); g_free (s3); } /* Other image sizes */ else { if (is_preview) s1 = (item->preview) ? item->preview : item->path; else s1 = (item->path == NULL && item->preview) ? item->preview : item->path; if (full_img_src) *full_img_src = g_build_filename (path_info->src_dir, s1, NULL); s2 = g_path_get_basename (s1); 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); } /* * generate_image: generate needed image sizes */ gboolean generate_image (TGallerySetup *setup, TAlbum *items, TIndexItem *item, unsigned int item_index, TPathInfo *path_info, gboolean query_update) { gboolean res; gboolean is_thumbnail; gboolean is_preview; gboolean is_original; gchar *img_src; gchar *img_dst; unsigned long img_w, img_h; int quality; GList *l; TImageSize *image_size; res = ! query_update; for (l = g_list_first (setup->design->image_sizes); l; l = g_list_next (l)) { image_size = l->data; is_thumbnail = g_ascii_strcasecmp ("thumbnail", image_size->name) == 0; is_preview = g_ascii_strcasecmp ("preview", image_size->name) == 0; is_original = g_ascii_strcasecmp ("original", image_size->name) == 0; get_image_paths (setup, items, item, item_index, path_info, image_size, &img_src, &img_dst, NULL); if (img_src == NULL || img_dst == NULL) continue; /* Do something when required */ res = res || needs_update (img_src, img_dst); if (! query_update) { /* Copy the source file */ if ((is_preview && item->preview) || (is_original && image_size->no_resize)) { if (! copy_file (img_src, img_dst)) log_error ("generate_image: error copying image %s\n", img_src); } /* Resize image */ else { get_image_sizes (img_src, &img_w, &img_h); if (img_w > 0 && img_h > 0) { stats_images_inc (); /* Calculate sizes */ if (is_thumbnail && setup->squared_thumbnail_type != THUMBNAIL_SQUARE_TYPE_NONE) img_w = img_h = image_size->square_size; else if (is_preview && item->width > 0 && item->height > 0) calculate_sizes (item->width, item->height, &img_w, &img_h); if (img_w > img_h) { if (is_preview && items->landscape_width > 0 && items->landscape_height > 0) calculate_sizes (items->landscape_width, items->landscape_height, &img_w, &img_h); else calculate_sizes (image_size->landscape_width, image_size->landscape_height, &img_w, &img_h); } else { if (is_preview && items->portrait_width > 0 && items->portrait_height > 0) calculate_sizes (items->portrait_width, items->portrait_height, &img_w, &img_h); else calculate_sizes (image_size->portrait_width, image_size->portrait_height, &img_w, &img_h); } /* Calculate quality */ quality = image_size->quality; if (is_preview && items->quality > 0 && items->quality <= 100) quality = items->quality; if (is_preview && item->quality > 0 && item->quality <= 100) quality = item->quality; /* Perform resize and strip */ if (! resize_image (img_src, img_dst, img_w, img_h, quality, is_thumbnail, setup->squared_thumbnail_type)) log_error ("generate_image: error resizing image %s\n", img_src); } else { log_error ("generate_image: image %s sizes are %lux%lu\n", img_src, img_w, img_h); } } } if (! is_thumbnail) modify_exif (img_dst, setup->erase_exif_thumbnail, setup->add_copyright); g_free (img_src); g_free (img_dst); } return res; } static TImageSize * find_image_size_for_name (TGallerySetup *setup, const gchar *name) { GList *l; TImageSize *image_size; for (l = g_list_first (setup->design->image_sizes); l; l = g_list_next (l)) { image_size = l->data; g_assert (image_size != NULL); if (g_ascii_strcasecmp (name, image_size->name) == 0) return image_size; } return NULL; } static gchar * get_index_filename (TAlbum *items, TGalleryDesignTheme *theme, TPathInfo *path_info, TIndexItem *retrieve_child) { gchar *s; TGalleryType gallery_type; gallery_type = items->type; if (retrieve_child) { s = g_build_filename (path_info->src_dir, retrieve_child->path, "index.xml", NULL); gallery_type = get_child_gallery_type (s); g_free (s); } return (gallery_type == GALLERY_TYPE_ALBUM || theme->index_filename == NULL) ? theme->album_filename : theme->index_filename; } /* * write_html_album: process album and index template files * * template_src = template file of the album/index * dst = save generated file as * items = array of items in the album/index * */ gboolean write_html_album (TGallerySetup *setup, TPathInfo *path_info, TGalleryDesignTheme *theme, const gchar *template_src, const gchar *dst, TAlbum *items) { FILE *fin; FILE *fout; gchar *line; gchar *block; gchar *s1, *s2, *s3, *s4, *s5; TAlbum *parent; TIndexItem *item; TIndexItem *tmp_item; int level, old_parent_item_index; gboolean res; int bb; int i; unsigned int real_total_items; unsigned long img_thumb_w, img_thumb_h; ReplaceTable *global_replace_table; ReplaceTable *local_replace_table; BlockParser *block_parser; TImageSize *image_size, *thumb_image_size; GHashTable *defines; fin = fopen (template_src, "r"); if (fin == NULL) { log_error ("write_html_index: error reading file \"%s\": %s\n", template_src, strerror (errno)); return FALSE; } fout = fopen (dst, "w"); if (fout == NULL) { log_error ("write_html_index: error writing to file \"%s\": %s\n", dst, strerror (errno)); fclose (fin); return FALSE; } res = TRUE; global_replace_table = replace_table_new_from_defines (theme->defines); block_parser = block_parser_new (); defines = clone_string_hash_table (theme->defines); block_parser_set_conditionals (block_parser, defines); /* Get number of real pictures in the list */ real_total_items = 0; for (i = 0; i < items->items->len; i++) { tmp_item = g_ptr_array_index (items->items, i); if (tmp_item->type == INDEX_ITEM_TYPE_PICTURE && (! tmp_item->hidden)) real_total_items++; } replace_table_add_key_int (global_replace_table, "TOTAL_ITEMS", real_total_items); /* Page title */ if (items->parent_index == NULL || setup->site_title == NULL) s1 = g_strdup (setup->site_title ? setup->site_title : items->ID); else s1 = g_strdup_printf ("%s | %s", items->title, setup->site_title); replace_table_add_key (global_replace_table, "PAGE_TITLE", s1); g_free (s1); /* Simple placeholders */ replace_table_add_key (global_replace_table, "ID", items->ID); replace_table_add_key (global_replace_table, "TITLE", items->title); replace_table_add_key (global_replace_table, "DESCRIPTION", items->desc); replace_table_add_key (global_replace_table, "FOOTNOTE", items->footnote); replace_table_add_key (global_replace_table, "FOOTER", setup->footer); /* Navigation bar (NOTE: 'int level' is used below + favicon) */ s1 = g_strdup (items->ID); old_parent_item_index = items->parent_item_index + 1; parent = items->parent_index; level = 1; if (parent) { tmp_item = g_ptr_array_index (parent->items, old_parent_item_index - 1); if (tmp_item && tmp_item->path && strlen (tmp_item->path) > 0) level += count_dir_levels (tmp_item->path) - 1; } /* Go Up string */ if (parent) { s3 = make_string ("../", level); s2 = setup->use_inpage_links ? g_strdup_printf ("#i%d", old_parent_item_index) : g_strdup (""); replace_table_add_key_printf (global_replace_table, "GO_UP_LINK", "%s%s%s", s3, get_index_filename (parent, theme, NULL, NULL), s2); g_free (s2); g_free (s3); } while (parent) { s3 = make_string ("../", level); s4 = g_strdup (parent->ID); s5 = setup->use_inpage_links ? g_strdup_printf ("#i%d", old_parent_item_index) : g_strdup (""); s2 = g_strdup_printf ("%s > %s", s3, get_index_filename (parent, theme, NULL, NULL), s5, s4, s1); g_free (s3); g_free (s1); g_free (s4); g_free (s5); s1 = s2; old_parent_item_index = parent->parent_item_index + 1; parent = parent->parent_index; level++; if (parent) { tmp_item = g_ptr_array_index (parent->items, old_parent_item_index - 1); if (tmp_item && tmp_item->path && strlen (tmp_item->path) > 0) level += count_dir_levels (tmp_item->path) - 1; } } replace_table_add_key (global_replace_table, "NAV_BAR", s1); g_free (s1); /* Supportfiles path */ s1 = make_string ("../", level - 1); replace_table_add_key (global_replace_table, "TEMPLATES_PATH", setup->supplemental_files_use_common_root ? s1 : ""); g_free (s1); /* META tags */ s1 = g_strdup_printf ("\t\n", APP_NAME_FULL, VERSION); if (setup->meta_author || items->meta_author) { s3 = g_strdup (items->meta_author ? items->meta_author : setup->meta_author); adjust_tags_parameter (&s3); s2 = g_strdup_printf ("%s\t\n", s1, s3); g_free (s3); g_free (s1); s1 = s2; } if (setup->meta_description || items->meta_description) { s3 = g_strdup (items->meta_description ? items->meta_description : setup->meta_description); adjust_tags_parameter (&s3); s2 = g_strdup_printf ("%s\t\n", s1, s3); g_free (s3); g_free (s1); s1 = s2; } if (setup->meta_keywords || items->meta_keywords) { s3 = g_strdup (items->meta_keywords ? items->meta_keywords : setup->meta_keywords); adjust_tags_parameter (&s3); s2 = g_strdup_printf ("%s\t\n", s1, s3); g_free (s3); g_free (s1); s1 = s2; } if (setup->favicon_file && strlen (setup->favicon_file) > 0) { s3 = make_string ("../", level - 1); if (setup->favicon_type) s2 = g_strdup_printf ("%s\t\n", s1, setup->favicon_type, setup->supplemental_files_use_common_root ? s3 : "", setup->favicon_file); else s2 = g_strdup_printf ("%s\t\n", s1, setup->supplemental_files_use_common_root ? s3 : "", setup->favicon_file); g_free (s1); g_free (s3); s1 = s2; } replace_table_add_key (global_replace_table, "CGG_META_TAGS", s1); g_free (s1); /* Atom feeds */ if (setup->feed_enabled) { s3 = make_string ("../", level - 1); s1 = g_strdup_printf ("\t\n", s3, setup->feed_filename, setup->feed_title); g_free (s3); replace_table_add_key (global_replace_table, "CGG_ATOM_FEED_TAGS", s1); g_free (s1); } /* Theming */ /* TODO: "image_size" will be used for album themes showing pictures inpage */ image_size = find_image_size_for_name (setup, theme->album_image_size); thumb_image_size = find_image_size_for_name (setup, "thumbnail"); /* Setup block parser */ block_parser_register_key (block_parser, "IMG_LIST", "IMG_LIST"); block_parser_register_key (block_parser, "IMG_LIST_LANDSCAPE", NULL); block_parser_register_key (block_parser, "IMG_LIST_PORTRAIT", NULL); block_parser_register_key (block_parser, "IMG_LIST_SQUARED", NULL); block_parser_register_key (block_parser, "LIST_SEPARATOR", NULL); block_parser_register_key (block_parser, "LIST_INTERSPACE", NULL); block_parser_register_key (block_parser, "GO_UP", "GO_UP"); /* Read through the template and replace placeholders with real data */ while (! feof (fin)) { line = block_parser_read_and_parse (block_parser, fin); if (line == NULL) break; /* Blocks */ if (block_parser_has_unused_data (block_parser, "GO_UP")) { block = block_parser_get_data (block_parser, "GO_UP"); if (block) { replace_table_process (&block, global_replace_table); replace_table_add_key (global_replace_table, "GO_UP", items->parent_index && setup->show_go_up ? block : ""); } g_free (block); } if (block_parser_has_unused_data (block_parser, "IMG_LIST")) { block = g_strdup (""); /* Now we have all block placeholders read, generate the items: */ for (i = 0; i < items->items->len; i++) { item = g_ptr_array_index (items->items, i); if (item == NULL) { log_error ("write_html_index: error getting item %d\n", i); continue; } /* Generate images (preview, original, thumbnail) */ local_replace_table = replace_table_new_from_defines (defines); s1 = NULL; switch (item->type) { case INDEX_ITEM_TYPE_PICTURE: /* Skip HTML code generation if it's a hidden item */ if (! item->hidden) { img_thumb_w = img_thumb_h = 0; get_image_paths (setup, items, item, i, path_info, thumb_image_size, NULL, &s2, &s3); if (s2 != NULL) get_image_sizes (s2, &img_thumb_w, &img_thumb_h); if (setup->squared_thumbnail_type != THUMBNAIL_SQUARE_TYPE_NONE || img_thumb_w == img_thumb_h) s1 = "IMG_LIST_SQUARED"; else s1 = (img_thumb_h > img_thumb_w) ? "IMG_LIST_PORTRAIT" : "IMG_LIST_LANDSCAPE"; s1 = block_parser_get_data (block_parser, s1); if (s3 != NULL) { replace_table_add_key (local_replace_table, "IMG_THUMBNAIL", s3); if (img_thumb_w > 0 && img_thumb_h > 0) { replace_table_add_key_int (local_replace_table, "IMG_SIZE_THUMB_W", img_thumb_w); replace_table_add_key_int (local_replace_table, "IMG_SIZE_THUMB_H", img_thumb_h); } } g_free (s2); g_free (s3); s2 = GET_ITEM_TARGET_FILENAME (item); replace_table_add_key_printf (local_replace_table, "IMG_SUBPAGE", theme->picture_filename, s2); replace_table_add_key (local_replace_table, "IMG_FILENAME", s2); g_free (s2); replace_table_add_key (local_replace_table, "IMG_TITLE", item->title); replace_table_add_key (local_replace_table, "IMG_DESCRIPTION", item->title_description); replace_table_add_key_printf (local_replace_table, "IMG_LIST_ID", "i%d", i + 1); if (items->type == GALLERY_TYPE_INDEX) { s3 = g_build_filename (path_info->src_dir, item->path, "index.xml", NULL); replace_table_add_key_int (local_replace_table, "ALBUM_NUM_ITEMS", get_album_objects_count (s3)); replace_table_add_key_printf (local_replace_table, "ALBUM_SUBPATH", "%s/%s", item->path, get_index_filename (items, theme, path_info, item)); g_free (s3); } } break; case INDEX_ITEM_TYPE_SEPARATOR: s1 = block_parser_get_data (block_parser, "LIST_SEPARATOR"); replace_table_add_key (local_replace_table, "LIST_SEPARATOR_TITLE", item->title); break; case INDEX_ITEM_TYPE_INTERSPACE: s1 = block_parser_get_data (block_parser, "LIST_INTERSPACE"); replace_table_add_key (local_replace_table, "LIST_INTERSPACE_TITLE", item->title); break; } if (s1) { replace_table_process (&s1, local_replace_table); s2 = g_strdup_printf ("%s%s", block, s1); g_free (block); block = s2; g_free (s1); } replace_table_free (local_replace_table); } replace_table_process (&block, global_replace_table); replace_table_add_key (global_replace_table, "IMG_LIST", block); g_free (block); /* We don't use data from this key directly, let's mark it as used since we've built the structure we needed. */ block_parser_set_as_used (block_parser, "IMG_LIST"); } /* Replace all known tags */ replace_table_process (&line, global_replace_table); /* Write to file */ bb = fputs (line, fout); g_free (line); if (bb < 0) { log_error ("write_html_index: error writing to file \"%s\": %s\n", dst, strerror (errno)); res = FALSE; break; } } fclose (fout); fclose (fin); g_hash_table_destroy (defines); replace_table_free (global_replace_table); block_parser_free (block_parser); return res; } /* * write_html_image: process single image template file * * template_src = template file of the album/index * dst = save generated file as * item = data for the current item * parent_items = array of items in the album, to determine our position and make links to previous/next image * */ gboolean write_html_image (TGallerySetup *setup, TPathInfo *path_info, TGalleryDesignTheme *theme, const gchar *template_src, const gchar *dst, TIndexItem *item, TAlbum *parent_items) { FILE *fin; FILE *fout; gchar *img_dst; gchar *img_dst_page; gchar *img_orig_src; gchar *img_orig_dst; gchar *img_orig_dst_page; TExifData *exif; unsigned long img_w, img_h; unsigned long img_orig_w, img_orig_h; unsigned int item_index, next_item_index, real_item_index, real_total_items; TIndexItem *previous_item; TIndexItem *next_item; TIndexItem *tmp_item; TAlbum *parent; int i; gchar *line; gchar *block; gchar *s1, *s2, *s3, *s4, *s5; gchar *imgname, *preload_imgname; gchar *title, *title_desc; gboolean res; int bb; int level, old_parent_item_index; gboolean override_title_meta; gboolean image_fullsize; gboolean theme_size_is_original; ReplaceTable *replace_table; BlockParser *block_parser; TImageSize *image_size; GHashTable *defines; fin = fopen (template_src, "r"); if (fin == NULL) { log_error ("write_html_image: error reading file \"%s\": %s\n", template_src, strerror (errno)); return FALSE; } fout = fopen (dst, "w"); if (fout == NULL) { log_error ("write_html_image: error writing to file \"%s\": %s\n", dst, strerror (errno)); fclose (fin); return FALSE; } img_orig_src = NULL; img_orig_dst = NULL; img_orig_dst_page = NULL; preload_imgname = NULL; res = TRUE; replace_table = replace_table_new_from_defines (theme->defines); block_parser = block_parser_new (); defines = clone_string_hash_table (theme->defines); block_parser_set_conditionals (block_parser, defines); /* Get our index in the album */ item_index = 0; real_item_index = 0; real_total_items = 0; for (i = 0; i < parent_items->items->len; i++) { tmp_item = g_ptr_array_index (parent_items->items, i); if (tmp_item->type == INDEX_ITEM_TYPE_PICTURE) { if (! item_index) real_item_index++; real_total_items++; } if (tmp_item == item) item_index = i + 1; } /* Get previous and next items */ previous_item = NULL; next_item = NULL; next_item_index = 0; for (i = item_index - 2; i >= 0 && (previous_item == NULL || previous_item->type != INDEX_ITEM_TYPE_PICTURE); i--) previous_item = g_ptr_array_index (parent_items->items, i); if (previous_item && previous_item->type != INDEX_ITEM_TYPE_PICTURE) previous_item = NULL; for (i = item_index; i < parent_items->items->len && (next_item == NULL || next_item->type != INDEX_ITEM_TYPE_PICTURE); i++) { next_item = g_ptr_array_index (parent_items->items, i); next_item_index = i; } if (next_item && next_item->type != INDEX_ITEM_TYPE_PICTURE) { next_item = NULL; next_item_index = 0; } /* If currently processed picture size is original, disable fullsize tags */ theme_size_is_original = g_ascii_strcasecmp (theme->picture_image_size, "original") == 0; /* Original size is needed for several things, like EXIF and IPTC metadata */ image_size = find_image_size_for_name (setup, "original"); get_image_paths (setup, parent_items, item, item_index, path_info, image_size, &img_orig_src, &img_orig_dst, &img_orig_dst_page); image_size = find_image_size_for_name (setup, theme->picture_image_size); get_image_paths (setup, parent_items, item, item_index, path_info, image_size, NULL, &img_dst, &img_dst_page); imgname = g_path_get_basename (img_dst); if (next_item && setup->preload) get_image_paths (setup, parent_items, next_item, next_item_index, path_info, image_size, NULL, NULL, &preload_imgname); /* Get EXIF data from the original image */ exif = NULL; if (img_orig_src) { exif = get_exif (img_orig_src); if (exif == NULL) log_error ("write_html_image: error getting exif data from file \"%s\"\n", img_orig_src); } /* Try destination image instead, though it might have the metadata stripped */ if (exif == NULL) { exif = get_exif (img_dst); if (exif == NULL) log_error ("write_html_image: error getting exif data from file \"%s\"\n", img_dst); } /* Retrieve image sizes of preview and original image */ get_image_sizes (img_dst, &img_w, &img_h); image_fullsize = ! theme_size_is_original && img_orig_dst != NULL && ! IS_NOFULLSIZE (item, parent_items, setup); if (image_fullsize) get_image_sizes (img_orig_dst, &img_orig_w, &img_orig_h); /* Get title and description from IPTC/EXIF/JPEG if not defined */ title = g_strdup (item->title); title_desc = g_strdup (item->title_description); if (setup->use_iptc_exif && title == NULL && title_desc == NULL && exif != NULL) { if (exif->iptc_caption) title = g_strdup (exif->iptc_caption); if (exif->jpeg_comment) { if (! title) title = g_strdup (exif->jpeg_comment); else title_desc = g_strdup (exif->jpeg_comment); } if (exif->exif_imgdesc) { if (! title) title = g_strdup (exif->exif_imgdesc); /* if (! title_desc) -- disabled title_desc = g_strdup (exif->exif_imgdesc); */ } if (exif->exif_usercomment) { if (! title) title = g_strdup (exif->exif_usercomment); if (! title_desc) title_desc = g_strdup (exif->exif_usercomment); } /* Convert line breaks to be visible in the HTML code */ if (title) { str_replace (&title, "\r\n", "
"); str_replace (&title, "\n", "
"); } if (title_desc) { str_replace (&title_desc, "\r\n", "
"); str_replace (&title_desc, "\n", "
"); } } if (title) title = g_strstrip (title); if (title_desc) title_desc = g_strstrip (title_desc); /* Page title */ s1 = (title && strlen (title) > 0) ? g_strdup_printf ("%s | ", title) : NULL; s2 = g_strdup_printf ("%s [%d/%d]", parent_items->title ? parent_items->title : parent_items->ID, real_item_index, real_total_items); s3 = setup->site_title ? g_strdup_printf (" | %s", setup->site_title) : NULL; s4 = g_strconcat (s1 ? s1 : "", s2, s3 ? s3 : "", NULL); replace_table_add_key (replace_table, "PAGE_TITLE", s4); g_free (s1); g_free (s2); g_free (s3); g_free (s4); /* Simple placeholders */ replace_table_add_key (replace_table, "FILE_NAME", imgname); replace_table_add_key (replace_table, "TITLE", title); replace_table_add_key (replace_table, "DESCRIPTION", title_desc); replace_table_add_key (replace_table, "FOOTER", setup->footer); replace_table_add_key_int (replace_table, "TOTAL_ITEMS", real_total_items); replace_table_add_key_int (replace_table, "FILE_NO", real_item_index); 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_printf (replace_table, "IMG_SRC", "%s%s/%s", TARGET_IMAGE_DIR_PREFIX, image_size->name, imgname); replace_table_add_key (replace_table, "IMG_SRC_PRELOAD", preload_imgname ? preload_imgname : ""); if (image_fullsize) { replace_table_add_key_int (replace_table, "IMG_SIZE_ORIG_W", img_orig_w); replace_table_add_key_int (replace_table, "IMG_SIZE_ORIG_H", img_orig_h); replace_table_add_key (replace_table, "IMG_SRC_FULL", img_orig_dst_page); } /* Navigation bar (NOTE: 'int level' is used below + favicon) */ s1 = g_strdup (imgname); parent = parent_items; old_parent_item_index = -1; level = 0; while (parent) { s3 = make_string ("../", level); s4 = g_strdup (parent->ID); s5 = setup->use_inpage_links ? g_strdup_printf ("#i%d", parent == parent_items ? item_index : old_parent_item_index) : g_strdup (""); s2 = g_strdup_printf ("%s > %s", s3, get_index_filename (parent, theme, NULL, NULL), s5, s4, s1); g_free (s3); g_free (s1); g_free (s4); g_free (s5); s1 = s2; old_parent_item_index = parent->parent_item_index + 1; parent = parent->parent_index; level++; if (parent) { tmp_item = g_ptr_array_index (parent->items, old_parent_item_index - 1); if (tmp_item && tmp_item->path && strlen (tmp_item->path) > 0) level += count_dir_levels (tmp_item->path) - 1; } } replace_table_add_key (replace_table, "NAV_BAR", s1); g_free (s1); /* Supportfiles path */ s1 = make_string ("../", level - 1); replace_table_add_key (replace_table, "TEMPLATES_PATH", setup->supplemental_files_use_common_root ? s1 : ""); g_free (s1); /* EXIF values */ if (exif) { replace_table_add_key (replace_table, "EXIF_ISO", exif->iso ? exif->iso : "??"); replace_table_add_key (replace_table, "EXIF_TIME", exif->exposure ? exif->exposure : "??"); replace_table_add_key (replace_table, "EXIF_APERTURE", exif->aperture ? exif->aperture : "??"); replace_table_add_key (replace_table, "EXIF_FOCAL_LENGTH", exif->focal_length ? exif->focal_length : "??"); replace_table_add_key (replace_table, "EXIF_FLASH", exif->flash ? exif->flash : "??"); replace_table_add_key (replace_table, "EXIF_DATE", exif->datetime ? exif->datetime : "??"); replace_table_add_key (replace_table, "EXIF_CAMERA_MODEL", exif->camera_model ? exif->camera_model : "??"); s1 = g_strdup_printf ("(%s)", exif->focal_length_35mm); replace_table_add_key (replace_table, "EXIF_FOCAL_35", exif->focal_length_35mm ? s1 : ""); g_free (s1); } /* Border style */ s1 = item->border_style; if (s1 == NULL) s1 = parent_items->border_style; if (s1 == NULL) s1 = setup->border_style; if (s1 == NULL) s1 = "border_single"; replace_table_add_key (replace_table, "IMG_BORDER_STYLE", s1); /* Next/Previous links */ if (next_item) { s2 = GET_ITEM_TARGET_FILENAME (next_item); replace_table_add_key_printf (replace_table, "LINK_NEXT", theme->picture_filename, s2); g_free (s2); } else replace_table_add_key (replace_table, "LINK_NEXT", get_index_filename (parent_items, theme, NULL, NULL)); if (previous_item) { s2 = GET_ITEM_TARGET_FILENAME (previous_item); replace_table_add_key_printf (replace_table, "LINK_PREV", theme->picture_filename, s2); g_free (s2); } else replace_table_add_key (replace_table, "LINK_PREV", get_index_filename (parent_items, theme, NULL, NULL)); /* META tags */ override_title_meta = setup->use_title_as_meta && title && (strlen (title) > 0); s1 = g_strdup_printf ("\t\n", VERSION); if (setup->meta_author || parent_items->meta_author) { s3 = g_strdup (parent_items->meta_author ? parent_items->meta_author : setup->meta_author); adjust_tags_parameter (&s3); s2 = g_strdup_printf ("%s\t\n", s1, s3); g_free (s3); g_free (s1); s1 = s2; } if (setup->meta_description || parent_items->meta_description || override_title_meta) { s3 = g_strdup (override_title_meta ? title : (parent_items->meta_description ? parent_items->meta_description : setup->meta_description)); adjust_tags_parameter (&s3); s2 = g_strdup_printf ("%s\t\n", s1, s3); g_free (s3); g_free (s1); s1 = s2; } if ((setup->meta_keywords || parent_items->meta_keywords) && (! override_title_meta)) { s3 = g_strdup (parent_items->meta_keywords ? parent_items->meta_keywords : setup->meta_keywords); adjust_tags_parameter (&s3); s2 = g_strdup_printf ("%s\t\n", s1, s3); g_free (s3); g_free (s1); s1 = s2; } if (setup->favicon_file && strlen (setup->favicon_file) > 0) { s3 = make_string ("../", level - 1); if (setup->favicon_type) s2 = g_strdup_printf ("%s\t\n", s1, setup->favicon_type, setup->supplemental_files_use_common_root ? s3 : "", setup->favicon_file); else s2 = g_strdup_printf ("%s\t\n", s1, setup->supplemental_files_use_common_root ? s3 : "", setup->favicon_file); g_free (s1); g_free (s3); s1 = s2; } replace_table_add_key (replace_table, "CGG_META_TAGS", s1); g_free (s1); /* Atom feeds */ if (setup->feed_enabled) { s3 = make_string ("../", level - 1); s1 = g_strdup_printf ("\t\n", s3, setup->feed_filename, setup->feed_title); g_free (s3); replace_table_add_key (replace_table, "CGG_ATOM_FEED_TAGS", s1); g_free (s1); } /* Setup block parser */ block_parser_register_key (block_parser, "IMG_FULLSIZE_LINK", "IMG_FULLSIZE_LINK"); block_parser_register_key (block_parser, "EXIF_TABLE", "EXIF_TABLE"); /* Read through the template and replace placeholders with real data */ while (! feof (fin)) { line = block_parser_read_and_parse (block_parser, fin); if (line == NULL) break; /* Blocks */ if (block_parser_has_unused_data (block_parser, "IMG_FULLSIZE_LINK")) { block = block_parser_get_data (block_parser, "IMG_FULLSIZE_LINK"); if (block) { replace_table_process (&block, replace_table); replace_table_add_key (replace_table, "IMG_FULLSIZE_LINK", image_fullsize ? block : ""); } g_free (block); } if (block_parser_has_unused_data (block_parser, "EXIF_TABLE")) { block = block_parser_get_data (block_parser, "EXIF_TABLE"); if (block) { replace_table_process (&block, replace_table); replace_table_add_key (replace_table, "EXIF_TABLE", setup->show_exif_table ? block : ""); } g_free (block); } /* Replace all known tags */ replace_table_process (&line, replace_table); /* Write to file */ bb = fputs (line, fout); g_free (line); if (bb < 0) { log_error ("write_html_image: error writing to file \"%s\": %s\n", dst, strerror (errno)); res = FALSE; break; } } fclose (fout); fclose (fin); g_free (title); g_free (title_desc); g_free (img_dst); g_free (img_dst_page); g_free (img_orig_src); g_free (img_orig_dst); g_free (img_orig_dst_page); g_free (imgname); g_free (preload_imgname); g_hash_table_destroy (defines); free_exif_data (exif); replace_table_free (replace_table); block_parser_free (block_parser); return res; }