bins-1.1.29/0000755000175000017500000000000010303167611013321 5ustar jeromejerome00000000000000bins-1.1.29/bins0000755000175000017500000057071210303167612014217 0ustar jeromejerome00000000000000#!/usr/bin/perl -w # -*- cperl-indent-level: 4 -*- # BINS Photo Album version 1.1.29 # Copyright (C) 2001-2005 Jérôme Sautret (Jerome@Sautret.org) # # Original SWIGS code : # Copyright (C) 2000 Brendan McMahan (mcmahahb@whitman.edu) # Initial code based on IDS 0.21 : # Copyright (C) John Moose (moosejc@muohio.edu) # # $Id: bins,v 1.182 2005/08/22 23:52:33 jerome Exp $ # # 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 # (at your option) 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; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # Type "bins -h" on command line for usage information # and read bins(1) man page. my $verbose = 1; # verbosity level (from 0 to 4) use strict; # Convention: When we pass around paths and directories (aka albums), # we always include the trailing backslash, like "albums/", so we can # easily combine the directories # General Perl modules use POSIX qw(strftime); use Storable qw(dclone); use File::Glob ':glob'; use File::Basename; use File::Spec; use IO::File; use UNIVERSAL; # qw(isa); use Getopt::Long; # Image manipulation use Image::Size; use Image::Info qw(image_info); use Image::Magick; # HTML manipulation use URI::Escape; use HTML::Entities; use HTML::Template; use HTML::Clean; #use HTML::Template::JIT; # XML parsing & writing use XML::Grove; use XML::Grove::Builder; use XML::Grove::Path; use XML::Grove::AsCanonXML; use XML::Grove::PerlSAX; use XML::Parser::PerlSAX; use XML::Handler::YAWriter; use Text::Iconv; # Date parsing use Date::Parse; # Used by the search engine use Text::Unaccent; #use XML::Handler::XMLWriter; #use XML::Grove::AsString; #use XML::Handler::Composer; #use XML::Filter::Reindent; #use XML::Handler::Sample; # Debugging #use Data::Dumper; #use XML::SAX::Expat; sub have_package; sub _; # alias for Getext, if present ############################################################################ # Configuration Section # ############################################################################ # I18N my $localePath = "/usr/local/share/locale"; # Base locale path (for I18N) my $I18N = have_package("Locale::gettext"); if ($I18N) { require Locale::gettext; require POSIX; POSIX::setlocale(&POSIX::LC_ALL, ""); Locale::gettext::bindtextdomain("bins", $localePath); Locale::gettext::textdomain("bins"); } # You can change the following parameters in the /etc/bins/binsrc or # ~/.bins/binrc configuration files or in the section of the # album or image description files (i.e. album.xml or # .jpg.xml) when it makes sense. # note that all of these options are now documented in bins.sgml; any # new options need corresponding new documentation. my %defaultConfig = ( homeURL => "/", # Set this to your home page. This is # used for the leave button in some # templates. feedbackMail => "", # Put here the mailaddress of the # album-maintainer. If this is set, you # will get a mail-icon in your views that # links to this address. treePreview => 1, # If set to 1, preview-thumbnails will be # showed in the album-tree-page. backgroundImage => "", # Set this to the image that should be displayed # as the background of the album-pages. # The Image will be copied to the static-files # directory. # The name should be unique for the entire album. customStyleSheet => "", # Set this to the name that should be used # for the current album and its subalbums # The Stylesheet will be copied to the # static-files directory. # The name should be unique for the entire album. dateString => "%c", # Specify the format of date strings; this # accepts all formats supported by date(1). excludeBackgroundImage => 1, # If set to 1, the image with the name given # in backgroundImage will be excluded from # the current directory. addExifToDescFile => 1, # If set to 1, write exif data found in # the image file to the image desc file. deExifyImages => 1, # If set to 1, do NOT copy exif data found # in the source images to any of the generated # resized images. Setting this option can yield # significant space savings, especially for # thumbnail and imagelist pages. createEmptyDescFields => 1,# If set to 1, add empty description # fields in the section # when the image description file is # created to ease later edition with an # text editor jpegQuality => 75, # Quality of scaled jpegs (lower number = more # compression, lower quality) in 1-100 range. jpegProgressify => "smaller", # values: never, always, smaller. whether # to make jpegs progressive using jpegtran # (if available). smaller means only if # the progressive file is smaller than the # original titleOnThumbnail => 1, # Should the title be displayed on top on the # thumbnail in the thumbnails page ? emptyAlbumDesc => 0, # If set to 1, and album desciption is # not set, no message will be displayed # (instead of the "No long/short # description available" one). reverseOrder => 0, # are we reversing sorting order (see -r) # (0=none,1=dirs,2=pix,3=both) defaultSize => 1, # Size to use when user clicks directly # on the thumbnail in the thumbnails # page instead of one of the size # name. 0 is the first size (Small in # the default config), 1 the second # (Medium), and so on. Set this variable # to -1 if you don't want the thumbnail # to be clickable. thumbnailPageCycling => 1, # If set to 0 next/prev-Links will be hidden if # the actual page is the last/first Thumbnailpage imagePageCycling => 1, # If set to 0 next/prev-Links will be hidden if # the actual page is the last/first Imagepage pathImgNum => 1, # If set to 1 the path in the imageview contains # the number of the current image pathShowIcon => 1, # If set to 1 the path contains icons thumbnailInImageList => 1, # Display thumbnails on the Image List page ? albumThumbInSubAlbumPage =>1, # If set to 1, display the current # album thumbnail in sub-albums page # if it has pictures, with links to # the thumbnails page. allThumbnailsPage => 0, # If set to 1, generate a page with all # thumbnails in the album and # sub-albums. This is deactivated # because it is an alpha feature which # seems to not work properly. borderOnThumbnails =>0, # Width of the border of the thumbnail's # image in the thumbnails page, in # pixels. 0 means no border. thumbnailBackground => 0, # If 1, add a background colour to the # thumbnail's cell in the thumbnails # page so that if the top and bottom # borders are wider than the image (for # example, if it is in portrait mode), # instead of spilling over, there is a # border around the whole picture. thumbsPerRow => 4, # Number of thumbnails displayed in each # row in an album. numThumbsPerPage => 16, # Number of thumbnails displayed # in each page in an album. previewMaxHeight => 150, # Max Thumbnail Height. previewMaxWidth => 150, # Max Thumbnail Width. thumbPrevNext => 1, # If set to 1, display thumbnails close # to the previous and next link at the # bottom of the image page. rotateImages => "destination",# Do we rotate images if the Orientation # Exif tag is found ? If set to # 'original', the original image is # rotated the first time, and then it is # left untouched. If set to # 'destination', this is all the scaled # images and thumbnails that are # rotated. This is less efficient, but # the original images are preserved. If # set to 'none', no rotation is # performed. rotateWithJpegtran => 0, # If set to 1, bins try to use the # jpegtran program to rotate JPEG images # if it is available. jpegtran is faster # and lossless, but some versions fail # to perform rotation correctly, so it # is deactivated in default config. If # set to 0 or if jpegtran is not found, # mogrify (from ImageMagick) is used. scaleIfSameSize => 0, # If set to 1, we scale the picture even # if destination size is the same as the # original picture, if set to 0, the # original image is just copied if the # size is correct. scaleMethod => "scale", # What method should be used to create # scaled pictures and thumbnails ? Can # be either scale or sample. sample is # faster, scale is better. whenSrcSmaller => "enlarge", # What to do if the source image is smaller # than the size of the generated image. # If set to "enlarge" the generated image is # enlarged to the requested size. # If set to "original" the generate image is # the same size as the original image. # If set to "skip" do not generate any image. linkInsteadOfCopy => 0, # If set to 1, we link the picture instead # of copying it if possible # (i.e. scaleIfSameSize is set to 0 and # destination image doesn't have to be # rotated : rotateImages is set to # original or none, or orientation is # already correct). linkRelative => 1, # If set to 1, we use a relative path for the # link updateOriginalPerms => 1, # attempt to update source image permissions maxAlbumsForLongSubAlbum => 20, # If the number of sub albums is greater, # generate a short sub album page # instead of the long one. stripDirPrefix => 0, # If set to 1, Numbers preceding # the album title, followed by an # underscore, are stripped. If this # parameter is set, then prefix # ordering numbers on directories # are removed. For example, if one # has directories may, june, and # august, they can be renamed # 0_may, 1_june, and 2_august and # they will appear in the album in # the correct order. This can be # overridden by the-p command line # option. compactHTML => 1, # If set to 1, generated # HTML code is cleaned up to reduce # the size of pages and thus, speed # up browsing This reduces the size # of HTML BINS files by about # 30%. See HTML::Clean(3) to know # how optimizations are performed. javaScriptPreloadImage => 1, # If set to 1, add some javascript # code in image pages to preload # the next image of the same size # when current one is loaded, to # speed up the album browsing. javaScriptPreloadThumbs => 1, # If set to 1, add some javascript # code in thumbnails pages to # preload thumbnails of the next # page when current one is loaded, # to speed up the album browsing. searchEngine => 1, # If 1, generate a search page. # Images can be searched on # description fields set in the # searchFields parameter. searchFields => "title description people location event comment", # Space separated list of # description field names used by # the search engine, if # searchEngine is set to 1. searchLimit => 50, # Maximum results returned by the # search engine. Note that if # this number is too high, it can # hang the browser. createHtaccess => 1, # If 1, create an Apache .htaccess file # in the root dir of the album with the # encoding charset bound to html and # htm files noRotation => '_Orig$' , # Don't perform rotation on files # matching this regexp excludeFiles => "" , # exclude image files that match # this regexp (if set). excludeDirs => '^CVS$' , # exclude directories that match # this regexp (if set). ignore => "", # Put here a comma separated list of keyword. If # one on this keyword is found in the "ignore" # field in the section of an # sub-album.xml, then this sub-album will be # ignored, i.e. it will not be processed. You can # also use the -i command line option. hidden => "", # Put here a comma separated list of keyword. If # one on this keyword is found in the "ignore" # field in the section of an # sub-album.xml, then this sub-album will be # hidden, i.e. it will be generated but not linked # anywhere. You can also use the -n command line # option. colorStyle => "blue", # name of the color style to use templateStyle => "swigs", # name of the template style to use # The following parameters cannot be set in config files for now : globalConfigDir => "/etc/bins", # System wide configuration directory globalDataDir => "/usr/local/share/bins", # System wide data directory userConfigDir => "~/.bins", # User configuration directory configFileName => "binsrc", # Configuration file. htmlEncoding => "UTF-8", # HTML pages charset encoding xmlEncoding => "UTF-8", # XML files charset encoding defaultEncoding => "ISO-8859-1", # Charset encoding of your # environment. This value # is overridden by your # real local encoding as # reported by the 'locale # charmap' unix command. # This is used to display # strings on console and to # convert strings from .po # files. ); my $codeset; eval { require I18N::Langinfo; I18N::Langinfo->import(qw(langinfo CODESET)); $codeset = langinfo(CODESET()); }; # ANSI is unspeakably primitive, keep LATIN1 instead # Solaris refers to ISO 646 as "646" but that is not a valid codeset if (!$@ && $codeset && $codeset ne "ANSI_X3.4-1968" && $codeset ne "646") { $defaultConfig{defaultEncoding} = $codeset; beVerboseN("Forcing encoding to $codeset", 2); } my $local2htmlConverter; $local2htmlConverter = Text::Iconv->new($defaultConfig{defaultEncoding}, $defaultConfig{htmlEncoding}); # Here are set number, name and size of scaled images. # This can be changed in the binsrc or album.xml files. # By default, there is three sizes, but you can remove or add some new # by editing the @scaledWidths, @scaledHeights, @sizeNames and # @longSizeNames lists. # This is this size of each scaled picture : my @scaledWidths = ("40%", "64%", "100%"); # Can be either a resolution or my @scaledHeights = ("40%", "64%", "100%"); # a % of the original picture #my @scaledWidths = (200, 400, 600, 3000); #my @scaledHeights = (200, 400, 600, 3000); #This is the name of each scaled picture. Remember that the _("") #function is used for I18N only and is not mandatory. my @sizeNames = (_("Sm"), _("Med"), _("Lg")); my @longSizeNames = (_("Small"), _("Medium"), _("Large")); my @fileSizeNames = ("small.png", "medium.png", "large.png", "huge.png"); my @fileActiveSizeNames = ("smallActive.png", "mediumActive.png", "largeActive.png", "hugeActive.png"); #my @sizeNames = (_("Sm"), _("Med"), _("Lg"), _("Hg")); #my @longSizeNames = (_("Small"), _("Medium"), _("Large"), _("Huge")); $defaultConfig{scaledWidths} = \@scaledWidths; $defaultConfig{scaledHeights} = \@scaledHeights; $defaultConfig{sizeNames} = \@sizeNames; $defaultConfig{longSizeNames} = \@longSizeNames; $defaultConfig{fileSizeNames} = \@fileSizeNames; $defaultConfig{fileActiveSizeNames} = \@fileActiveSizeNames; # Fields to display (in the list order) under the picture. These # fields are defined in the getFields function below. my @mainFields = ("description", "people", "location", "date", "event", "comment"); # Fields to display (in the list order) in the details page. These # fields are in the getFields function below. my @secondaryFields = ( # DigiCam _("BINS-SECTION DigiCam Info"), "make", "model", "owner", "firmware", # DigiCam settings for the image _("BINS-SECTION DigiCam settings for the image"), "artist", "copyright", "imagedescription", "usercomment", "canon_quality", "canon_image_size", "CanonContrast", "CanonSaturation", "CanonSharpness", # DigiCam settings for the photo _("BINS-SECTION DigiCam settings for the photo"), "canon_easy_shooting_mode", "canon_macro", "lightsource", "flash", "canon_flash_mode", "flashenergy", "CanonISO", "iso", "exposure_time", "exposure_prog", "canon_digital_zoom", "canon_focus_mode", "CanonFocusType", "subject_distance", "metering_mode", "focal_length", "shutter_speed_value", "brightness", "aperture_value", "max_aperture_value", "fnumber", "canon_timer_length", "canon_continuous_drive_mode", "focal_plane_x_resolution", "focal_plane_y_resolution", "orientation", # Image characteristics _("BINS-SECTION Image Characteristics"), "date", "comment", "file_media_type", "jpeg_type", "interlace", "color_type", "samples_per_pixel", "bits_per_sample", "resolution", "compression", "usercomment", "exif_version", "image_width", "image_length", "compressed_bits", "BINS-SECTION end", # close the last section ); sub getFields { # The key is the string used as the name in the picture # description file. # Name corresponds to the string displayed under the picture. # EXIF is the name of the field in the EXIF structure # found in some JPEG images. # The value of the EXIF structure is only used if no value # is present in the picture description file. # Transform is a Perl operator used to convert an exif value # to the desired format to display. It is evaluated as # normal Perl code and the result has to be in $_. my %fields = ( "title" => { Name => _("Title"), }, "description" => { Name => _("Description"), }, "people" => { Name => _("People"), }, "location" => { Name => _("Location"), }, "date" => { Name => _("Date"), EXIF => "DateTimeOriginal", Transform => '$_ = local2html(strftime $configHash->{dateString}, gmtime str2time "$_") if str2time "$_"', # Alternatively, you could use regex substitution: # English version is yyyy:mm:dd hh:mm:ss to yyyy/mm/dd hh:mm:ss : # Transform => 's%^(\\d+):(\\d+):(\\d+) (.*)$%\$1/\$2/\$3 \$4%', # French version is yyyy:mm:dd hh:mm:ss to dd/mm/yyyy hh:mm:ss : # Transform => 's%^(\d+):(\d+):(\d+) (.*)$%$3/$2/$1 $4%', }, "event" => { Name => _("Event"), }, "comment" => { Name => _("Comment"), EXIF => "Comment", }, "model" => { Name => _("Equipment Model"), EXIF => "Model", }, "make" => { Name => _("Equipment Make"), EXIF => "Make", }, "firmware" => { Name => _("Software"), # EXIF => "Canon-Tag-0x0007", EXIF => "Software", Tip => _("Firmware (internal software of device) version number."), }, "owner" => { Name => _("Owner name"), # EXIF => "Canon-Tag-0x0009", EXIF => "Owner", Tip => _("Name of the owner of the digicam."), }, "artist" => { Name => _("Artist name"), EXIF => "Artist", Tip => _("Name of the camera owner, photographer or image creator."), }, "copyright" => { Name => _("Copyright"), EXIF => "Copyright", Tip => _("Copyright information."), }, "flash" => { Name => _("Flash"), EXIF => "Flash", }, "usercomment" => { Name => _("User comment"), EXIF => "UserComment", }, "file_media_type" => { Name => _("File Media Type"), EXIF => "file_media_type", Tip =>_("This is the MIME type that is appropriate for the given file format."), }, "color_type" => { Name => _("Color Type"), EXIF => "color_type", }, "jpeg_type" => { Name => _("JPEG Type"), EXIF => "JPEG_Type", }, "interlace" => { Name => _("Interlace method"), EXIF => "Interlace", Tip => _("Interlace method used."), }, "metering_mode" => { Name => _("Metering Mode"), EXIF => "MeteringMode", Tip => _("Exposure metering method."), }, "samples_per_pixel" => { Name => _("Samples Per Pixel"), EXIF => "SamplesPerPixel", Tip => _("This says how many channels there are in the image. For some image formats this number might be higher than the number implied from the \"Color Type\""), }, "resolution" => { Name => _("Physical Resolution"), EXIF => "resolution", Tip => _("The value of this field normally gives the physical size of the original image on screen or paper. When there is no unit then this field denotes the squareness of pixels in the image."), }, "compression" => { Name => _("Compression Algorithm"), EXIF => "Compression", }, "exif_version" => { Name => _("Exif Version"), EXIF => "ExifVersion", }, "subject_distance" => { Name => _("Subject Distance"), EXIF => "SubjectDistance", Tip => _("Distance to focus point."), }, "bits_per_sample" => { Name => _("Bits Per Sample"), EXIF => "BitsPerSample", Tip => _("This says how many bits are used to encode each of samples."), }, "exposure_time" => { Name => _("Exposure Time"), EXIF => "ExposureTime", Tip => _("Exposure time (reciprocal of shutter speed)."), }, "shutter_speed_value" => { Name => _("Shutter Speed Value"), EXIF => "ShutterSpeedValue", Tip => _("Shutter speed. The unit is the APEX (Additive System of Photographic Exposure) setting"), }, "brightness" => { Name => _("Brightness"), EXIF => "BrightnessValue", Tip => _("The value of brightness. The unit is the APEX (Additive System of Photographic Exposure) value."), }, "focal_length" => { Name => _("Focal Length"), EXIF => "FocalLength", Tip => _("Focal length of lens used to take image."), }, "aperture_value" => { Name => _("Aperture Value"), EXIF => "ApertureValue", Tip => _("The actual aperture value of lens when the image was taken."), }, "max_aperture_value" => { Name => _("Maximum Aperture Value"), EXIF => "MaxApertureValue", Tip => _("Maximum aperture value of lens."), }, "fnumber" => { Name => _("F-Number"), EXIF => "FNumber", Tip => _("The actual F-number (F-stop) of lens when the image was taken."), }, "focal_plane_y_resolution" => { Name => _("Focal Plane Y Resolution"), EXIF => "FocalPlaneYResolution", Tip => _("Pixel density at CCD's position. If you have MegaPixel digicam and take a picture by lower resolution (e.g.VGA mode), this value is re-sampled by picture resolution. In such case, Focal Plane Y Resolution is not same as CCD's actual resolution."), }, "focal_plane_x_resolution" => { Name => _("Focal Plane X Resolution"), EXIF => "FocalPlaneXResolution", Tip => _("Pixel density at CCD's position. If you have MegaPixel digicam and take a picture by lower resolution (e.g.VGA mode), this value is re-sampled by picture resolution. In such case, Focal Plane X Resolution is not same as CCD's actual resolution."), }, "canon_macro" => { Name => _("Macro"), EXIF => "CanonMacro", #Tip => _(""), }, "canon_timer_length" => { Name => _("Timer Length"), EXIF => "CanonTimerLength", #Tip => _(""), }, "canon_quality" => { Name => _("Quality"), EXIF => "CanonQuality", #Tip => _(""), }, "canon_continuous_drive_mode" => { Name => _("Continuous Drive Mode"), EXIF => "CanonContinuousDriveMode", #Tip => _(""), }, "canon_flash_mode" => { Name => _("Flash Mode"), EXIF => "CanonFlashMode", #Tip => _(""), }, "canon_focus_mode" => { Name => _("Focus Mode"), EXIF => "CanonFocusMode", #Tip => _(""), }, "canon_image_size" => { Name => _("Image Size"), EXIF => "CanonImageSize", #Tip => _(""), }, "canon_digital_zoom" => { Name => _("Digital Zoom"), EXIF => "CanonDigitalZoom", #Tip => _(""), }, "canon_easy_shooting_mode" => { Name => _("Easy Shooting Mode"), EXIF => "CanonEasyShootingMode", #Tip => _(""), }, "CanonContrast" => { Name => _("Contrast"), EXIF => "CanonContrast", #Tip => _(""), }, "CanonSaturation" => { Name => _("Saturation"), EXIF => "CanonSaturation", #Tip => _(""), }, "CanonSharpness" => { Name => _("Sharpness"), EXIF => "CanonSharpness", #Tip => _(""), }, "CanonISO" => { Name => _("ISO"), EXIF => "CanonISO", #Tip => _(""), }, "iso" => { Name => _("ISO"), EXIF => "ISOSpeedRatings", Tip => _("ISO Speed and ISO Latitude of the camera or input device as specified in ISO 12232."), }, "CanonFocusType" => { Name => _("Focus Type"), EXIF => "CanonFocusType", #Tip => _(""), }, "exposure_prog" => { Name => _("Exposure Program"), EXIF => "ExposureProgram", Tip => _("The class of the program used by the camera to set exposure when the picture is taken."), }, "image_width" => { Name => _("Original Image Width"), EXIF => "ExifImageWidth", #Tip => _(""), }, "image_length" => { Name => _("Original Image Length"), EXIF => "ExifImageLength", #Tip => _(""), }, "compressed_bits" => { Name => _("Compression Quality"), EXIF => "CompressedBitsPerPixel", #Tip => _(""), }, "Orientation" => { Name => _("Orientation"), EXIF => "Orientation", #Tip => _(""), }, "lightsource" => { Name => _("Light Source"), EXIF => "LightSource", Tip => _("The kind of light source."), }, "usercomment" => { Name => _("User Comment"), EXIF => "UserComment", Tip => _("Keywords or comments on the image."), }, "imagedescription" => { Name => _("Image Description"), EXIF => "ImageDescription", #Tip => _(""), }, "flashenergy" => { Name => _("Flash Energy"), EXIF => "FlashEnergy", Tip => _("Indicates the strobe energy at the time the image is captured, as measured in Beam Candle Power Seconds (BCPS)."), }, "sensingmethod" => { Name => _("Sensing Method"), EXIF => "SensingMethod", Tip => _("Indicates the image sensor type on the camera or input device."), }, ); return \%fields; } my @priorityExifTags = (); # the field in this list are taken from # the desc file, even if they are present # in image file (normally, image field # takes precedence on desc file # these substitutions are made in all templates, useful for doing easy # color assignments, etc. The colors can be set in the bins/colors # section of config files or album/pictures desc files. my %colorsSubs = (blue => { PAGE_BACKCOLOR => "#FFFFFF", PAGE_TITLECOLOR => "#000000", MAINBAR_BACKCOLOR => "#000077", MAINBAR_TITLECOLOR => "#FFFFFF", MAINBAR_LINKCOLOR => "#eedd82", MAINBAR_CURRENTPAGECOLOR => "#d2d2d2", SUBBAR_BACKCOLOR => "#6060af", SUBBAR_LINKCOLOR => "#eedd82", SUBBAR_CURRENTPAGECOLOR => "#000000", SUBBAR_TITLECOLOR => "#FFFFFF", }); $defaultConfig{colorsSubs} = \%colorsSubs; sub getIntlSubs{ my $configHash = shift; # Strings to translate in the HTML template pages (if I18N is used) my %intlSubs = ( STRING_THUMBNAILS => _("thumbnails"), STRING_IMAGELIST => _("Image List"), STRING_HOME => _("Home"), STRING_ALBUM => _("Album"), STRING_UP => _("Up one album"), STRING_PREV => _("previous"), STRING_NEXT => _("next"), STRING_FIRST => _("first"), STRING_LAST => _("last"), STRING_SUBALBUMS => _("Sub Albums"), STRING_INTHISALBUM => _("In This Album"), STRING_BACK => _("Back"), STRING_BACKTOTHEIMAGE => _("Back to the image"), STRING_IMAGE => _("Image"), STRING_TREE => _("tree"), STRING_ALBUMTREE => _("Album Tree"), STRING_ALBUMGENERATEDBY => _("Album generated by"), STRING_FEEDBACK => _("Send Feedback"), STRING_YOURIMAGE => _("Your Image"), STRING_YOURALBUM => _("Your Album"), STRING_IMAGESEARCH => _("Image Search"), STRING_SEARCHKEYWORDS => _("Search keywords"), STRING_SEARCHONLYWHOLEWORDS => _("Search only whole words"), STRING_SEARCHJSERROR => _("ERROR: your browser must have Javascript enable in order to use the search feature"), STRING_SEARCH => _("search"), STRING_SEARCHTITLE => _("Search a picture in all albums"), STRING_TOOMANYRESULTS => gettext("Too many results, only the first %d are displayed. Try to refine your search."), STRING_NODOM => gettext("Your browser doesn't support the Level 1 DOM"), STRING_SEARCHCOMPLETED => gettext("Search completed: %d found"), BINS_VERSION => "1.1.29", ENCODING => $defaultConfig{htmlEncoding}, GENERATED_DATE => _("on "). local2html(strftime($configHash->{dateString}, localtime)), BINS_ID => '', ); return \%intlSubs; } # @knownImageExtentions defines file extensions that BINS can handle as # input image. BINS _should_ handle all input format of ImageMagick # (see ImageMagick(1) man page), but there is some formats that cause # problems. If you have tested successfully a format that is not # listed here, or if you have a problem with one of the following # format, please let me know. my @knownImageExtentions = ("jpg", "jpeg", "gif", "png", "tiff", "bmp", "tga", "ps", "eps", "fit", "pcx", "miff", "pix", "pnm", "rgb", "im1", "xcf", "xwd", "xpm", "avs", "dcm", "dcx", "dib", "dps", "dpx", "epdf", "epi", "ept", "fpx", "icb", "mat", "mtv", "pbm", "pcd", "pct", "pdb", "ppm", "ptif", "pwp", "ras", "thm", ); my @webFormats = ("JPEG", "GIF", "PNG"); # Image formats that can go # into the web album (other # formats will be converted # to JPEG). my @filesToLinkExtensions = ( "avi", "mpg", "mpeg", "mov" ); ############################################################################ # End of Configuration Section # ############################################################################ #subroutine declarations sub usage; sub beVerbose; sub beVerboseN; sub min; sub readConfigFile; sub fileSize; sub generateAlbumPages; sub filenameToPreviewName; sub getSizeLinks; sub openTemplate; sub doSubstitutions; sub generateTreeLoop; sub generateImage; sub getRootDir; #sub generateScaledImage; sub getDesc; sub getExif; sub readField; sub trimWhiteSpace; sub stringToBool; sub ignoreSet; sub getFields; sub getIntlSubs; sub generateThumbnailPages; sub generateThumbEntry; sub generateThumbPage; sub generateImagesInAlbum; sub write_htaccess; print "\nBINS Photo Album 1.1.29 (http://bins.sautret.org/)\n"; print "Copyright © 2001-2004 Jérôme Sautret (Jerome\@Sautret.org)\n"; print "Some parts of code:\n"; print "Copyright © 2000 Brendan McMahan (mcmahahb\@whitman.edu)\n"; print "Copyright © John Moose (moosejc\@muohio.edu)\n\n"; print "This is free software with ABSOLUTELY NO WARRANTY.\n"; print "See COPYING file for details.\n\n"; # EVG (Evil Global Variables) # Some on them should be moved to the config hash so they can be # managed by config files my $ignoreOpts=""; # to ignore some albums (see -i) my $hiddenOpts=""; # to hide some albums my $genEditableAlbum; # are we creating a editable album (see -e) my ($imageSource, $oneCopy); # How to handle scaled images my $appendToDescFile; # write to desc file ? (see -d) my $templateDir; my ($picdir, $albumdir); # source and destination directories # charset converters my ($xml2htmlConverter, $html2xmlConverter, $xml2localConverter); my $optimizeConversion = 0; # this cause problem if set to 1, # but may help on Sun Solaris. main(); # process command line arguments before reading config file sub preProcessArgs { my $configHash = shift; # process args my %option; Getopt::Long::Configure("bundling"); die "Invalid options\n" if (!GetOptions(\%option, "h", "p", "r:s", "e", "o:s", "t=s", "d=s", "s=s", "c=s", "v:i", "i=s", "n=s", "f=s")); if (defined($option{v})) { $verbose = $option{v}; } beVerboseN("Verbosity level is set to $verbose.", 2); #get the config file from the command line if ( $option{'f'} ) { (my $junk ,$defaultConfig{'userConfigDir'},$defaultConfig{'configFileName'}) = File::Spec->splitpath(File::Spec->rel2abs($option{'f'})); $defaultConfig{'userConfigDir'} =~ s|/*$||; } return \%option; } # process command line arguments after reading config file sub postProcessArgs { my $option = shift; my $configHash = shift; my %option = %{$option}; if (defined($option{i})) { $ignoreOpts="$option{i}"; beVerboseN("Ignore is set to $ignoreOpts.", 2); } if (defined($option{n})) { $hiddenOpts="$option{n}"; beVerboseN("Hidden is set to $hiddenOpts.", 2); } $genEditableAlbum = ($option{e} ? 1 : 0); if (defined($option{s})) { $configHash->{templateStyle} = $option{s}; } $imageSource = "scaled"; $oneCopy = 0; if (defined($option{o})) { $oneCopy = 1; $imageSource = ($option{o} ? $option{o} : "scaled"); } if (defined($option{d})) { $appendToDescFile = $option{d}; } else { $appendToDescFile = "always"; } die 'invalid option for switch -d. Must be one of "always",'. '"never" or "exist"' if ( $appendToDescFile ne "always" && $appendToDescFile ne "never" && $appendToDescFile ne "exist"); if ($option{t}) { $templateDir = $option{t}; die "template location $templateDir doesn't exist" if (! -d $templateDir); #if ( substr($templateDir,-1,1) eq "/" ) { # $templateDir .= "/"; } if ($option{c}) { $configHash->{colorStyle} = $option{c}; beVerboseN("Color style $option{c} selected.", 2); } $configHash->{reverseOrder} ||= 0; if (defined($option{r})) { if ($option{r} =~ "dirs") { $configHash->{reverseOrder} = 1; } if ($option{r} =~ "pictures") { $configHash->{reverseOrder} += 2; } } #$stripOrderNum = ($option{p} ? 1 : 0); if ($option{p}) { $configHash->{stripDirPrefix} = 1; } my $printHelp = ($option{h} ? 1 : 0); if ($printHelp) { usage(); exit 1; } if ( $oneCopy && !($imageSource =~ /^(scaled|copied|custom)$/) ) { print "\nInvalid image source for -o. If you are leaving the src\n"; print "argument off to get the default, put the -o switch at the\n"; print "end of the line, or use \"-o -\" to get the default.\n\n"; usage(); exit 1; } # directories if ($#ARGV < 1) { print "source_dir and target_dir are required.\n"; print "Type bins -h for more help.\n"; exit 1; } $picdir = $ARGV[0]; $albumdir = $ARGV[1]; { # check that $albumdir is _not_ a subdirectory of $picdir # to avoid an infinite recursivity # we can't just use $albumdir and $picdir since they may contain # "../" that will pose problems: # foo/../bar would be considered a subdirectory of foo/ my $pwd = File::Spec->rel2abs("."); #print "pwd: $pwd\n"; chdir($picdir) or warn "Can't chdir $picdir: $!"; my $picdir2 = File::Spec->rel2abs("."); chdir($pwd); if (! -d "$albumdir") { mkdir $albumdir, 0755 or die("\nCannot create $albumdir: $?"); } chdir($albumdir) or warn "Can't chdir $albumdir: $!"; my $albumdir2 = File::Spec->rel2abs("."); chdir($pwd); #print "picdir: $picdir2\n"; #print "albumdir: $albumdir2\n"; die "albumdir_dir ($albumdir) can't be a subdirectory of picdir_dir ($picdir)" if ($albumdir2 =~ m/^$picdir2\//); } $picdir = File::Spec->rel2abs(File::Spec->canonpath($picdir)); $albumdir = File::Spec->rel2abs(File::Spec->canonpath($albumdir)); $picdir =~ s|/*$|/|; $albumdir =~ s|/*$|/|; die "You must specify a source (picture) directory.\n" if (!$picdir); die "You must specify a target (web) directory.\n" if (!$albumdir); #print "\$oneCopy = $oneCopy\n"; #print "\$imageSource = $imageSource\n" if $oneCopy; #print "\$templateDir = $templateDir\n"; #print "\$picdir = $picdir\n"; #print "\$albumdir = $albumdir\n"; } # figure out a relative path from 1 file to another for relative linking sub relpath { my $p1 = $_[0]; my $p2 = $_[1]; my $l1 = length($p1); my $l2 = length($p2); my $cl = cls($p1, $p2); my $p2r = substr( $p2, $cl, $l2); my $p1dc = 0; my $i = 0; #print "relpath($p1, $p2)\n"; #print " \$p2r = $p2r\n"; for ( $i=$l1; $i > $cl; $i--) { if ( substr($p1,$i,1) eq "/" ) { $p1dc++; } } for( $i = 0 ; $i < $p1dc ; $i++ ) { $p2r = "../" . $p2r; } #print "-> $p2r\n"; return $p2r; } # taken directly from # http://www.people.cornell.edu/pages/tco2/papers/common_leading_substring/2000-06-09-0830 # which is a paper by # Todd Olson # Cornell University # tco2 at cornell.edu sub cls { my $l0 = length($_[0]); my $l1 = length($_[1]); my $l = ($l0 < $l1) ? $l0 : $l1; my $i = 0; for ( $i=0; $i < $l; $i++) { last if ( substr($_[0],$i,1) ne substr($_[1],$i,1) ); } return $i; } sub initConverters { if (! $optimizeConversion || $defaultConfig{xmlEncoding} ne $defaultConfig{htmlEncoding}) { $xml2htmlConverter = Text::Iconv->new($defaultConfig{xmlEncoding}, $defaultConfig{htmlEncoding}); $html2xmlConverter = Text::Iconv->new($defaultConfig{htmlEncoding}, $defaultConfig{xmlEncoding}); } if ($verbose >= 1 && (!$optimizeConversion || $defaultConfig{xmlEncoding} ne $defaultConfig{defaultEncoding})) { $xml2localConverter = Text::Iconv->new($defaultConfig{xmlEncoding}, $defaultConfig{defaultEncoding}); } beVerboseN("Your system charset encoding is ". $defaultConfig{defaultEncoding}, 2); } # Convert from XML encoding to HTML encoding sub xml2html{ if ($optimizeConversion && $defaultConfig{xmlEncoding} eq $defaultConfig{htmlEncoding}){ return shift; } return $xml2htmlConverter->convert(shift); } # Convert from HTML encoding to XML encoding sub html2xml{ if ($optimizeConversion && $defaultConfig{xmlEncoding} eq $defaultConfig{htmlEncoding}){ return shift; } return $html2xmlConverter->convert(shift); } # Convert from XML encoding to local encoding sub xml2local{ if ($optimizeConversion && $defaultConfig{xmlEncoding} eq $defaultConfig{defaultEncoding}){ return shift; } return $xml2localConverter->convert(shift); } # Convert from local encoding to XML encoding sub local2html{ if ($optimizeConversion && $defaultConfig{htmlEncoding} eq $defaultConfig{defaultEncoding}){ return shift; } return $local2htmlConverter->convert(shift); } ##### main ##### sub main{ my @recursiveImageData; # create charset converters initConverters(); # pre process command line args before reading config files my $options = preProcessArgs(\%defaultConfig); # read configurations files my $defaultConfig = readConfigFile(\%defaultConfig); # post process command line args after reading config files postProcessArgs($options, $defaultConfig); # Create the Apache .htaccess for charset encoding write_htaccess($albumdir, $defaultConfig); # write files used by the search engine writeSearchFiles($albumdir, $defaultConfig); # generate the root directory, do recursive traversal of all subalbums my %rootAlbumHash = generateAlbumPages("", \@recursiveImageData, $defaultConfig); # and finally create the tree page. generateTree($rootAlbumHash{config}, %rootAlbumHash); } # Test if a package is installed on the system at run time. # We use it to test LOCALE::Gettext is here (or else, we don't do any I18N). sub have_package { my $name = shift(@_); $name =~ s%::%/%g; foreach my $prefix (@INC) { if (-f "$prefix/$name.pm") { return 1; } } return 0; } # return translated string with HTML encoding sub _ { if ($I18N) { return local2html(Locale::gettext::gettext(shift)); } return local2html(shift); } # return translated string without any encoding transformation sub gettext{ if ($I18N) { return Locale::gettext::gettext(shift); } return shift; } # return translated string without changing encoding sub translate { if ($I18N) { return Locale::gettext::gettext(shift); } return shift; } BEGIN{ my @done; # list of template styles which have their static dir already copied sub write_static_dir{ my $destDir = shift; my $configHash = shift; if (grep(/^$configHash->{templateStyle}$/, @done)) { return; } push @done, $configHash->{templateStyle}; my $staticDir = templateStaticDir($configHash); $destDir =~ s%/$%%; $destDir .= "/static.".$configHash->{templateStyle}; if ($staticDir) { if (! -d "$destDir") { mkdir $destDir, 0755 or die("\nCannot create $destDir: $?"); } system("cp", "-R", bsd_glob("$staticDir/*", GLOB_TILDE), "$destDir") == 0 or die("\nCannot copy $staticDir directory content to $destDir: $?"); } else { beVerboseN(" Cannot find any static template directory.", 4); } } } sub write_bg_image { my $album = shift; my $configHash = shift; my $staticDir = templateStaticDir($configHash); my $destDir = $albumdir; $destDir =~ s%/$%%; $destDir .= "/static.".$configHash->{templateStyle}; if (! -d "$destDir") { mkdir $destDir, 0755 or die("\nCannot create $destDir: $?"); } system("cp", "-p", "$picdir$album$configHash->{backgroundImage}", "$destDir") == 0 or die("\nCannot copy file $configHash->{backgroundImage} to $destDir: $?"); } sub write_custom_css { my $album = shift; my $configHash = shift; my $staticDir = templateStaticDir($configHash); my $destDir = $albumdir; $destDir =~ s%/$%%; $destDir .= "/static.".$configHash->{templateStyle}; if (! -d "$destDir") { mkdir $destDir, 0755 or die("\nCannot create $destDir: $?"); } system("cp", "-p", "$picdir$album$configHash->{customStyleSheet}", "$destDir") == 0 or die("\nCannot copy file $configHash->{customStyleSheet} to $destDir: $?"); } sub createSearchResultTemplate { my $source = shift; my $dest = shift; open(FILEOUT, ">", $dest) or die("\nCannot open file $dest for writing: $?"); print(FILEOUT "result_html=''+\n"); open(FILEIN, $source) or die("\nCannot open file $source: $?"); while() { chomp; print(FILEOUT "'$_\\n'+\n"); } close (FILEIN) || die ("can't close $source ($!)"); print(FILEOUT "''\n"); close (FILEOUT) || die ("can't close $dest ($!)"); unlink($source); } # write templates and javascript files used for the search functionality sub writeSearchFiles { my $album = shift; my $configHash = shift; if (! $configHash->{searchEngine}) { return } # transform searchFields parameter in a list my @l = $configHash->{searchFields} =~ /(\w+)/g; $configHash->{searchFields}= \@l; my $staticDir = templateStaticDir($configHash); my $destDir = $albumdir; if (! -d "$destDir") { mkdir $destDir, 0755 or die("\nCannot create $destDir: $?"); } # Copy the javascript my $source_file; foreach my $file ("search_data.js",) { $source_file = templateFileName($file, $configHash); system("cp", "-p", $source_file, "$destDir") == 0 or die("\nCannot copy file $file to $destDir: $?"); } # Render the HTML templates my %subsHash; if ($configHash->{backgroundImage}) { # Do not set this if not configured, so that template # can check for whether defined. $subsHash{BG_IMAGE} = $subsHash{STATIC_PATH}."/".$configHash->{backgroundImage}; } $subsHash{SEARCH_LIMIT} = $configHash->{searchLimit}; renderFile(templateFileName("search.js", $configHash), $album."search.js", \%subsHash, $configHash); $subsHash{HOME_LINK} = $configHash->{homeURL}; $subsHash{ALBUM_THUMB} = $configHash->{treePreview}; $subsHash{PATH_SHOW_ICON} = $configHash->{pathShowIcon}; $subsHash{DATE} = strftime($configHash->{dateString}, localtime); renderTemplate("search", $album."search.html", \%subsHash, $configHash); my $tmpfile = $album."search_result.html"; renderTemplate("search_result", $tmpfile, \%subsHash, $configHash); createSearchResultTemplate($tmpfile, $album."search_result.js"); } sub write_htaccess{ my $dir = shift; my $configHash = shift; if (! $configHash->{createHtaccess}) { return } my $file = $dir."/.htaccess"; mkdir("$dir", 0755) if (! -d "$dir"); # 20030422 Hack by Yves Mettier # don't overwrite .htaccess if it is already OK if(open(FILE, $file)) { my $encoding = $configHash->{htmlEncoding}; while() { if(/AddDefaultCharset $encoding/) { close (FILE) || die ("can't close $file ($!)"); return; } if(/AddType text\/html;charset=$encoding html htm/) { close (FILE) || die ("can't close $file ($!)"); return; } } close (FILE) || die ("can't close $file ($!)"); } # End of hack beVerboseN("Writing .htaccess file for album with ". "charset encoding $configHash->{htmlEncoding}.", 2); open(FILE, ">>",$file) or die("Cannot write to file $file ($!)"); printf(FILE "AddDefaultCharset %s\n", ($configHash->{htmlEncoding})); close (FILE) || die ("can't close $file ($!)"); } sub generateTree{ # album hash -- other entries as defined in getAlbumInfo # hash{subalbums} -- returns a ref to a list of subalbums to the album # each entry in the list is a ref to an albumhash of this format my ($configHash, %albumHash) = @_; my $tableHTML = "\n".&generateTreeUL(%albumHash)."\n"; my %subsHash; $subsHash{TREE_TABLE} = $tableHTML; $subsHash{TREE_LOOP} = generateTreeLoop(%albumHash); #beVerboseN("Generate tree Table html:\n $tableHTML ", 3); $subsHash{STATIC_PATH} = "static.".$configHash->{templateStyle}; if ($configHash->{backgroundImage}) { # Do not set this if not configured, so that template # can check for whether defined. $subsHash{BG_IMAGE} = $subsHash{STATIC_PATH}."/".$configHash->{backgroundImage}; } $subsHash{HOME_LINK} = $configHash->{homeURL}; $subsHash{ALBUM_THUMB} = $configHash->{treePreview}; $subsHash{PATH_SHOW_ICON} = $configHash->{pathShowIcon}; $subsHash{DATE} = strftime($configHash->{dateString}, localtime); renderTemplate("tree", $albumdir."tree.html", \%subsHash, $configHash); } sub generateTreeUL{ my %albumHash = @_; my $link = "". $albumHash{title}.""; my $UL = "
    \n
  • $link\n"; my @subAlbumHashRefList = @{$albumHash{subalbums}}; # may be empty my $subAlbumHashRef; foreach $subAlbumHashRef (@subAlbumHashRefList) { $UL .= &generateTreeUL(%{$subAlbumHashRef})."\n"; } $UL .= "
\n"; return $UL; } sub generateTreeLoop { my(%albumHash) = @_; my @result; my @subAlbumHashRefList = @{$albumHash{subalbums}}; # may be empty my $subAlbumHashRef; my($prepath, $preimage, $preimageTmp, $preimagePath, $preid); my $hasChild; $prepath = $albumHash{link}; $preimage = filenameToPreviewName($albumHash{sampleimage}); $prepath =~ s/index.html//; $prepath =~ s/^\///; if ($prepath eq "") { $preimage =~ s/^[^\/]+//; } $preimageTmp = $preimage; $preimageTmp =~ s/\/([^\/]+)$//; $preimagePath = $preimageTmp; while (rindex($prepath, $preimageTmp) == -1 && $preimageTmp ne "") { if (index($preimageTmp, "/") > -1) { $preimageTmp =~ s/\/[^\/]+$//; } else { $preimageTmp =~ s/^[^\/]+$//; } } $preimage = substr($preimage, length($preimageTmp) + 1); $preid = "ID$prepath"; $preid =~ s/\//_/g; push(@result, {TREE_NAME => $albumHash{title}, TREE_LINK => $albumHash{link}, TREE_IMAGES => "$albumHash{numImages} "._("images"), TREE_SAMPLE => $prepath . $preimage, TREE_ALT => $albumHash{title}, TREE_SAMPLEID => $preid, TREE_HASCHILD => @subAlbumHashRefList > 0, }); if (@subAlbumHashRefList) { foreach $subAlbumHashRef (@subAlbumHashRefList) { my $array = generateTreeLoop(%{$subAlbumHashRef}); push(@result, @$array); } push(@result, {TREE_OUT => "1"}); } return \@result; } sub usage { my $commandname = $0; $commandname =~ s/^.*\///; print < fields in section. If any of the iKeys match those in the album's "ignore" field, that album will not be processed. See also the ignore parameter. -n iKey,iKey,... Sets "hidden" keywords which will be compared against the contents of the "ignore" field of the album's XML file, in the fields in section. If any of the iKeys match those in the album's "ignore" field, that album will not be linked anywhere. See also the hidden parameter. -v X X is the verbosity level (between 0 and 3) -h print this help message EoFprint } sub min { my($a,$b) = @_; if ($a < $b) { return($a); } else { return($b); } } sub fileSize { my($item) = shift(@_); #print("filesize of $item\n"); my($filesize) = ((-s "$item") / 1024); #get the file's size in KB. if ($filesize > 1024) { # is it larger than a MB? $filesize = ($filesize / 1024); $filesize =~ s/(\d+[\.,]\d)\d+/$1/; $filesize = $filesize._("MB"); } else { $filesize =~ s/(\d+)[\.,]\d+/$1/; $filesize = $filesize._("KB"); } return $filesize; } # $album is path of album, minus $picdir. # @parentDirNames is list of parent dirs, not including this one # for example if album = /album/may_13_2000/party_pics/ # then dirs might be (Album, May 13th, 2000, Party Pictures) # @parentDirNames is used for generating the back links in the path sub generateAlbumPages{ my ($album, $recursiveImageData, $configHash, @parentDirNames) = @_; #print "-------------------\n".Dumper($configHash)."\n"; my $oldBackground = $configHash->{backgroundImage}; my $oldCss = $configHash->{customStyleSheet}; my $bgchange = 0; my $albumHashRef; ($albumHashRef, $configHash) = getAlbumInfo($album, $configHash); my %albumHash = %{$albumHashRef}; $albumHash{config} = $configHash; # Don't generate anything else (recurse any further) if we want to ignore # this album if ( ignoreSet($albumHash{ignore}, $album, $configHash) ) { return(%albumHash); } # create the directory containing static elements (icons, # javascript, css, ...) write_static_dir($albumdir, $configHash); # Check if a new backgroundimage has to be copied if ( $configHash->{backgroundImage} ne "" && $oldBackground ne $configHash->{backgroundImage}) { write_bg_image($album, $configHash); $bgchange = 1; } # Check whether a new stylesheet has to be copied if ( $configHash->{customStyleSheet} ne "" && $oldCss ne $configHash->{customStyleSheet}) { write_custom_css($album, $configHash); } push(@parentDirNames, $albumHash{title}); $albumHash{parentDirNames} = \@parentDirNames; # albumHash info is complete, except for list of subalbums # which is complete after recursive traversal my @subalbumHashList; # goes into albumHash #print "generateAlbumPages($album)\n"; if ($verbose >=1) { print xml2local($_)." > " foreach (@parentDirNames); print "\n"; } # first, make sure web directory exists # use mkdir -p to make parents as needed mkdir("$albumdir$album", 0755) if (! -d "$albumdir$album"); # returns the names of _all_ files/directories in this album's directory opendir(DIR, "$picdir$album") || die "can't open dir $picdir$album: $!"; my @filesInAlbum = grep { !/^\./ } readdir(DIR); closedir DIR; my @tmpDirs; my @tmpFiles; foreach my $file (@filesInAlbum) { if (-d "$picdir$album$file") { push(@tmpDirs, $file); } else { push(@tmpFiles, $file); } } # Exclude files if needed @tmpFiles = grep(!/$configHash->{excludeFiles}/, @tmpFiles) if ($configHash->{excludeFiles}); if ( $bgchange && $configHash->{backgroundImage} && $configHash->{excludeBackgroundImage}) { @tmpFiles = grep(!/$configHash->{backgroundImage}/, @tmpFiles); } @tmpDirs = grep(!/$configHash->{excludeDirs}/, @tmpDirs) if ($configHash->{excludeDirs}); # Now put them in new sorted order back to @filesInAlbum if ($configHash->{reverseOrder} & 1) { @filesInAlbum = sort {$b cmp $a} @tmpDirs; } else { @filesInAlbum = sort @tmpDirs; } # # smr Jan 2004 -- sort according to file album.list (if there) # # first show all images in album.list in the order they appear in # this file any image names preceeded with a . are suppressed for # the album generation all images in the directory which are not in # album.list are appended in usual (sorted) order # if (-r "$picdir$album/album.list") { my(%isfile); foreach(@tmpFiles) { $isfile{$_} = 1; } open (INLIST, "$picdir$album/album.list") or die "can't open $picdir$album/album.list, $!"; while() { chomp; s/^\s+//; s/\s+$//; next if /^#/ || /^$/; if(/^\./) { s/^\.\s*//; } else { push(@filesInAlbum, $_) if $isfile{$_}; } $isfile{$_} = 0; } close INLIST; $#tmpFiles = -1; foreach (keys %isfile) { push(@tmpFiles, $_) if $isfile{$_} == 1; } } if ($configHash->{reverseOrder} & 2) { push(@filesInAlbum, sort {$b cmp $a} @tmpFiles); } else { push(@filesInAlbum, sort @tmpFiles); } my($fileInAlbum, @urlimageList, @imageList, @xlinkList, $numAlbums); $numAlbums = 0; foreach $fileInAlbum (@filesInAlbum) { if (-d "$picdir$album$fileInAlbum") { # Is this a subdirectory? my %localAlbumHash = generateAlbumPages($album.$fileInAlbum."/", $recursiveImageData, $configHash, @parentDirNames); # If the "ignore" keyword matches one of the ones passed in the # command line, don't push or count this album. if (! ignoreAndHiddenSet($localAlbumHash{ignore}, $fileInAlbum, $configHash) ) { push(@subalbumHashList, \%localAlbumHash); $numAlbums++; } } else { my $known = 0; foreach my $ext (@knownImageExtentions){ if ($fileInAlbum =~ /\.$ext\Z/i) { $known = 1; last; } } if ($known) { # this is a known image format--remember its name push @imageList, $fileInAlbum; } else { foreach my $ext (@filesToLinkExtensions){ if ($fileInAlbum =~ /\.$ext\Z/i) { $known = 1; last; } } if ($known) { push @xlinkList, $fileInAlbum; my $from="$picdir$album$fileInAlbum"; my $to="$albumdir$album$fileInAlbum"; if ( ! -f $to ) { `cp -p "$from" "$to"`; } } } } } #get virtual images to include my @virtualInclude = getVirtualInclude($album); #print "$_, " foreach (@virtualInclude); push(@imageList, @virtualInclude); $albumHash{subalbums} = \@subalbumHashList; $albumHash{numImages} = $#imageList+1; # note that if (! @imageList), # $#imageList = -1 $albumHash{numSubAlbums} = $numAlbums; $albumHash{numXLinks} = $#xlinkList + 1; # decide whether index page is first thumbnail page (or subalbum page) my $firstIsIndex; if ($numAlbums == 0 ) { $firstIsIndex = 1; } else { $firstIsIndex = 0; } $albumHash{thumbIsIndex} = $firstIsIndex; # generate image pages and get image data my @imageData = generateImagesInAlbum($album, \%albumHash, $firstIsIndex, $configHash, @imageList); $albumHash{sampleimage} = chooseSampleImage(\%albumHash, \@imageData) if (! $albumHash{sampleimage}); # generate thumbnail pages generateThumbnailPages($album, \%albumHash, $firstIsIndex, $configHash, \@xlinkList, @imageData); # generate image list page if ($albumHash{numImages} > 0) { generateImageListPage($album, \%albumHash, \@imageData, \@xlinkList, $configHash); } beVerboseN(" sample image for $album is $albumHash{sampleimage}", 3); # generate subalbum page if ($numAlbums > 0) { generateSubAlbumPage($album, \%albumHash, $recursiveImageData, $configHash); } if ($configHash->{allThumbnailsPage}) { # Munge the @imageData so that it includes path information, and dump this # in @recursiveImageData. for my $thisImageData ( @imageData ) { $thisImageData->{'thumblink'}=$album.$thisImageData->{'thumblink'}; for my $width ( 0..$#{$configHash->{scaledWidths}} ) { $thisImageData->{$width}{'htmlFile'}=$album. $thisImageData->{$width}{'htmlFile'}; } push(@{$recursiveImageData}, $thisImageData); } } return %albumHash; } sub jssafe_uri_escape { return uri_escape(@_, '^-A-Za-z0-9/_\.'); } # if we don't have a sample image from the initial getAlbumInfo # then we pick the first one. If we don't have images in this # album, choose a sampleimage from a subalbum. If that fails, # then no sampleimage. # returns name of sampleimage (a file with path info) sub chooseSampleImage{ my ( $albumHashRef, $imageDataRef) = @_; my @imageData = @{ $imageDataRef }; if (@imageData) { my $th = $imageData[0]->{thumblink}; $th =~ s/_pre\.jpg$/.jpg/; $th = jssafe_uri_escape($albumHashRef->{dirname}) . "/" . $th; # print "Returning from ImageData = $th\n"; return $th; }else{ my @subAlbumHashList = @{ $albumHashRef->{subalbums} }; my $subAlbumHashRef; foreach $subAlbumHashRef (@subAlbumHashList) { if ($subAlbumHashRef->{sampleimage}) { my $th = jssafe_uri_escape($albumHashRef->{dirname}) . "/" . $subAlbumHashRef->{sampleimage}; # print "Returning from sub-album \$th = $th\n"; return($th); } } } return ""; } # takes in an image name (with some or no path info), and returns # preview name with equivalent path info sub filenameToPreviewName { my $imageName = shift(@_); my($base, $path, $type); ($base,$path,$type) = fileparse($imageName, '\.[^.]+\z'); # what the thumbnail will be named: my($newPreviewName) = $path.$base . '_pre.jpg'; beVerboseN("Preview name for $imageName is $newPreviewName", 3); return $newPreviewName; } sub getVirtualInclude{ my $album = shift(@_); my $virtualImageFile = $picdir.$album."include_images.txt"; return () if (! -e $virtualImageFile); open (INCLUDE, $virtualImageFile) || die ("cannot open $virtualImageFile for reading: ($!)"); my @include; LINE: while () { chomp; next LINE if /^#/; #discard comments next LINE if /^\s*$/; #ignore total whitespace push(@include, $_); } close (INCLUDE) || die ("can't close $virtualImageFile ($!)"); return @include; } # return tree and path links of album as a list of hash refs sub pathLinks{ my ($album, $title, @dirs) = @_; my @result; push @result, {PATH_NAME => _("tree"), PATH_TITLE => _("Tree of all albums and sub-albums"), PATH_LINK => getRootDir($album)."tree.html", }; my ($i, $pathlinks); my $count = $#dirs-1; $count++ if ($title); for my $i (0..$count) { my $url=""; my $dirname = $dirs[$i]; #$dirname=~ s/_/ /g; $url .="../" foreach ($i..($#dirs-1)); $url .= "index.html"; push @result, {PATH_NAME => $dirname, PATH_TITLE => $dirname, PATH_LINK => $url, PATH_ISALBUM => 1, PATH_FIRST => ($i == 0), }; } my $dirname = $dirs[$#dirs]; if (!$title) { push @result, {PATH_NAME => $dirname, PATH_ISALBUM => 1, PATH_FIRST => ($#dirs == 0), }; }else{ #for image page push @result, {PATH_NAME => $title, }; } return \@result; } # crntPage is "subalbum", "thumb0", ... etc # values is thumb0, or subalbum, never index # return a list or hash refs sub navBarLinks{ my ($crntPage, $album, $configHash, %albumHash) = @_; my @result; my $firstIsIndex = $albumHash{thumbIsIndex}; my $numImages = $albumHash{numImages}; # my $navrows; my $numThumbPages = calcNumThumbPages($numImages, $configHash); #subalbum link if ($crntPage eq "subalbum") { # we have a subalbum page (duh) push @result, {NAV_NAME => _("Sub Albums"), NAV_ICON => "subalbum.png"}; } elsif (! $firstIsIndex) { # we have a subalbum page -- it must be # index.html push @result, {NAV_NAME => _("Sub Albums"), NAV_LINK => "index.html", NAV_ICON => "subalbum.png", NAV_ID => "sub"}; } #image list link if ($crntPage eq "imagelist") { push @result, {NAV_NAME => _("Image List"), NAV_ICON => "imagelist.png"}; } elsif ($numImages > 0) { push @result, {NAV_NAME => _("Image List"), NAV_LINK => "imagelist.html", NAV_ICON => "imagelist.png", NAV_ID => "imgl"}; } #if ($crntPage ne "image") { # first thumbnail page if ($numThumbPages > 0) { # we have a first thumbnail page my($thumbpage); if ($numThumbPages == 1) { $thumbpage = _("Thumbnail Page"); } else { $thumbpage = _("Thumbnail Page 1"); } if ($crntPage eq "thumb0") { # and we are on it push @result, {NAV_NAME => $thumbpage, NAV_ICON => "thumbnails.png"}; } elsif ($firstIsIndex) { # and it is index.html push @result, {NAV_NAME => $thumbpage, NAV_LINK => "index.html", NAV_ICON => "thumbnails.png", NAV_ID => "th0"}; } elsif ($numThumbPages > 0) { # it is thumb0.html push @result, {NAV_NAME => $thumbpage, NAV_LINK => "thumb0.html", NAV_ICON => "thumbnails.png", NAV_ID => "th0"}; } } # remaining thumbnail pages my $i; for $i (1..($numThumbPages-1)) { if ($crntPage eq "thumb$i") { push @result, {NAV_NAME => _("Thumbnail Page") . " ". ($i+1), NAV_ICON => "thumbnails.png"}; }else{ push @result, {NAV_NAME => _("Thumbnail Page") . " ". ($i+1), NAV_LINK => "thumb".$i.".html", NAV_ICON => "thumbnails.png", NAV_ID => "th$i"}; } } #} # all thumbnail page # If we have more than one thumbnail page (this is a thumbnail page), or # this is the main page (subalbum page), or this is "thumb-2" (a subalbum # thumb page)... if ( $configHash->{allThumbnailsPage} && (($numThumbPages > 1) || ($crntPage eq "subalbum") || ($crntPage eq "thumb-2") )) { if ($crntPage eq "thumb-1" || $crntPage eq "thumb-2" ) { # we are on it push @result, {NAV_NAME => _("All Thumbnails")}; } else { # we are not on an allthumbnails page push @result, {NAV_NAME => _("All Thumbnails"), NAV_LINK => "allthumbs.html"}; } } return \@result; } sub getAlbumNumInfo{ my (%albumHash) = @_; my $numInfo=""; my $numImages = $albumHash{numImages}; my $numAlbums = $albumHash{numSubAlbums}; my $numXLinks = $albumHash{numXLinks}; if ($numImages == 1) { $numInfo = "1 "._("image"); } elsif ($numImages > 1) { $numInfo = "$numImages "._("images"); } $numInfo .= ", " if (length $numInfo > 0 && $numXLinks > 0); if ($numXLinks == 1) { $numInfo .= "1 "._("media file"); } elsif ($numXLinks > 1) { $numInfo .= "$numXLinks "._("media files"); } $numInfo .= ", " if (length $numInfo > 0 && $numAlbums > 0); if ($numAlbums == 1) { $numInfo .= "1 "._("subalbum"); } elsif ($numAlbums > 1) { $numInfo .= "$numAlbums "._("subalbums"); } return $numInfo; } sub generateImageListPage{ my ($album, $albumHashRef, $imageDataRef, $xlinksRef, $configHash) = @_; my %albumHash = %{$albumHashRef}; my @imageData = @{$imageDataRef}; my $pwd; # hash for final substitutions my %finalsubs; $finalsubs{NUM_INFO} = getAlbumNumInfo(%albumHash); $finalsubs{ALBUM_TITLE} = $albumHash{title}; $finalsubs{NAV_BAR_TABLE} = navBarLinks('imagelist', $album, $configHash, %albumHash); $finalsubs{ALBUM_PATH_LINKS} = pathLinks($album, 0, @{$albumHash{parentDirNames}}); $finalsubs{TREE_NAME} = _("tree"); $finalsubs{TREE_TITLE} = _("Tree of all albums and sub-albums"); $finalsubs{TREE_LINK} = getRootDir($album)."tree.html"; if ($#{$albumHash{parentDirNames}} > 0) { $finalsubs{UP_NAME} = _("up"); $finalsubs{UP_TITLE} = _("Up one subalbum"); $finalsubs{UP_LINK} = "../index.html"; } if ($genEditableAlbum) { $pwd = `pwd`; chop($pwd); $pwd = jssafe_uri_escape($pwd); $finalsubs{ALBUM_DESC} = "". $albumHash{longdesc}.""; } else { $finalsubs{ALBUM_DESC} = $albumHash{longdesc}; } my @tables; my $thumbid = 0; foreach my $imageInfoRef (@imageData) { my %imageInfo = %{$imageInfoRef}; my %tablesubs; my @sizes; $thumbid += 1; $tablesubs{THUMB_ID} = $thumbid; for my $i (0..$imageInfo{'maxSize'}) { if ($i == $configHash->{defaultSize}) { push @sizes , {SIZE_LINK => $imageInfo{$i}{'htmlFile'}, SIZE_NAME => $imageInfoRef->{configuration}{sizeNames}[$i], SIZE_TITLE => $imageInfoRef->{configuration}{longSizeNames}[$i]. " ($imageInfo{$i}{'width'}x$imageInfo{$i}{'height'})", SIZE_FILE => $imageInfoRef->{configuration}{fileSizeNames}[$i], SIZE_DFLT => 1, }; } else { push @sizes , {SIZE_LINK => $imageInfo{$i}{'htmlFile'}, SIZE_NAME => $imageInfoRef->{configuration}{sizeNames}[$i], SIZE_TITLE => $imageInfoRef->{configuration}{longSizeNames}[$i]. " ($imageInfo{$i}{'width'}x$imageInfo{$i}{'height'})", SIZE_FILE => $imageInfoRef->{configuration}{fileSizeNames}[$i], }; } } if ($genEditableAlbum) { $tablesubs{TITLE} = "". $imageInfo{title}.""; } else { $tablesubs{TITLE} = $imageInfo{title}; } $tablesubs{SIZE_LINKS} = \@sizes; my $atLeastOneField = 0; my $tagValue; $tablesubs{DESC_TABLE} = getDescTable(\%imageInfo, $configHash); if ($configHash->{defaultSize} >= 0){ $tablesubs{THUMB_DEFAULT_SIZE} = $imageInfo{$configHash->{defaultSize}}{'htmlFile'}; } if ($configHash->{thumbnailInImageList}) { %tablesubs = ((THUMB_LINK => $imageInfo{'thumblink'}, THUMB_WIDTH => $imageInfo{'twidth'}, THUMB_HEIGHT => $imageInfo{'theight'}, THUMB_ALT => _("Click on one of the size names above to enlarge this image"), THUMB_LINK_TITLE => _("Click on one of the size names above to enlarge this image"), ), %tablesubs); } push @tables, \%tablesubs; } $finalsubs{XLINK} = getXLinks($xlinksRef); $finalsubs{STATIC_PATH} = getRootDir($album)."static.".$configHash->{templateStyle}; if ($configHash->{backgroundImage}) { # Do not set this if not configured, so that template # can check for whether defined. $finalsubs{BG_IMAGE} = $finalsubs{STATIC_PATH}."/".$configHash->{backgroundImage}; } $finalsubs{CUSTOM_CSS} = $configHash->{customStyleSheet}; $finalsubs{ROOT_PATH} = getRootDir($album); $finalsubs{IMAGE_LIST_TABLE} = \@tables; $finalsubs{HOME_LINK} = $configHash->{homeURL}; $finalsubs{FEEDBACK_LINK} = $configHash->{feedbackMail}; $finalsubs{PATH_SHOW_ICON} = $configHash->{pathShowIcon}; $finalsubs{DATE} = strftime($configHash->{dateString}, localtime); renderTemplate("imagelist", $albumdir.$album."imagelist.html", \%finalsubs, $configHash); } sub generateSubAlbumPage{ my ($album, $albumHashRef, $recursiveImageData, $configHash) = @_; my $numAlbums = $albumHashRef->{numSubAlbums}; if (1 || $numAlbums <= $configHash->{maxAlbumsForLongSubAlbum}) { generateLongSubAlbumPage($album, $albumHashRef, $configHash); }else{ # Short album page is not is not supported for the moment generateShortSubAlbumPage($album, $albumHashRef, $configHash); } if ($configHash->{allThumbnailsPage}){ # Create a thumbnail page of all images generateThumbPage($album, $albumHashRef, "-2", "1", "allthumbs.html", "", "", "", $configHash, undef, undef, $recursiveImageData->[0..$#{$recursiveImageData}]); } } # XXX Short album page is not supported for the moment sub generateShortSubAlbumPage{ my ($album, $albumHashRef, $configHash) = @_; my %albumHash = %{$albumHashRef}; my $pwd = `pwd`; chop($pwd); $pwd = jssafe_uri_escape($pwd); # hash for final subsitutions my %finalsubs; $finalsubs{''} = getAlbumNumInfo(%albumHash); $finalsubs{''} = $albumHash{title}; $finalsubs{''} = getNavBarLinks('subalbum', $album, $configHash, %albumHash); $finalsubs{''} = getPathLinks($album, 0, @{$albumHash{parentDirNames}}); if ($genEditableAlbum) { $finalsubs{''} = "'} .= $pwd."/"; } $finalsubs{''} .= $albumHash{descFileName}."\">". $albumHash{longdesc}.""; } else { $finalsubs{''} = $albumHash{longdesc}; } my $titleRowText = '   '; my $descRowText = '     '; my $subalbumHashRef; my $tableData = ''; my @subalbumHashList = @{$albumHash{subalbums}}; for $subalbumHashRef (@subalbumHashList) { my %subshash; my %albuminfo = %{$subalbumHashRef}; $subshash{''} = &getAlbumNumInfo(%albuminfo); $subshash{''} = $albuminfo{title}; $subshash{''} = jssafe_uri_escape($albuminfo{dirname}). "/index.html"; if ($genEditableAlbum) { $subshash{''} = "$albuminfo{shortdesc}"; } else { $subshash{''} = $albuminfo{shortdesc}; } $tableData .= doSubstitutions($titleRowText, $configHash, %subshash); $tableData .= doSubstitutions($descRowText, $configHash, %subshash) if (! $subshash{''} =~ /No short description available/); #print "table after SUBS\n: $tableData\n"; } $tableData .= '
'; $finalsubs{''} = $tableData; my $pageContent = openTemplate("subalbum"); $pageContent = doSubstitutions($pageContent, $configHash, %finalsubs); renderTemplate($albumdir.$album."index.html", $pageContent); } sub generateLongSubAlbumPage{ my ($album, $albumHashRef, $configHash) = @_; my %albumHash = %{$albumHashRef}; # hash for final subsitutions my %templateParameters = ( NUM_INFO => getAlbumNumInfo(%albumHash), ALBUM_TITLE => $albumHash{title}, NAV_BAR_TABLE => navBarLinks('subalbum', $album, $configHash, %albumHash), ALBUM_PATH_LINKS => pathLinks($album, 0, @{$albumHash{parentDirNames}}), TREE_NAME => _("tree"), TREE_TITLE => _("Tree of all albums and sub-albums"), TREE_LINK => getRootDir($album)."tree.html", ); if ($configHash->{albumThumbInSubAlbumPage} && $albumHash{numImages} > 0) { my $sampleImage = "./".filenameToPreviewName($albumHash{sampleimage}); if ($albumHash{dirname} ne "") { $sampleImage = "../$sampleImage"; } %templateParameters = (%templateParameters, ( ALBUM_THUMB => 1, DESC => $albumHash{shortdesc}, TITLE => $albumHash{title}, CURRENT_NUM_INFO => ($albumHash{numImages} > 1) ? $albumHash{numImages}." "._("images") : "1 "._("image"), LINK => "thumb0.html", THUMB_ALT => _("Click to view thumbnails of the current album"), THUMB_LINK_TITLE => _("Click to view thumbnails of the current album"), THUMB_LINK => $sampleImage, ) ); } my $pwd; if ($genEditableAlbum) { $pwd = `pwd`; chop($pwd); $pwd = jssafe_uri_escape($pwd); $templateParameters{ALBUM_DESC} = "". $albumHash{longdesc}.""; } else { $templateParameters{ALBUM_DESC} = $albumHash{longdesc}; } my @subAlbunTable; my $cnt = 0; for my $subalbumHashRef (@{$albumHash{subalbums}}) { my %albuminfo = %{$subalbumHashRef}; $cnt += 1; my %subshash = ( NUM_INFO => getAlbumNumInfo(%albuminfo), TITLE => $albuminfo{title}, LINK => jssafe_uri_escape($albuminfo{dirname})."/index.html", THUMB_ALT => _("Click to view this album"), THUMB_LINK_TITLE => _("Click to view this album"), THUMB_LINK => filenameToPreviewName($albuminfo{sampleimage}), THUMB_NUM => $cnt ); if ($genEditableAlbum) { $subshash{'DESC'} = "". $albuminfo{shortdesc}.""; } else { $subshash{'DESC'} = $albuminfo{shortdesc}; } push @subAlbunTable, \%subshash; } $templateParameters{SUBALBUMS_TABLE} = \@subAlbunTable; if ($#{$albumHash{parentDirNames}} > 0) { $templateParameters{UP_NAME} = _("up"); $templateParameters{UP_TITLE} = _("Up one subalbum"); $templateParameters{UP_LINK} = "../index.html"; } $templateParameters{STATIC_PATH} = getRootDir($album)."static.".$configHash->{templateStyle}; if ($configHash->{backgroundImage}) { # Do not set this if not configured, so that template # can check for whether defined. $templateParameters{BG_IMAGE} = $templateParameters{STATIC_PATH}."/".$configHash->{backgroundImage}; } $templateParameters{CUSTOM_CSS} = $configHash->{customStyleSheet}; $templateParameters{HOME_LINK} = $configHash->{homeURL}; $templateParameters{FEEDBACK_LINK} = $configHash->{feedbackMail}; $templateParameters{PATH_SHOW_ICON} = $configHash->{pathShowIcon}; $templateParameters{DATE} = strftime($configHash->{dateString}, localtime); renderTemplate("subalbum", $albumdir.$album."index.html", \%templateParameters, $configHash); } sub getAlbumInfo{ my $album = shift(@_); my $configHash = shift(@_); my %albuminfo; # what we want to generate $albuminfo{link} = jssafe_uri_escape($album)."index.html"; #link is from $albumdir -- otherwise need to add getRootDir to make work #$album = $picdir.$album; # we need this for the root dir to be right -- # correct behaviour if passed "" my $albumdescfile = "$picdir$album"."album.xml"; if (-e $albumdescfile) { $albuminfo{descFileName} = jssafe_uri_escape($albumdescfile); $configHash = getDescAlbum($albumdescfile, \%albuminfo, $configHash); # Don't calculate this album's info if it is flagged "ignore". if ( ignoreSet($albuminfo{ignore}, $album, $configHash) ) { return(\%albuminfo); } if (exists $albuminfo{sampleimage} && $albuminfo{sampleimage}) { #$albuminfo{sampleimage} = uri_escape($albuminfo{sampleimage}, # '^-A-Za-z0-9/_\.'); #add directory name of album to sample image my $dirname = $album; $dirname =~ s%^.*/([^/]+)/$%$1/%; $albuminfo{sampleimage} = $dirname.$albuminfo{sampleimage}; $albuminfo{sampleimage} = jssafe_uri_escape($albuminfo{sampleimage}); # $albuminfo{sampleimage} = uri_escape($albuminfo{sampleimage}, # '^-A-Za-z0-9/_\.'); } } else { $albuminfo{descFileName} = ""; } if (! $albuminfo{shortdesc} && ! $albuminfo{longdesc}) { if ($configHash->{emptyAlbumDesc}) { $albuminfo{shortdesc} = ""; $albuminfo{longdesc} = ""; } else { $albuminfo{shortdesc} = _("No short description available"); $albuminfo{longdesc} = _("No long description available"); } } elsif (! $albuminfo{shortdesc}) { $albuminfo{shortdesc} = $albuminfo{longdesc}; } elsif (! $albuminfo{longdesc}) { $albuminfo{longdesc} = $albuminfo{shortdesc}; } #get album title my $albumtitle = $picdir.$album; # strip ending / if ($album ne "") { my $endChar = chop($albumtitle); $albumtitle = $album if ($endChar ne "/") ; $albumtitle =~ s/^.*\///g; #remove path } else { $albumtitle = "" } $albuminfo{dirname} = $albumtitle; #single dir name, without path info if (!$albuminfo{title}){ if ($configHash->{stripDirPrefix}) { $albumtitle =~ s/^\d+_//g; } $albumtitle =~ s/_/ /g; # replace underscores with spaces $albuminfo{title} = local2html($albumtitle) ; } beVerboseN("title for album $album is $albuminfo{title}.", 3); return (\%albuminfo, $configHash); } sub calcNumThumbPages{ my $numImages = shift (@_); my $configHash = shift (@_); my $numPages=0; if ($numImages % $configHash->{numThumbsPerPage} == 0) { $numPages = $numImages/$configHash->{numThumbsPerPage}; }else{ $numPages = int($numImages/$configHash->{numThumbsPerPage}) + 1; } return $numPages; } sub getXLinks{ my $xLinksRef = shift; my @xLinks=(); foreach my $xLink ( @$xLinksRef ) { my %row = ( link => $xLink ); push(@xLinks, \%row); } return \@xLinks; } # escape a string so it can used as a javascript string sub escapeJSString{ my $string = shift; $string =~ s/\"/\\\"/g; $string =~ s/\n//g; return $string; } # normalize a string by translating accents sub normalizeString{ my $charset = shift; my $string = shift; my $result; $result = lc($string); $result = unac_string($charset, $result); if (!defined($result)) { warn "Invalid encoding $charset for string '$string'"; return ""; } return $result; } # split a string into keywords for search engine sub splitInKeywords{ my $string = shift; $string =~ s/[^a-z0-9]/ /gi; return $string; } # write data for the search engine sub writeSearchString{ my $imageHashRef = shift; my $configHash = shift; my $albumHashRef = shift; my $album = jssafe_uri_escape(shift); beVerboseN(" Writing information for the search engine.", 4); my $charset = $configHash->{htmlEncoding}; my $search_string = " "; foreach my $field (@{$configHash->{searchFields}}){ if ($$imageHashRef{$field}) { $search_string .= escapeJSString(normalizeString($charset, $$imageHashRef{$field}))." "; } } $search_string = splitInKeywords($search_string); my $size = $configHash->{defaultSize}; if (! $size >= 0){ $size = 0; } my $url = $album.$$imageHashRef{$size}{'htmlFile'}; my $album_title = $albumHashRef->{'title'}; my $album_url = $albumHashRef->{'link'}; my $thumb_url = $album.$imageHashRef->{'thumblink'}; my $title = escapeJSString($imageHashRef->{'title'}); my $width = $imageHashRef->{'twidth'}; my $height = $imageHashRef->{'theight'}; my $file = $albumdir."search_data.js"; open(FILE, ">>", $file) or die("Cannot write to file $file ($!)"); print(FILE "sd[sd.length] = new io(\"$search_string\", \"$title\", \"$url\", \"$thumb_url\", \"$width\", \"$height\", \"$album_title\", \"$album_url\");\n"); close (FILE) || die ("can't close $file ($!)"); } sub generateThumbnailPages{ my ($album, $albumHashRef, $firstIsIndex, $configHash, $xlinkListRef, @imageData) = @_; my @xlinkList=@$xlinkListRef; my %albumHash = %{$albumHashRef}; my $numImages = scalar(@imageData); #element count my $numPages = calcNumThumbPages($numImages, $configHash); my $crntPage; # generate number link for each page my @numLink; if ($firstIsIndex){ push @numLink, {NUMBER => "1", NUM_LINK => "index.html" }; }else{ push @numLink, {NUMBER => "1", NUM_LINK => "thumb0.html" }; } for($crntPage=1; $crntPage < $numPages; $crntPage++) { push @numLink, {NUMBER => ($crntPage+1), NUM_LINK => "thumb".$crntPage.".html" }; } for($crntPage=0; $crntPage < $numPages; $crntPage++) { #calculate prev, next thumb page # we set prev and next equal to the empty string # if we have only 1 page to # to indicate prev and next buttons should not be displayed. my ($prev, $next); if ($numPages == 1) { $prev = ""; $next = ""; }else{ $prev = ($crntPage -1 + $numPages)%$numPages; $prev = "thumb".$prev.".html"; $next = ($crntPage + 1)%$numPages; $next = "thumb".$next.".html"; # special cases if ($configHash->{thumbnailPageCycling} == 1) { $next = "index.html" if ($firstIsIndex && ($crntPage == $numPages-1)); } else { $prev = "" if ($crntPage == 0); $next = "" if ($crntPage == $numPages-1); } $prev = "index.html" if ($firstIsIndex && ($crntPage == 1)); } #first and last images on page my $first = $crntPage*$configHash->{numThumbsPerPage}; my $last = $first + $configHash->{numThumbsPerPage} - 1; $last = $#imageData if ($#imageData <= $last); my @preloadImages; if ($configHash->{javaScriptPreloadThumbs}) { # get the names of images on the next page to preload them using # javascript my $lastNext = $last + $configHash->{numThumbsPerPage}; $lastNext = $#imageData if ($#imageData <= $lastNext); for ( my $i = $last+1 ; $i <= $lastNext ; $i++){ my %image; $image{PRELOAD_IMAGE_NB} = $i-$last; $image{PRELOAD_IMAGE_NAME} = $imageData[$i]->{'thumblink'}; $image{PRELOAD_IMAGE_WIDTH} = $imageData[$i]->{'twidth'}; $image{PRELOAD_IMAGE_HEIGHT} = $imageData[$i]->{'theight'}; push @preloadImages, \%image; } } #fileName my $filename = "thumb".$crntPage.".html"; $filename = "index.html" if ($firstIsIndex && ($crntPage == 0)); # generate sequence of number links my $numLinkSeq = dclone(\@numLink); $numLinkSeq->[$crntPage]{NUM_LINK} = ""; generateThumbPage($album, $albumHashRef, $crntPage, $numPages, $filename, $prev, $next, $numLinkSeq, $configHash, \@preloadImages, \@xlinkList, @imageData[$first..$last]); } # Generate an "all images" thumbnail page if more than one page was # generated. if ( $configHash->{allThumbnailsPage} && $numPages > 1 ) { generateThumbPage($album, $albumHashRef, "-1", "1", "allthumbs.html", "", "", "", $configHash, undef, undef, @imageData[0..$#imageData]); } } sub generateThumbPage{ my ($album, $albumHashRef, $pageNumber, $numPages, $filename, $prevPage, $nextPage, $numberLinks, $configHash, $preloadImages, $xlinkListRef, @imageData) = @_; my @xlinkList; if (!defined($xlinkListRef)) { @xlinkList=(); } else { @xlinkList=@$xlinkListRef; } my %albumHash = %{$albumHashRef}; my $thumbsOnPage = scalar(@imageData); # generate the table containing the thumbnails my $crntImage; my @thumbTable; for ($crntImage = 0; $crntImage<$thumbsOnPage; $crntImage++) { #create the row my $row = thumbEntry($imageData[$crntImage], $imageData[$crntImage]{configuration}); $row->{THUMB_ID} = $crntImage; # begin new row if needed if ( (($crntImage+1) % $configHash->{thumbsPerRow} == 0) && ($crntImage+1 < $thumbsOnPage)) { $row->{THUMB_NEW_LINE} = 1; } push @thumbTable, $row; } # set up all the substitutions, first with subs for header my %subsHash; $subsHash{THUMBS_TABLE} = \@thumbTable; $subsHash{PRELOAD_IMAGES} = $preloadImages; $subsHash{THUMB_NUMBER_LINKS} = $numberLinks; $subsHash{NUM_INFO} = getAlbumNumInfo(%albumHash); $subsHash{ALBUM_TITLE} = $albumHash{title}; $subsHash{NAV_BAR_TABLE} = navBarLinks("thumb$pageNumber", $album, $configHash, %albumHash); $subsHash{ALBUM_PATH_LINKS} = pathLinks($album, 0, @{$albumHash{parentDirNames}}); $subsHash{TREE_NAME} = _("tree"); $subsHash{TREE_TITLE} = _("Tree of all albums and sub-albums"); $subsHash{TREE_LINK} = getRootDir($album)."tree.html"; if ($nextPage eq "" and $prevPage eq "") { $subsHash{MULTIPLE_PAGES} = 0; } else { $subsHash{MULTIPLE_PAGES} = 1; } if ($#{$albumHash{parentDirNames}} > 0) { $subsHash{UP_NAME} = _("up"); $subsHash{UP_TITLE} = _("Up one subalbum"); $subsHash{UP_LINK} = "../index.html"; } if ($genEditableAlbum) { $subsHash{ALBUM_DESC} = "". $albumHash{longdesc}.""; } else { $subsHash{ALBUM_DESC} = $albumHash{longdesc}; } if ($nextPage) { $subsHash{NEXT_THUMB_PAGE} = $nextPage; } if ($prevPage) { $subsHash{PREV_THUMB_PAGE} = $prevPage; } # Correct the special-casing of "-1" and "-2" to mean this is an # "allthumbs" page. if ( $pageNumber=="-1" || $pageNumber=="-2" ) { $pageNumber="0"; } my $pagenumber_string = $pageNumber+1; $pagenumber_string .= "/$numPages"; $subsHash{THUMB_PAGE_NUMBER} = $pagenumber_string; $subsHash{XLINK} = getXLinks(\@xlinkList); $subsHash{STATIC_PATH} = getRootDir($album)."static.".$configHash->{templateStyle}; if ($configHash->{backgroundImage}) { # Do not set this if not configured, so that template # can check for whether defined. $subsHash{BG_IMAGE} = $subsHash{STATIC_PATH}."/".$configHash->{backgroundImage}; } $subsHash{CUSTOM_CSS} = $configHash->{customStyleSheet}; $subsHash{HOME_LINK} = $configHash->{homeURL}; $subsHash{FEEDBACK_LINK} = $configHash->{feedbackMail}; $subsHash{PATH_SHOW_ICON} = $configHash->{pathShowIcon}; $subsHash{DATE} = strftime($configHash->{dateString}, localtime); if ($albumHashRef->{numSubAlbums} == 0){ $subsHash{FIRST_PAGE} = "index.html"; }else{ $subsHash{FIRST_PAGE} = "thumb0.html"; } $subsHash{LAST_PAGE} = "thumb".($numPages-1).".html"; renderTemplate("thumbnail", $albumdir.$album.$filename, \%subsHash, $configHash); } #creates a single entry in the table of thumbnails for the given image sub thumbEntry{ my $imageHashRef = shift; my $configHash = shift; my ($links, $i); my %thumb = (THUMB_LINK => $imageHashRef->{'thumblink'}, THUMB_WIDTH => $imageHashRef->{'twidth'}, THUMB_HEIGHT => $imageHashRef->{'theight'}, THUMB_ALT => _("Click on one of the size names below to enlarge this image"), THUMB_LINK_TITLE => _("Click on one of the size names below to enlarge this image"), ); if ($configHash->{defaultSize} >= 0){ $thumb{THUMB_DEFAULT_SIZE} = $$imageHashRef{$configHash->{defaultSize}}{'htmlFile'}; } if ($configHash->{titleOnThumbnail}) { $thumb{THUMB_TITLE} = $$imageHashRef{title}; } if (! $configHash->{thumbnailBackground}){ $thumb{THUMB_BACKGROUND} = $configHash->{colorsSubs}{$configHash->{colorStyle}}{PAGE_BACKCOLOR}; }else{ $thumb{THUMB_BACKGROUND} = $configHash->{colorsSubs}{$configHash->{colorStyle}}{SUBBAR_BACKCOLOR}; } #print 'for image'.$imageHashRef->{'filename'}.'we have #$imageHashRef->{\'maxSize\'} = '.$imageHashRef->{'maxSize'}."\n"; my @sizes; for $i (0..($imageHashRef->{'maxSize'})) { if ($i == $configHash->{defaultSize}) { push @sizes , {SIZE_LINK => $$imageHashRef{$i}{'htmlFile'}, SIZE_NAME => $configHash->{sizeNames}[$i], SIZE_TITLE => $configHash->{longSizeNames}[$i]. " ($imageHashRef->{$i}{'width'}x". "$imageHashRef->{$i}{'height'})", SIZE_FILE => $configHash->{fileSizeNames}[$i], SIZE_DFLT => 1, }; } else { push @sizes , {SIZE_LINK => $$imageHashRef{$i}{'htmlFile'}, SIZE_NAME => $configHash->{sizeNames}[$i], SIZE_TITLE => $configHash->{longSizeNames}[$i]. " ($imageHashRef->{$i}{'width'}x". "$imageHashRef->{$i}{'height'})", SIZE_FILE => $configHash->{fileSizeNames}[$i], }; } } $thumb{THUMB_SIZES} = \@sizes; return \%thumb; } sub generateSecondaryFieldsPage{ my $imageInfo = shift; my $album = shift; my $albumInfo = shift; my $imageName = shift; my $configHash = shift; my $table=""; my $fileName=""; my $tagValue; my $sectionTitle=""; my $tableSection=""; my @sections; my @fields; my @tmpFields; foreach my $tagName (@secondaryFields) { if ($tagName =~ m/^BINS-SECTION /) { if ($sectionTitle && @tmpFields){ push (@fields, {SECTION_TITLE => $sectionTitle}); @fields = (@fields, @tmpFields); @tmpFields = (); push (@sections, {SECTION_TITLE => $sectionTitle}); } $sectionTitle = $tagName; $sectionTitle =~ s/^BINS-SECTION //; }else{ $tagValue = getFields($configHash)->{$tagName}; if ($imageInfo->{$tagName}) { my %row = (FIELD_NAME => $tagValue->{'Name'}, FIELD_VALUE => local2html($imageInfo->{$tagName}) ); if ($tagValue->{'Tip'}) { $row{FIELD_TIP} = $tagValue->{'Tip'}; # Escape double quote to unconfuse emacs code highlighter. $row{FIELD_TIP} =~ s/\"/"/g; } push (@tmpFields, \%row); } } } if (! @fields) { return "" } # on which size of image we go when "back to the image" is clicked and # JavaScript is deactivated: my $size = $configHash->{defaultSize}; if ($size == -1){ $size = 0; } my %subs_hash; $subs_hash{TREE_LINK} = getRootDir($album)."tree.html"; $subs_hash{ALBUM_TITLE} = $album; $subs_hash{IMAGE_PAGE_LINK} = $imageInfo->{$size}{'htmlFile'}; $subs_hash{IMAGE_SIZE_NAME} = _("size "). $configHash->{longSizeNames}[$size]; $subs_hash{FILE_NAME} = encode_entities($imageName); $subs_hash{THUMB_PAGE} = $imageInfo->{'thumbpage'}; $subs_hash{ALBUM_PATH_LINKS} = pathLinks($album, $imageInfo->{'title'}, @{$albumInfo->{parentDirNames}}); $subs_hash{TITLE} = $imageInfo->{'title'}; $subs_hash{DESC_TABLE} = \@fields; $subs_hash{LINKS_TABLE} = \@sections; $subs_hash{STATIC_PATH} = getRootDir($album)."static.".$configHash->{templateStyle}; if ($configHash->{backgroundImage}) { # Do not set this if not configured, so that template # can check for whether defined. $subs_hash{BG_IMAGE} = $subs_hash{STATIC_PATH}."/".$configHash->{backgroundImage}; } $subs_hash{HOME_LINK} = $configHash->{homeURL}; $subs_hash{FEEDBACK_LINK} = $configHash->{feedbackMail}; $subs_hash{PATH_SHOW_ICON} = $configHash->{pathShowIcon}; $subs_hash{DATE} = strftime($configHash->{dateString}, localtime); $subs_hash{CUSTOM_CSS} = $configHash->{customStyleSheet}; my @array; push @array, {NAV_NAME => getIntlSubs($configHash)->{STRING_BACKTOTHEIMAGE}, NAV_LINK => "javascript:history.back();", NAV_ICON => "back.png", NAV_ID => "back"}; # $subs_hash{NAV_BAR_TABLE} = navBarLinks('secondaryFields', $album, $configHash, %albumHash); $subs_hash{NAV_BAR_TABLE} = \@array; #### $fileName = $imageName.".details.html"; my $outputPage = $albumdir.$album.$fileName; renderTemplate("details", $outputPage, \%subs_hash, $configHash); #$fileName=''. # _("Additional information on the picture").''; $fileName = jssafe_uri_escape($fileName); return $fileName; } # copy the source image in the dest album, and eventually, perform a # rotation sub copyImage { my ($source, $dest, $imageData, $configHash) = @_; if ( (! -e "$dest") || (-M "$source" < -M "$dest") ) { `cp -p "$source" "$dest"`; system("chmod", "a+r", "$dest") == 0 or die("\nCannot set write permission on $dest: $?"); if ($configHash->{rotateImages} eq 'destination') { # Perform a rotation of the picture if needed if (rotateImage($dest, $imageData->{'Orientation'}, "", $configHash) == 1) { progressifyImage($dest, "", $configHash); # swap width & height my $numsizes = $#{$configHash->{scaledWidths}}; for(my $j=0; $j<=$numsizes; $j++) { #my $tmp = $imageData->{$j}{'width'}; #$imageData->{$j}{'width'} = $imageData->{$j}{'height'}; #$imageData->{$j}{'height'} = $tmp; ($imageData->{$j}{'width'}, $imageData->{$j}{'height'}) = ($imageData->{$j}{'height'}, $imageData->{$j}{'width'}); } } } } } # copy the source file to the given destination sub copyFile { } sub getHTMLImagePageLink{ my ($imageData, $size, $num) = @_; my $sizeLink = $imageData->{'maxSize'}; if ($sizeLink >= $size) { $sizeLink = $size; } return jssafe_uri_escape($imageData->{'basename'})."_". $imageData->{configuration}{sizeNames}[$sizeLink]. ".jpg.".$num.".html"; } # $album is the album we are generating. # imagepath is path to actual image location. sub generateImagesInAlbum{ my ($album, $albumHashRef, $firstIsIndex, $configHash, @imagesToDisplay) = @_; # an array of references to hashes storing information about each image my @imageData; # generate thumbnails and scaled images for each image # we will display, and generate HTML my $numImages = $#imagesToDisplay+1; my $i; #get description information for($i=0; $i<$numImages; $i++) { my $crntImage = $album.$imagesToDisplay[$i]; $imageData[$i] = getDesc($crntImage, $configHash); #print "-------------------".Dumper($imageData{'configuration')); } #calculate the thumbnail page each image will be on for($i=0; $i<$numImages; $i++) { #my $crntImage = $imagesToDisplay[$i]; $imageData[$i]{'thumbpage'} = getThumbPage($i, $firstIsIndex, $configHash); } #determine scaled sizes, create scaled copies my(@largestSize); # array indexed by image number, holds index of largest # available size for each image. for ($i=0; $i<$numImages; $i++) { my $imageConfigHash = $imageData[$i]{'configuration'}; $largestSize[$i] = 0; my $crntImage = $imagesToDisplay[$i]; beVerbose("\n", 2); beVerboseN(" Image $crntImage", 1); my ($crntImageBase,$imagePath,$crntImageType) = &fileparse($crntImage, '\.[^.]+\z'); $imageData[$i]{'filename'} = $crntImage; $imageData[$i]{'basename'} = $crntImageBase; $imageData[$i]{'type'} = $crntImageType; # don't escape the / character #$imageData[$i]{'imagepath'} = $album; #print "imagepath : «$imagePath»\n"; #$imageData[$i]{'imageurl'} = $url; # to handle virtual images, make sure the images album exists # first, make sure web directory exists if (! -e "$albumdir$album") { beVerboseN(" Creating dir $albumdir$album", 1); `mkdir -p "$albumdir$album"` } # load the image to check if it is bigger than current max dims # to see if need new scaled image # first try with Image::Size, which is quicker than ImageMagick my($width, $height) = imgsize("$picdir$album$crntImage"); if (! defined $width) { # if Image::Size fails (format not recognized), load with # ImageMagick and get the size my($preview) = Image::Magick->new; # read in the picture my($x) = $preview->Read("$picdir$album$crntImage"); warn "$x" if "$x"; ($width, $height) = $preview->Get('width', 'height'); } $imageData[$i]{'width'} = $width; $imageData[$i]{'height'} = $height; #generate thumbnail (with dir if needed) my $thumbName = "$crntImageBase"."_pre.jpg"; #$imageData[$i]{'thumblink'} = &getWebBase($album).$thumbName; $imageData[$i]{'thumblink'} = jssafe_uri_escape($thumbName); my ($twidth, $theight); #if (! -e $albumdir.$album.$thumbName) { beVerboseN(" Generating thumbnail $album$thumbName from image ". "$crntImageBase.", 3); ($twidth, $theight)= generateThumbnail($album.$crntImage, $album.$thumbName, $width, $height, $imageData[$i], $imageData[$i]{'configuration'}); $imageData[$i]{twidth} = $twidth; $imageData[$i]{theight} = $theight; my $j; # generate scaled sizes, largestSize, write scaled # version if not oneCopy my $filling_in_sizes = 0; my $scaledImage; my $maxWidth; my $maxHeight; my ($scaledWidth, $scaledHeight); for ($j=0; $j <= $#{$imageConfigHash->{scaledWidths}}; $j++) { if (! $filling_in_sizes ) { my $size = $imageConfigHash->{sizeNames}[$j]; $size =~ s/\.//g ; $scaledImage = $crntImageBase."_". $size.".jpg"; $maxWidth = $imageConfigHash->{scaledWidths}[$j]; $maxHeight = $imageConfigHash->{scaledHeights}[$j]; ($scaledWidth, $scaledHeight) = getScaledSize($width, $height, $maxWidth, $maxHeight, $imageConfigHash); beVerboseN(" $imageConfigHash->{sizeNames}[$j] size is ". "$scaledWidth x $scaledHeight.", 3); } # generate scaled version if needed $imageData[$i]{$j}{'width'} = $scaledWidth; $imageData[$i]{$j}{'height'} = $scaledHeight; if (! $filling_in_sizes ) { $largestSize[$i] = $j; if (! $oneCopy) { ($imageData[$i]{$j}{'width'}, $imageData[$i]{$j}{'height'}) = writeRotateScaledVersion($album.$crntImage, $album.$scaledImage, $scaledWidth, $scaledHeight, $imageData[$i], $imageData[$i]{'configuration'}); } #if ( ($width <= $scaledWidth) && ($height <= $scaledHeight) ) { # $filling_in_sizes = 1; #} } } # if oneCopy, create a single canonical image copy, # with the same name as the original if ($oneCopy) { if ($imageSource eq "scaled") { ($imageData[$i]{$j}{'width'}, $imageData[$i]{$j}{'height'}) = writeRotateScaledVersion($album.$crntImage, $album.$crntImage, $imageData[$i]{$largestSize[$i]}{'width'}, $imageData[$i]{$largestSize[$i]}{'height'}, $imageData[$i], $imageData[$i]{'configuration'}); } elsif ($imageSource eq "copied") { copyImage($picdir.$album.$crntImage, $albumdir.$album.$crntImage, $imageData[$i], $imageConfigHash); } elsif ($imageSource eq "orig") { #not yet implemented } elsif ($imageSource eq "custom") { # gets size in KB my $fileSize = ((-s "$picdir$album$crntImage") / 1024); beVerboseN(" Size is $fileSize KB.", 3); if ($fileSize > 900) { beVerbose("Image $crntImage is BIG, resizing...", 3); my( $newW, $newH) = getScaledSize($imageData[$i]{'width'}, $imageData[$i]{'height'}, 1600, 1600, $imageConfigHash); ($imageData[$i]{$j}{'width'}, $imageData[$i]{$j}{'height'}) = writeRotateScaledVersion($album.$crntImage, $album.$crntImage, $newW, $newH, $imageData[$i], $imageData[$i]{'configuration'}); beVerboseN("done.", 3); } else { beVerbose("Image $crntImage is SMALL, copying...", 3); copyImage("$picdir$album$crntImage", "$albumdir$album$crntImage", $imageData[$i], $imageConfigHash); beVerboseN("done.", 3); } } } beVerboseN(" setting maxSize to $i ($imageData[$i]->{filename})", 3); $imageData[$i]->{'maxSize'}= $largestSize[$i]; } # now calculate everything needed to generate html next, prev html # names, etc #print "crntImage is $crntImage\n"; for ($i=0; $i < $numImages; $i++) { my $imageConfigHash = $imageData[$i]{'configuration'}; #print "-------------------".Dumper($imageConfigHash); my $crntImage = $imagesToDisplay[$i]; my ($crntImageBase,$imagePath,$crntImageType) = &fileparse($crntImage, '\.[^.]+\z'); #now generate scaled versions and HTML for (my $j=0; $j <= $imageData[$i]->{maxSize}; $j++) { #print "\$j = $j\n"; my $maxWidth = $imageConfigHash->{scaledWidths}[$j]; my $maxHeight = $imageConfigHash->{scaledHeights}[$j]; # suffix of filename of this size (add .html for html, # needs prefix) #my $crntSizeSuffix = ; my $size = $imageConfigHash->{sizeNames}[$j]; $size =~ s/\.//g ; my $scaledImage = $crntImageBase."_".$size.".jpg"; #determine next, prev image my $nextImageNum = ($i+1) % ($numImages); my $prevImageNum = ($i-1+$numImages)% ($numImages) ; my $npdiff = $nextImageNum - $prevImageNum; #my ($xbase, $xpath, $xtype) = #fileparse($imagesToDisplay[$nextImageNum], '\.[^.]+\z'); my $sizeLink = $imageData[$nextImageNum]->{'maxSize'}; if ($sizeLink >= $j ) { $sizeLink = $j; } $imageData[$i]{$j}{'nextHTML'} = getHTMLImagePageLink($imageData[$nextImageNum], $j, $nextImageNum); $imageData[$i]{$j}{'preloadIMG'} = jssafe_uri_escape($imageData[$nextImageNum]{'basename'})."_". $imageData[$nextImageNum]{configuration}{sizeNames}[$sizeLink]. ".jpg"; $imageData[$i]{$j}{'imgNum'} = $i + 1; $imageData[$i]{$j}{'imgCount'} = $numImages; $imageData[$i]{$j}{'nextIsFirst'} = ($nextImageNum == 0); $imageData[$i]{$j}{'prevIsLast'} = (($prevImageNum + 1) == $numImages); $imageData[$i]{$j}{'prevHTML'} = getHTMLImagePageLink($imageData[$prevImageNum], $j, $prevImageNum); $imageData[$i]{$j}{'nextTitle'}= $imageData[$nextImageNum]{'title'}; $imageData[$i]{$j}{'prevTitle'}= $imageData[$prevImageNum]{'title'}; if ($configHash->{thumbPrevNext}) { $imageData[$i]{$j}{'nextThumb'} = jssafe_uri_escape($imageData[$nextImageNum]{'basename'})."_pre.jpg"; $imageData[$i]{$j}{'prevThumb'} = jssafe_uri_escape($imageData[$prevImageNum]{'basename'})."_pre.jpg"; } # used in URL $imageData[$i]{$j}{'htmlFile'}= jssafe_uri_escape($scaledImage). ".$i.html"; # used to access the file on disk $imageData[$i]{$j}{'htmlFileName'}= $scaledImage.".$i.html"; # sizedFile is the text to go into the link for this image size if ($oneCopy) { #$imageData[$i]{$j}{'sizedFile'} = # &getWebBase($album).$imageData[$i]{'filename'}; $imageData[$i]{$j}{'sizedFile'} = $crntImageBase.$crntImageType; } else { #$imageData[$i]{$j}{'sizedFile'} = # &getWebBase($album).$imageData[$i]{'imagepath'}. # $scaledImage; $imageData[$i]{$j}{'sizedFile'} = $scaledImage; } } $imageData[$i]{'detailsLink'} = generateSecondaryFieldsPage($imageData[$i], $album, $albumHashRef, $crntImageBase.$crntImageType, $configHash); if ( $configHash->{searchEngine}) { writeSearchString($imageData[$i], $configHash, $albumHashRef, $album); } } # now generate html for ($i=0; $i<$numImages; $i++) { for (my $j=0; $j <= $imageData[$i]->{maxSize}; $j++) { my $lastImageURL = getHTMLImagePageLink($imageData[$numImages-1], $j, $numImages-1); my $firstImageURL = getHTMLImagePageLink($imageData[0], $j, 0); generateImage($imageData[$i], $j, $album, $albumHashRef, $imageData[$i]{'configuration'}, $firstImageURL, $lastImageURL); } } #printImageData(@imageData); beVerboseN(" We have ". scalar(@imageData). " images in the album.", 2); return @imageData; } sub getThumbPage{ my ($crntNumber, $firstIsIndex, $configHash) = @_; my $thumbPageNumber = int($crntNumber/$configHash->{numThumbsPerPage}); return "index.html" if ($thumbPageNumber == 0 && $firstIsIndex); return "thumb$thumbPageNumber.html"; } sub generateThumbnail{ my ($crntImage, $thumbName, $width, $height, $imageData, $configHash) = @_; my ($newWidth, $newHeight) = getScaledSize($width, $height, $configHash->{previewMaxWidth}, $configHash->{previewMaxHeight}, $configHash); return writeRotateScaledVersion($crntImage, $thumbName, $newWidth, $newHeight, $imageData, $configHash); } sub getScaledSize{ my ($width, $height, $maxWidth, $maxHeight, $configHash) = @_; my $xfactor; my $yfactor; #if width or height are zero, that is a problem if (not ( $width and $height ) ) { return ($maxWidth,$maxHeight); } if (substr($maxWidth, -1) eq "%") { chop($maxWidth); $xfactor = $maxWidth / 100; $maxWidth = $width * $xfactor; } else { $xfactor = $maxWidth/$width; } if (substr($maxHeight, -1) eq "%") { chop($maxHeight); $yfactor = $maxHeight / 100; $maxHeight = $height * $yfactor; } else { $yfactor = $maxHeight/$height; } my ($newWidth, $newHeight); if ($xfactor <= $yfactor) { $newWidth = $maxWidth; $newHeight = $xfactor*$height; }else{ $newHeight = $maxHeight; $newWidth = $yfactor*$width; } ($newWidth, $newHeight) = (int($newWidth), int($newHeight)); if ($width<$newWidth || $height<$newHeight) { if ($configHash->{whenSrcSmaller} eq 'enlarge') { beVerboseN("Enlarging small image from ${width}x${height} to ${newWidth}x${newHeight}", 2); } elsif ($configHash->{whenSrcSmaller} eq 'original') { beVerboseN("Keeping original size of small image, instead of from ${width}x${height} to ${newWidth}x${newHeight}", 2); ($newWidth, $newHeight) = ($width, $height); } elsif ($configHash->{whenSrcSmaller} eq 'skip') { beVerboseN("Skipping small image instead of scaling from ${width}x${height} to ${newWidth}x${newHeight}", 2); next; } else { warn "Unrecognized configuration setting for \"whenSrcSmaller\":".$configHash->{whenSrcSmaller}; } } return ($newWidth, $newHeight); } # takes origName and newName with path info (but not pic_dir, of course) sub writeScaledVersion{ my ($origName, $newName, $newWidth, $newHeight, $imageRef, $configHash) = @_; beVerbose(" Generating scaled version of $picdir$origName\n". " to be written to $newName... ", 2); if (-e "$albumdir$newName"){ if (((lstat("$albumdir$newName"))[9]) >= ((stat("$picdir$origName"))[9])){ beVerboseN("\n image already exists and is newer, skipping.", 2); return 0; } } my($preview) = Image::Magick->new; my($x) = $preview->Read("$picdir$origName"); # read in the picture warn "$x" if "$x"; my $format = $preview->Get("magick"); if (!$configHash->{scaleIfSameSize} and grep (/^$format$/, @webFormats ) ) { my ($width, $height) = $preview->Get("width", "height"); if ($width == $newWidth && $height == $newHeight) { if ($configHash->{linkInsteadOfCopy} && (! ($configHash->{rotateImages} eq 'destination') || (! defined $imageRef->{'Orientation'} || $imageRef->{'Orientation'} eq "top_left"))) { beVerbose("\n Image has the right size, just linking... ", 2); my $newpath; if( $configHash->{linkRelative} ) { $newpath = relpath("$albumdir$newName", "$picdir$origName"); } else { $newpath = "$picdir$origName"; } beVerboseN("Linking from $albumdir$newName to $newpath... ", 2); system("ln", "-sf", $newpath, "$albumdir$newName") == 0 or die("\nCannot link $albumdir$newName to $newpath: $?"); # the original file may be r/o but we don't have to modify it # but it must be readable by the http deamon if ($configHash->{updateOriginalPerms}) { system("chmod", "a+r", "$picdir$origName") == 0 or die("\nCannot set read permission on $albumdir$newName: $?"); } beVerboseN("done.", 2); return 0; # Image is processed, no need to try to process it # again. } else { beVerbose("\n Image has the right size, just copying... ", 2); system("cp", "-p", "$picdir$origName", "$albumdir$newName") == 0 or die("\nCannot copy $picdir$origName to $albumdir$newName: $?"); # make it writable in case $origName was r/o system("chmod", "u+w,a+r", "$albumdir$newName") == 0 or die("\nCannot set write permission on $albumdir$newName: $?"); beVerboseN("done.", 2); return 1; } } } $x = $preview->Set(quality => $configHash->{jpegQuality}); warn "$x" if "$x"; if ($configHash->{deExifyImages}) { $x = $preview->Profile(name => "*", profile => ""); warn "$x" if "$x"; } if ($configHash->{scaleMethod} eq "sample") { $x = $preview->Sample(width=>$newWidth, height=>$newHeight); } else { if ($configHash->{scaleMethod} ne "scale") { warn "Unknown scaleMethod $configHash->{scaleMethod}, using scale" } $x = $preview->Scale(width=>$newWidth, height=>$newHeight); } warn "$x" if "$x"; my $borderOnThumbnails = $configHash->{borderOnThumbnails}; if ($borderOnThumbnails) { $x = $preview->Border(color=>'black',width=>$borderOnThumbnails, height=>$borderOnThumbnails); warn "$x" if "$x"; } beVerbose("\n Writing scaled image $albumdir$newName... ", 3); $x = $preview->Write("$albumdir$newName"); warn "$x" if "$x"; beVerboseN("done.", 2); return 1; } sub writeRotateScaledVersion{ my ($origName, $newName, $newWidth, $newHeight, $imageRef, $configHash) = @_; if (writeScaledVersion($origName, $newName, $newWidth, $newHeight, $imageRef, $configHash)){ if ($configHash->{rotateImages} eq 'destination'){ # Perform a rotation of the picture if needed if (rotateImage("$albumdir$newName", $imageRef->{'Orientation'}, "", $configHash) == 1){ progressifyImage("$albumdir$newName", "", $configHash); return ($newHeight, $newWidth); } } progressifyImage("$albumdir$newName", "", $configHash); return ($newWidth, $newHeight); } ($newWidth, $newHeight) = imgsize($albumdir.$newName); return ($newWidth, $newHeight); } # $album is album we are generating, _not_ path to image. # For the actual image path, use $imageHashRef sub generateImage { my ($imageHashRef, $size, $album, $albumHashRef, $configHash, $firstImage, $lastImage) = @_; my $crntImage = $imageHashRef->{'filename'}; my $imagetodisplay = $imageHashRef->{$size}{'sizedFile'}; my $filesize = &fileSize("$albumdir$album$imagetodisplay"); $imagetodisplay = jssafe_uri_escape($imagetodisplay); my $imagetitle = $crntImage; $imagetitle =~ s/\.(\S+)\Z//; $imagetitle =~ s/_/ /g; my($fileExtension) = $imageHashRef->{'type'}; if ($fileExtension =~ /jpg|jpeg/i) { $fileExtension = "JPEG"; } elsif ($fileExtension =~ /gif/i) { $fileExtension = "GIF"; } elsif ($fileExtension =~ /png/i) { $fileExtension = "PNG"; } else { # if the type is unwkown, the image has been converted to JPEG $fileExtension = "JPEG"; } my $width = $imageHashRef->{$size}{width}; my $height = $imageHashRef->{$size}{height}; my $pictureinfo = _('$filesize $fileExtension image, $width x $height pixels'); $pictureinfo = eval "\"$pictureinfo\""; #add strings to substitute hash my %subs_hash; #$subs_hash{ALBUM_TITLE} = $album; $subs_hash{WIDTH} = $width+2; $subs_hash{HEIGHT} = $height+2; $subs_hash{IMAGE_TO_DISPLAY} = $imagetodisplay; $subs_hash{PICTURE_INFO} = $pictureinfo; #$subs_hash{''} = getRootDir($album); $subs_hash{NEXT_IMAGE} = $imageHashRef->{$size}{nextHTML}; if ($configHash->{imagePageCycling}) { $subs_hash{NEXT_IMAGE_PAGE} = 1; $subs_hash{PREV_IMAGE_PAGE} = 1; } else { $subs_hash{NEXT_IMAGE_PAGE} = ! $imageHashRef->{$size}{nextIsFirst}; $subs_hash{PREV_IMAGE_PAGE} = ! $imageHashRef->{$size}{prevIsLast}; } $subs_hash{IMG_NUM} = $imageHashRef->{$size}{imgNum}; $subs_hash{IMG_COUNT} = $imageHashRef->{$size}{imgCount}; if ($configHash->{javaScriptPreloadImage}) { $subs_hash{IMG_PRELOAD} = $imageHashRef->{$size}{preloadIMG}; } $subs_hash{PREV_IMAGE} = $imageHashRef->{$size}{prevHTML}; $subs_hash{NEXT_TITLE} = $imageHashRef->{$size}{nextTitle}; $subs_hash{PREV_TITLE} = $imageHashRef->{$size}{prevTitle}; if ($configHash->{thumbPrevNext}) { $subs_hash{NEXT_THUMB} = $imageHashRef->{$size}{nextThumb}; $subs_hash{PREV_THUMB} = $imageHashRef->{$size}{prevThumb}; } $subs_hash{FILE_NAME} = encode_entities($imageHashRef->{basename}) . $imageHashRef->{'type'}; $subs_hash{THUMB_PAGE} = $imageHashRef->{thumbpage}; $subs_hash{SIZE_LINKS} = getSizeLinks($size, $imageHashRef, $configHash); my $title = $imageHashRef->{title}; $subs_hash{ALBUM_PATH_LINKS} = pathLinks($album, $title, @{$albumHashRef->{parentDirNames}}); $subs_hash{TITLE} = $title; $subs_hash{DESC_TABLE} = getDescTable(\%{$imageHashRef}, $configHash); $subs_hash{DETAILS_LINK} = $imageHashRef->{detailsLink}; $subs_hash{STRING_DETAILS} = _("Additional information on the picture"); $subs_hash{NAV_BAR_TABLE} = navBarLinks('image', $album, $configHash, %$albumHashRef); $subs_hash{TREE_NAME} = _("tree"); $subs_hash{TREE_TITLE} = _("Tree of all albums and sub-albums"); $subs_hash{TREE_LINK} = getRootDir($album)."tree.html"; $subs_hash{STATIC_PATH} = getRootDir($album)."static.".$configHash->{templateStyle}; $subs_hash{HOME_LINK} = $configHash->{homeURL}; $subs_hash{FEEDBACK_LINK} = $configHash->{feedbackMail}; $subs_hash{DATE} = strftime($configHash->{dateString}, localtime); if ($configHash->{backgroundImage}) { # Do not set this if not configured, so that template # can check for whether defined. $subs_hash{BG_IMAGE} = $subs_hash{STATIC_PATH}."/".$configHash->{backgroundImage}; } $subs_hash{CUSTOM_CSS} = $configHash->{customStyleSheet}; $subs_hash{PATH_IMG_NUM} = $configHash->{pathImgNum}; $subs_hash{PATH_SHOW_ICON} = $configHash->{pathShowIcon}; $subs_hash{FIRST_IMAGE} = $firstImage; $subs_hash{LAST_IMAGE} = $lastImage; $subs_hash{IMAGE_COMMENT} = $imageHashRef->{comment}; renderTemplate("image", $albumdir.$album.$imageHashRef->{$size}{htmlFileName}, \%subs_hash, $configHash); } sub getSizeLinks{ my ($size, $imageHashRef, $configHash) = @_; my @sizes; if ( $size eq 'full' ) { $size = -1; } for my $i (0..$imageHashRef->{'maxSize'}) { if ($i != $size) { # output link push @sizes, {SIZE_NAME => $configHash->{longSizeNames}[$i], SIZE_LINK => $imageHashRef->{$i}{'htmlFile'}, SIZE_TITLE => $imageHashRef->{$i}{'width'}."x". $imageHashRef->{$i}{'height'}, SIZE_FILE => $configHash->{fileSizeNames}[$i], }; } else { #mark as current page push @sizes, {SIZE_NAME => $configHash->{longSizeNames}[$i], SIZE_FILE => $configHash->{fileActiveSizeNames}[$i]}; } } return \@sizes; } sub getDescTable{ my ($hashref, $configHash) = @_; my @descTable; foreach my $tagName (@mainFields) { if (${%$hashref}{$tagName}) { my $value=${%$hashref}{$tagName}; $value =~ s/'/'/g ; # in case it's used in javascript code push @descTable, {DESC_FIELD_NAME => getFields($configHash)->{$tagName}->{'Name'}, DESC_FIELD_VALUE => $value, }; } } return \@descTable; } # Given a path, not including $picdir, gives the relative path back # to the root of the hierarchy. Note that the trailing slash is critical for the # current implementation. For example, if given as input sample_dir/, which # corresponds to web/sample_dir/ and pic_dir/sample_dir/, the function # returns "../". # changed on 11/15 so it only points into base dir of web hierarchy sub getRootDir{ my $path = $_[0]; my $slashcount = 0; $slashcount++ while($path =~ m'/'g); my $relPath =""; my $i; for($i=$slashcount; $i>0; $i--) { $relPath = $relPath."../"; } return $relPath; } # given an album (path), not including $albumdir, # provides the relative path back to $albumdir. # closely related to getRootDir sub getWebBase{ my $path = $_[0]; my $slashcount = 0; $slashcount++ while($path =~ m'/'g); my $relPath =""; my $i; for($i=$slashcount; $i>0; $i--) { $relPath = $relPath."../"; } return $relPath; } # given the name of a directory in $picdir, not including the leading # $picdir, generates the entry for the table on the home page sub generateAlbumEntry { my $album = shift(@_); my $prettyalbum = $album; $prettyalbum =~ s/_/ /g; # replaces underscores with spaces my $result = ''.$prettyalbum.'
'; return $result; } # return list of directories where templates can be found sub templateDirs { my $configHash = shift; my @dirs; if ($templateDir) { push(@dirs, bsd_glob($templateDir."/templates.". $configHash->{templateStyle}, GLOB_TILDE)); } push(@dirs, bsd_glob($configHash->{userConfigDir}."/templates.". $configHash->{templateStyle}, GLOB_TILDE)); push(@dirs, bsd_glob($configHash->{globalDataDir}."/templates.". $configHash->{templateStyle}, GLOB_TILDE)); return @dirs; } # return static directory path (with dir) if it exists. sub templateStaticDir { my $configHash = shift; my $staticDir; my @dirs = templateDirs($configHash); foreach my $dir (@dirs) { beVerboseN(" Looking for static template directory in $dir...", 4); if (-d $dir."/static") { $staticDir = $dir."/static"; beVerboseN(" Found static template directory $staticDir.", 4); last; } } return $staticDir; } # return template file (with dir) from template name sub templateFileName { my $templateName = shift; my $configHash = shift; my $templateFile; my @dirs = templateDirs($configHash); if ($templateDir) { push(@dirs, bsd_glob($templateDir."/templates.". $configHash->{templateStyle}, GLOB_TILDE)); } push(@dirs, bsd_glob($configHash->{userConfigDir}."/templates.". $configHash->{templateStyle}, GLOB_TILDE)); push(@dirs, bsd_glob($configHash->{globalDataDir}."/templates.". $configHash->{templateStyle}, GLOB_TILDE)); foreach my $dir (@dirs) { beVerboseN(" Looking for HTML template $templateName in $dir...", 4); if (-f $dir."/".$templateName) { $templateFile = $dir."/".$templateName; beVerboseN(" Found HTML template $templateFile...", 4); last; } } if (!$templateFile) { print("Error: cannot find HTML template $templateName\n"); exit 2; } return $templateFile; } # render an html file from the templates sub renderTemplate{ my $templateName = shift; my $outputFileName = shift; my $templateParameters = shift; my $configHash = shift; renderFile(templateFileName($templateName.".html", $configHash), $outputFileName, $templateParameters, $configHash, ); } # render a file (replace template tags with real values) sub renderFile{ my $sourceFileName = shift; my $outputFileName = shift; my $templateParameters = shift; my $configHash = shift; %{$templateParameters} = (%{$templateParameters}, %{$configHash->{colorsSubs}{$configHash->{colorStyle}}}, %{getIntlSubs($configHash)}, ); # open the html template #my $template = # HTML::Template::JIT->new(jit_debug => 1, # jit_path => '/tmp', my $template = HTML::Template->new( filename => $sourceFileName, blind_cache => 1, loop_context_vars => 1, die_on_bad_params => 0, global_vars => 1, ); # fill in the parameters $template->param($templateParameters); open(OUTFILE, ">$outputFileName") or die "Couldn't open $outputFileName"; if ($configHash->{compactHTML}){ my $page = $template->output(); my $h = new HTML::Clean(\$page); $h->strip({whitespace => 1, shortertags => 1, blink => 0, contenttype => 0, comments => 1, entities => 0, dequote => 1, defcolor => 1, javascript => 1, htmldefaults => 0, # when set to 1, htmldefaults cause problems # with UTF-8 encodings lowercasetags => 0, meta => "", }); my $page2 = $h->data(); print OUTFILE $$page2; } else { $template->output(print_to => *OUTFILE); } close(OUTFILE); } # Given an image file (no album_dir, with path, as usual), returns # name of the .xml file associated with this image sub getDescFile{ my $crntImage = shift(@_); my ($base,$dir,$type) = &fileparse($crntImage, '\.[^.]+\z'); my $descFile = $picdir.$dir.$base.$type.".xml"; if( ! -e $descFile){ $descFile = $picdir.$dir.$base.".xml"; } if( ! -e $descFile){ $descFile = $picdir.$dir.$base.$type.".xml"; } return $descFile; } sub getXMLAsGrove{ my $file=shift(@_); #my $sample = XML::Handler::Sample->new(); # Get XML document as a Grove my $grove_builder = XML::Grove::Builder->new; my $parser = XML::Parser::PerlSAX->new ( Handler => $grove_builder); #my $parser = XML::SAX::Expat->new ( Handler => $grove_builder); return $parser->parse ( Source => { SystemId => $file } ); } sub getDesc{ my $crntImage = shift(@_); my $configHash= shift(@_); my ($base,$dir,$type) = &fileparse($crntImage, '\.[^.]+\z'); my $descFile = getDescFile($crntImage); my %descHash; my %exifHash; my $document; my @priorityList; if (-e $descFile) { beVerboseN(" Reading desc file $descFile.", 3); $document = getXMLAsGrove($descFile); %descHash = getDescXML($document, $configHash); #$descHash{descFileName} = uri_escape($descFile, '^-A-Za-z0-9/_\.'); $configHash = getConfigXML($document, '/image/bins', $configHash); %exifHash = getExifXML($document, \@priorityList); } else { $descHash{descFileName} = ""; } processExif($crntImage, \%descHash, \%exifHash, $document, \@priorityList, $configHash); # If no title is set, use the picture file name. if (!trimWhiteSpace($descHash{'title'})) { # If trimming whitespace gets rid of everything (returns empty string) my $imagetitle = $base; $imagetitle =~ s/_/ /g; # replace underscores with spaces $descHash{'title'} = local2html($imagetitle); } $descHash{'configuration'} = $configHash; return \%descHash; } # Given an XML doc as a Grove, returns # fields from that images description file. sub getDescXML{ my ($document, $configHash) = @_; my $fieldName; my $fieldValue; my %descHash; beVerboseN(" Reading user description fields...", 3); foreach my $element (@{$document->at_path('/image/description')->{Contents}}) { if (UNIVERSAL::isa($element, 'XML::Grove::Element') && $element->{Name} eq "field") { $fieldName = $element->{Attributes}{'name'}; $fieldValue = ""; if (grep (/^$fieldName$/, keys(%{getFields($configHash)}))) { beVerbose(" Reading field '$fieldName':", 3); foreach my $characters (@{$element->{Contents}}) { #if (UNIVERSAL::isa($characters, 'XML::Grove::Characters')) { $fieldValue .= $characters->as_canon_xml(); } $fieldValue = trimWhiteSpace(decode_entities(xml2html($fieldValue))); beVerbose("'".$fieldValue."'\n", 3); $descHash{$fieldName} = $fieldValue; } else { beVerbose(" Ignoring unknown field '$fieldName'.", 3); } } } return %descHash; } # Given an XML doc as a Grove, returns # hash from the Exif fields of the description file. sub getExifXML{ my $document = shift; my $priorityList = shift; #my $fieldNb; my $fieldName; my $fieldValue; my %descHash; beVerboseN(" Reading Exif data from description file...", 3); @{$priorityList} = @priorityExifTags; foreach my $element (@{$document->at_path('/image/exif')->{Contents}}) { if (UNIVERSAL::isa($element, 'XML::Grove::Element') && $element->{Name} eq "tag") { #$fieldNb = $element->{Attributes}{'no'}; $fieldName = $element->{Attributes}{'name'}; $fieldValue = ""; beVerbose(" Reading Exif field '$fieldName':", 3); foreach my $characters (@{$element->{Contents}}) { #if (UNIVERSAL::isa($characters, 'XML::Grove::Characters')) { $fieldValue .= $characters->as_canon_xml(); } if (defined $fieldValue){ $fieldValue = trimWhiteSpace(decode_entities(xml2html($fieldValue))); } else { $fieldValue = ""; } beVerbose("'".$fieldValue."'\n", 3); $descHash{$fieldName} = $fieldValue; if ($element->{Attributes}{'priority'}){ push @{$priorityList}, $fieldName; } } } return %descHash; } sub addExif{ my $tagName = shift; my $tagValue = shift; my $exifHash = shift; my $priorityList = shift; $tagValue = trimWhiteSpace($tagValue); if (grep (/^$tagName$/, @{$priorityList})){ beVerboseN(" Keeping value '$exifHash->{$tagName}' for $tagName", 3); beVerboseN(" $tagName has priority over exif value '$tagValue'.", 3); return 0; } if ( ! (exists $exifHash->{$tagName} && $exifHash->{$tagName} eq $tagValue) ) { beVerboseN(" Found new value '".$tagValue."' for $tagName", 3); beVerboseN(" old value was '".$exifHash->{$tagName}."'", 3) if ($exifHash->{$tagName}); beVerboseN(" bla '".$exifHash->{$tagName}."'", 3) if ($exifHash->{$tagName}); $exifHash->{$tagName} = $tagValue; return 1; } return 0; } sub addSpecialExif{ my $tagName = shift; my $tagValue = shift; my $exifHash = shift; my $priorityList = shift; if (UNIVERSAL::isa(\$tagValue, 'SCALAR')){ # Canon special tags if ($tagName eq "Canon-Tag-0x0007"){ return addExif("Software", $tagValue, $exifHash, $priorityList); } if ($tagName eq "Canon-Tag-0x0009"){ return addExif("Owner", $tagValue, $exifHash, $priorityList); } } elsif (UNIVERSAL::isa($tagValue, 'ARRAY')) { if ($tagValue->[1] eq 0) { return 0; } if ($tagName eq "SubjectDistance") { $tagValue = $tagValue->[0]/$tagValue->[1]; $tagValue .= translate(" meters"); return addExif($tagName, $tagValue, $exifHash, $priorityList); } if ($tagName eq "ExposureTime") { if (($tagValue->[0] == 0) || ($tagValue->[1] == 0)) { $tagValue = 0; } else { $tagValue = "1/".sprintf("%.0f", 1/($tagValue->[0]/$tagValue->[1])); } $tagValue .= translate(" second"); return addExif($tagName, $tagValue, $exifHash, $priorityList); } if ($tagName eq "ShutterSpeedValue") { # this is the actual APEX Value my $APEXval = $tagValue->[0]/$tagValue->[1]; # ...but we want to see time in seconds instead if ($APEXval > 0) { $tagValue = sprintf("1/%d", 2**((1)*$APEXval)); } else { $tagValue = sprintf("%d", 2**((-1)*$APEXval)); } $tagValue .= translate(" sec"); return addExif($tagName, $tagValue, $exifHash, $priorityList); } if ($tagName eq "FNumber" || $tagName eq "FocalPlaneXResolution" || $tagName eq "FocalPlaneYResolution") { $tagValue = sprintf("%.2f", $tagValue->[0]/$tagValue->[1]); return addExif($tagName, $tagValue, $exifHash, $priorityList); } if ($tagName eq "FocalLength") { $tagValue = sprintf("%.2f", $tagValue->[0]/$tagValue->[1]). translate(" millimeters"); return addExif($tagName, $tagValue, $exifHash, $priorityList); } if ($tagName eq "ApertureValue" || $tagName eq "MaxApertureValue") { $tagValue = "F".sprintf("%.2f", sqrt(2)**($tagValue->[0]/$tagValue->[1])). " (".sprintf("%.2f", $tagValue->[0]/$tagValue->[1])." APEX)"; return addExif($tagName, $tagValue, $exifHash, $priorityList); } if ($tagName eq "BitsPerSample") { my $result=""; $result .= $_." " foreach(@{$tagValue}); return addExif($tagName, $result, $exifHash, $priorityList); } if ($tagName eq "CompressedBitsPerPixel") { my $result; SWITCH: { $tagValue->[0]==1 && do { $result="Basic"; last; }; $tagValue->[0]==2 && do { $result="Normal"; last; }; $tagValue->[0]==3 && do { $result="Normal"; last; }; $tagValue->[0]==4 && do { $result="Fine"; last; }; $tagValue->[0]==5 && do { $result="Very fine"; last; }; } $result .= " ($tagValue->[0]:$tagValue->[1])"; return addExif($tagName, $result, $exifHash, $priorityList); } if ($tagName eq "Canon-Tag-0x0001") { # CanonMacro my $value = $tagValue->[1]; if ($value == 1) { $value = translate("On"); } elsif ($value == 2) { $value = translate("Off"); } else { $value=""; } my $modified = addExif("CanonMacro", $value, $exifHash, $priorityList) if($value); # CanonTimerLength $value = $tagValue->[2]; if ($value) { $value = $value."/10".translate(" second"); $modified |= addExif("CanonTimerLength", $value, $exifHash, $priorityList); } # CanonQuality $value = $tagValue->[3]; if ($value == 2) { $value = translate("Normal"); } elsif ($value == 3) { $value = translate("Fine"); } elsif ($value == 5) { $value = translate("Superfine"); } else { $value=""; } $modified |= addExif("CanonQuality", $value, $exifHash, $priorityList) if ($value); # CanonFlashMode $value = $tagValue->[4]; if ($value == 1) { $value = translate("Auto"); } elsif ($value == 2) { $value = translate("On"); } elsif ($value == 3) { $value = translate("Red-eye reduction"); } elsif ($value == 4) { $value = translate("Slow synchro"); } elsif ($value == 5) { $value = translate("Auto + red-eye reduction"); } elsif ($value == 6) { $value = translate("On + red-eye reduction"); } elsif ($value == 16) { $value = translate("External flash"); } else { $value=""; } $modified |= addExif("CanonFlashMode", $value, $exifHash, $priorityList) if ($value); # CanonContinuousDriveMode $value = $tagValue->[5]; if ($value) { $value = translate("On"); $modified |= addExif("CanonContinuousDriveMode", $value, $exifHash, $priorityList); } # CanonFocusMode $value = $tagValue->[7]; if ($value == 1) { $value = translate("AI Servo"); } elsif ($value == 2) { $value = translate("AI Focus"); } elsif ($value == 3) { $value = translate("MF"); } elsif ($value == 4) { $value = translate("Single"); } elsif ($value == 5) { $value = translate("Continuous"); } elsif ($value == 6) { $value = translate("MF"); } elsif ($value == 0) { $value = translate("One-Shot"); } else { $value=""; } $modified |= addExif("CanonFocusMode", $value, $exifHash, $priorityList) if ($value); # CanonImageSize $value = $tagValue->[10]; if ($value == 0) { $value = translate("Large"); } elsif ($value == 1) { $value = translate("Medium"); } elsif ($value == 2) { $value = translate("Small"); } else { $value=""; } $modified |= addExif("CanonImageSize", $value, $exifHash, $priorityList) if ($value); # CanonEasyShootingMode $value = $tagValue->[11]; if ($value == 1) { $value = translate("Manual"); } elsif ($value == 2) { $value = translate("Landscape"); } elsif ($value == 3) { $value = translate("Fast Shutter"); } elsif ($value == 4) { $value = translate("Slow Shutter"); } elsif ($value == 5) { $value = translate("Night"); } elsif ($value == 6) { $value = translate("B&W"); } elsif ($value == 7) { $value = translate("Sepia"); } elsif ($value == 8) { $value = translate("Portrait"); } elsif ($value == 9) { $value = translate("Sports"); } elsif ($value == 10) { $value = translate("Macro / Close-Up"); } elsif ($value == 11) { $value = translate("Pan Focus"); } elsif ($value == 0) { $value = translate("Full Auto"); } else { $value=""; } $modified |= addExif("CanonEasyShootingMode", $value, $exifHash, $priorityList) if ($value); # CanonDigitalZoom $value = $tagValue->[12]; if ($value == 1) { $value = translate("2x"); } elsif ($value == 2) { $value = translate("4x"); } elsif ($value == 0) { $value = translate("None"); } else { $value=""; } $modified |= addExif("CanonDigitalZoom", $value, $exifHash, $priorityList) if ($value); # CanonContrast $value = $tagValue->[13]; if ($value == 0xFFFF) { $value = translate("Low"); } elsif ($value == 0x0000) { $value = translate("Normal"); } elsif ($value == 0x0001) { $value = translate("High"); } else { $value=""; } $modified |= addExif("CanonContrast", $value, $exifHash, $priorityList) if ($value); # CanonSaturation $value = $tagValue->[14]; if ($value == 0xFFFF) { $value = translate("Low"); } elsif ($value == 0x0000) { $value = translate("Normal"); } elsif ($value == 0x0001) { $value = translate("High"); } else { $value=""; } $modified |= addExif("CanonSaturation", $value, $exifHash, $priorityList) if ($value); # CanonSharpness $value = $tagValue->[15]; if ($value == 0xFFFF) { $value = translate("Low"); } elsif ($value == 0x0000) { $value = translate("Normal"); } elsif ($value == 0x0001) { $value = translate("High"); } else { $value=""; } $modified |= addExif("CanonSharpness", $value, $exifHash, $priorityList) if ($value); # CanonISO $value = $tagValue->[16]; if ($value == 15) { $value = translate("Auto"); } elsif ($value == 16) { $value = "50"; } elsif ($value == 17) { $value = "100"; } elsif ($value == 18) { $value = "200"; } elsif ($value == 19) { $value = "400"; } else { $value=""; } $modified |= addExif("CanonISO", $value, $exifHash, $priorityList) if ($value); # CanonFocusType if ($tagValue->[18]) { $value = $tagValue->[18]; if ($value == 1) { $value = translate("Auto"); } elsif ($value == 3) { $value = translate("Close-up (macro)"); } elsif ($value == 8) { $value = translate("locked (pan mode)"); } elsif ($value == 0) { $value = translate("Manual"); } else { $value=""; } $modified |= addExif("CanonFocusType", $value, $exifHash, $priorityList) if ($value); } return $modified; } } return 0; } # Merge picture Exif data with Exif data from desc file, then update # descHash if tag is in @fields and if description text file field is void. # Finally, write Exif tags to the desc file if it was updated. sub processExif{ my $crntImage = shift(@_); my $descHash = shift(@_); my $exifHash = shift(@_); my $document = shift(@_); my $priorityList = shift(@_); my $configHash = shift(@_); my ($base,$dir,$type) = &fileparse($crntImage, '\.[^.]+\z'); beVerboseN(" Reading Exif info from picture file $crntImage...", 2); my $pictureFile = $picdir.$dir.$base.$type; my($camerainfo) = image_info($pictureFile); if (exists $camerainfo->{"error"}) { beVerboseN(" Can't read info from picture file $crntImage: ". $camerainfo->{"error"}."\n", 2); return } # Add new Exif tags from picture file to Exif Hash from desc file my $tagName; my $tagValue; my $modified = 0; while ( ($tagName, $tagValue) = each(%$camerainfo) ) { $tagName =~ s/[\x00-\x1F]//g; if (UNIVERSAL::isa(\$tagValue, 'SCALAR')){ # strip characters after the first control code (ascii code <32 ) #$tagValue =~ s/^([\x20-\xFF]*)[^\x20-\xFF].*$/$1/; $tagValue =~ s/[\x00-\x1F].*$//s; $modified |= addExif($tagName, $tagValue, $exifHash, $priorityList); } #print "«$tagName» : "; #print $_, ', ' foreach(@{$tagValue}); #print "\n"; $modified |= addSpecialExif($tagName, $tagValue, $exifHash, $priorityList); } # add value to desc Hash if field is void foreach my $field (keys(%{getFields($configHash)})) { my $fieldExif = getFields($configHash)->{$field}->{'EXIF'}; if ((! $descHash->{$field}) && $fieldExif && $exifHash->{$fieldExif}) { beVerboseN(" Using '$field' from EXIF data: ". $exifHash->{$fieldExif}, 3); my $func = getFields($configHash)->{$field}->{'Transform'}; if ($func) { $_ = $exifHash->{$fieldExif}; beVerbose(" Evaluating '$func' from '$_'", 4); eval $func; if ($@) { beVerboseN("", 4); print("Error: evaluation of transformation for $field failed.\n"); exit 2; } $descHash->{$field} = $_; beVerboseN(" to '$descHash->{$field}'.", 4); } else { $descHash->{$field} = $exifHash->{$fieldExif}; } } } if ($configHash->{rotateImages} eq 'original'){ # Perform a rotation of the picture if needed # we're doing it here because we must change and save the # orientation tag if the image was rotated if(rotateImage($pictureFile, $exifHash->{Orientation}, $exifHash->{file_ext}, $configHash)){ progressifyImage("$pictureFile", $exifHash->{file_ext}, $configHash); push @{$priorityList}, "Orientation"; $exifHash->{Orientation} = "top_left"; } } # Write Exif tags to desc file if ($modified && $configHash->{addExifToDescFile}) { writeExif($crntImage, $exifHash, $document, $priorityList, $configHash); } } sub charac_indent{ my $n = shift(@_); my $s="\n"; for (1..$n){ $s .= " "; } return XML::Grove::Characters->new ( Data => $s ); } sub writeExif{ my $crntImage = shift; my $descHash = shift; my $document = shift; my $priorityList = shift; my $configHash = shift; my $description; my $exif; my $element; my $characters; my $file = getDescFile($crntImage); # create Grove document if file didn't exist if (!$document) { beVerbose(" Creating new XML description file $file... ", 3); $description = XML::Grove::Element->new ( Name => 'description', Contents => [charac_indent(1)]); my $bins = XML::Grove::Element->new ( Name => 'bins', Contents => [charac_indent(1)]); $exif = XML::Grove::Element->new ( Name => 'exif', Contents => [charac_indent(2)]); $element = XML::Grove::Element->new ( Name => 'image', Contents => [charac_indent(1), $description, charac_indent(1), $bins, charac_indent(1), $exif ]); $document = XML::Grove::Document->new ( Contents => [ $element ] ); if ($configHash->{createEmptyDescFields}){ # Add standard fields if a new file is generated (so you can # edit it better) my @fields = @mainFields; push @fields, 'title'; foreach my $field (@fields) { $element = XML::Grove::Element->new ( Name => 'field', Contents => [charac_indent(3), charac_indent(2)], Attributes => {"name" => $field}); push @{$description->{Contents}}, (charac_indent(2), $element); } push @{$description->{Contents}}, charac_indent(1); } beVerboseN("OK.", 3); } # Add exif tags to the Grove if (!$exif) { $exif = $document->at_path('/image/exif'); @{$exif->{Contents}}=(); } my $tagName; my $tagValue; while ( ($tagName, $tagValue) = each(%$descHash) ) { beVerboseN(" Adding Exif tag '$tagName'='$tagValue' in XML desc file.", 3); #$tagValue = html2xml($tagValue); $characters = XML::Grove::Characters->new ( Data => $tagValue ); $element = XML::Grove::Element->new ( Name => 'tag', Contents => [charac_indent(3), $characters, charac_indent(2)], Attributes => {"name" => $tagName}); if (grep (/^$tagName$/, @{$priorityList})){ $element->{Attributes}{"priority"} = "1"; beVerboseN(" with 'priority' attribute.\n", 3); } push @{$exif->{Contents}}, (charac_indent(2), $element); } push @{$exif->{Contents}}, charac_indent(1); # Write the Grove to the desc file beVerbose(" Saving XML description file $file... ", 3); my $fileHandler = new IO::File; open($fileHandler, '>', $file) or die("Cannot open file $file to write Exif tag ($!)"); binmode($fileHandler, ":utf8") if $^V ge v5.8.0; # my $composer = new XML::Handler::Composer (); # my $my_handler = new XML::Filter::Reindent (Handler => $composer); #print Dumper($document); my $my_handler = new XML::Handler::YAWriter( 'Output' => $fileHandler, 'Encoding' => $configHash->{xmlEncoding}, # 'Pretty' => { # 'NoProlog' =>0, # 'NoDTD' =>0, # 'NoPI' =>0, # 'PrettyWhiteIndent'=>1, # 'PrettyWhiteNewline'=>1, # 'NoWhiteSpace'=>0, # 'NoComments'=>0, # 'AddHiddenNewline'=>0, # 'AddHiddenAttrTab'=>1, # } ); # my $my_handler = XML::Handler::XMLWriter->new( Output => $fileHandler, # Newlines => 0); $document->parse(DocumentHandler => $my_handler); close ($fileHandler) || die ("can't close $file ($!)"); beVerboseN("OK.", 3); } sub getDescAlbum { my $descFile = shift(@_); # file name of the album desc file my $hash = shift(@_); # ref to the album description hash my $configHash = shift(@_);# ref to the current config hash my $fieldName; my $fieldValue; my @AlbumFieldNames = ( "title", "sampleimage", "shortdesc", "longdesc", "ignore"); beVerboseN("Reading album description file '$descFile'...", 3); my $document = getXMLAsGrove($descFile); # I have to do that, don't ask me why... #$XML::UM::ENCDIR="/usr/lib/perl5/XML/Parser/"; #my $encode = XML::UM::get_encode ( # Encoding => 'ISO-8859-9', # EncodeUnmapped => \&XML::UM::encode_unmapped_dec); $configHash = getConfigXML($document, "/album/bins", $configHash); foreach my $element (@{$document->at_path('/album/description')->{Contents}}) { if (UNIVERSAL::isa($element, 'XML::Grove::Element') && $element->{Name} eq "field") { $fieldName = $element->{Attributes}{'name'}; $fieldValue = ""; if (grep (/^$fieldName$/, @AlbumFieldNames)) { beVerbose(" Reading field '$fieldName':", 3); foreach my $characters (@{$element->{Contents}}) { $fieldValue .= $characters->as_canon_xml(); } #if ($fieldName ne "shortdesc" && $fieldName ne "longdesc"){ # $fieldValue = decode_entities($fieldValue); #} if ($fieldName eq "sampleimage"){ $fieldValue = trimWhiteSpace(decode_entities($fieldValue)); beVerbose("'".$fieldValue."'\n", 3); }else{ $fieldValue = trimWhiteSpace(decode_entities(xml2html($fieldValue))); beVerbose("'".$fieldValue."'\n", 3); } # $fieldValue = $encode->(trimWhiteSpace($fieldValue)); $hash->{$fieldName} = $fieldValue; } else { beVerboseN(" Ignoring unknown field '$fieldName'.", 3); } } } return $configHash; } sub getConfigColors{ my $colors = shift; my $style = shift; my $configHash = shift; my $modified = 0; foreach my $color (@{$colors->{Contents}}) { if (UNIVERSAL::isa($color, 'XML::Grove::Element')){ if ($color->{Name} eq "color") { if (defined $color->{Attributes}{'name'}){ my $fieldName = $color->{Attributes}{'name'}; my $fieldValue; foreach my $characters (@{$color->{Contents}}) { $fieldValue .= $characters->as_canon_xml(); } if (defined $fieldValue){ $fieldValue = trimWhiteSpace(decode_entities(xml2html($fieldValue))); } if ($fieldValue){ $configHash->{colorsSubs}{$style}{$fieldName.'COLOR'} = $fieldValue; $modified = 1; } else { beVerboseN("Warning, no value for '$fieldName' color, ignoring.", 1); } } else { beVerboseN("Warning, missing 'name' attribute for tag, ". "ignoring.", 1); } } else { beVerboseN("Warning, unknown tag <".$color->{Name}. "> in section, ignoring.", 1); } } } return $modified; } sub getConfigSizes{ my $sizes = shift; my $configHash = shift; my (@names, @shortNames, @heights, @widths); foreach my $size (@{$sizes->{Contents}}) { if (UNIVERSAL::isa($size, 'XML::Grove::Element')){ if ($size->{Name} eq "size") { if (defined $size->{Attributes}{'name'}){ push @names, _(trimWhiteSpace($size->{Attributes}{'name'})); } else { beVerboseN("Warning, missing parameter 'name' in tag , ". "ignoring all sizes.", 1); return 0; } if (defined $size->{Attributes}{'shortname'}){ push @shortNames, _(trimWhiteSpace($size->{Attributes}{'shortname'})); } else { beVerboseN("Warning, missing parameter 'shortname' in tag , ". "ignoring all sizes.", 1); return 0; } if (defined $size->{Attributes}{'height'}){ push @heights, _(trimWhiteSpace($size->{Attributes}{'height'})); } else { beVerboseN("Warning, missing parameter 'height' in tag , ". "ignoring all sizes.", 1); return 0; } if (defined $size->{Attributes}{'width'}){ push @widths, _(trimWhiteSpace($size->{Attributes}{'width'})); } else { beVerboseN("Warning, missing parameter 'width' in tag ". "in section, ignoring all sizes.", 1); return 0; } } else { beVerboseN("Warning, unknown tag <".$size->{Name}."> ". "in section, ignoring.", 1); } } } if (@names) { $configHash->{longSizeNames} = \@names; $configHash->{sizeNames} = \@shortNames; $configHash->{scaledWidths} = \@widths; $configHash->{scaledHeights} = \@heights; return 1; } else { print "Warning, section is empty, ignoring.\n" } return 0; } # Given an XML doc as a Grove, the path to tag and the current # configuration hash, returns hash from the config section of files # ( tag) merged with current hash. sub getConfigXML{ my $document = shift(@_); # Grove document my $path = shift(@_); # path of the tag in the document my $currentConfigHash = shift(@_); # hash ref to the current configuration #my $fieldNb; my $fieldName; my $fieldValue; my %configHash = %{ dclone($currentConfigHash) }; beVerboseN(" Reading configuration data from file...", 3); my $modified = 0; foreach my $element (@{$document->at_path($path)->{Contents}}) { if (UNIVERSAL::isa($element, 'XML::Grove::Element')){ if ($element->{Name} eq "parameter") { $fieldName = $element->{Attributes}{'name'}; $fieldValue = ""; foreach my $characters (@{$element->{Contents}}) { #if (UNIVERSAL::isa($characters, 'XML::Grove::Characters')) { $fieldValue .= $characters->as_canon_xml(); } if (defined $fieldValue){ $fieldValue = trimWhiteSpace(decode_entities(xml2html($fieldValue))); } else { $fieldValue = ""; } beVerbose(" Reading configuration parameter '$fieldName':", 3); $configHash{$fieldName} = $fieldValue; beVerbose("'".$fieldValue."'\n", 3); $modified = 1; } elsif ($element->{Name} eq "sizes") { beVerbose(" Reading sizes parameters...", 3); $modified |= getConfigSizes($element, \%configHash); } elsif ($element->{Name} eq "colors") { my $style = $element->{Attributes}{'style'}; if ($style){ beVerboseN(" Reading color style parameter '$style'...", 3); $modified |= getConfigColors($element, $style, \%configHash); } else { beVerboseN(" Warning, no 'style' attribute to tag ". "in section, ignoring.", 1); } } else { beVerboseN(" Warning, unknown tag <$element->{Name}> ". "in section, ignoring.", 1); } } } if (!$modified){ return $currentConfigHash; # return the original to not keep the # new copy in memory } return \%configHash; } sub commandAvailable{ my $command = shift; my $exists = 0; my (@PATH) = split (/:/, $ENV{"PATH"}); foreach (@PATH) { beVerboseN(" looking for $_/$command...", 4); $exists++ if (-f "$_/$command" && -x "$_/$command"); last if $exists; } return $exists; } BEGIN { my $rotateGeneric="none"; sub rotateGenericCommand{ my $file = shift; my $degrees = shift; my $verbose = shift; if ($rotateGeneric eq "none") { beVerbose(" Looking for a generic rotation utility (mogrify)... ", 3); if (commandAvailable("mogrify")) { $rotateGeneric = 'mogrify -rotate %s "%s"'; beVerboseN(" found mogrify.", 3); } else { beVerboseN(" not found, cannot rotate.", 3); $rotateGeneric = ""; } } if ($rotateGeneric) { $file =~ s|\\|\\\\|g; $file =~ s|\$|\\\$|g; $file =~ s|"|\\"|g; $file =~ s|`|\\`|g; return sprintf($rotateGeneric, $degrees, $file); } return ""; } } BEGIN { my $rotateJPEG="none"; sub rotateJPEGCommand{ my $file = shift; my $degrees = shift; my $verbose = shift; if ($rotateJPEG eq "none") { beVerbose("\n Looking for a JPEG rotation utility (jpegtran)... ", 3); if (commandAvailable("jpegtran")) { $rotateJPEG = 'jpegtran -copy all -rotate %s -outfile "%s.tmp" "%s" && mv "%s.tmp" "%s"'; beVerboseN(" found jpegtran.", 3); } elsif (commandAvailable("jpegtran-mmx")) { $rotateJPEG = 'jpegtran-mmx -copy all -rotate %s -outfile "%s.tmp" "%s" && mv "%s.tmp" "%s"'; beVerboseN(" found jpegtran-mmx.", 3); } else { $rotateJPEG = ""; beVerboseN(" not found, trying a generic one.", 3); } } if ($rotateJPEG) { $file =~ s|\\|\\\\|g; $file =~ s|\$|\\\$|g; $file =~ s|"|\\"|g; $file =~ s|`|\\`|g; return sprintf($rotateJPEG, $degrees, $file, $file, $file, $file); } return rotateGenericCommand($file, $degrees); } } # return the best command available for rotating a given file type sub rotateCommand{ my $type = shift; my $file = shift; my $degrees = shift; my $configHash = shift; if ($type eq "jpg" && $configHash->{rotateWithJpegtran}){ return rotateJPEGCommand($file, $degrees, $verbose); }else{ return rotateGenericCommand($file, $degrees, $verbose); } } # Rotate an image. Return 0 if no rotation was performed, 1 if a # rotation was performed and it changed width and heigth, and 2 if it # was a 180 degree rotation sub rotateImage{ my $imageName = shift; my $orientation = shift; my $ext = shift; my $configHash = shift; #if (!$imageInfo->{'BinsRotated'} && $imageInfo->{'Orientation'}){ if (!$orientation){ return 0; } beVerboseN(" Orientation for picture is '$orientation'", 3); if ($orientation eq "top_left"){ return 0; } if ($imageName =~ m/$configHash->{noRotation}/) { return 0; } my $degrees; if ($orientation eq "right_top"){ $degrees = 90; }elsif ($orientation eq "left_bot"){ $degrees = 270; }elsif ($orientation eq "bot_right"){ $degrees = 180; } else { print "Warning, Orientation field has an unknown value '$orientation'.\n"; return 0; } beVerbose(" Performing $degrees degrees rotation clockwise on $imageName... ", 2); my $type = ""; if ($ext) { $type = $ext; }else{ $type="jpg"; } my $command = rotateCommand($type, $imageName, $degrees, $configHash); if ($command){ beVerbose("\n Running '$command'... ", 3); if(!system($command)){ #$imageInfo->{'BinsRotated'}="yes"; beVerboseN("OK", 2); if ($degrees == 180){ return 2; } return 1; } }else{ beVerboseN("impossible.\n Cannot perform rotation, no utility installed.", 2); } return 0; } BEGIN { my $progressifyJPEG="none"; sub progressifyJPEGCommand{ my $filein = shift; my $fileout = shift; my $verbose = shift; if ($progressifyJPEG eq "none") { beVerbose("\n Looking for a progressive JPEG utility (jpegtran)... ", 3); if (commandAvailable("jpegtran")) { $progressifyJPEG = 'jpegtran -copy all -progressive -outfile "%s" "%s"'; beVerboseN(" found jpegtran.", 3); } else { $progressifyJPEG = ""; beVerboseN(" not found, cannot make JPEGs progressive", 3); } } if ($progressifyJPEG) { $filein =~ s|\\|\\\\|g; $filein =~ s|\$|\\\$|g; $filein =~ s|"|\\"|g; $filein =~ s|`|\\`|g; $fileout =~ s|\\|\\\\|g; $fileout =~ s|\$|\\\$|g; $fileout =~ s|"|\\"|g; $fileout =~ s|`|\\`|g; return sprintf($progressifyJPEG, $fileout, $filein); } return ""; } } # fileSizeCmp(file1, file2): return file1.file-size - file2.file-size sub fileSizeCmp { my $file1 = shift; my $file2 = shift; return ((stat($file1))[7]) - ((stat($file2))[7]); } # progressifyJPEGImage(imageName, configHash) # make a JPEG image progressive. Return 0 if no conversion was performed, and 1 if a # conversion was performed sub progressifyJPEGImage{ my $imageName = shift; my $configHash = shift; my $tempFile = "$imageName.tmp"; beVerbose(" Making $imageName progressive JPEG... ", 2); my $command = progressifyJPEGCommand($imageName, $tempFile, $verbose); if ($command) { beVerbose("\n Running '$command'... ", 3); if(!system($command)){ if (($configHash->{jpegProgressify} eq "always")) { rename($tempFile, $imageName) or die("\nfailed to rename $tempFile to $imageName: $?"); beVerboseN("OK", 2); return 1; } my $diff = fileSizeCmp($tempFile, $imageName); if ($diff < 0) { rename($tempFile, $imageName) or die("\nfailed to rename $tempFile to $imageName: $?"); $diff = -$diff; beVerbose("$diff bytes smaller; ", 3); beVerboseN("OK", 2); return 1; } else { beVerbose("$diff bytes larger; ", 3); beVerboseN("NO", 2); unlink($tempFile) or warn("\nfailed to unlink $tempFile: $?"); } } }else{ beVerboseN("impossible.\n Cannot make progressive JPEG, no utility installed.", 2); } return 0; } # progressifyImage(imageName, ext, configHash) # make a JPEG image progressive. Return 0 if no conversion was performed, and 1 if a # conversion was performed. Skips non JPEG images or when jpegProgressify # is false (returns 0). sub progressifyImage{ my $imageName = shift; my $ext = shift; my $configHash = shift; my $type = $ext ? $ext : "jpg"; if (($type eq "jpg") && ($configHash->{jpegProgressify} ne "never")) { return progressifyJPEGImage($imageName, $configHash); } return 0; } sub readConfigFile{ my $configHash = shift(@_); my $document; my $globalConfigFile = bsd_glob($configHash->{'globalConfigDir'}."/". $configHash->{'configFileName'}, GLOB_TILDE); if ($globalConfigFile && -e $globalConfigFile) { beVerboseN("Reading global configuration file $globalConfigFile.", 3); $document = getXMLAsGrove($globalConfigFile); $configHash = getConfigXML($document, "/bins", $configHash); }else{ beVerboseN("No global configuration file ". $configHash->{'globalConfigDir'}."/". $configHash->{'configFileName'}." found.", 3); } my $userConfigFile = bsd_glob($configHash->{'userConfigDir'}."/". $configHash->{'configFileName'}, GLOB_TILDE); if ($userConfigFile && -e $userConfigFile) { beVerboseN("Reading user configuration file $userConfigFile.", 3); $document = getXMLAsGrove($userConfigFile); $configHash = getConfigXML($document, "/bins", $configHash); }else{ beVerboseN("No user configuration file ".$configHash->{'userConfigDir'}."/". $configHash->{'configFileName'}." found.", 3); } return $configHash; } sub stringToBool{ my $string = shift(@_); if (! $string) {return 0;} if (trimWhiteSpace($string) eq "true") { return 1;} return 0; } sub trimWhiteSpace{ my $string = shift(@_); return "" if (! defined $string); for ($string) { s/^\s+//; s/\s+$//; } return $string; } sub BEGIN { my %ignoredSets; my %hiddenSets; # this function is only used by ignoreSet, hiddenSet and # ignoreAndHiddenSet functions below sub ignoreOrHiddenSet{ my $ignoreLine = shift; my $album = shift; my $type = shift; my $configHash = shift; my ($set, $userSet); if ($type eq "ignore") { $set = \%ignoredSets; $userSet = $ignoreOpts; if ($ignoreOpts && $configHash->{ignore}){ $userSet .= "," } $userSet .= $configHash->{ignore}; } elsif ($type eq "hidden") { $set = \%hiddenSets; $userSet = $hiddenOpts; if ($hiddenOpts && $configHash->{hidden}){ $userSet .= "," } $userSet .= $configHash->{hidden}; } else { return 0; } # Remove the trailing slash if there is one (or more!) in $album, so # that the hash works for $fileInAlbum invocations as well. if ( defined($album) ) { $album =~ s/\/$//sog; } # Use the hash to optimize the checking of ignoreSets(), since this is # called three times for each album, and it could be expensive if there # are many ignore directives. If we have already checked this album, # just report what we concluded last time. if ( defined($set->{$album}) && $album ne "" ) { return( $set->{$album} ); } if ( defined($ignoreLine) ) { for my $thisIgnoreOpts ( split(',', $userSet ) ) { for my $thisIgnoreLine ( split('\s*,\s*',$ignoreLine) ) { if ( $thisIgnoreOpts eq $thisIgnoreLine ) { $set->{$album}=1; beVerboseN("Skipping \"$album\" because of \"$thisIgnoreOpts\"". " IGNORE directive.", 2); return(1); } } } } $set->{$album}=0; return(0); } } # return 1 if one of $ignoreLine is a ignored album sub ignoreSet{ my $ignoreLine = shift; my $album = shift; my $configHash = shift; return ignoreOrHiddenSet($ignoreLine, $album, "ignore", $configHash); } # return 1 if one of $ignoreLine is a hidden album sub hiddenSet{ my $ignoreLine = shift; my $album = shift; my $configHash = shift; return ignoreOrHiddenSet($ignoreLine, $album, "hidden", $configHash); } # return 1 if one of $ignoreLine is a ignored or hidden album sub ignoreAndHiddenSet{ my $ignoreLine = shift; my $album = shift; my $configHash = shift; if (ignoreOrHiddenSet($ignoreLine, $album, "ignore", $configHash)) { return 1 } return ignoreOrHiddenSet($ignoreLine, $album, "hidden", $configHash); } sub beVerbose { my $output = shift; my $level = shift; print "$output" if ($verbose >= $level); } sub beVerboseN { my $output = shift; my $level = shift; if ($verbose >= $level){ beVerbose($output, $level); print "\n"; } } # for .po generation, until xgettext handles Perl correctly sub dummy_I18N{ _("Thumbnail Page"); _("Thumbnail Page 1"); _("tree"); _("subalbum"); _("subalbums"); _("Hg"); _("Huge"); _("image"); _("images"); _("Click on one of the size names above to enlarge this image"); _("Click to view thumbnails of the current album"); _("Click to view this album"); } bins-1.1.29/bins_edit0000755000175000017500000003253610303167612015221 0ustar jeromejerome00000000000000#!/usr/bin/perl -w # bins_edit for BINS Photo Album version 1.1.29 # Copyright (C) 2001-2004 Jérôme Sautret (Jerome@Sautret.org) # # $Id: bins_edit,v 1.21 2004/10/24 13:19:16 jerome Exp $ # # 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 # (at your option) 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; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # Type "bins_edit -h" on command line for usage information. use strict; use Getopt::Long; use IO::File; use UNIVERSAL qw(isa); # XML parsing & writing use XML::Grove; use XML::Grove::Builder; use XML::Grove::Path; use XML::Grove::PerlSAX; use XML::Parser::PerlSAX; #use XML::Handler::XMLWriter; use XML::Handler::YAWriter; use Text::Iconv; use HTML::Entities; my $verbose = 1; my $html=0; my $localEncoding; $localEncoding = `locale charmap`; if ($? != 0 ) { $localEncoding = "LATIN1"; } else { if (! $localEncoding or ($localEncoding eq "ANSI_X3.4-1968")) { chop($localEncoding); # ANSI is unspeakably primitive, promote it. $localEncoding = "LATIN1"; print "Forcing encoding to $localEncoding\n" if ($verbose >=2); } } my $converter = Text::Iconv->new($localEncoding, "UTF-8"); # decode HTML entites which doesn't exist in XML sub decodeEntites{ my $s = shift; my %entities = ( AElig => 'Æ', # capital AE diphthong (ligature) Aacute => 'Á', # capital A, acute accent Acirc => 'Â', # capital A, circumflex accent Agrave => 'À', # capital A, grave accent Aring => 'Å', # capital A, ring Atilde => 'Ã', # capital A, tilde Auml => 'Ä', # capital A, dieresis or umlaut mark Ccedil => 'Ç', # capital C, cedilla ETH => 'Ð', # capital Eth, Icelandic Eacute => 'É', # capital E, acute accent Ecirc => 'Ê', # capital E, circumflex accent Egrave => 'È', # capital E, grave accent Euml => 'Ë', # capital E, dieresis or umlaut mark Iacute => 'Í', # capital I, acute accent Icirc => 'Î', # capital I, circumflex accent Igrave => 'Ì', # capital I, grave accent Iuml => 'Ï', # capital I, dieresis or umlaut mark Ntilde => 'Ñ', # capital N, tilde Oacute => 'Ó', # capital O, acute accent Ocirc => 'Ô', # capital O, circumflex accent Ograve => 'Ò', # capital O, grave accent Oslash => 'Ø', # capital O, slash Otilde => 'Õ', # capital O, tilde Ouml => 'Ö', # capital O, dieresis or umlaut mark THORN => 'Þ', # capital THORN, Icelandic Uacute => 'Ú', # capital U, acute accent Ucirc => 'Û', # capital U, circumflex accent Ugrave => 'Ù', # capital U, grave accent Uuml => 'Ü', # capital U, dieresis or umlaut mark Yacute => 'Ý', # capital Y, acute accent aacute => 'á', # small a, acute accent acirc => 'â', # small a, circumflex accent aelig => 'æ', # small ae diphthong (ligature) agrave => 'à', # small a, grave accent aring => 'å', # small a, ring atilde => 'ã', # small a, tilde auml => 'ä', # small a, dieresis or umlaut mark ccedil => 'ç', # small c, cedilla eacute => 'é', # small e, acute accent ecirc => 'ê', # small e, circumflex accent egrave => 'è', # small e, grave accent eth => 'ð', # small eth, Icelandic euml => 'ë', # small e, dieresis or umlaut mark iacute => 'í', # small i, acute accent icirc => 'î', # small i, circumflex accent igrave => 'ì', # small i, grave accent iuml => 'ï', # small i, dieresis or umlaut mark ntilde => 'ñ', # small n, tilde oacute => 'ó', # small o, acute accent ocirc => 'ô', # small o, circumflex accent ograve => 'ò', # small o, grave accent oslash => 'ø', # small o, slash otilde => 'õ', # small o, tilde ouml => 'ö', # small o, dieresis or umlaut mark szlig => 'ß', # small sharp s, German (sz ligature) thorn => 'þ', # small thorn, Icelandic uacute => 'ú', # small u, acute accent ucirc => 'û', # small u, circumflex accent ugrave => 'ù', # small u, grave accent uuml => 'ü', # small u, dieresis or umlaut mark yacute => 'ý', # small y, acute accent yuml => 'ÿ', # small y, dieresis or umlaut mark # Some extra Latin 1 chars that are listed in the HTML3.2 draft (21-May-96) copy => '©', # copyright sign reg => '®', # registered sign nbsp => "\240", # non breaking space # Additional ISO-8859/1 entities listed in rfc1866 (section 14) iexcl => '¡', cent => '¢', pound => '£', curren => '¤', yen => '¥', brvbar => '¦', sect => '§', uml => '¨', ordf => 'ª', laquo => '«', 'not' => '¬', # not is a keyword in perl shy => '­', macr => '¯', deg => '°', plusmn => '±', sup1 => '¹', sup2 => '²', sup3 => '³', acute => '´', micro => 'µ', para => '¶', middot => '·', cedil => '¸', ordm => 'º', raquo => '»', frac14 => '¼', frac12 => '½', frac34 => '¾', iquest => '¿', 'times' => '×', # times is a keyword in perl divide => '÷', ); while (my($entity, $char) = each(%entities)) { $s =~ s/\&$entity\;/$char/g; } return $s; } sub charac_indent{ my $n = shift(@_); my $s="\n"; for (1..$n){ $s .= " "; } return XML::Grove::Characters->new ( Data => $s ); } sub setField{ my $field = shift(@_); # field to add or modify my $value = shift(@_); # value to set to field my $fileType = shift(@_); # type of file (iamge or album) my $document = shift(@_); # XML document as a Grove if (! $html) { $value = encode_entities($value, '\00-\31<&"'); } my $characters = XML::Grove::Characters->new( Data => decodeEntites($value)); #my $characters = XML::Grove::Characters->new ( Data => $value ); my $fieldName; my $fieldValue; foreach my $element (@{$document->at_path('/'.$fileType.'/description')->{Contents}}) { if (isa($element, 'XML::Grove::Element') && $element->{Name} eq "field") { $fieldName = $element->{Attributes}{'name'}; $fieldValue = ""; if ($fieldName eq $field) { print " Modifying field '$fieldName' to '$value'... " if ($verbose >= 3); @{$element->{Contents}} = ( charac_indent(3), $characters, charac_indent(2)); print "OK.\n" if ($verbose >= 3); return; } } } print " Adding field '$field' with value '$value'... " if ($verbose >= 2); my $element = XML::Grove::Element->new ( Name => 'field', Contents => [charac_indent(3), $characters, charac_indent(2)], Attributes => {"name" => $field}); push @{$document->at_path('/'.$fileType.'/description')->{Contents}}, (charac_indent(2), $element, charac_indent(1)); print "OK.\n" if ($verbose >= 2); } sub setFields{ my $file = shift(@_); my $fields = shift(@_); my $album = shift(@_); # type of file (0 if image or 1 if album) my $document; my $fileType; if ($album) { $fileType = "album"; } else{ $fileType = "image"; } if (-e $file) { # Get XML document as a Grove print " Reading file '$file'... " if ($verbose >= 2); my $grove_builder = XML::Grove::Builder->new; my $parser = XML::Parser::PerlSAX->new ( Handler => $grove_builder ); $document = $parser->parse ( Source => { SystemId => $file } ); print "OK.\n" if ($verbose >= 2); } else { print " Creating file '$file'... " if ($verbose >= 2); my @elements; push @elements, (charac_indent(1), XML::Grove::Element->new ( Name => 'description', Contents => [charac_indent(1)]), charac_indent(1), XML::Grove::Element->new ( Name => 'bins', Contents => [charac_indent(1)]), ); if (!$album) { push @elements, ( charac_indent(1), XML::Grove::Element->new ( Name => 'exif', Contents => [charac_indent(1)]), ); } push @elements, charac_indent(0); my $element = XML::Grove::Element->new ( Name => $fileType, Contents => \@elements); $document = XML::Grove::Document->new ( Contents => [ $element ] ); print "OK.\n" if ($verbose >= 3); } my $fieldName; my $fieldValue; while ( ($fieldName, $fieldValue) = each(%$fields) ) { if (defined $fieldValue) { setField($fieldName, $fieldValue, $fileType, $document); } } print " Writing file '$file'... " if ($verbose >= 2); # Write the Grove to the desc file my $fileHandler = new IO::File; open($fileHandler, '>', $file) or die("Cannot open file $file to write Exif tag ($!)"); binmode($fileHandler, ":utf8") if $^V ge v5.8.0; my $my_handler = new XML::Handler::YAWriter( 'Output' => $fileHandler, # 'Escape' => { # '--' => '—', #'&' => '&', # }, 'Encoding' => "UTF-8", ); # my $my_handler = XML::Handler::XMLWriter->new( Output => $fileHandler, # Newlines => 0); $document->parse(DocumentHandler => $my_handler); close ($fileHandler) || bail ("can't close $file ($!)"); print "OK.\n" if ($verbose >= 2); } sub copyleft{ print "\nbins_edit for BINS Photo Album 1.1.29 (http://bins.sautret.org/)\n"; print "Copyright © 2001-2004 Jérôme Sautret (Jerome\@Sautret.org)\n"; print "This is free software with ABSOLUTELY NO WARRANTY.\n"; print "See COPYING file for details.\n\n"; } sub usage{ my $exit=shift; # should we exit after usage information ? copyleft(); print <BINS is cool' file.jpg Set the title short description and sample image of the album in the current directory (note the dot as final parameter): bins_edit -a -t "My Album" --sample image.jpg --shortdesc "This is my album" . EoF exit 1; } sub main{ my %values; my $album = 0; # 1 if it a album description file # process args Getopt::Long::Configure("bundling"); GetOptions('t|title:s' => \$values{title}, 'e|event:s' => \$values{event}, 'l|location:s' => \$values{location}, 'p|people:s' => \$values{people}, 'y|date:s' => \$values{date}, 'd|description:s' => \$values{description}, 'longdesc:s' => \$values{longdesc}, 'shortdesc:s' => \$values{shortdesc}, 'sample:s' => \$values{sampleimage}, 'g|generic=s%' => \%values, 'm|html' => \$html, 'a|album' => \$album, 'v|verbose+' => \$verbose, 'q|quiet' => sub { $verbose = 0 }, 'h|help' => sub { help() }, 'copyright' => sub { copyleft() }, ) or usage(1); my @files; if ($#ARGV < 0) { if ($album) { @files = ("."); } else { print "No files specified.\n"; usage(1) } } else { @files = @ARGV; } copyleft() if ($verbose >=2); foreach my $file (@files) { if ($album) { $file .= "/album.xml"; } if ($file !~ m/.xml$/) { $file .= ".xml"; } print "Processing file '$file'... " if ($verbose >= 1); print "\n" if ($verbose >= 2); setFields($file, \%values, $album); print "OK.\n" if ($verbose == 1); } } main(); bins-1.1.29/bins-edit-gui0000755000175000017500000006315410303167611015720 0ustar jeromejerome00000000000000#!/usr/bin/perl # bins-edit-gui -- graphical editor for BINS-format XML tag files # # Copyright 2002 Mark W. Eichin # The Herd of Kittens # # -- GPL notice -- $gpl_text = <" ."\n". _("This is free software distributed under the GPL. There is NO WARRANTY.") ."\n". GetOptions('debug+' => \$debug, 'h|help' => \$o_help, 'v|version' => \$o_version, ) or usage('error'); usage('user') if $o_help; if ($o_version) { print $fullversion; exit 0; } # take this out when we have a file browser usage('error') if scalar(@ARGV) < 1; # find a way to do this in Perl; nl_langinfo seems to be coming in 5.8 my $localEncoding = ""; my $codeset; eval { require I18N::Langinfo; I18N::Langinfo->import(qw(langinfo CODESET)); $codeset = langinfo(CODESET()); }; # ANSI is unspeakably primitive, keep LATIN1 instead # Solaris refers to ISO 646 as "646" but that is not a valid codeset if (!$@ && $codeset && $codeset ne "ANSI_X3.4-1968" && $codeset ne "646") { $localEncoding = $codeset; print "Forcing encoding to $codeset"; } chop($localEncoding); if (! $localEncoding) { $localEncoding = "LATIN1"; } $Latin2UTF = Text::Iconv->new($localEncoding, "UTF-8"); $UTF2Latin = Text::Iconv->new("UTF-8", $localEncoding); my_init_rotations(); Gtk->set_locale; Gnome->init("bins-edit-gui", $version); Gtk->init; $glade = "/usr/local/share/bins/bins-edit-gui.glade"; if (! -r $glade) { $glade = "bins-edit-gui.glade" ; # developer hack print "DEVELOPER HACK\n"; if (! -r $glade) { die "No bins-edit-gui.glade available"; } } #$g = new Gtk::GladeXML($glade, 'image_edit_top'); $g = new Gtk::GladeXML($glade); die "Gtk::GladeXML($glade) initialization failed; check required packages" unless $g; $g->signal_autoconnect_from_package('main'); # main:: so we can grab stuff directly # get the "global" widgets $w = $g->get_widget('image_edit_pixmap'); # GTK-Interface/widget/name $w->signal_connect(expose_event => \&on_test_expose_event); $name_entry = $g->get_widget("field_name_entry"); $value_entry = $g->get_widget("field_value_entry"); $ilist = $g->get_widget("image_prop_list"); $ilist->column_titles_passive; # shouldn't this be in the .glade? # work around libglade 0.17 bug (debbugs #147051) $ilist->set_column_title(0, _("Property")); $ilist->set_column_title(1, _("Value")); # end workaround. $statusbar = $g->get_widget('statusbar1'); $aboutbox = $g->get_widget('about_box'); $aboutbox->close_hides; $licensebox = $g->get_widget('license_box'); $licensetext = $g->get_widget('license_text'); # GtkText #print ref($licensetext),": ",join("\n\t|",%Gtk::Text::),"\n"; $gpl_text =~ s/^\# ?//gm; $licensetext->insert(undef, undef, undef, $gpl_text); ## album-panel globals $albumedit = $g->get_widget('album_edit_top'); $albumfile = $g->get_widget('album_edit_filename'); $albumprop = $g->get_widget('album_prop_list'); # work around libglade 0.17 bug (debbugs #147051) $albumprop->set_column_title(0, _("Property")); $albumprop->set_column_title(1, _("Value")); # end workaround. $albumname = $g->get_widget('album_name_entry'); $albumname->set_popdown_strings(@album_tags); $albumvalue = $g->get_widget('album_edit_text'); sub on_dismiss_about_clicked { $licensebox->hide; status(_("Thank you for sharing.")); } sub status { my $msg = shift; $statusbar->pop(1); $statusbar->push(1, $msg); } use Image::Info; # original orientation for viewing sub get_image_orientation($) { my $filename = shift; # bail directly if we have a tag-loaded value return $newimage_tagged_or if (defined $newimage_tagged_or); # try and find a way to get this from imlib? my $info = Image::Info::image_info($filename); if (exists $info->{'error'}) { my $msg = sprintf(_("Couldn't read EXIF info from %s: %s, ignoring."), $filename, $info->{'error'}); status($msg); print $msg if $debug; return "top_left"; } $info->{'Orientation'}; } # see http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html # for the meaning of the orientations. # see /usr/share/doc/imlib-base/html/index.html # for the not-quite-apology for the function supplied. # see the qiv sources for an example of how to use it anyway... sub my_real_gdk_rotate($$) { my ($newimage,$orientation) = @_; my $degrees; if ($orientation eq "right_top"){ $degrees = 90; $newimage->rotate_image('a 45 degree mirror is *not* a rotate'); $newimage->flip_image_horizontal (); } elsif ($orientation eq "left_bot"){ $degrees = 270; $newimage->rotate_image('a 45 degree mirror is *not* a rotate'); $newimage->flip_image_vertical (); } elsif ($orientation eq "right_bot"){ $degrees = 180; # test this, maybe simplify... $newimage->rotate_image('a 45 degree mirror is *not* a rotate'); $newimage->flip_image_horizontal (); $newimage->rotate_image('a 45 degree mirror is *not* a rotate'); $newimage->flip_image_horizontal (); } elsif ($orientation eq "top_left"){ # do nothing return; } else { print STDERR "Warning, Orientation field has an unknown value '$orientation'.\n" if $debug; # still do nothing return 0; } } sub load_image_tags($); sub load_image { # no proto, we're cheating and doing 1arg/2arg (or should that be @?) my $test_filename = shift; my $extra = shift; my $ilabel = $g->get_widget('image_filename_label'); $newimage->destroy_image() if defined $newimage; $newimage = load_image Gtk::Gdk::ImlibImage($test_filename); if (defined $newimage) { if ($extra ne "keeptags") { load_image_tags $test_filename; $newimage_loaded_or = $newimage_or = get_image_orientation($test_filename); print "$test_filename: got orientation <$newimage_or>\n" if $debug; } my_real_gdk_rotate($newimage,$newimage_or); $ilabel->set($test_filename); status(sprintf(_("Loaded %s."), $test_filename)); } else { # no image - just skip. we've already filtered xml files, though. $ilabel->set(_("Load failed: ") . $test_filename); status(sprintf(_("IMLib failed loading %s."), $test_filename)); } # regardless, rerender if (defined $imagesized) { undef $imagesized; on_test_expose_event(); # cheat, it doesn't use it } } # from bins_edit # my $grove_builder = XML::Grove::Builder->new; # my $parser = XML::Parser::PerlSAX->new ( Handler => $grove_builder ); # $document = $parser->parse ( Source => { SystemId => "${test_filename}.xml" } ); # now only internal for load... sub load_image_tags($) { %old_field = %field; # save for later recall my $test_filename = shift; $parser = new XML::DOM::Parser; if (-r "${test_filename}.xml" ) { $doc = $parser->parsefile ("${test_filename}.xml"); } else { # literal minimal tree $doc = $parser->parse(''); status(sprintf(_("%s not found, constructing"), "${test_filename}.xml")); } undef %field; for my $i (@image_tags) { $field{$i} = ""; } for my $field_node ($doc->xql("image/description/field")) { # # Sjenka my $fieldname = ($field_node->xql("\@name"))[0]->xql_toString; my $fieldval = $field_node->xql_toString; print "N: $fieldname V: $fieldval\n" if $debug; my $newval; do { $newval = $UTF2Latin->convert($fieldval); charmap_failed("load_image_tags", $fieldval) if (not defined $newval); } until defined $newval; $field{$fieldname} = $newval; } undef $newimage_tagged_or; # right_top for my $tag_node ($doc->xql("image/exif/tag[\@name = 'Orientation']")) { my $tagname = ($tag_node->xql("\@name"))[0]->xql_toString; my $tagprio_node = ($tag_node->xql("\@priority"))[0]; my $tagprio; $tagprio = $tagprio_node->xql_toString if defined $tagprio_node; my $tagval = $tag_node->xql_toString; # but actually, we only care about orientation print "N: $tagname V: $tagval P: $tagprio\n" if $debug; if ($tagprio == 1) { $newimage_tagged_or = $tagval; } } # a clist is output only. someday, replace it with a list of # editboxes, even if we have to write one all in perl. # in the mean time, we vector out to a pair of combo boxes and let # the user edit there, while copying the changes back live. # save last index if any... my $oldtag; my $oldrow = $ilist->focus_row(); $oldtag = $ilist->get_text($oldrow, 0) if $oldrow > 0; print "old $oldrow: $oldtag\n" if $debug; $ilist->clear; for my $i (sort keys %field) { $ilist->append("\u$i", $field{$i}); } if ($oldrow > 0) { my $newrow = my_gtk_find_row($ilist, 0, $oldtag); print "new $newrow\n" if $debug; if ($newrow > 0) { $ilist->set_focus_row($newrow); $ilist->grab_focus(); } } # help the user enter stuff $name_entry->set_popdown_strings(@known_tags); # tag as unchanged $dirty = 0; } sub charmap_failed($$) { my $ipop = $g->get_widget('iconv_failed_dialog'); my $lbutton = $g->get_widget('iconv_latin1_charmap_button'); $lbutton->set_active(Gtk->true); # really we mean it my $ubutton = $g->get_widget('iconv_user_charmap_button'); my $uentry = $g->get_widget('iconv_user_charmap_entry'); # if there's a value there, it is from the previous attempt, and is wrong. $uentry->set_text(""); $ipop->run_and_close; if ($lbutton->get_active) { set_encoding("LATIN1"); } elsif ($ubutton->get_active) { set_encoding($uentry->get_text); } } sub save_image_tags { my $test_filename = shift; if ((not $dirty) && ($newimage_or eq $newimage_loaded_or)) { status(sprintf(_("%s not dirty, not saved"), ${test_filename})); return; } my $parent = ($doc->xql("image/description"))[0]; # first one my $exif = ($doc->xql("image/exif"))[0]; my %f = %field; # write out the tree... for my $xmlfield ($doc->xql("image/description/field")) { my $namestr = $xmlfield->getAttribute("name"); if (defined $f{$namestr}) { # delete this node so we can append it later $xmlfield->getParentNode->removeChild($xmlfield); } } # now append the remaining ones... for my $k (keys %f) { next if ($f{$k} eq ""); my $newfield = new XML::DOM::Element($doc, "field"); print "creating <$k> with <$f{$k}>\n" if $debug; $newfield->setAttribute("name", $k); # needs quoting! print "k: ", $k, " f: ", $f{$k}, " L2U: ", $Latin2UTF->convert($f{$k}), "\n" if $debug; my $newval; do { $newval = $Latin2UTF->convert($f{$k}); charmap_failed("save_image_tags", $f{$k}) if (not defined $newval); } until defined $newval; $newfield->addText($newval); $parent->appendChild($newfield); print "created $k with $f{$k}\n" if $debug; } # and orientation, if set if ($newimage_or ne $newimage_loaded_or) { for my $tag_node ($doc->xql("image/exif/tag[\@name = 'Orientation']")) { # delete the node, then construct a new one $tag_node->getParentNode->removeChild($tag_node); } my $newtag = new XML::DOM::Element($doc, "tag"); $newtag->setAttribute("name", "Orientation"); $newtag->setAttribute("priority", "1"); $newtag->addText($Latin2UTF->convert($newimage_or)); # unneeded conversion $exif->appendChild($newtag); print "Set orientation <$newimage_or> (loaded $newimage_loaded_or) in exif tag\n" if $debug; } $doc->printToFile("${test_filename}.xml"); status(sprintf(_("Saved %s."), $test_filename)); # undirty it $dirty = 0; $newimage_loaded_or = $newimage_or; } # if they enter or select a known one, snarf the value $name_entry->entry->signal_connect('changed', sub { my $entry = shift; my $val = $field{$entry->get_text}; if (defined $val) { $value_entry->entry->set_text($val); $value_entry->entry->set_editable(Gtk->true); } $dirty = 1; }); sub my_album_replace_text($$) { my $aw = shift; my $text = shift; $aw->set_point(0); $aw->forward_delete($albumvalue->get_length()); $aw->insert(undef, undef, undef, $text); $aw->set_editable(Gtk->true); } # album version $albumname->entry->signal_connect('changed', sub { my $entry = shift; my $val = $album{$entry->get_text}; if (defined $val) { my_album_replace_text($albumvalue, $val); } $album_dirty = 1; }); sub my_gtk_find_row { # returns row my ($clist, $col, $value) = @_; for my $i (0..$clist->rows) { my $cell = $clist->get_text($i, $col); return $i if ($cell ne "" && lc($cell) eq lc($value)); } return -1; } # if the value changes, update the text $value_entry->entry->signal_connect('changed', sub { my $entry = shift; my $newval = $entry->get_text; my $tag = lc($name_entry->entry->get_text); $field{$tag} = $newval; $dirty = 1; my $row = my_gtk_find_row($ilist, 0, $tag); print "row: $row tag: $tag newval: $newval\n" if $debug; # oh, no tag yet, add one if ($row != -1) { $ilist->set_text($row, 1, $newval); } else { # triggers select-row? $ilist->append("\u$tag", $newval); # update the dropdown too @known_tags = sort (@known_tags, $tag); $name_entry->set_popdown_strings(@known_tags); # force it all back $ilist->select_row($ilist->rows()-1, 0); } }); # album version $albumvalue->signal_connect('changed', sub { my $entry = shift; my $newval = $entry->get_chars(0,-1); my $tag = lc($albumname->entry->get_text); $album{$tag} = $newval; $dirty = 1; my $row = my_gtk_find_row($albumprop, 0, $tag); print "row: $row tag: $tag newval: $newval\n" if $debug; # oh, no tag yet, add one if ($row != -1) { $albumprop->set_text($row, 1, $newval); } else { # triggers select-row? $albumprob->append("\u$tag", $newval); # update the dropdown too @known_tags = sort (@known_tags, $tag); $albumname->set_popdown_strings(@known_tags); # force it all back $albumprob->select_row($ilist->rows()-1, 0); } }); $ilist->signal_connect('select-row', sub { my ($clist, $row, $col, $event, $udata) = @_; print "list: $clist row: $row col: $col event: $event udata: $udata\n" if $debug; $name_entry->entry->set_text($clist->get_text($row,0)); $value_entry->entry->set_text($clist->get_text($row,1)); print "focus on $value_entry\n" if $debug; $value_entry->entry->grab_focus(); }); # album version $albumprop->signal_connect('select-row', sub { my ($clist, $row, $col, $event, $udata) = @_; print "list: $clist row: $row col: $col event: $event udata: $udata\n" if $debug; $albumname->entry->set_text($clist->get_text($row,0)); my_album_replace_text($albumvalue, $clist->get_text($row,1)); print "focus on $value_entry\n" if $debug; $albumvalue->grab_focus(); }); # filter out .xml files, as we always derive them from the images # (also lets us eventually use the images as database keys instead) @filenames = grep (!/\.xml$/, @ARGV); $current_n = 0; $current_filename = $filenames[$current_n]; load_image $current_filename; Gtk->main; ## callbacks.. # new callbacks # sgrep -o '%r\n' 'stag("HANDLER") __ etag("HANDLER") ' bins-edit-gui.glade | while read sub; do grep "$sub" bins-edit-gui.pl >/dev/null || echo "$sub"; done sub on_save1_activate { save_image_tags $current_filename; } sub on_about2_activate { $aboutbox->show; } sub on_license1_activate { $licensebox->show; my $button = $g->get_widget('dismiss_about'); $button->grab_focus(); } sub on_open2_activate { status(_("File browser not yet implemented.")); } sub on_revert1_activate { load_image $current_filename; status(sprintf(_("Reverted from %s."), $current_filename)); } sub set_filename_index($) { $current_n = shift; $current_filename = $filenames[$current_n]; load_image $current_filename; } sub move_filename_index($) { save_image_tags $current_filename; my $delta = shift; my $new_n = $current_n + $delta; # clamp it $new_n = 0 if $new_n < 0; $new_n = $#filenames if $new_n > $#filenames; if ($new_n == $current_n) { # we didn't move status(_("Out of filenames.")); } else { set_filename_index($new_n); } } sub on_next_file1_activate { move_filename_index(+1); } sub on_prev_file1_activate { move_filename_index(-1); } sub on_forward_10_activate { move_filename_index(+10); } sub on_back_10_activate { move_filename_index(-10); } sub on_start_of_list1_activate { set_filename_index(0); } sub on_end_of_list1_activate { set_filename_index($#filenames); } # auto fill from old_field sub on_auto_fill1_activate { for my $k (keys %old_field) { if ($field{$k} eq "" && $old_field{$k} ne "") { $field{$k} = $old_field{$k}; $dirty = 1; # and change it on-screen my $row = my_gtk_find_row($ilist, 0, $k); if ($row != -1) { print "updating row $row with $k ($field{$k})\n" if $debug; $ilist->set_text($row, 1, $field{$k}); } # maybe warn, or add field, if not found? } } status("Auto-filled fields."); } sub on_exit1_activate { save_image_tags $current_filename; Gtk->main_quit; } sub on_test_expose_event { my($widget) = @_; # print "otee, ",defined $imagesized,"\n"; # if (1 || not defined $imagesized) { my $w = $g->get_widget('image_edit_pixmap'); # GTK-Interface/widget/name # x,y,width,height my ($alloc_x, $alloc_y, $alloc_w, $alloc_h) = @{$w->allocation}; my $widget_w = $alloc_w; my $widget_h = $alloc_h; if ($debug) { print join("| ", @{$w->allocation}); print "| x: $widget_w y: $widget_h "; print "nw: ", $newimage->rgb_width, " nh: ", $newimage->rgb_height, "\n" if defined $newimage; print " x/y: ",$widget_w/$widget_h, " nw/x: ", $newimage->rgb_width/$widget_w, " nh/y: ", $newimage->rgb_height/$widget_h, "\n" if defined $newimage; } # print "ox: $old_x oy: $old_y ww: $widget_w wh: $widget_h I:$imagesized\n"; # return if same size if ($old_x == $widget_w && $old_y == $widget_h) { # but not if we never dealt before return if (defined $imagesized); } if (defined $newimage) { my ($use_w, $use_h) = ($newimage->rgb_width, $newimage->rgb_height); my $rat_w = $use_w/$widget_w; my $rat_h = $use_h/$widget_h; $rat = ($rat_w > $rat_h) ? $rat_w : $rat_h; $use_w = $use_w / $rat; $use_h = $use_h / $rat; $newimage->render($use_w, $use_h); my $my_image = $newimage->copy_image(); # returns Gtk::Gdk::Pixmap my $my_mask = $newimage->copy_mask(); # returns Gtk::Gdk::Bitmap $w->set($my_image, $my_mask); $my_image->imlib_free(); } else { # come up with more clever "test pattern" later? $w->set(undef, undef); } $old_x = $widget_w; $old_y = $widget_h; #undef $imagesized; $imagesized = 1; # } } # rotations that override, or rather compound, the EXIF values # build the rotation-ring first sub my_init_rotations { my @rotation_order = ("right_top", "right_bot", "left_bot", "top_left"); my $left = $rotation_order[$#rotation_order]; for my $curr (@rotation_order) { $rotate_right{$left} = $curr; $rotate_left{$curr} = $left; $left = $curr; } # special case none->top_left $rotate_right{""} = $rotate_right{"top_left"}; $rotate_left{""} = $rotate_left{"top_left"}; } sub my_image_rotate { my $delta_or = shift; print "$test_filename: new user-requested rotation $delta_or to $newimage_or\n" if $debug; my_real_gdk_rotate($newimage,$delta_or); # consider noticing that $newimage_or == $newimage_loaded_or and reverting. # regardless, rerender if (defined $imagesized) { undef $imagesized; on_test_expose_event(); } status(_("Rotated.")); } sub on_rotate_right_cw1_activate { $newimage_or = $rotate_right{$newimage_or}; my_image_rotate("right_top"); } sub on_rotate_left1_activate { $newimage_or = $rotate_left{$newimage_or}; my_image_rotate("left_bot"); } # don't actually undo the rotations, just reload - but don't lose tags sub on_cancel_rotation1_activate { load_image $current_filename, "keeptags"; status(_("Image restored.")); } ### album stuff ### sub load_album_tags($); sub on_album1_activate { $current_album = $current_filename; # basename $current_album =~ s{[^/]*$}{}; # } perl-mode-sucks # make a complete name out of it $current_album .= "album.xml"; #if (-d "${current_album}"); $albumfile->set($current_album); load_album_tags($current_album); $albumedit->show; } sub on_open2_activate { status(_("File browser not yet implemented.")); } sub on_close1_activate { # save if dirty save_album_tags($current_album) if $album_dirty; $albumedit->hide; } sub on_revert2_activate { load_album_tags $current_album; status(sprintf(_("Reverted from %s."), $current_album)); } sub save_album_tags; sub on_save2_activate { save_album_tags $current_album; } # sub on_exit2_activate { # &on_exit1_activate(@_); # } sub load_album_tags($) { %old_album = %album; # save for later recall my $test_filename = shift; $parser = new XML::DOM::Parser; if (-r "${test_filename}" ) { $album_doc = $parser->parsefile ("${test_filename}"); } else { # literal minimal tree $album_doc = $parser->parse(''); status(sprintf(_("%s not found, constructing"), "${test_filename}")); } undef %album; for my $i (@album_tags) { $album{$i} = ""; } for my $field_node ($album_doc->xql("album/description/field")) { my $fieldname = ($field_node->xql("\@name"))[0]->xql_toString; my $fieldval = $field_node->xql_toString; print "N: $fieldname V: $fieldval\n" if $debug; $album{$fieldname} = $UTF2Latin->convert($fieldval); } # a clist is output only. someday, replace it with a list of # editboxes, even if we have to write one all in perl. # in the mean time, we vector out to a pair of combo boxes and let # the user edit there, while copying the changes back live. # save last index if any... my $oldtag; my $oldrow = $albumprop->focus_row(); $oldtag = $albumprop->get_text($oldrow, 0) if $oldrow > 0; print "old $oldrow: $oldtag\n" if $debug; $albumprop->clear; for my $i (sort keys %album) { $albumprop->append("\u$i", $album{$i}); } if ($oldrow > 0) { my $newrow = my_gtk_find_row($albumprop, 0, $oldtag); print "new $newrow\n" if $debug; if ($newrow > 0) { $albumprop->set_focus_row($newrow); $albumprop->grab_focus(); } } # help the user enter stuff $albumname->set_popdown_strings(@known_tags); # tag as unchanged $dirty = 0; } sub save_album_tags { my $test_filename = shift; if (not $album_dirty) { status(sprintf(_("%s not dirty, not saved"), ${test_filename})); return; } my $parent = ($album_doc->xql("album/description"))[0]; # first one my %f = %album; # write out the tree... for my $xmlfield ($album_doc->xql("album/description/field")) { my $namestr = $xmlfield->getAttribute("name"); if (defined $f{$namestr}) { # delete this node so we can append it later $xmlfield->getParentNode->removeChild($xmlfield); } } # now append the remaining ones... for my $k (keys %f) { next if ($f{$k} eq ""); my $newfield = new XML::DOM::Element($album_doc, "field"); print "creating <$k> with <$f{$k}>\n" if $debug; $newfield->setAttribute("name", $k); # needs quoting! $newfield->addText($Latin2UTF->convert($f{$k})); $parent->appendChild($newfield); print "created $k with $f{$k}\n" if $debug; } $album_doc->printToFile("${test_filename}"); status(sprintf(_("Saved %s."), $test_filename)); # undirty it $album_dirty = 0; } bins-1.1.29/bins-edit-gui.glade0000644000175000017500000007215710303167611016773 0ustar jeromejerome00000000000000 Bins-edit bins-edit src pixmaps Perl True True True GtkWindow image_edit_top BINS Image Property Editor GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False True False GtkVBox vbox3 False 0 GtkMenuBar menubar2 GTK_SHADOW_OUT 0 False False GtkMenuItem file2 GNOMEUIINFO_MENU_FILE_TREE GtkMenu file2_menu GtkPixmapMenuItem save1 activate on_save1_activate Wed, 01 May 2002 14:29:53 GMT GNOMEUIINFO_MENU_SAVE_ITEM GtkPixmapMenuItem open2 activate on_open2_activate Wed, 01 May 2002 14:29:53 GMT GNOMEUIINFO_MENU_OPEN_ITEM GtkPixmapMenuItem revert1 activate on_revert1_activate Wed, 01 May 2002 14:29:53 GMT GNOMEUIINFO_MENU_REVERT_ITEM GtkPixmapMenuItem album1 Edit the album this picture is in. 0 GDK_F2 activate activate on_album1_activate Mon, 03 Jun 2002 06:17:05 GMT False GNOME_STOCK_MENU_BOOK_OPEN GtkPixmapMenuItem exit1 activate on_exit1_activate Thu, 02 May 2002 16:04:05 GMT GNOMEUIINFO_MENU_EXIT_ITEM GtkMenuItem go1 False GtkMenu go1_menu GtkPixmapMenuItem next_file1 Save this file and load the next one. GDK_CONTROL_MASK GDK_n activate activate on_next_file1_activate Mon, 06 May 2002 21:18:06 GMT False GNOME_STOCK_MENU_FORWARD GtkPixmapMenuItem forward_10 GDK_MOD1_MASK GDK_Page_Down activate activate on_forward_10_activate Sun, 12 May 2002 21:26:57 GMT False GNOME_STOCK_MENU_DOWN GtkPixmapMenuItem prev_file1 Save this file and load the previous one. GDK_CONTROL_MASK GDK_p activate activate on_prev_file1_activate Mon, 06 May 2002 21:18:06 GMT False GNOME_STOCK_MENU_BACK GtkPixmapMenuItem back_10 GDK_MOD1_MASK GDK_Page_Up activate activate on_back_10_activate Sun, 12 May 2002 21:26:57 GMT False GNOME_STOCK_MENU_UP GtkPixmapMenuItem start_of_list1 GDK_MOD1_MASK GDK_Home activate activate on_start_of_list1_activate Sun, 12 May 2002 21:26:57 GMT False GNOME_STOCK_MENU_FIRST GtkPixmapMenuItem end_of_list1 GDK_MOD1_MASK GDK_End activate activate on_end_of_list1_activate Sun, 12 May 2002 21:26:57 GMT False GNOME_STOCK_MENU_LAST GtkMenuItem edit1 GNOMEUIINFO_MENU_EDIT_TREE GtkMenu edit1_menu GtkPixmapMenuItem auto_fill1 Fill in blank fields from most recently seen image. GDK_CONTROL_MASK GDK_a activate activate on_auto_fill1_activate Wed, 08 May 2002 18:43:48 GMT False GNOME_STOCK_MENU_CONVERT GtkPixmapMenuItem rotate_right_cw1 Rotate image to the Right (Clockwise) GDK_SHIFT_MASK GDK_greater activate activate on_rotate_right_cw1_activate Sun, 19 May 2002 00:11:57 GMT False GNOME_STOCK_MENU_REDO GtkPixmapMenuItem rotate_left1 Rotate image to the Left (Counter Clockwise) GDK_SHIFT_MASK GDK_less activate activate on_rotate_left1_activate Sun, 19 May 2002 00:11:57 GMT False GNOME_STOCK_MENU_UNDO GtkPixmapMenuItem cancel_rotation1 Restore original orientation (based on the EXIF tags, if any) activate on_cancel_rotation1_activate Sun, 19 May 2002 00:11:57 GMT False GNOME_STOCK_MENU_STOP GtkMenuItem help2 GNOMEUIINFO_MENU_HELP_TREE GtkMenu help2_menu GtkPixmapMenuItem about2 activate on_about2_activate Wed, 01 May 2002 14:29:53 GMT GNOMEUIINFO_MENU_ABOUT_ITEM GtkPixmapMenuItem license1 GPL activate on_license1_activate Fri, 10 May 2002 04:50:31 GMT False GNOME_STOCK_MENU_BOOK_OPEN GtkHPaned hpaned2 10 6 0 True True GtkScrolledWindow scrolledwindow2 GTK_POLICY_ALWAYS GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS True True GtkCList image_prop_list True 2 80,80 GTK_SELECTION_SINGLE True GTK_SHADOW_IN GtkLabel CList:title label4 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label5 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkVBox vbox6 False 0 True True GtkLabel image_filename_label GTK_JUSTIFY_LEFT False 0.5 0.5 0 0 0 False False GtkPixmap image_edit_pixmap 0 0 0 0 True 0 True True GtkHBox fixed1 False 0 0 False False GtkVBox vbox4 False 0 0 False False GtkLabel label6 GTK_JUSTIFY_LEFT False 0.5 0.5 0 0 0 False False GnomeEntry field_name_entry 175 15 0 True True GtkEntry GnomeEntry:entry combo-entry1 True True True 0 GtkVBox vbox5 False 0 0 True True GtkLabel label7 GTK_JUSTIFY_LEFT False 0.5 0.5 0 0 0 False False GnomeEntry field_value_entry 10 0 True True GtkEntry GnomeEntry:entry combo-entry2 True True True 0 GtkStatusbar statusbar1 0 False False GtkDialog license_box False BINS License GTK_WINDOW_DIALOG GTK_WIN_POS_NONE True True True False GtkVBox Dialog:vbox dialog-vbox1 False 0 GtkHBox Dialog:action_area dialog-action_area1 10 True 5 0 False True GTK_PACK_END GtkHButtonBox hbuttonbox1 GTK_BUTTONBOX_DEFAULT_STYLE 30 85 27 7 0 0 True True GtkButton dismiss_about True True clicked on_dismiss_about_clicked Fri, 10 May 2002 05:07:03 GMT GNOME_STOCK_BUTTON_OK GTK_RELIEF_NORMAL GtkScrolledWindow scrolledwindow3 GTK_POLICY_NEVER GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS 0 True True GtkText license_text True False GnomeAbout about_box False True Copyright 2002 Mark W. Eichin <eichin@thok.org> Mark W. Eichin <eichin@thok.org> The Herd Of Kittens See bins-edit-gui(1) and bins_edit(1) for details. GtkWindow album_edit_top False window1 GTK_WIN_POS_NONE False False True False GtkVBox vbox7 False 0 GtkMenuBar menubar3 GTK_SHADOW_OUT 0 False False GtkMenuItem file3 GNOMEUIINFO_MENU_FILE_TREE GtkMenu file3_menu GtkPixmapMenuItem save2 activate on_save2_activate Mon, 03 Jun 2002 05:56:22 GMT GNOMEUIINFO_MENU_SAVE_ITEM GtkPixmapMenuItem revert2 activate on_revert2_activate Mon, 03 Jun 2002 05:56:22 GMT GNOMEUIINFO_MENU_REVERT_ITEM GtkPixmapMenuItem close1 activate on_close1_activate Mon, 03 Jun 2002 05:56:22 GMT GNOMEUIINFO_MENU_CLOSE_ITEM GtkPixmapMenuItem exit2 activate on_exit1_activate Mon, 03 Jun 2002 05:56:22 GMT GNOMEUIINFO_MENU_EXIT_ITEM GtkMenuItem help3 GNOMEUIINFO_MENU_HELP_TREE GtkMenu help3_menu GtkPixmapMenuItem about3 activate on_about2_activate Mon, 03 Jun 2002 05:56:22 GMT GNOMEUIINFO_MENU_ABOUT_ITEM GtkLabel album_edit_filename GTK_JUSTIFY_LEFT False 0.5 0.5 0 0 0 False False GtkHPaned hpaned3 10 6 0 True True GtkScrolledWindow scrolledwindow4 GTK_POLICY_ALWAYS GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS True True GtkCList album_prop_list True 2 80,80 GTK_SELECTION_SINGLE True GTK_SHADOW_IN GtkLabel CList:title label9 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label10 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkVBox vbox8 False 0 True True GtkHBox hbox1 False 0 0 False False GtkLabel label11 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 False False GnomeEntry album_name_entry 10 0 True True GtkEntry GnomeEntry:entry combo-entry3 True True True 0 GtkVBox vbox9 False 0 0 True True GtkLabel label12 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 False False GtkScrolledWindow scrolledwindow5 GTK_POLICY_NEVER GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS 0 True True GtkText album_edit_text True True GnomeDialog iconv_failed_dialog False GTK_WINDOW_POPUP GTK_WIN_POS_MOUSE True False False False True True GtkVBox GnomeDialog:vbox dialog-vbox4 False 8 4 True True GtkHButtonBox GnomeDialog:action_area dialog-action_area4 GTK_BUTTONBOX_END 8 85 27 7 0 0 False True GTK_PACK_END GtkButton button2 True True GNOME_STOCK_BUTTON_OK GtkVBox vbox10 False 0 0 True True GtkLabel label13 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 True True GtkRadioButton iconv_latin1_charmap_button True True True iconv_failed_group 0 True True GtkHBox hbox3 False 0 0 True True GtkRadioButton iconv_user_charmap_button True False True iconv_failed_group 0 True True GnomeEntry entry1 10 0 True True GtkEntry GnomeEntry:entry iconv_user_charmap_entry True True True 0 bins-1.1.29/install.sh0000755000175000017500000001323110303167611015326 0ustar jeromejerome00000000000000#!/bin/sh # -*-ksh-*- # This is the BINS install procedure. # Run it as root to install BINS system wide # or run it with your user to install it only for this user # PREFIX, RC and DESTDIR environment variables can be set to choose # installation paths # $Id: install.sh,v 1.34 2005/08/24 21:29:44 jerome Exp $ set -o errexit set -o nounset langs="fr de pl it ru es zh_TW nl ja eo fi hu ca" templates="swigs joi satyap marc petrus mwolson martin" DESTDIR="${DESTDIR:-}" # prefix to append to the install dirs # this is used by the Mandrake and Debian packages PREFIX="${PREFIX:-/usr/local}" ETC="${ETC:-/etc}" RC="${RC:-/etc/bins}" GLOBAL_RC="$RC" DESTDIR=`echo "$DESTDIR"|sed 's%/$%%'` PREFIX=$DESTDIR/`echo "$PREFIX"|sed 's%^/%%'` PREFIX=`echo "$PREFIX"|sed 's%/$%%'` ETC=$DESTDIR/`echo "$ETC"|sed 's%^/%%'` ETC=`echo "$ETC"|sed 's%/$%%'` RC=$DESTDIR/`echo "$RC"|sed 's%^/%%'` RC=`echo "$RC"|sed 's%/$%%'` BIN="$PREFIX/bin" SHARE="$PREFIX/share" DATA="$SHARE/bins" GLADE="$DATA" LOCALE="$SHARE/locale" MAN="$PREFIX/man/man1" cd `dirname $0` cat </dev/null || true if [ -w $BIN ] ; then echo "Installing program files in $BIN" # bins_cleanupgallery anti_bins cp bins bins_edit bins-edit-gui $BIN chmod a+rx $BIN/bins chmod a+rx $BIN/bins_edit chmod a+rx $BIN/bins_cleanupgallery chmod a+rx $BIN/bins-edit-gui chmod a+rx $BIN/anti_bins # perl -pi -e "s{/usr/local/share}{$SHARE}g" \ # $BIN/bins $BIN/bins_edit $BIN/bins-edit-gui # perl -pi -e "s{/etc/bins}{$RC}g" \ # $BIN/bins $BIN/bins_edit $BIN/bins-edit-gui return 0 else echo "Cannot write to $BIN directory." return 1 fi } install_config() { mkdir -p $RC 2>/dev/null || true if [ -w $RC ]; then echo "Installing configuration file in $RC" cp binsrc $RC for T in $templates do if [ -d "$RC/templates.$T" ]; then echo "Removing old template.$T in $RC" rm -Rf "$RC/templates.$T" fi done chmod -R a+r $RC/* else echo "Cannot write to $RC." return 1 fi } install_data() { mkdir -p $DATA 2>/dev/null || true if [ -w $DATA ]; then for T in $templates do echo "Installing default HTML templates in $DATA/templates.$T" if [ ! -d $DATA/templates.$T ] ; then mkdir $DATA/templates.$T fi cp templates.$T/*.html $DATA/templates.$T if ls templates.$T/*.js >/dev/null 2>&1 ; then cp templates.$T/*.js $DATA/templates.$T fi if [ -d templates.$T/static ] ; then cp -R templates.$T/static $DATA/templates.$T fi done chmod -R a+r $DATA/* return 0 else echo "Cannot write to $DATA." return 1 fi } # program files set +o errexit install_binaries if [ "$?" -eq "1" ] ; then BIN=~/bin echo "Trying $BIN..." install_binaries if [ "$?" -eq "1" ] ; then echo "Error: unable to find a directory to write program files, aborting." exit 2 fi fi # config file install_config if [ "$?" -eq "1" ] ; then RC=~/.bins echo "Trying $RC..." install_config if [ "$?" -eq "1" ] ; then echo "Error: unable to find a directory to write configuration file, aborting." exit 2 fi fi # templates install_data if [ "$?" -eq "1" ] ; then DATA=~/.bins echo "Trying $DATA..." install_data if [ "$?" -eq "1" ] ; then echo "Error: unable to find a directory to write templates, aborting." exit 2 fi fi set -o errexit # additionnal files mkdir -p $GLADE 2>/dev/null || true if [ -w $GLADE ] ; then echo "Installing additionnal files in $GLADE" cp bins-edit-gui.glade $GLADE fi # man pages mkdir -p $MAN 2>/dev/null || true if [ -w $MAN ] ; then echo "Installing man page in $MAN" cp doc/*.1 $MAN fi # bash completion if [ -w $ETC/bash_completion.d ] ; then echo "Installing bash completion system wide." cp -f bash_completion $ETC/bash_completion.d/bins else mkdir ~/.bash_completion 2>/dev/null || true if [ -w ~/.bash_completion ] ; then echo "Installing bash completion for user `whoami`." cp -f bash_completion ~/.bash_completion/bins fi fi # I18N files mkdir -p $LOCALE 2>/dev/null || true if [ -w $LOCALE ] ; then echo "Installing internationalization messages files." for L in $langs do mkdir -p $LOCALE/$L/LC_MESSAGES 2>/dev/null || true cp intl/$L.mo $LOCALE/$L/LC_MESSAGES/bins.mo if [ -f intl/gui-$L.mo ]; then cp intl/gui-$L.mo $LOCALE/$L/LC_MESSAGES/bins-edit-gui.mo fi done else cat </dev/null 1,\$s%/usr/local/share%$SHARE%g 1,\$s%/etc/bins%$GLOBAL_RC%g wq EoF done echo . echo echo "Installation complete" bins-1.1.29/binsrc0000644000175000017500000003744610303167611014542 0ustar jeromejerome00000000000000 swigs / blue 1 0 1 0 1 1 1 1 0 1 %c hidden ignore 75 smaller 1 0 1 1 1 0 0 0 16 4 150 150 1 destination 0 scale enlarge 0 0 1 40 1 _Orig$ ^(CVS|RCS)$ 1 1 1 1 50 title description people location event comment 1 1 #FFFFFF #000000 #000077 #FFFFFF #EEDD82 #D2D2D2 #6060AF #EEDD82 #FFFFFF #FFFFFF #FFFFFF #000000 #90A080 #FFFFFF #000082 #000000 #A8B898 #0000A0 #000000 #FFFFFF #8B7E66 #FFFFFF #FFFFF0 #8B4513 #CD853F #000000 #FFEBCD #8B8682 #000000 #8B795E #FFC0CB #B03060 #FFFFFF #FFBBFF #000000 #FF69B4 #FFBBFF #000000 #FFFFFF bins-1.1.29/tools/0000755000175000017500000000000010303167611014461 5ustar jeromejerome00000000000000bins-1.1.29/tools/add_num_prefix0000755000175000017500000000131110303167611017367 0ustar jeromejerome00000000000000#!/bin/sh # Add a numeric prefix starting at $1, incrementing by $2 on $3..$n files # (c) 2005 Jérôme SAUTRET # This script is distributed under GNU GPL. Ask Stallman for details. # $Id: add_num_prefix,v 1.1 2005/08/22 19:58:27 jerome Exp $ set -o errexit if [ -z "$3" ] ; then cat < $new" mv "$file" "$new" let i=i+inc done bins-1.1.29/tools/remove_num_prefix0000755000175000017500000000110110303167611020131 0ustar jeromejerome00000000000000#!/bin/sh # Remove a numeric prefix (ex 0010_filename -> filename) on files # (c) 2005 Jérôme SAUTRET # This script is distributed under GNU GPL. Ask Stallman for details. # $Id: remove_num_prefix,v 1.1 2005/08/22 19:58:27 jerome Exp $ set -o errexit if [ -z "$1" ] ; then cat < filename) on files. EoF exit 1 fi files="$@" i=$min for file in $files do new="`echo "$file" | sed 's/^0*[0-9][0-9]*_\(.*\)$/\1/'`" echo "$file -> $new" mv "$file" "$new" donebins-1.1.29/tools/bins_cleanupgallery0000755000175000017500000000617310303167611020440 0ustar jeromejerome00000000000000#!/usr/bin/perl # # CleanupGallery v0.1 for BINS # Copyright (C) 2003 by Jochen Schaeuble # # $Id: bins_cleanupgallery,v 1.3 2003/04/08 18:29:46 jerome Exp $ # # 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 # (at your option) 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; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. use File::Glob ':glob'; @knownImageExtentions = ("jpg", "jpeg", "gif", "png", "tiff", "bmp", "tga", "ps", "eps", "fit", "pcx", "miff", "pix", "pnm", "rgb", "im1", "xcf", "xwd", "xpm", "avs", "dcm", "dcx", "dib", "dps", "dpx", "epdf", "epi", "ept", "fpx", "icb", "mat", "mtv", "pbm", "pcd", "pct", "pdb", "ppm", "ptif", "pwp", "ras", "thm", ); $imageExts = join('|', @knownImageExtentions); @webFormats = ("jpg", "jpeg", "gif", "png"); $webExts = join('|', @webFormats); sub ProcessDir { local *DIR; (local $curdir, local $dstdir, local $srcdir) = @_; opendir(DIR, "$dstdir/$curdir"); while ($file = readdir(DIR)) { $file = "$curdir/$file"; if (-d "$dstdir/$file" && $file !~ m/\.\.?$/ && $file !~ m/static\.\w*$/) { if (-d "$srcdir/$file") { # Directory exists in src and dest, process it &ProcessDir($file, $dstdir, $srcdir); } else { # Directory only available in dest remove it print "## Removing dir: $dstdir/$file\n"; `rm -Ri \"$dstdir/$file\"`; } } elsif ((-f "$dstdir/$file" || -l "$dstdir/$file") && $file =~ m/.*\.($webExts)$/i) { my @srcfiles = bsd_glob("$srcdir/$curdir/*", GLOB_NOCASE | GLOB_QUOTE | GLOB_TILDE); $filefound = 0; FILESEARCH: foreach $curfile (@srcfiles) { # remove trailing .xml if ($curfile =~ m/.*\.xml$/i) { $curfile =~ s/(.*)\.xml$/$1/i; } # remove file extension $curfile =~ s/.*\/([^\/]*)\.($imageExts)$/$1/i; if (($curfile ne "") && ($file =~ m/$curfile.*\.($webExts)$/i)) { $filefound = 1; last FILESEARCH; } } if ($filefound == 0) { $file =~ s/(.*)_\w+\.($webExts)$/$1/i; print "## Removing file: $dstdir/$file*\n"; `rm -v \"$dstdir/$file\"*`; } } } closedir(DIR) } sub usage { print "CleanupGallery v0.1 (c) 2003 by Jochen Schaeuble \n"; print "\n"; exit(0); } if ($#ARGV != 1 || !-d $ARGV[0] || !-d $ARGV[1]) { &usage; } ($srcdir, $dstdir) = @ARGV; ProcessDir("", $dstdir, $srcdir); bins-1.1.29/tools/anti_bins0000755000175000017500000000525210303167611016361 0ustar jeromejerome00000000000000#!/bin/sh # This program creates a image files tree for each image size from a BINS album. # Edit the variables in the configuration section and run it. # (c) 2003 Jérôme SAUTRET # This script is distributed under GNU GPL. Ask Stallman for details. # $Id: anti_bins,v 1.1 2004/05/08 20:02:39 jerome Exp $ set -o nounset #################################################################### # Configuration section ALBUM="Album" # Path of the HTML album directory HTML_ALBUM="$HOME/Photos/$ALBUM/html" # Path of the destination images directory IMAGE_ALBUM="$HOME/Photos/$ALBUM/Images" # size names in the image file, # followed by the names of the directories that will be created for each picture sizes # separated by a colon IMAGE_SIZES="Sm:Small Images,Med:Medium Images,Lg:Large Images" #IMAGE_SIZES="Pt:Petites images,Moy:Images moyennes,Gd:Grandes images" # Copy command COPY="ln -f" # use this to create hard links, works only if source & dest are on same partition #COPY="ln -sf" # use this to create symbolic links #COPY="cp -f" # use this to copy images # Image extensions IMAGE_TYPES="jpg|png" # Set this to 1 when configuration is done. CONFIGURATION_IS_OK=0 # End of configuration section ##################################################################### ls --ignore-backups --file-type >/dev/null 2>/dev/null if [ $? != 0 ] ; then echo "This program runs only with a 'ls' supporting the '--file-type' option" echo "Install GNU ls or send me a patch..." exit 2 fi if [[ $CONFIGURATION_IS_OK == 0 ]] ; then echo "Edit this script to set configuration variables." exit 1 fi IMAGE_SIZES="$IMAGE_SIZES," SIZES="`echo "$IMAGE_SIZES" | sed "s/\([^:]*\):[^,]*,/\1 /g"`" size_name() { echo "$IMAGE_SIZES" | sed "s/^.*$1:\([^,]*\),.*$/\1/" } copy_dir() { local SOURCE DEST F SOURCE="$1" DEST="$2" echo "Traitement du répertoire $1" cd "$SOURCE" for SIZE in $SIZES do SIZE_NAME="`size_name $SIZE`" mkdir -p "$IMAGE_ALBUM/$SIZE_NAME/$DEST" >/dev/null for F in `ls --ignore-backups|grep -E "_$SIZE.($IMAGE_TYPES)$"` do DEST_FILE="`echo "$F" | sed "s/_$SIZE\\././"`" DEST_FILE="$IMAGE_ALBUM/$SIZE_NAME/$DEST$DEST_FILE" if [ ! -f "$DEST_FILE" ] ; then echo "copie de" "$SOURCE$F" vers "$DEST_FILE" $COPY "$SOURCE$F" "$DEST_FILE" fi done done for F in `ls --ignore-backups --file-type | grep "/$"` do # Decode URL DEST_DIR="`echo "$F"|sed 's/%\([A-F0-9][A-F0-9]\)/\\\\x\\1/g'`" DEST_DIR="`printf "$DEST_DIR"`" # _ to spaces DEST_DIR=`echo "$DEST_DIR"|sed 's/_/ /g'` copy_dir "$SOURCE$F" "$DEST$DEST_DIR" done # Remove dir if empty rmdir "$IMAGE_ALBUM/"*"/$DEST" 2>/dev/null } copy_dir "$HTML_ALBUM/" ./ bins-1.1.29/tools/bins_txt2xml0000755000175000017500000000415210303167611017046 0ustar jeromejerome00000000000000#!/usr/bin/perl -w use strict; my $verbose=1; my $bins_edit="bins_edit"; sub readTxt{ my $file=shift; my %hash; if (! open (FILE, $file)) { print "Warning: cannot open file '$file' for reading ($!), skiping."; return 1; } my $tag; my $value=""; LINE: while () { chomp; next LINE if /^#/; #discard comments next LINE if /^\s*$/; #ignore total whitespace s/^\s+//; s/\s+$//; print " Reading line '$_'\n" if ($verbose >= 3); if ($tag) { if (m%%) { print " Found end tag , " if ($verbose >= 2); chomp($value); $hash{$tag} = $value; print "value is '$hash{$tag}'\n" if ($verbose >= 2); $tag = ""; $value = ""; } else { $value .= $_."\n"; } } elsif (m/<\w+>/) { $tag = $_; $tag =~ s/<(\w+)>/$1/; print " Found begin tag <$tag>\n" if ($verbose >= 2); } } close (FILE) || bail ("can't close $file ($!)"); return %hash; } sub processFile{ my $file = shift; my $album = shift; # -a if album, empty string otherwise my %hash = readTxt($file); my $commandLine; if ($file =~ m%/album.txt$%) { $file =~ s%/album.txt$%/.%; $commandLine="$bins_edit --html --album "; } else { $file =~ s/.txt$/.xml/; $commandLine="$bins_edit --html "; } $commandLine .= "-v " foreach (2..$verbose); my $tagName; my $tagValue; while ( ($tagName, $tagValue) = each(%hash) ) { $tagValue =~ s/\'/\'\\\'\'/g; $commandLine .= "-g $tagName='$tagValue' " } $commandLine .= "$file"; print " Executing «$commandLine»" if ($verbose >= 3); system($commandLine); } sub main { my $dir = shift; print "Processing directory '$dir'...\n" if ($verbose >= 1); if (!opendir(DIR, "$dir")) { print ("Warning: can't open dir $dir: $!\n"); return; } my @files = grep { !/^\./ } readdir(DIR); closedir DIR; foreach my $file (@files) { if (-d $dir."/".$file) { main ($dir."/".$file) } elsif ($file =~ m/^album.txt$/) { processFile($dir."/".$file, "-a"); } elsif ($file =~ m/.txt$/) { processFile($dir."/".$file, ""); } } } main($ARGV[0]); bins-1.1.29/tools/bins_addtext0000755000175000017500000000406310303167611017062 0ustar jeromejerome00000000000000#!/usr/bin/perl -w #-*- mode: perl -*- sub process_file { my ($dir, $file, $title, $desc) = @_; chomp $desc; #print "File: $file\n\tTitle: $title\n\tDesc: $desc\n"; #print "\n$file\n"; if($file eq "album") { ($longdesc, $shortdesc, $sample) = split /\|/, $desc; if($sample) { $cmd_str = "bins_edit -a -m --sample \"$sample\" $dir"; print "$cmd_str\n"; `$cmd_str`; } if($shortdesc) { $cmd_str = "bins_edit -a -m --shortdesc \"$shortdesc\" $dir"; print "$cmd_str\n"; `$cmd_str`; } if($longdesc) { $cmd_str = "bins_edit -a -m --longdesc \"$longdesc\" $dir"; print "$cmd_str\n"; `$cmd_str`; } #print "\t$cmd_str\n"; $cmd_str = "bins_edit -a -m --title \"$title\" $dir"; print "$cmd_str\n"; `$cmd_str`; } else { $cmd_str = "bins_edit -m -t \"$title\" $dir/$file"; print "$cmd_str\n"; `$cmd_str`; #print "\t$cmd_str\n"; $cmd_str = "bins_edit -m -d \"$desc\" $dir/$file"; print "$cmd_str\n"; `$cmd_str`; #print "\t$cmd_str\n\n"; } } $inc_file = "include_images.txt"; for($i=0; $i<=$#ARGV; $i++) { $dir = $ARGV[$i]; if($dir eq "-f" && $i<$#ARGV ) { $i++; $inc_file=$ARGV[$i]; next; } open(FILE, "$dir/$inc_file") or die "Could not open: $dir/$inc_file"; $title = ""; $desc = ""; $img_file = "album"; $section = 1; while() { chomp; $line=$_; if(substr($line, 0 , 1) eq "") { next; } if(substr($line, 0 , 1) ne "#") { process_file($dir, $img_file, $title, $desc); $img_file = $line; $title = ""; $desc = ""; $section = 1; } else { if ($section == 1) { $title = substr($line, 1); $section++; } elsif ($section == 2) { $desc .= substr($line, 1)."\n"; } } } if($section) { process_file($dir, $img_file, $title, $desc); } close(FILE) ; } bins-1.1.29/LICENSE0000644000175000017500000004312710303167611014335 0ustar jeromejerome00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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 (at your option) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. bins-1.1.29/README0000644000175000017500000001616210303167612014210 0ustar jeromejerome00000000000000========================================================== BINS Photo Album Version 1.1.29 Mar. 17, 2002 http://bins.sautret.org/ Jerome@Sautret.org BINS is free software, licensed under the GNU GPL. See the COPYING file for details. ========================================================== (Une documentation en français est disponible dans doc/index_fr.html ou en-ligne sur http://bins.sautret.org/index_fr.html ) A complete documention in HTML format can be found in doc/index.html or on-line on http://bins.sautret.org. See it for BINS installation and usage. See also the bins(1), bins_edit(1) and bins-edit-gui(1) man pages. The aim of BINS is to generate HTML photo albums. Some of the functionalities of BINS are: - album can contains other albums (sub albums): the album can have a tree structure ; - generation of a thumbnail and of scaled images of each picture ; - number and size of scaled pictures can be personalized, in pixels or percentage of the original image ; - several description fields (date, location, etc...) can be associated with the pictures ; - usethe EXIF data structure found on some JPEG (usually, those produced by digital cameras) to fill automatically some fields (date and time for example). You can see an example of an album generated by BINS at http://album.sautret.org/ This my personal album with french I18N. BINS (BINS Is Not SWIGS) is a modified version of SWIGS (Structured Web Image Gallery System). I've made these modifications because I need them. I tried to contact SWIGS author, but I've got no response, so I decided to publish my modified version in case someone is interested. See ChangeLog file for differences between SWIGS and BINS. Migrating from BINS version earlier than 1.1.0 ============================================== A new XML format is use for pictures and albums description files in BINS 1.1.0. There is an utility bins_txt2xml to convert from old format to new one: WARNING: make a backup of your album before proceding to the migration, just in case something goes wrong. Install the new bins and bins_edit program in tour path as explained in the installation documentation. Run the bins_txt2xml with the source directory of the album as a parameter : bins_txt2xml ~/album This will create .xml files for each .txt in your album and its subalbums. This can take some time... You can then run the new bins to check if the new desc files are OK. When you are sure all is OK. You can delete the old .txt files: find ~/album -name \*.txt -exec rm -f {} \; License ======= BINS is free software, licensed under the GNU GPL. See COPYING file for details. BINS is Copyright (c) 2001-2004 Jérôme Sautret (Jerome @ Sautret.org). Original SWIGS code is Copyright (c) 2000 Brendan McMahan (mcmahahb @ whitman.edu). Initial code based on IDS 0.21 is Copyright (c) John Moose (moosejc @ muohio.edu). Original SWIGS README: ====================== _______________________________________________________________________________ SWIGS README, INSTALL, and DOCUMENTATION version 0.1.1 Dec. 31, 2000 Brendan McMahan (mcmahahb@whitman.edu) http://people.whitman.edu/~mcmahahb/projects/swigs.html _______________________________________________________________________________ Document Contents: Requirements Installation and Usage Overview SWIGS command line options File Formats for Image Text Files File Formats for Album Text Files Requirements: * ImageMagick with PerlMagick (http://www.imagemagick.org/) * the "Image::Size" Perl module (http://www.cpan.org/). Installation and Usage Overview: 1 Decompress swigs.tar.gz into a directory, say ~/swigs/ 2 To immediately test your installation, run ./swigs.pl -t templates/ sample_input/ sample_output/ 3 The default search location for templates is $HOME/.swigs_templates You can copy the templates to that location so you don't have to specificy the -t option everytime you run swigs. 4 Put the images you want into a directory (possibly including subdirectories), say ~/pics/ 5 Edit the HTML templates in ~/swigs/templates/ if desired 6 Create text files with annotations for each image and directory if desired. For a description of the file formats, see below. 7 run ./swigs.pl ~/pics/ ~/swigs-output/ SWIGS command line options: swigs.pl [-o [src]] [-t template_dir] source_dir target_dir -o Tells script to use only one copy of image, using html size specs (height, width specs in the image tag) for scaled versions. The default src of the single image is scaled. The possible values are: "scaled" (make scaled copy of orig in target_dir hierarchy, sized to max size). Default. "copied" (copy orig to web dir) "custom" (use copy if filesize < 1meg resize, resave, if bigger than 1 meg) -t template_dir directory where html templates are stored. If nothing is specified, then the direcory is assumed to be templates/ -p If this option is given, then prefix ordering numbers on directories are removed. For example, if one has directories may, june, and august, they can be renamed 0_may, 1_june, and 2_august and they will appear in the album in the correct order. Procceeding numbers followed by an underscore are stripped. File Formats for Image Text Files: * If the image is named foo.jpg (or foo.someothersupportedformat) then the associated description file should be foo.jpg.txt. The older format, foo.txt, is also still recognized, but should be avoid do to possible conflicts if you hava a foo.jpg and a foo.png in the same directory (for example). * Each starting or ending tag goes on its own line. Each block of data between tags may take any number of lines. Type a short title for the image. The event where the image was taken. The location where the image was taken. The names of the people in the image. Should be a comma separated list without the word "and" to allow for easy parsing in future versions that allow searching. For example: Colin, Mike, Steph, Jeff, Marc The date and time the image was taken. A description of the image and any other information. File Formats for Album Text Files: * Each starting or ending tag goes on its own line. Each block of data between tags may take any number of lines. * The text file must be called album.txt * One album.txt file may be included in each directory. A short title for the album. If none is specified, the directory name is used with underscores replaced by spaces. The name of an image (without any path information) in the directory to use as a representative for the album. Only specified if there are actually images in the directory. For example: Image003.jpg A short description of the contents of the album. A longer description of the contents of the album. If none is specified, the short description is used. bins-1.1.29/README.gui0000644000175000017500000000266410303167611014774 0ustar jeromejerome00000000000000bins-edit-gui -- graphical editor for BINS-format XML tag files Copyright 2002 Mark W. Eichin The Herd of Kittens Licensed under the GPL; see COPYING. -------------------------------------------------------------- Perl packages used: Getopt::Long Gtk Gtk::GladeXML XML::DOM XML::XQL XML::XQL::DOM XML::Writer Gtk::Gdk::ImlibImage Gnome Glade::PerlRun Text::Iconv Image::Info -------------------------------------------------------------- Debian packages used, beyond what bins already uses: libglade-perl libgladexml-perl libgnome-perl libgtk-imlib-perl libimage-info-perl libparse-yapp-perl libtext-iconv-perl libxml-writer-perl libxml-xql-perl -------------------------------------------------------------- I18N: domain is "bins-edit-gui" Don't bother marking or translating anything under $debug. -------------------------------------------------------------- Open bugs that bins-edit-gui works around: debian #147051: libglade0: i18n: CList titles not properly handled debian #147341: gettext: xgettext -D breaks -j Bugs fixed/features added as a direct result of bins development: debian #147516: libjpeg-progs: output error message unclear -------------------------------------------------------------- Thanks to: Jérôme Sautret [for BINS itself, and for encouraging my feedback, and for cleaning up the French] Rene Weber [for being the first hint that anyone else cared about the debian package] bins-1.1.29/RELEASE.gui0000644000175000017500000000240510303167611015110 0ustar jeromejerome00000000000000# Release notes/log for bins-edit-gui # cvs log -rrelease_thok_0_8:: for logs, or # cvs diff -u -rrelease_thok_0_8 for full diffs 20020611 - 0.9 - Fix grey-out of filename box. Force LATIN1 if 7-bit ANSI is selected. Add charmap override box if either conversion fails. 20020607 - 0.8 - more error checks. Primitive "current album" editor. Free server-side pixmap correctly (oops.) Update man page. 20020602 - 0.7 - workaround non-debian LC_MESSAGES bug. Guess encoding from locale. Add slider between tags and image (which cleans up some other visual sizing bugs automatically.) 20020521 - 0.6 - handle bad/missing filenames, filter out .xml files from argument list, updated french translation. Add user-specified rotation to interface; cleaned up "revert" as a side effect. 20020516 - 0.5 - i18n support, including an approximate french translation. Added more list navigation, moved them all to a separate menu. 20020512 - 0.4 - Support EXIF rotation tag. Stopped using GtkFixed and improved the space usage significantly, especially in full screen mode. 20020510 - 0.3 - First thok release. "real looking", including getopt and about boxes; also has proper focus-row preservation and properly frees previous images, and handles XML UTF correctly. bins-1.1.29/TODO0000644000175000017500000000675110303167611014022 0ustar jeromejerome00000000000000TODO file for BINS (in no particular order) ------------------ - fix date encoding - use chmod() and symlink() instead of system() - add author email in default templates. - include bins_cleanupgallery in bins program. - copy the origninal image to the destination album, with a link in the HTML, if it is not already there (same source & destination size, scaleIfSameSize=0 and no rotation). - link .avi files to .thm when possible. - rotate JPEG images with a size that is not multiple of the iMCU with mogrify instead of jpegtran (and perhaps remove border on scaled images to avoid such size problems). - display numbers of images for each album in tree page. - don't process empty dirs. - possibilty to have images and sub-album in top level album (currently, the thumbnail of the top level album is not displayed). - possibility to put XML files in another location (so images from CD-ROM can be used). - more sophisticated install procedure to not erase HTML templates and config files - command line option to select XML encoding. - handle correctly date/time format using plxgettext from Mandrake package: lacks -k option for now. - add long option names with getopt - select images to include in album by using contents of desc fields (eg: album with all images where 'people' contains 'joe'). - add possibility to exclude directory (like CVS ones). - generic description tag in the album.xml, to be used with all image in this album missing this tag. - blue bar on the left is too long if lot of thumbs pages - possibility to have albums in different langages - gzip .xml files (controlled by an option) - use of CSS - possibility to have parameter by album (in the album.xml) or by image (in its .xml file) to permit different image sizes, for example : almost done for some parameters - use of the JIT compiler for HTML:Template: impossible for now, due to bugs in HTML::Template:JIT. Some characters ($, \, %, @) must be escaped (see http://rt.cpan.org/NoAuth/Bug.html?id=349 for bug report). **************************************************************************** - hotkeys : DONE - don't overwrite .htaccess file if it exists, but edit it : DONE - preserve timestamp on files using cp -p when possible : DONE - possiblity to have different number of scaled images in a album: DONE. - width and height are not inversed on rotation with -o copied: CORRECTED - parameter to choose to rotate the original or the destination image: DONE - attribute (in exif section) to tell BINS to not read EXIF fields in picture but only in desc file: DONE - use the previous attibute to set the new orientation when bins rotate the original image and get rid of the BinsRotated parameter in Exif section: DONE - use of TITLE attibute on some links or image to give help as tooltips (for image title, sizes, etc...): DONE - thumb of current album (if any) in subalbum page: DONE. - add date of generation in the HTML code: DONE. - use of a config file to store parameters (instead of putting them directly at the beginning og the code): DONE - chmod u+w on destination image after a cp: done - guess local encoding from locales setting: done - correct bug with grayscales jpeg: done - use of color styles (to select a set of colors): done - process .tiff files, as well as other formats: done - screenshot of bins-edit-gui: done - strip any . in the short size name when creating file names - handle broken jpegtran - use of javascript to preload images of next thumnails page when current one is loaded. bins-1.1.29/ChangeLog0000644000175000017500000010336310303167611015101 0ustar jeromejerome00000000000000BINS Change Log -*- text -*- BINS 1.1.29 ----------- - A search engine has been added. It only woks on web browser supporting javascript and DOM. It can be deactivated via the new searchEngine parameter. It allows search on image description fields set in the new searchFields parameter. Maximum results returned by the search engine is set by the searchLimit parameter. This adds a new dependency on Text::Unaccent. - Michael Olson's mwolson templates have been added. Michael can be joined at . - Martin Pohlack's martin templates have been added. Martin can be joined at . These templates are based upon marc ones, in turn based on joi. Here are the modifications with marc: - fixed some bugs in the css - more layout stuff done in css - changed colors to grey-levels, which allows the viewer to concentrate on the important parts, the images (if you don't like it, you only have to change some lines in the css). - some layout changes, links (next, prev, ...) have a fixed position now, so you don't have to move the mouse if you want to cycle through many images. - use transparent pngs for the slide background in browser which support it -> smoother slide corners (round corners are oversampled, compare the gif and the png) - Display the content of the jpeg-comment filed below the image - Fixed a bug when javaScriptPreloadImage was set to 1 : the next image preloaded was always at maximum size. Patch from Malcolm Parsons - Add support for jpegtran with MMX (libjpeg-mmx-progs). Patch by Ludovic Rousseau . - Fix -f option so it can work with files given with a relative path. Patch by Ludovic Rousseau . - Default template has been renamed to swigs, has it may not be the default in the future (it uses tables and don't use CSS). - A tools directory has been added in the archive, containing the small BINS related utilities. The new tools add_num_prefix, remove_num_prefix and bins_addtext have been added. All is documented on the web site. - A FAQ has been added. - BINS now has a page on gna!, see https://gna.org/projects/bins/ BINS 1.1.28 ----------- - Replaced parameter "enlarge" with "whenSrcSmaller" to dictate what to do if the source image is smaller than the size of the generated image. Fixed a bug that prevented enlarged image from actually being generated. Patch from Alexander Blazej . - Added new linkRelative parameter allow to use relative links if linkInsteadOfCopy is set to 1. Patch from Dan McMahill . - Transform functionality now allow perl code. A new dateString parameter allow to specify the date string to be used (following date(1)), introducing a dependency on Date::Parse. Patch from Martin Michlmayr . - Handle buggy EXIF information in DateTimeOriginal. Patch from Martin Michlmayr . - Fix on deExifyImages option. Patch from Martin Michlmayr . - Fix encoding problem whith ISO 646 used by Solaris. Patch from Martin Michlmayr . - Fix bug when source directories is a prefix of the destination one. Patch from Pizza . - Make JPEG Comments available as image subtext. Patch from Martin Pohlack . - Catalan translation (ca) has been added. Thanks to Joan Antoja Sabin . - A CSS bug in marc template has been fixed. Correction from Martin Pohlack . - The image details page, using the Joi template, now respects use of a background image. Fix by Alexander Blazej . - The image details page's "Album Tree" link is fixed. Fix by Alexander Blazej . - Standardized indentation (4 columns). Done by Alexander Blazej . - Default value of borderOnThumbnails has been set to 0. BINS 1.1.27 ----------- - Added new parameter borderOnThumbnails to change or remove the border of the thumbnail's image in the thumbnails page, in pixels. - Exit if target_dir is in source_dir since it will generate an infinite recursion. Correction from Ludovic Rousseau . - Bug on tips popup when text contained double quotes has been corrected. Patch from Arthur de Jong . - bugs on -e and -o custom options has been fixed. Patch from Adam Lackorzynski . - Adding a check for Perl < 5.8 in bins_edit for utf-8 handling. Correction from Robert Funnell . - Hungarian translation (hu) has been added. Thanks to Aurel Gabris . - zh language code has been changed to zh_TW. - Correction in comments of binsrc. Patch from Robert Funnell . - Added RCS directories in excludeDirs parameter of binsrc to shown regexp use. Suggestion from Ambrose Li . The following changes have been made in bins-edit-gui by Mark W. Eichin : - Primitive "current album" editor. - Force LATIN1 if 7-bit ANSI is selected. Add charmap override box if either conversion fails. - Free server-side pixmap correctly (oops.) - Fix grey-out of filename box. - more error checks. - Update man page. - Also, shortcut for autofill has been corrected (now CTRL A). Correction from Ivan Daou BINS 1.1.26 ----------- - Added new marc template from Marc Menem . It is based on the joi template, so it has all of it's features. It don't use any table for the positioning but only css: this allows the number of images displayed on one line to scale according to the width of the browser window. http://quentinlepingouin.free.fr/album/apples-gal/ - Added new petrus template from Petrus . It is just a modified version of the joi template with a different look : http://www.campus.ecp.fr/~petrus/bins/index.html - Added support for more Exif tags. - Fix a divide by zero error crash, due to a corrupt image. Patch from Phillip Cole . - Fix javascript errors occured when a singe quote was included in a filename. Patch from Phillip Cole . - Fix bug on joi template : accesskey="t" was showing in the pages. Patch from Gerard Gerritsen and Phillip Cole . - Fix missing /IF directive in images pages on satyap template. Patch from Guillaume Rousse . BINS 1.1.25 ----------- - The images in each directory can now be displayed in an arbitrary, custom order. This is done via an optional file album.list (a slibling file to album.xml) that lists the files in the order you want them displayed. If album.list doesn't exist in a directory the sorting by image name is done as usual. Patch from Stefan Rueger . - Added hot keys (use with Alt key) : (N)ext, (P)revious, (U)p, (H)ome, images (L)ist, (T)ree. - Added first, last, index, parent, up and index relation links in thumbnail and image pages. They are used by Mozilla and Opera navigation bar. - Added first and last links on thumbnail and image pages in default templates. - Templates are now installed under /usr/local/share/bins, as data file, instead of /etc as configuration files Patch from Guillaume Rousse . - Fix bug on images list page for custom sizes (defined in description image file). - Added BINS completion for bash. Send by Guillaume Rousse . - Updated Spanish translation. Send by David Barroso . - Updated Esperanto translation. Send by Pier Luigi Cinquantini BINS 1.1.24 ----------- - Added anti_bins program, to create a clean image files tree for each image size from a BINS album. - Added jpegProgressify config option. Now, generated jpeg can be progressive (instead of baseline) using jpegtran. Usually progressive jpegs save space, but by default it only makes them progressive if it does save space. See bins man page for usage detail. Patch from Bill Clarke . - When backgroundImage was empty, the background attribute on body was not correct and thus produced 404 HTTP error on web server. patch from David Pfitzner . - Use the more generic AddDefaultCharset directive (instead of AddType) in the .htaccess file for setting HTTP headers encoding. - Corrected wrong orientation for value 3 (bot_right, 180° rotation). Patch from Guillaume Rousse . - Added prev/next link element (to enable Mozilla's link prefetching feature and site navigation toolbar) in joi templates . - Added JavaScript image pre-loading in satyap templates. - Esperanto translation (eo) has been added. Thanks to Revuo - Finish translation (fi) has been added. Thanks to Ville Pohjanheimo . - Russian translation (ru) has been updated. Thanks to Andrei Emeltchenko - Italian translation (it) has been updated. Thanks to Lele Gaifax . - Added BINS CVS Web interface : http://kashmir.sautret.org/cgi-bin/viewcvs.cgi/bins BINS 1.1.23 ----------- - new parameter 'deExifyImages' which performs a Profile("*") call just before the resizing. This removes all Exif information in resized pictures and thus, saves some disk spaces and network consumption. This is specially noticeable on thumbnails an images list pages. Patch from Leo Breebaart . - the "Unknown discipline ':utf8'" bug in Perl versions older than 5.8.0 has been corrected. - images were sometimes copied even if they were identical. This has been corrected and thus, runtime speed has been improved (about 15-20% on my album without regenerating images). Patch from Stuffed Crust . - the ' (quote) character was not correctly encoded in URL. Reported by Benjamin Wilbur . - corrects a bug where descriptions containing a ' (quote) were used in javascript (like information popup window in joi templates). - added icons for custom huge picture size in joi templates (see panoramas on http://album.sautret.org/200_vacances/700_Irlande_2003/thumb5.html). - japanese translation (ja) has been added. Thanks to Yoshinori Okuji - german translation (de) has been updated. Thanks to Christian Bang . BINS 1.1.22 ----------- - Perl 5.8 UTF-8 file writting problem has been corrected. - htmldefaults option of HTML::Clean has been removed, because it breaks UTF-8 strings in Perl 5.8 - added satyap style templates from Satya . - added Dutch translation (nl). Thanks to Eelco Maljaars BINS 1.1.21 ----------- - PNG images can now be used directly in the album (even if then are still renamed to .jpg...). - File timestamps are now preserved when they are copied in the gallery. - bins_cleanupgallery script has been added. Use it to remove any unused file in your HTML galleries. Run it without argument for usage information. Note that this script is still experimental, so if it performs wrong, just re-run bins to recreate erased files. This program was written by Jochen Schaeuble . - default templates has been updated as follow : * link element was added in default templates to enable Mozilla's link prefetching feature and site navigation toolbar. (http://www.mozilla.org/projects/netlib/Link_Prefetching_FAQ.html) Patch from Chris Croome. * a width problem was corrected in the "In this album" column and the overall display now uses 90% of the screen. Patch from Migrec. * imagePageCycling option now works in default templates. Bug reported by Migrec. - joi templates have been updated by Joachim Kohlhammer as follow : * the full width of the browserwindow is used; the width of the navigationbar is set to a fixed width * more colors and mouse-over-highlights * usage of custom stylesheets per subalbum (config option customStyleSheet, works like the backgroundImage-option) * initial support for video, the number of media files is displayed along with the number of images and subalbums * the Mozilla next/previous-buttons-navigation-collapse-bug is fixed Note there are still some known problems with this version of the joi templates : * Konqueror displays the lower info-popup wrong * Opera has problems with all (?) mouseover-popups - A mailing-list about BINS has been set up, thanks to Chris Croome. See http://www.email-lists.org/mailman/listinfo/bins for information. BINS 1.1.20 ----------- - corrects bug with UTF-8 local encoding BINS 1.1.19 ----------- - added Traditional Chinese translation (zh). Thanks to Chris Chau - es.mo (spanish messages file) was not included in the archive. BINS 1.1.18 ----------- - joi templates has been updated by Joachim Kohlhammer : * The Albumtree works now correctly, even the thumbnail for the root-album works, i.e. no more broken images. * New icon for the albumtree. * Redesign of the image-view. The icons moved to the left border. * Leave was renamed to Home; the variable in the template is now called HOME_LINK. The icon was changed to a little house. The old icon is still included. * If the option pathImgNum is set, the image-view shows (Image/Imagecount) in the path. * The path contains a icon for each level (corresponding to the type of the level (albumtree, album, image)) if the variable pathShowIcon is set to 1. * In the Thumbnailview the bar with the next/prev-buttons shows only if there are two or more pages. If the bar shows, it now has a grey background. * The "cycling" of the thumbnailpages and the imageviews can be disabled by setting the options thumbnailPageCycling and imagePageCycling to 1. - If only one Thumbnailpage exists, the navigation bar shows "Thumbnail Page" instead of "Thumbnail Page 1". (from Joachim Kohlhammer's patch) - select LATIN1 as default encoding on systems lacking the locale command (like *BSD systems) (patch from Dan ). - added new parameter emptyAlbumDesc to get rid of the "No long/short description available" message if no description was set. - added Spanish translation. (thanks to David Barroso). BINS 1.1.17 ----------- - new parameter feedbackMail to add a link "Send Feedback" in the pages (only used in the joi templates for now). - new parameter treePreview to add a the thumbnail album in the tree page (only used in the joi templates for now). - new parameters backgroundImage & excludeBackgroundImage to use an image as a wallpaper (only used in the joi templates for now). - joi templates have been updated, using above features. (templates and patch by Joachim Kohlhammer). - Russian translation has been updated. (thanks to Andrei Emeltchenko). BINS 1.1.16 ----------- - static elements (icons, css, javascript, etc.) can now be used by the templates, by using a static subdir in the templates directory (see the joi templates). - joi templates has been added. It uses icons, css and javascript. See http://album.sautret.org/300_lieux/500_Paris/index.html for an example applied on some of the sub-albums of my main album. You can use it with the templateStyle parameter in the binsrc or album.xml, or with the -s command line parameter (see bins(1) man page). (templates and patch by Joachim Kohlhammer). - new parameter homeURL has been added to link your home page to the Leave button of the joi template. - javaScriptPreloadImage parameter has been renamed to javaScriptPreloadThumbs. New javaScriptPreloadImage parameter can be used to add some javascript code in image pages to preload the next image of the same size when current one is loaded, to speed up the album browsing. (patch from David Panofsky). - added Russian translation. (thanks to Andrei Emeltchenko). - Mandrake 9.0 and NetBSD packages are now available. Check the download page. (mdk rpm by Cédric Thevenet, NetBSD package by Thomas Klausner <(wiz at netbsd dot org>) - install.sh script can now install BINS in specified directories. For example, to install it in /opt/bins, use the following command : PREFIX=/opt/bins install.sh BINS 1.1.15 ----------- - New parameter linkInsteadOfCopy has been added, to create a link to the image in the destination directory instead of copying it, when it's possible. Patch from Vincent Bernat. - Correct a bug that crashed bins with Perl 5.8.0 Patch from Marty Leisner - Include links for movie files (avi, mpeg and mov) in the navigation bar of albums ("In this album" upper left box). Patch from Vincent Cautaer. - Scale method (to created scaled pictures and thumbnails) can now be chose with the new scaleMethod parameter. It can be either scale or sample. sample is faster, scale is better. Idea from Mark W. Eichin. - Don't perform rotation on files matching the regexp defined by the new noRotation parameter (default to _Orig suffix). This can be used in conjunction with scaleIfSameSize=0 and a scaled size of 100%x100% to keep original pictures in your album. Patch from Vincent Cautaer. - Correct a bad behavior with some little pictures when scaled sizes uses mixed pixels and percentages. Patch from Vincent Cautaer. - jpegtran can now be used with image names containing spaces. Patch from Vincent Bernat. - Define $verbose earlier to avoid warning. Patch from Vincent Bernat. - Chop local encoding to avoid carrier return. Patch from Vincent Bernat. - A sample album.xml file is provided in the doc directory. Take a look at it to see how you can customize a album. BINS 1.1.14 ----------- - Some image files and directories can now be excluded by setting some regexp to excludeFiles and excludeDirs new parameters. excludeDirs is set to ^CVS$ in default config, and thus, CVS subdirs aren't processed by bins now. - HTML generation performances have been increased by using the blind_cache parameter of HTML::Template. Thanks to Mark Eichin for this one. - Corrected a bug that wrongly set width and height of thumbnails and prevented Internet Explorer (at least version 5) to display them. - Changed the image template so that Internet Explorer can display the title tooltip on the prev/next thumbnails (when thumbPrevNext is 1). - bins now process .thm (THuMbnail) files. Accroding to Mark Eichin, Canon cameras that do movies generate mvi*.thm files which are really small JPEGs with exif data. BINS 1.1.13 ----------- - It is now possible to use the parameter in picture description files to have different scaled images number and scaled sizes for pictures in the same album (for example, one can have three scaled pictures, small, medium and big, for most of the images of an album, and a fourth one, huge, for big panoramas). Some other parameters, such as titleOnThumbnail, defaultSize or thumbnailBackground, can now also be used on a per image basis. - A bug introduced in 1.1.10 version that caused scaleIfSameSize parameter to be always 1 has been corrected. Thanks to Mark Eichin for pointing out the problem and to Dan (mcmahill @ mtl.mit.edu) and Kamil Iskra for the correction path. - jpegtran can now be used even if it cannot handle the same file in input and output (this is the case for the jpegtran shipped with most GNU/Linux distribution, except Debian). Patch from Kamil Iskra. - Corrected encoding problem on creation date. BINS 1.1.12 ----------- - Sorting order for directories and/or pictures can now be reversed, using the -r command line option or the reverseOrder parameter. Patch from Christian Hoenig for the -r option. - A bug on automatic rotation of destination image when -o was used has been corrected (width and height were inversed). - French translation has been corrected. BINS 1.1.11 ----------- - Some javascript code is now added in thumbnails pages to preload thumbnails of the next page when current one is loaded, to speed up the album browsing. This can be deactivated with the new javaScriptPreloadImages parameter. - Generated HTML code is now cleaned up to reduce the size of pages and thus, speed up browsing. This reduces the size of HTML BINS files by about 30%. This uses the HTML::Clean(3) library (new dependency). This can be deactivated with the new compactHTML parameter. - Use of the jpegtran program is now deactivated in default config (some versions fail to perform rotation correctly). A new parameter rotateWithJpegtran has been added. Set it to 1 in binsrc to continue to use jpegtran. - Added some non breakable spaces in HTML code. - Strip . (dots) in small size names when creating file names (this caused problem with italian i18n). You may have to delete all your generated HTML files before running bins on a old italian album to clean it up. - Some minor bugs have been corrected. - French translation has been corrected. BINS 1.1.10 ----------- - Most of the formats that ImageMagick can handle are now supported by BINS. See the @knownImageExtentions variable in the configuration section in bins. - Italian i18n has been added. Thanks to Lele Gaifax (lele @ seldati.it). - added 'ignore' parameter, that works like the -i command line options. - added -n command line option and 'hidden' parameter to prevent some sub-album from being linked, in the same way -i and 'ignore' works. This can be used to create private albums. - Remove link to details page if there is no data about the picture. - new parameter stripDirPrefix to strip numeric prefix in directories, like the -p command line option. - Typos corrections (patch from Leo Breebaart). BINS 1.1.9 ---------- - Corrected bug which broke album thumbnails when using include_images. Patch from Mark W. Eichin. - Corrected bug that crashed bins when run on some particular images, in particular grayscaled JPEG. - Corrected bug that crashed bins when run on some particular exif structures images. Patch from Klaus Ethgen. - Corrected problem with -v option that appeared in 1.1.8 version. - New 0.7 version of Mark W. Eichin's bins-edit-gui which corrects some miscellaneous bugs. See RELEASE.gui file for more details. BINS 1.1.8 ---------- - Use of color styles to choose a set of colors via the colorStyle parameter in the config/desc files or using the new -c command line option. Color styles provided in the binsrc are blue (default one), green, ivory and pink. - Get charset encoding from the system's locales, instead of the ISO-8859-1 hardcoded value. - new -f command line option to use an alternate configuration file instead of ~/.bins/binsrc. (patch from Bill Carlson). - Correct a bug with read only images and scaleIfSameSize=0 (set write permission on destination image after copying it). Thanks to Mark W. Eichin for the bug report. - Correct some bugs with the -e option (editable albums). (patch from Christian Hoenig). - Correct bugs with command lines parameters (command line options now override config file parameters). - Use of verbose functions to display command line messages (patch from Christian Hoenig). - Updated man page, thanks to Mark W. Eichin. - New 0.6 version of Mark W. Eichin's bins-edit-gui which adds user-specified rotation to interface plus some other improvements. See RELEASE.gui file for more details. BINS 1.1.7 ---------- - Use of HTML:Template to manage HTML creation from template files. Thus, the HTML code is totally separated from the Perl code. - new version 0.5 of bins-edit-gui by Mark W. Eichin, supporting i18n via gettext (French translation is provided). See RELEASE.gui file for more details. BINS 1.1.6 ---------- - rotation can now be performed on destination images, thus, original images can be preserved. This is controlled by the rotateImages parameter. See the comment on it in the binsrc for more information. Note that you may have to manually add this attribute in the desc file of picture if the original image was already rotated by previous version of BINS (or else, the original image will be rotated each time you run BINS). - the priority attribute is added in the exif tag in XML desc files to use value from desc file instead of exif data from image file (normally, data from image file takes precedence on values from XML desc file). In particular, this is used to not read the Orientation tag in image file when the original is already rotated. - use of the title HTML attribute to show tooltips on prev and next links (display title of picture), sizes (display long names and resolution) and other links (misc help). - display the current album thumbnail in sub-albums page if it has pictures, with links to the first thumbnail page. This is controlled by the albumThumbInSubAlbumPage parameter (see binsrc file). - a bug on sample images with special characters in the file name has been corrected. - man pages have been added. Thanks to Mark W. Eichin for writing them. - new version 0.4 of bins-edit-gui by Mark W. Eichin, see RELEASE.gui file for more details. BINS 1.1.5 ---------- - new bins-edit-gui program to set or edit description fields using a GTK+ graphical interface. Thanks to Mark W. Eichin who wrote this program. - an "ignore" directive for the album.xml has been added with a new -i command line option, so that entire albums can be ignored (not indexed and published) (patch from Rene Weber) - new -e option to add link to .xml description files in HTML album, to ease the edition of description fields. (patch from Christian Hoenig) - number, sizes and size names of scaled images can now be personalized in config files and desc files (see comment in binsrc). - the default scaled image size (which is displayed when user clicks directly on the thumbnail in the thumbnails page instead of one of the size name) is configurable in the config files using the defaultSize parameter. - check explicitly for -t directory existing (catches typos) (patch from Mark W. Eichin). - clearer -h explanation of what -t does, and clarification of what -p does. (patch from Mark W. Eichin) - use of generic exif tag "Software" and "Owner" instead of Canon specific ones. (patch from Christian Hoenig) - transform the Apex Value to the exposure time in seconds for ShutterSpeedValue. (patch from Christian Hoenig) - add empty description fields in the section when the image description file is created to ease later edition with an text editor (this controlled by the createEmptyDescFields parameter in the configuration files). (patch from Christian Hoenig) - corrected a bug with the "-o copied" command line option. (patch from Rene Weber) - the addition of "all thumbnails" pages for the parent directory and sub-directories that have thumbnails that take more than page for off-line browsing. This is controlled by the allThumbnailsPage parameter and is an alpha feature and doesn't seems to works properly. It is deactivated in the default config. (patch from Rene Weber) BINS 1.1.4 ---------- - strip control code characters in Exif tag name. Some DigiCam (at least Kodak ones) puts some 0 code in their Exif tag names, which crashed bins or bin_edit during the XML parsing. BINS 1.1.3 ---------- - add a parameter to display thumbnails close to the previous and next link at the bottom of the image page. Thanks to Rene Weber for the patch. - new parameter templateStyle and command line switch -s to choose a style of template. The only style provided for now is "default". If anyone want to make some new ones, don't hesitate to contact me, I'm so bad at HTML design... - new template footer.html to add a footer on all generated pages. Thanks to Rene Weber for the patch. - add a parameter thumbnailBackground that allow to add a background colour to the thumbnail's cell in the thumbnails page so that if the top and bottom borders are wider than the image (for example, if it is in portrait mode), instead of spilling over, there is a border around the whole picture. Thanks to Rene Weber for the patch. - center the list of image size names under thumbnail. Thanks to Rene Weber for the patch. BINS 1.1.2 ---------- - use of configuration files /etc/bins/binsrc and ~/.bins/binsrc to personalize BINS. - personalization parameters can be used in album or image description files too. - new Exif tags for ISO, Exposure Program, Original Image Width and Length, and Compression Quality (tested with Olympus camera). Thanks to Rene Weber for the patch. - new install script. - BINS is now in Sid (Debian unstable version), thanks to Mark W. Eichin. - some typos corrections (thanks to Mark W. Eichin and Rene Weber). BINS 1.1.1 ---------- - automatically rotate picture if the Orientation EXIF tag is found and the orientation isn't correct. This tag is set when you rotate pictures on the DigiCam. For JPEG files, BINS use jpegtran if found, otherwise use mogrify (form ImageMagick). - corrected bug in reading EXIF fields from picture file. - corrected bug on date format (gettext doesn't seems to work with perl string containing backslash, if anyone has an idea...). For now, default date format is set to French. You have to set it manually if you want to change it : just edit the Transform field of the date record in the %fields hash in the configuration of bins file (near the beginning, read comment). - removed forgotten debug output. BINS 1.1.0 ---------- - new details pages which displays all information available on file and DigiCam settings for each picture, with tooltip explaining the meaning of some fields. Additional information for Canon DigiCams are provided. - customizable charset encoding, including full support for UTF-8 (Unicode), with Generation of the Apache .htaccess file for correct encoding charset in HTTP headers. - use XML as desc file format (with a utility to convert old .txt format to new .xml format called bins_txt2xml). - all Exif information is now saved in the XML description file, preventing they disappear when the image is modified. - ability to change background color (thanks to Christian Hoenig). - center links under thumbnails. - don't center decription fields under picture. - corrected bug on URL that wasn't correctly escaped in tree page and for album thumbnails (thanks for Andrew Ruthven for this last one). BINS 1.0.4 ---------- - use of the tags to show tooltips on short size names. - added a sample album.txt and album_fr.txt in the templates directory. - complete the doc with use of album.txt. - complete the doc with names of the mandrake 8.1 & 8.2 packages to install. (thanks to Cédric Thevenet) - display BINS version at bottom of each page. BINS 1.0.3 ---------- - Correct a bug with path of thumbnails in album page when an album.txt is used - new command line option -d to control addition of EXIF tags in description files - New parameter $defaultSize to turn thumbnails into a link - Use more appropriate alt on thumbnails - Work around for corrupt images that return a zero size (thanks to Bill Carlson) BINS 1.0.2 ---------- - Correctly escape space and other odd characters in directory & file names using URI:Escape. - correct a random bug that caused problems in HTML generation when I18N is used. - added date of generation in HTML - added BINS version and CVS Id tag in generated HTML - some tables where empty when no description field exists (this is not allowed by HTML 4.0) - fix some minor problems - some code clean up BINS 1.0.1 ---------- - added German (thanks to Colin Marquardt and Polish translations (thanks to Grzegorz Borek ). BINS 1.0.0 (differences with SWIGS 0.1.1) ---------- - Possibility to display the title of each image on top of its thumbnail. (see the $titleOnThumbnail parameter at the beginning of the bins file) - Possibility to display the thumbnails in the image list page, if $thumbnailInImageList parameter is set. Be warned that this may produce a really loaded page if the album contains lots of pictures. (see the $thumbnailInImageList parameter at the beginning of the bins file) - Template modified & some little bugs corrected to produce some valid HTML 4.0 Transitional pages, as checked by the WDG HTML Validator (http://www.htmlhelp.com/tools/validator/source.html). - I18N, using Locale::gettext, to produce fully translated album (French translation is provided). If Locale::gettext is not installed on the running system, album will be generated in English. - Verbose command line option, with different levels, to see work progression. - Use of a generic parameter to define the list of fields describing a picture, with the possibility of reading the EXIF data structure (see below). See the @fields structures in the bins file for details. - Possibility of reading the EXIF data structure found on some images (usually, those produced by digital cameras) to fill automatically the desired fields (date and time, for example). See the @fields structures in the bins file for details. - bins_edit utility: it can be used to set or edit description fields on several pictures in one command. - Size of scaled pictures can now be expressed in percentage of the original picture, i.e. you can write my @scaledWidths = ("640", "66%","100%"); my @scaledHeights = ("480", "66%", "100%"); and SWIGS generate 640 x 480, 1024 x 768 and 1600 x 1200 scaled pictures from an 1600 x 1200 original picture. It is useful if your pictures are not all of the same size. - Don't convert an image if it has already the right size, if $scaleIfSameSize parameter is 0. In this case, the original picture is just copied, instead of being rescaled to the same size with a new JPEG quality. Thus, you can keep the original picture in the album (otherwise, you loose conpression level for jpeg). - Don't generate scaled and thumbnails images if they already exists and the original is older. This speed up regeneration of albums. - Use Image::Size insteed of loading an image to get its size. This speed up regeneration of albums. bins-1.1.29/CREDITS0000644000175000017500000000431510303167611014344 0ustar jeromejerome00000000000000BINS Credits BINS is a modified version of SWIGS 0.1.1 created by Jérôme SAUTRET bins-edit-gui was written by Mark W. Eichin . joi template was writen by Joachim Kohlhammer satyap template was writen by Satya . petrus template was writen by Thus0 , based on joi template. marc template was writen by Marc Menem , based on joi template. mwolson template was writen by Michael Olson . martin template was writen by Martin Pohlack , based on marc template. German translation by Colin Marquardt Polish translation by Grzegorz Borek Italian translation by Lele Gaifax Russian translation by Andrei Emeltchenko Spanish translation by David Barroso Traditional Chinese translation by Chris Chau Esperanto translation by Pier Luigi Cinquantini Finish translation by Ville Pohjanheimo Japanese translation by Yoshinori Okuji Dutch translation by Eelco Maljaars Hungarian translation by Aurel Gabris Catalan translation by Joan Antoja Sabin Thanks also to all the other contributors for their patchs, comments or other contributions. Image & Exif tag descritions are from - the _Description of Exif file format_ document of TsuruZoh Tachibanaya (tsuruzoh @ ba.wakwak.com) you can find here it here: http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html - _EXIF MakerNote of Canon_ from David Burren (db061 @ burren.cx) you can find here it here: http://www.burren.cx/david/canon.html - and from the Image::Info documentation. SWIGS 0.1.1 Credits * David Guichard for bug fixes and cleanup for 0.1.1 release * Brent Bryan (bryanba@whitman.edu) for design advice, html templates, and debugging. And kicking my butt so I keep working on this. * Initial code based on IDS 0.21 by John Moose (moosejc@muohio.edu) bins-1.1.29/doc/0000755000175000017500000000000010303167611014066 5ustar jeromejerome00000000000000bins-1.1.29/doc/bins-edit-gui_man.html0000644000175000017500000001441210303167611020251 0ustar jeromejerome00000000000000 BINS

BINS

Name

bins-edit-gui -- Set fields in XML picture description files for BINS (using a GNOME-based GUI)

Synopsis

bins-edit-gui [files...]

DESCRIPTION

This manual page documents briefly the bins-edit-gui command.

bins-edit-gui sets values in the XML picture description files that bins(1) uses to generate galleries. It displays the image (scaled down to fit the window) and allows you to fill in the predefined fields (or add new ones.) For command-line editing of the same data, see bins_edit(1).

OPTIONS

This program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below.

file

file is the filename of the image itself.

-v, --version

Displays program version.

-v, --version

Displays program version.

-h, --help

Displays command-line options.

--debug

Enables random developer debugging messages.

COMMANDS

C-n Next file

Save current tags set (if any changes have been made) and move on to the next image.

M-Page Down Forward 10

Save current tags set (if any changes have been made) and skip forward by 10 files.

C-p Previous file

Save current tags set (if any changes have been made) and move back to the previous image.

M-Page Up Back 10

Save current tags set (if any changes have been made) and skip backwards by 10 files.

M-Home Start of List

Save current tags set (if any changes have been made) and jump to the first file.

M-End End of List

Save current tags set (if any changes have been made) and jump to the last file.

M-a Auto-fill

Fill in any blank fields with the values from the most recently seen image. Particularly useful for copying a location or event across a set of images.

Revert

Reload tags from the XML file, wiping unsaved changes.

C-s Save

Save changes, if any.

F2 Album

Edit the album this picture is in. (Under construction, but functional.)

F3 Open

Not yet implemented. Should provide a file browser later.

> Rotate Right

Rotate image to the Right (Clockwise.) Actually sets the Orientation tag with priority 1 so that it overrides the corresponding EXIF tag; it does not modify the image file itself.

Cancel rotation

Cancels any current changes to the rotation tags (effectively, this is a "revert" function for the rotation, it doesn't to back to the original EXIF tags in the JPEG file.)

< Rotate Left

Rotate image to the Left (Counter Clockwise.) Actually sets the Orientation tag with priority 1 so that it overrides the corresponding EXIF tag; it does not modify the image file itself.

C-q Quit

Quit program, saving current changes (if any.)

About

Display About box.

License

Display License box.

EXAMPLES

Edit all the images in a directory:

bins-edit-gui $(find bins-picture-dir -name '*.jpg')

SEE ALSO

bins (1), bins_edit (1).

AUTHOR

This manual page was written by Mark W. Eichin .

bins-1.1.29/doc/bins_edit_man.html0000644000175000017500000002370010303167611017551 0ustar jeromejerome00000000000000 BINS

BINS

Name

bins_edit -- Set fields in XML picture description files for BINS

Synopsis

bins_edit [-a | --album] [-m | --html] [-t title | --title title] [-e event | --event event] [-l location | --location location] [-p people | --people people] [-y date | --date date] [-d description | --description description] [--longdesc longDescription] [--shortdesc shortDescription] [--sample pictureFileName] [-g tag=value | --generic tag=value] [-h | --help] [-v | --verbose] [-q | --quiet] [file] [files...]

DESCRIPTION

This manual page documents briefly the bins_edit command.

This manual page was written for the Debian distribution because the original program does not have a manual page. Instead, it has documentation in HTML in /usr/share/doc/bins/index.html as well as a --help option.

bins_edit sets values in the XML picture description files that bins(1) uses to generate galleries.

OPTIONS

This program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below.

file

By default, file is the filename of the XML file with the image properties. If the argument has no .xml suffix, it is added, so you can directly give picture names on the command line. Spaces and other special characters (even newlines) can be used in values given as parameters as long as they are enclosed between quotes.

If the --album option is given, the filename refers to the directory of images, and the album.xml in that directory will be modified instead.

-a, --album

edit album description (instead of the default of editing the image description.) In this case, the file parameter must be the source directory of the album. Only the --title, --longdesc, --shortdesc and --sample switches make sense with this option.

-m, --html

input value will be interpreted as HTML code, thus, no HTML encoding or quoting will be done.

-t title, --title title

Set the title (of an image.)

-e event, --event event

Set the event name (of an album or image.)

-l location, --location location

Set the location (of an image.)

-p people, --people people

Set the list of people (of an image.)

-y date, --date date

Set the date (of an image.)

-d description, --description description

Set the description (of an image.)

--longdesc longDescription

Set the long description (of an album.)

--shortdesc shortDescription

Set the short description (of an album.)

--sample pictureFileName

Select the sample picture, within this album, to be used on the album list (template subalbum.html.) Note that the filename is relative to the album directory, and thus doesn't have a directory component.

-g tag=value, --generic tag=value

This lets you set arbitrary fields in the relevant XML file (of the image or the album.) Generic tags appear inside description which appears inside image; the tag appears as the name attribute of a field element, and the value appears as the content of the element.

-h, --help

Gives quick help (which this man page is based on.)

-v, --verbose

This switch can appear several times to increase verbosity level.

-q, --quiet

Suppress output.

EXAMPLES

Set the title of the Image.jpg file to "My picture":

bins_edit -t "My picture" Image.jpg

Set the title and location of all JPEG pictures in the directory:

bins_edit --title Holiday --location Paris *.jpg

Use of HTML values:

bins_edit --html --description '<b>BINS</b> is cool' file.jpg

Set the title short description and sample image of the album in the current directory (note the dot as final parameter):

bins_edit -a -t "My Album" --sample image.jpg --shortdesc "This is my album" .

SEE ALSO

bins (1).

AUTHOR

This manual page was written by Mark W. Eichin for the Debian system (but may be used by others). As it is mostly derived from the bins_edit program itself, it is covered by the GNU General Public License.

bins-1.1.29/doc/bins_man.html0000644000175000017500000007372410303167611016557 0ustar jeromejerome00000000000000 BINS

BINS

Name

bins -- Generate a static HTML photo albums using XML and EXIF tags

Synopsis

bins [-f config_file] [-o STR] [-d STR] [-c color_style] [-s style] [-t template_dir] [-p] [-e] [-i iKey,iKey...] [-v X] [-h] {source_dir} {target_dir}

DESCRIPTION

This manual page documents briefly the bins command.

This manual page was written for the Debian distribution because the original program does not have a manual page. Instead, it has documentation in HTML in /usr/share/doc/bins/index.html as well as a -h option.

bins is a program that takes a collection of directories and files containing JPEG images and XML descriptions, combines them with a set of HTML templates, and produces a complete photo gallery of static HTML files, rescaled images at three sizes, and thumbnails.

OPTIONS

-f config_file

use an alternative configuration file, instead of ~/.bins/binsrc..

-o STR

Tells script to use only one copy of image using HTML size specs (height, width specs in the image tag) for scaled versions (instead of generating several images, one for each size).

Default is false.

STR is an optional argument to set how the one image is generated. Possible values:

scaled

(make scaled copy of orig in target_dir hierarchy, sized to max size). Default.

copied

(copy orig to web dir)

custom

(use copy if filesize < 1meg resize, resave, if bigger than 1 meg)

-d STR

Determine if tags found in EXIF structure are added in desc files.

STR is one of "always", "never" or "exist" ("exist" only adds if the desc file already exist.) Default is always.

-c color_style

Color style to use. Can be blue (default one), green, ivory and pink or any other one defined in configuration/description files. This option is deprecated (and thus, not supported by all templates), in favor of alternate stylesheets and the customStyleSheet parameter.

-s style

Template style to use (styles provided for now are joi, marc, martin, mwolson petrus, satyap and swigs).

-t template_dir

Specify location of html templates.

Default is ~/.bins, falling back to default versions in /etc/bins/templates.style.

-p

Numbers preceding the album title, followed by an underscore are stripped. If this option is given, then prefix ordering numbers on directories are removed. For example, if one has directories may, june, and august, they can be renamed 0_may, 1_june, and 2_august and they will appear in the album in the correct order.

-e

Tells the script to generate an editable version of the album. If set, some more links and icons are added to directly access the .xml files for editing. This is for editing purposes, not for a final album.

-i iKey,iKey...

Sets "ignore" keywords which will be compared against the contents of the ignore field of the album's XML file, in the ignore field in description section. If any of the iKeys match those in the album's "ignore" field, that album will not be processed. See also the ignore parameter.

-n iKey,iKey...

Sets "hidden" keywords which will be compared against the contents of the ignore field of the album's XML file, in the ignore field in description section. If any of the iKeys match those in the album's "ignore" field, that album will be hidden: it will not be linked anywhere. See also the hidden parameter.

-v X

X is the verbosity level (between 0 and 3)

-h

Show the help string this man page was originally based on.

SETTINGS

bins is also controlled by other files.

/etc/bins/binsrc, ~/.bins/binsrc

The binsrc files are XML files with a top level bins tag. There are three element names with bins: parameter, colors, and sizes. Each of these has a name attribute which names the data in the element content.

The colors element has a style attribute, that can be used with the colorStyle parameter or the -c command line option. It contains color elements. The color elements name has one of the following values which is substituted into the template files. This tag is deprecated, in favor of alternate stylesheets and the customStyleSheet parameter.

PAGE_BACK
PAGE_TITLE
MAINBAR_BACK
MAINBAR_TITLE
MAINBAR_LINK
MAINBAR_CURRENTPAGE
SUBBAR_BACK
SUBBAR_LINK
SUBBAR_CURRENTPAGE
SUBBAR_TITLE

The sizes element contains size elements which each have a name attribute, a shortname attribute, a height attribute, and a width attribute. These default to

Small, Sm, 40%, 40%
Medium, Med, 64%, 64%
Large, Lg, 100%, 100%

name and shortname are used in the output HTML and in generated filenames. The default values listed above are passed through gettext for localization; overrides in binsrc files are not, and should be in the desired language.

For the parameter elements the name attribute names one of the following parameters.

addExifToDescFile

If set to 1 (the default), write EXIF data found in the image file to the image desc file (but see also the -d flag).

albumThumbInSubAlbumPage

If set to 1 (the default), display the current album thumbnail in sub-albums page if it has pictures, with links to the thumbnails page.

allThumbnailsPage

If set to 1, generate a page with all thumbnails in the album and sub-albums. This is deactivated because it is an alpha feature which seems to not work properly.

backgroundImage

Set this to the image that should be displayed as the background of the album pages. The Image will be copied to the static files directory. This works only with joi, marc, martin and petrus templates for now.

borderOnThumbnails

Width of the border of the thumbnail's image in the thumbnails page, in pixels. 0 means no border.

colorStyle

Name of the color style to use. Default is blue. See also the -c option which takes precedence. This option is deprecated (and thus, not supported by all templates), in favor of alternate stylesheets and the customStyleSheet parameter.

compactHTML

If set to 1, generated HTML code is cleaned up to reduce the size of pages and thus, speed up browsing. This reduces the size of HTML BINS files by about 30%. See HTML::Clean(3) to know how optimizations are performed.

configFileName

Can be set in the global config file, but only influences the basename of the local user config file. Defaults to .binsrc.

createEmptyDescFields

If set to 1 (the default), add empty description fields in the description section when the image description file is created to ease later manual editing.

createHtaccess

If 1, create an Apache .htaccess file in the root dir of the album with the encoding charset bound to html and htm files. This is a parameter global for the album, it can't be set in album.xml.

customStyleSheet

Set this to the CSS file that should be used as the stylesheet for the album pages. The CSS file will be copied to the static files directory. This works only with joi, marc, martin and petrus templates for now.

dateString

Specify the format of date strings. This variable accepts all formats supported by date(1).

defaultSize

Size to use when user clicks directly on the thumbnail in the thumbnails page instead of one of the size name. 0 is the first size (Small in the default config), 1 the second (Medium), and so on. Set this variable to -1 if you don't want the thumbnail to be clickable.

deExifyImages

If set to 1, do NOT copy exif data found in the source images to any of the generated resized images. Setting this option can yield significant space savings, especially for thumbnail and imagelist pages.

emptyAlbumDesc

If set to 1, and album desciption is not set, no message will be displayed (instead of the "No long/short description available" one).

enlarge

If set to 1, small images are enlarged in the "med" and "large" series. (defaults to 0).

excludeBackgroundImage

If set to 1, the image with the name given in backgroundImage will be excluded from the current directory.

excludeDirs

Exclude directories that match this regexp (if set). Set to ^CVS$ in default config, so that CVS subdirs aren't processed by bins.

excludeFiles

Exclude image files that match this regexp (if set). No image files are excluded in default config.

globalConfigDir

Can't usefully be set, since it has already been used when the first config file is read. Defaults to /etc/bins.

hidden

Put here a comma separated list of keyword. If one on this keyword is found in the ignore field in the description section of an album.xml, then this sub-album will be hidden, i.e. it will be generated but not linked anywhere. You can also use the -n command line option.

homeURL

Set this to your home page's URL. This is used for the leave button in some templates.

htmlEncoding

HTML pages charset encoding.

ignore

Put here a comma separated list of keyword. If one on this keyword is found in the ignore field in the description section of an album.xml, then this sub-album will be ignored, i.e. it will not be processed. You can also use the -i command line option.

imagePageCycling

If set to 0 next/prev-Links will be hidden if the actual page is the last/first Image page.

javaScriptPreloadImage

If set to 1, add some javascript code in image pages to preload the next image of the same size when current one is loaded, to speed up the album browsing.

javaScriptPreloadThumbs

If set to 1, add some javascript code in thumbnails pages to preload thumbnails of the next page when current one is loaded, to speed up the album browsing.

jpegQuality

Quality of scaled jpegs (lower number = more compression, lower quality) in 1-100 range (default of 75). See imagemagick docs for more details.

linkInsteadOfCopy

If set to 1, we link the picture instead of copying it if possible (i.e. scaleIfSameSize is set to 0 and destination image doesn't have to be rotated: rotateImages is set to original or none, or orientation is already correct). Warning : if whenSrcSmaller is set to enlarge, original image can be modified.

linkRelative

If set to 1, we use a relative path for the link if linkInsteadOfCopy is set to 1.

maxAlbumsForLongSubAlbum

If the number of sub albums is greater (than this value which defaults to 20), generate a short sub album page instead of the long one. (Short sub album pages appear to be unsupported at the moment; this option is disabled.)

noRotation

Don't perform rotation on files matching this regexp. This can used in conjunction with scaleIfSameSize=0 and a scaled size of 100%x100% to keep original pictures in your album.

numThumbsPerPage

Number of thumbnails (default of 16) displayed in each page in an album.

pathImgNum

If set to 1 the path in the imageview contains the number of the current image.

pathShowIcon

If set to 1 the path contains icons.

previewMaxWidth, previewMaxHeight

Max thumbnail width and height (default 150x150).

jpegProgressify

whether to convert generated jpegs to progressive using jpegtran (if available). can be never, always, or smaller (if the progressified file is smaller than the baseline).

reverseOrder

Are we reversing sorting order for pictures or directories ? 0=none, 1=dirs, 2=pix, 3=both. See also -r command line option.

rotateImages

Do we rotate images if the Orientation EXIF tag is found? If set to original (the default), the original image is rotated the first time, and then it is left untouched. If set to destination, this is all the scaled images and thumbnails that are rotated. This is less efficient, but the original images are preserved (and is useful if the original images are read-only). If set to none, no rotation is performed.

rotateWithJpegtran

If set to 1, bins try to use the jpegtran program to rotate JPEG images if it is available. jpegtran is faster and lossless, but some versions fail to perform rotation correctly, so it is deactivated in default config. If set to 0 or if jpegtran is not found, mogrify (from ImageMagick) is used.

scaleIfSameSize

If set to 1, we scale the picture even if destination size is the same as the original picture, if set to 0 (the default), the original image is just copied if the size is correct.

scaleMethod

What method should be used to create scaled pictures and thumbnails ? Can be either scale or sample. sample is faster, scale is better.

searchEngine

If 1, generate a search page. Images can be searched on description fields set in the searchFields parameter.

searchFields

Space separated list of description field names used by the search engine, if searchEngine is set to 1.

searchLimit

Maximum results returned by the search engine, if searchEngine is set to 1. Note that if this number is too high, it can hang the browser.

stripDirPrefix

If 1, numbers preceding the album title, followed by an underscore, are stripped. If this parameter is set, then prefix ordering numbers on directories are removed. For example, if one has directories may, june, and august, they can be renamed 0_may, 1_june, and 2_august and they will appear in the album in the correct order. This can be overridden by the -p command line option.

templateStyle

Name of the template style to use. Default is swigs. Other templates provided with BINS are joi, marc, martin, petrus and satyap. Several templates can be used for different sub-album of an album, by using this parameter in the bins section of the album.xml files. See also the -s option which takes precedence over binsrc (but not album.xml).

thumbnailBackground

If set to 1, add a background colour (SUBBAR_BACK) to the thumbnail's cell in the thumbnails page so that if the top and bottom borders are wider than the image (for example, if it is in portrait mode), instead of spilling over, there is a border around the whole picture. By default, use the PAGE_BACK color.

thumbnailInImageList

Display thumbnails on the Image List page, set to 1 by default.

thumbnailPageCycling

If set to 0 next/prev-Links will be hidden if the actual page is the last/first Thumbnail page.

thumbPrevNext

If set to 1 (the default), display thumbnails close to the previous and next link at the bottom of the image page.

thumbsPerRow

Number of thumbnails (default of 4) displayed in each row in an album.

titleOnThumbnail

Should the title be displayed on top on the thumbnail in the thumbnails page? (defaults to 1.)

treePreview

If set to 1, preview thumbnails will be showed in the album tree page. This works only with joi, marc and petrus templates for now.

updateOriginalPerms

If set to 1, read permissions on images will be set, to ensure http deamon will be able to read them.

userConfigDir

Can be set in the global config file (since after the user one is read, it is too late). Defaults to ~/.bins and is processed by bsd_glob (see File::Glob for details.)

xmlEncoding

XML files charset encoding.

image.jpg

The EXIF tags are extracted from the image. Currently only the Orientation tag influences the processing, but a variety of settings are copied into the HTML file generated via the details.html template.

image.jpg.xml

The XML file contains an image element, which contains three child elements:

description

which has field children that contain per-image data. The name attribute names the tag (allowing simple extensibility, see the bins_edit --generic flag) but bins itself currently only makes use of

title
description
people
location
date
event

bins

which works as described with the binsrc file settings, except that many of the settings are not meaningful in the context of a single picture.

exif

which has a cache of values copied from the EXIF tags in the image, to allow simpler processing by other tools.

If a user wants to override the EXIF values and provide a replacement (such as a corrected Orientation or an Owner setting that reflects who you loaned the camera to) adding a priority attribute with a value of "1" will prevent bins from replacing it with the value in the image.

album.xml

This file contains an album element, which contains description and bins stanza as described for an image. The are extensible in the same manner, but bins only makes use of

dirname
descFileName
shortdesc
title
sampleimage
longdesc

include_images.txt

includes image filenames (relative to the current album, i.e. the directory where the include_images.txt file is stored.) Each filename appears on a line by itself; a line beginning with a # is a comment, and lines composed entirely of whitespace are ignored. Otherwise, the line is exactly the filename. These images are included in the order listed, and added after any that actually appear in the directory.

template.html

There are a number of template HTMLfiles which are used to generate the actual images. The base names of these are

tree
imagelist
subalbum
thumbnail
details
image

The default versions of these files in /etc/bins/templates.default should show how they work, as does the HTML::Template documentation. Aside from the COLOR substitutions described above, a template can also reference

BINS_VERSION
ENCODING
GENERATED_DATE
BINS_ID

SEE ALSO

bins_edit (1), jpegtran (1), File::Glob, HTML::Template, imagemagick.

AUTHOR

This manual page was written by Mark W. Eichin for the Debian system (but may be used by others). As it is mostly derived from the bins program itself, it is covered by the GNU General Public License.

bins-1.1.29/doc/index_fr.html0000644000175000017500000005220010303167611016551 0ustar jeromejerome00000000000000 BINS album photo

Attention, cette page n'est à jour par rapport à la version anglaise.

BINS

La page de référence est http://bins.sautret.org/.

Si vous désirez recevoir un mail annonçant les nouvelles versions, allez sur la page Freshmeat de BINS et cliquez sur Subscribe to new releases.


Introduction

Le but de BINS est de créer des albums photos HTML statiques. Voici quelques unes de fonctionnalités de BINS :

  • un album peut contenir d'autres albums (des sous albums) : l'album peut avoir une structure d'arbre ;
  • génération d'une image timbre-poste et d'images à différentes échelles pour chaque image originale ;
  • l'album généré peut être entièrement personnalisé en utilisant des modèles HTML et via des paramètres de configuration qui permettent de modifier : les couleurs, la taille et le nombre des timbres-poste, le nombre et la taille de chaque image à l'échelle (en pixel ou en pourcentage de l'image originale pour la taille), les champs à afficher, etc. Ces paramètres peuvent être changés globalement, par utilisateur, par album, sous-album ou même par image (par exemple, vous pouvez changer les couleurs d'un sous-album ou de la page d'une image particulière). ;
  • plusieurs champs de description (date, lieu, etc.) peuvent être associés avec l'image. Ces descriptions peuvent être auformat texte ou HTML. Il est possible de personnaliser ou d'ajouter des champs. Ces données sont sauvegardées dans des fichiers XML propres à chaque image ;
  • support du format Exif est des appareils photos numériques :
    • BINS peut utiliser la structure de données EXIF que l'on trouve dans certaines images (notamment dans celles générées par les appareils photos numériques) pour remplir automatiquement certains champs (date et heure ou modèle de l'appareil, par exemple) ;
    • BINS utilise le tag EXIF Orientation (qui normalement utilisé quand vous faites une rotation de photo sur votre appareil numérique) pour effectuer une rotation de automatique de l'image vers l'orientation correcte.
    • pour chaque image, une page donne toutes les informations disponibles sur ses caractéristiques et sur les paramètres de l'appareil photo numérique lors de la prise de vue ;
    • des informations supplémentaires sont fournies pour les appareils photos numériques Canon ;
    • une fenêtre d'aide explique la signification de certaines informations ;
    • toutes les informations en provenance du fichier Exif sont sauvegardées dans les fichiers de description XML, évitant ainsi qu'ils disparaissent lors de modification de l'image ;
  • internationalisation (génération d'album dans différents langages) via gettext. Les langues actuellement supportées sont : anglais, français, allemand et polonais ;
  • l'encodage du jeu de caractères des fichiers HTML générés est paramétrable, avec support par défaut de l'UTF-8 (Unicode). Création du fichier .htaccess d'Apache pour l'envoi de l'encodage du jeu de caractères correct dans l'en-tête HTTP ;
  • utilisation de fichiers XML pour sauvegarder les descriptions utilisateur des images et des albums/sous-albums ainsi que les données Exif provenant des images ;
  • les noms de fichiers et de répertoires contenant des espaces et autres caractères spéciaux (sauf /) sont gérés et des URL valides sont créés ;
  • BINS produit du code HTML 4 valide.

BINS (BINS Is Not SWIGS) est une version modifiée de SWIGS (Structured Web Image Gallery System). J'ai fais ces modifications parce que j'en avais besoin. J'ai essayé de contacter l'auteur de SWIGS, mais je n'ai eu aucune réponse, c'est pourquoi j'ai décidé de publier ma version modifiée, au cas où elle intéresse quelqu'un.

Voir le fichier ChangeLog (en anglais) pour les différences entre BINS et SWIGS ainsi que les nouveautés de chaque version.


Exemple

Vous pouvez voir un exemple d'un album généré par BINS sur http://album.sautret.org/. Il s'agit de mon album personnel avec l'I18N française.


Téléchargement

La dernière version de BINS est la 1.1.10.

BINS est maintenant dans Sid (version unstable de Debian). Vous pouvez trouver le paquetage sur la page Debian de BINS.

Un tarball contenant l'ensemble des bibliothèques pour faire fonctionner BINS sur une Mandrake est disponible. Vous aurez quand même besoin d'un des tarballs disponibles ci-dessous.

Attention, le format des fichiers de description des images et des albums a changé dans la version 1.1.0. Lisez le fichier README pour savoir comment migrer vos anciens fichiers de description.

format gzip format bzip2
bins-1.1.10.tar.gz bins-1.1.10.tar.bz2
bins-1.1.9.tar.gz bins-1.1.9.tar.bz2
bins-1.1.8.tar.gz bins-1.1.8.tar.bz2
bins-1.1.7.tar.gz bins-1.1.7.tar.bz2
bins-1.1.6.tar.gz bins-1.1.6.tar.bz2
bins-1.1.5.tar.gz bins-1.1.5.tar.bz2
bins-1.1.4.tar.gz bins-1.1.4.tar.bz2
bins-1.1.3.tar.gz bins-1.1.3.tar.bz2
bins-1.1.2.tar.gz bins-1.1.2.tar.bz2
bins-1.1.1.tar.gz bins-1.1.1.tar.bz2
bins-1.1.0.tar.gz bins-1.1.0.tar.bz2
bins-1.0.4.tar.gz bins-1.0.4.tar.bz2
bins-1.0.3.tar.gz bins-1.0.3.tar.bz2
bins-1.0.2.tar.gz bins-1.0.2.tar.bz2
bins-1.0.1.tar.gz bins-1.0.1.tar.bz2
bins-1.0.0.tar.gz bins-1.0.0.tar.bz2

Installation

Procédure rapide :

  • vérifiez que vous avez les logiciels et bibliothèques nécessaires
  • détarez l'archive
  • lancer le script install.sh (en tant que root si vous pouvez)
  • exécutez bins -h pour obtenir de l'aide, et lisez la section utilisation de ce document

dépendances

Vous avez besoin de Perl pour utiliser BINS, ainsi que des bibliothèques Perl suivantes (les noms de paquetage Debian et Mandrake sont mentionnés quand ils sont connus).

Ce tarball regroupe l'ensemble de ces bibliothèques au format rpm pour Mandrake ou tar.gz quand aucun rpm n'est disponible (voir ci dessous pour l'installation de bibliothèque Perl à partir d'un tarball).

Bibliothèque Perl Paquetage Debian Paquetage Mandrake 8.1 & 8.2
POSIX perl-base perl-base-5.601-7mdk
IO::File perl-base perl-base-5.601-7mdk
Getopt::Long perl-base perl-base-5.601-7mdk
File::Basename perl-modules perl-base-5.601-7mdk
Storable libstorable-perl
IO:String libio-string-perl
Image::Size libimage-size-perl perl-Image-Size-2.903-5mdk
Image::Info libimage-info-perl perl-Image-Info-1.07-1mdk
Image::Magick (avec la collection d'outils ImageMagick) perlmagick perl-Magick-5.4.2.3-3mdk
HTML::Entities libhtml-parser-perl perl-HTML-Parser-3.25-3mdk
URI:Escape liburi-perl perl-URI-1.18-1mdk
XML::Parser::PerlSAX libxml-perl perl-libxml-perl-0.07-5mdk
XML::Grove libxml-grove-perl perl-XML-Grove-0.46alpha-2mdk
XML::Handler::YAWriter libxml-handler-yawriter-perl
Text::Iconv libtext-iconv-perl
Locale::gettext (optionnel si vous ne désirez pas avoir d'album dans une autre langue que l'anglais.) liblocale-gettext-perl perl-gettext-1.0-10mdk

Référez-vous à cette page pour savoir comment installer ces bibliothèques. Vous pouvez trouver l'interpéteur perl et toutes ces bibliothèques Perl sur CPAN.

BINS utilise la collection d'outils ImageMagick, qui est probablement déjà utilisée si vous utilisez une des distributions GNU/Linux communes. Pour vous en assurer, vérifier que vous avez les programmes convert (utilisé pour changer la taille des images) et mogrify (utilisé pour faire les rotations d'images).

BINS peut également utiliser jpegtran pour effectuer les rotations des JPEG. S'il ne le trouve pas, il utilisera mogrify (d'ImageMagick) à la place. Le programme jpegtran peut effectuer des transformations sans perte et il est plus rapide que mogrify. Il peut être trouvé dans le paquetage Debian libjpeg-progs ou dans le tarball jpegsrc accessible sur ce site FTP.

Installation automatique de BINS

Une fois toutes les dépendances remplies, il faut extraire l'archive dans un répertoire de votre choix.

Vous pouvez installer BINS globalement ou pour un utilisateur. Attention, cette procédure va écraser les anciens programmes, fichiers de configuration et templates HTML. Faîtes une sauvegarde si vous les avez modifiés.

pour installer BINS globalement, lancer le scipt install.sh en tant que root. Cela installera les programmes dans /usr/local/bin, les fichiers d'internationalisation dans /usr/local/share/locale et les fichiers de configuration dans /etc/bins. Si vous voulez changer la configuration pour un seul utilisateur, vous pouvez toujours copier le contenu de /etc/bins dans ~/.bins et ensuite éditer les fichiers dans ~/.bins.

Pour installer BINS pour un seul utilisateur, lancer le script install.sh avec cet utilisateur. Cela installera les programmes dans ~/bin les fichiers de configuration dans ~/.bins. Notez que les fichiers d'internationalisation (utilisés pour créer des album dans une langue autre que l'anglais) ne seront PAS copiés, car ils doivent être installés dans /usr/local/share/locale.

Installation manuelle de BINS

Si vous ne faites pas confiance au script install.sh, vous pouvez effectuer l'installation manuellement.

Copiez les fichiers bins et bins_edit quelque part dans votre PATH (/usr/local/bin est approprié ou ~/bin si vous n'êtes pas root). Ensuite copiez le contenu du répertoire template dans /etc/bins ou ~/.bins :


$ cp bins bins_edit ~/bin
$ mkdir ~/.bins
$ cp templates/* ~/.bins

Si vous voulez utiliser l'I18N (traduction de l'album):


$ mkdir -p /usr/local/share/locale/fr/LC_MESSAGES/
$ cd intl
$ cp fr.mo /usr/local/share/locale/fr/LC_MESSAGES/bins.mo

l'exemple donné est pour les traduction en français.

Notez que seul l'album est traduit, les messages fournis sur la ligne de commande sont en anglais


Utilisation

Mettez toutes vos images dans un répertoire, disons ~/image. Vos images peuvent être rangées dans des sous répertoires de ce répertoire. Ensuite, créez un répertoire dans lequel l'album sera créé, au même niveau que le précédent, disons ~/album :
$ mkdir ~/album

Allez au niveau supérieur de ces répertoires :
$ cd ~

Et lancez bins avec les deux répertoires en paramètre (source et destination) :
$ bins images album

Cela va créer un album HTML, avec des éventuels sous-albums, des images timbre-poste et des images à l'échelle.

bins possède des options de ligne de commande. Tapez :
$ bins -h

Pour les voir. Jetez un oeil au README original de SWIGS pour en apprendre plus.

Si vous désirez ajouter des commentaires pour les images, vous pouvez utiliser le programme bins_edit. Par exemple, pour ajouter le commentaire « mon image » à img.jpg, rendez-vous dans le répertoire des image (là ou se trouve img.jpg), et tapez :
$ bins_edit -d "my picture" img.jpg

l'option -d indique qu'il s'agit de la description. Vous pouvez ajouter d'autre champs, comme le lieu ou la date. Lancez bins_edit sans arguments pour voir les champs disponibles. Le texte de la description peut être en HTML avec l'option --html. Vous pouvez lancez bins_edit sur plusieurs images, par exemple :
$ bins_edit -l "Paris" -y "2001" *.jpg

bins_edit créé un fichier .xml pour chaque image. Vous pouvez éditer ce fichier à la main si vous le désirer à l'aide d'un éditeur supportant l'Unicode.

Pour chaque album (et sous-album) vous pouvez également mettre un titre, une description et choisir une image pour représenter l'album. Pour cela, utilisez bins_edit avec l'option --album. Tapez bins_edit --help pour plus d'information.

Vous pouvez personnaliser bins en éditant les valeurs des paramètres du fichier de configuration binsrc. Un tel fichier est fourni avec BINS. Il se trouve dans /etc/bins si vous avez effectué l'installation en tant que root, sinon il se trouve dans ~/.bins. Dans le premier cas, vous pouvez le copier de /etc/bins vers ~/.bins et ensuite l'éditer ~/.bins si vous ne voulez pas changer la configuration globale. Lisez les commentaires dans ce fichier pour plus d'informations.

Vous pouvez également utiliser ces paramètres (quand cela a un sens) dans la section <bins> des fichiers de description des albums (album.xml) ou des images (fichier_image.jpg.xml par exemple). Vous pouvez ainsi changer les paramètres pour un album particulier (ou un sous-album et ses descendants) ou même pour une page d'image.

L'apparence des albums peut aussi être changée via les templates HTML. BINS recherche ces fichiers d'abord dans le repertoire spécifié par l'option -t, puis dans ~/.bins et enfin dans /etc/bins.

Licence

BINS est un logiciel libre, sous la GNU GPL.

BINS est Copyright © 2001,2002 Jérôme Sautret (Jerome @ Sautret.org).

Code original de SWIGS est Copyright © 2000 Brendan McMahan (mcmahahb @ whitman.edu).

Code initial basé sur IDS 0.21 est Copyright © John Moose (moosejc @ muohio.edu).

Software Patent Free Europe Valid HTML 4.01!


Jérôme SAUTRET
Last modified: Sun Jun 9 21:47:09 CEST 2002 bins-1.1.29/doc/index.html0000644000175000017500000001531510303167611016070 0ustar jeromejerome00000000000000 BINS Photo Album bins-1.1.29/doc/bins-edit-gui.sgml0000644000175000017500000002173710303167611017424 0ustar jeromejerome00000000000000 Mark"> Eichin"> June 7, 2002"> 1"> eichin@thok.org"> BINS"> Debian"> GNU"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2002 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; Set fields in XML picture description files for BINS (using a GNOME-based GUI) &dhpackage; files DESCRIPTION This manual page documents briefly the &dhpackage; command. &dhpackage; sets values in the XML picture description files that bins(1) uses to generate galleries. It displays the image (scaled down to fit the window) and allows you to fill in the predefined fields (or add new ones.) For command-line editing of the same data, see bins_edit(1). OPTIONS This program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. file file is the filename of the image itself. Displays program version. Displays program version. Displays command-line options. Enables random developer debugging messages. COMMANDS C-n Next file Save current tags set (if any changes have been made) and move on to the next image. M-Page Down Forward 10 Save current tags set (if any changes have been made) and skip forward by 10 files. C-p Previous file Save current tags set (if any changes have been made) and move back to the previous image. M-Page Up Back 10 Save current tags set (if any changes have been made) and skip backwards by 10 files. M-Home Start of List Save current tags set (if any changes have been made) and jump to the first file. M-End End of List Save current tags set (if any changes have been made) and jump to the last file. M-a Auto-fill Fill in any blank fields with the values from the most recently seen image. Particularly useful for copying a location or event across a set of images. Revert Reload tags from the XML file, wiping unsaved changes. C-s Save Save changes, if any. F2 Album Edit the album this picture is in. (Under construction, but functional.) F3 Open Not yet implemented. Should provide a file browser later. > Rotate Right Rotate image to the Right (Clockwise.) Actually sets the Orientation tag with priority 1 so that it overrides the corresponding EXIF tag; it does not modify the image file itself. Cancel rotation Cancels any current changes to the rotation tags (effectively, this is a "revert" function for the rotation, it doesn't to back to the original EXIF tags in the JPEG file.) < Rotate Left Rotate image to the Left (Counter Clockwise.) Actually sets the Orientation tag with priority 1 so that it overrides the corresponding EXIF tag; it does not modify the image file itself. C-q Quit Quit program, saving current changes (if any.) About Display About box. License Display License box. EXAMPLES Edit all the images in a directory: bins-edit-gui $(find bins-picture-dir -name '*.jpg') SEE ALSO bins (1), bins_edit (1). AUTHOR This manual page was written by &dhusername; &dhemail;.
bins-1.1.29/doc/bins_edit.sgml0000644000175000017500000002776410303167611016732 0ustar jeromejerome00000000000000 Mark"> Eichin"> April 22, 2002"> 1"> eichin@thok.org"> BINS"> Debian"> GNU"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2002 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; Set fields in XML picture description files for BINS &dhpackage; file files DESCRIPTION This manual page documents briefly the &dhpackage; command. This manual page was written for the &debian; distribution because the original program does not have a manual page. Instead, it has documentation in HTML in /usr/share/doc/bins/index.html as well as a option. &dhpackage; sets values in the XML picture description files that bins(1) uses to generate galleries. OPTIONS This program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. file By default, file is the filename of the XML file with the image properties. If the argument has no .xml suffix, it is added, so you can directly give picture names on the command line. Spaces and other special characters (even newlines) can be used in values given as parameters as long as they are enclosed between quotes. If the option is given, the filename refers to the directory of images, and the album.xml in that directory will be modified instead. edit album description (instead of the default of editing the image description.) In this case, the file parameter must be the source directory of the album. Only the , , and switches make sense with this option. input value will be interpreted as HTML code, thus, no HTML encoding or quoting will be done. Set the title (of an image.) Set the event name (of an album or image.) Set the location (of an image.) Set the list of people (of an image.) Set the date (of an image.) Set the description (of an image.) Set the long description (of an album.) Set the short description (of an album.) Select the sample picture, within this album, to be used on the album list (template subalbum.html.) Note that the filename is relative to the album directory, and thus doesn't have a directory component. This lets you set arbitrary fields in the relevant XML file (of the image or the album.) Generic tags appear inside description which appears inside image; the tag appears as the name attribute of a field element, and the value appears as the content of the element. Gives quick help (which this man page is based on.) This switch can appear several times to increase verbosity level. Suppress output. EXAMPLES Set the title of the Image.jpg file to "My picture": bins_edit -t "My picture" Image.jpg Set the title and location of all JPEG pictures in the directory: bins_edit --title Holiday --location Paris *.jpg Use of HTML values: bins_edit --html --description '<b>BINS</b> is cool' file.jpg Set the title short description and sample image of the album in the current directory (note the dot as final parameter): bins_edit -a -t "My Album" --sample image.jpg --shortdesc "This is my album" . SEE ALSO bins (1). AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others). As it is mostly derived from the &dhpackage; program itself, it is covered by the &gpl;.
bins-1.1.29/doc/bins.sgml0000644000175000017500000010755410303167611015721 0ustar jeromejerome00000000000000 Mark"> Eichin"> April 22, 2002"> 1"> eichin@thok.org"> BINS"> Debian"> GNU"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2002 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; Generate a static HTML photo albums using XML and EXIF tags &dhpackage; source_dir target_dir DESCRIPTION This manual page documents briefly the &dhpackage; command. This manual page was written for the &debian; distribution because the original program does not have a manual page. Instead, it has documentation in HTML in /usr/share/doc/bins/index.html as well as a option. &dhpackage; is a program that takes a collection of directories and files containing JPEG images and XML descriptions, combines them with a set of HTML templates, and produces a complete photo gallery of static HTML files, rescaled images at three sizes, and thumbnails. OPTIONS use an alternative configuration file, instead of ~/.bins/binsrc.. Tells script to use only one copy of image using HTML size specs (height, width specs in the image tag) for scaled versions (instead of generating several images, one for each size). Default is false. STR is an optional argument to set how the one image is generated. Possible values: scaled (make scaled copy of orig in target_dir hierarchy, sized to max size). Default. copied (copy orig to web dir) custom (use copy if filesize < 1meg resize, resave, if bigger than 1 meg) Determine if tags found in EXIF structure are added in desc files. STR is one of "always", "never" or "exist" ("exist" only adds if the desc file already exist.) Default is always. Color style to use. Can be blue (default one), green, ivory and pink or any other one defined in configuration/description files. This option is deprecated (and thus, not supported by all templates), in favor of alternate stylesheets and the customStyleSheet parameter. Template style to use (styles provided for now are joi, marc, martin, mwolson petrus, satyap and swigs). Specify location of html templates. Default is ~/.bins, falling back to default versions in /etc/bins/templates.style. Numbers preceding the album title, followed by an underscore are stripped. If this option is given, then prefix ordering numbers on directories are removed. For example, if one has directories may, june, and august, they can be renamed 0_may, 1_june, and 2_august and they will appear in the album in the correct order. Tells the script to generate an editable version of the album. If set, some more links and icons are added to directly access the .xml files for editing. This is for editing purposes, not for a final album. Sets "ignore" keywords which will be compared against the contents of the ignore field of the album's XML file, in the ignore field in description section. If any of the iKeys match those in the album's "ignore" field, that album will not be processed. See also the ignore parameter. Sets "hidden" keywords which will be compared against the contents of the ignore field of the album's XML file, in the ignore field in description section. If any of the iKeys match those in the album's "ignore" field, that album will be hidden: it will not be linked anywhere. See also the hidden parameter. X is the verbosity level (between 0 and 3) Show the help string this man page was originally based on. SETTINGS &dhpackage; is also controlled by other files. /etc/bins/binsrc ~/.bins/binsrc The binsrc files are XML files with a top level bins tag. There are three element names with bins: parameter, colors, and sizes. Each of these has a name attribute which names the data in the element content. The colors element has a style attribute, that can be used with the colorStyle parameter or the -c command line option. It contains color elements. The color elements name has one of the following values which is substituted into the template files. This tag is deprecated, in favor of alternate stylesheets and the customStyleSheet parameter. PAGE_BACK PAGE_TITLE MAINBAR_BACK MAINBAR_TITLE MAINBAR_LINK MAINBAR_CURRENTPAGE SUBBAR_BACK SUBBAR_LINK SUBBAR_CURRENTPAGE SUBBAR_TITLE The sizes element contains size elements which each have a name attribute, a shortname attribute, a height attribute, and a width attribute. These default to Small, Sm, 40%, 40% Medium, Med, 64%, 64% Large, Lg, 100%, 100% name and shortname are used in the output HTML and in generated filenames. The default values listed above are passed through gettext for localization; overrides in binsrc files are not, and should be in the desired language. For the parameter elements the name attribute names one of the following parameters. addExifToDescFile If set to 1 (the default), write EXIF data found in the image file to the image desc file (but see also the flag). albumThumbInSubAlbumPage If set to 1 (the default), display the current album thumbnail in sub-albums page if it has pictures, with links to the thumbnails page. allThumbnailsPage If set to 1, generate a page with all thumbnails in the album and sub-albums. This is deactivated because it is an alpha feature which seems to not work properly. backgroundImage Set this to the image that should be displayed as the background of the album pages. The Image will be copied to the static files directory. This works only with joi, marc, martin and petrus templates for now. borderOnThumbnails Width of the border of the thumbnail's image in the thumbnails page, in pixels. 0 means no border. colorStyle Name of the color style to use. Default is blue. See also the option which takes precedence. This option is deprecated (and thus, not supported by all templates), in favor of alternate stylesheets and the customStyleSheet parameter. compactHTML If set to 1, generated HTML code is cleaned up to reduce the size of pages and thus, speed up browsing. This reduces the size of HTML BINS files by about 30%. See HTML::Clean(3) to know how optimizations are performed. configFileName Can be set in the global config file, but only influences the basename of the local user config file. Defaults to .binsrc. createEmptyDescFields If set to 1 (the default), add empty description fields in the description section when the image description file is created to ease later manual editing. createHtaccess If 1, create an Apache .htaccess file in the root dir of the album with the encoding charset bound to html and htm files. This is a parameter global for the album, it can't be set in album.xml. customStyleSheet Set this to the CSS file that should be used as the stylesheet for the album pages. The CSS file will be copied to the static files directory. This works only with joi, marc, martin and petrus templates for now. dateString Specify the format of date strings. This variable accepts all formats supported by date(1). defaultSize Size to use when user clicks directly on the thumbnail in the thumbnails page instead of one of the size name. 0 is the first size (Small in the default config), 1 the second (Medium), and so on. Set this variable to -1 if you don't want the thumbnail to be clickable. deExifyImages If set to 1, do NOT copy exif data found in the source images to any of the generated resized images. Setting this option can yield significant space savings, especially for thumbnail and imagelist pages. emptyAlbumDesc If set to 1, and album desciption is not set, no message will be displayed (instead of the "No long/short description available" one). enlarge If set to 1, small images are enlarged in the "med" and "large" series. (defaults to 0). excludeBackgroundImage If set to 1, the image with the name given in backgroundImage will be excluded from the current directory. excludeDirs Exclude directories that match this regexp (if set). Set to ^CVS$ in default config, so that CVS subdirs aren't processed by bins. excludeFiles Exclude image files that match this regexp (if set). No image files are excluded in default config. globalConfigDir Can't usefully be set, since it has already been used when the first config file is read. Defaults to /etc/bins. hidden Put here a comma separated list of keyword. If one on this keyword is found in the ignore field in the description section of an album.xml, then this sub-album will be hidden, i.e. it will be generated but not linked anywhere. You can also use the -n command line option. homeURL Set this to your home page's URL. This is used for the leave button in some templates. htmlEncoding HTML pages charset encoding. ignore Put here a comma separated list of keyword. If one on this keyword is found in the ignore field in the description section of an album.xml, then this sub-album will be ignored, i.e. it will not be processed. You can also use the -i command line option. imagePageCycling If set to 0 next/prev-Links will be hidden if the actual page is the last/first Image page. javaScriptPreloadImage If set to 1, add some javascript code in image pages to preload the next image of the same size when current one is loaded, to speed up the album browsing. javaScriptPreloadThumbs If set to 1, add some javascript code in thumbnails pages to preload thumbnails of the next page when current one is loaded, to speed up the album browsing. jpegQuality Quality of scaled jpegs (lower number = more compression, lower quality) in 1-100 range (default of 75). See imagemagick docs for more details. linkInsteadOfCopy If set to 1, we link the picture instead of copying it if possible (i.e. scaleIfSameSize is set to 0 and destination image doesn't have to be rotated: rotateImages is set to original or none, or orientation is already correct). Warning : if whenSrcSmaller is set to enlarge, original image can be modified. linkRelative If set to 1, we use a relative path for the link if linkInsteadOfCopy is set to 1. maxAlbumsForLongSubAlbum If the number of sub albums is greater (than this value which defaults to 20), generate a short sub album page instead of the long one. (Short sub album pages appear to be unsupported at the moment; this option is disabled.) noRotation Don't perform rotation on files matching this regexp. This can used in conjunction with scaleIfSameSize=0 and a scaled size of 100%x100% to keep original pictures in your album. numThumbsPerPage Number of thumbnails (default of 16) displayed in each page in an album. pathImgNum If set to 1 the path in the imageview contains the number of the current image. pathShowIcon If set to 1 the path contains icons. previewMaxWidth previewMaxHeight Max thumbnail width and height (default 150x150). jpegProgressify whether to convert generated jpegs to progressive using jpegtran (if available). can be never, always, or smaller (if the progressified file is smaller than the baseline). reverseOrder Are we reversing sorting order for pictures or directories ? 0=none, 1=dirs, 2=pix, 3=both. See also -r command line option. rotateImages Do we rotate images if the Orientation EXIF tag is found? If set to original (the default), the original image is rotated the first time, and then it is left untouched. If set to destination, this is all the scaled images and thumbnails that are rotated. This is less efficient, but the original images are preserved (and is useful if the original images are read-only). If set to none, no rotation is performed. rotateWithJpegtran If set to 1, bins try to use the jpegtran program to rotate JPEG images if it is available. jpegtran is faster and lossless, but some versions fail to perform rotation correctly, so it is deactivated in default config. If set to 0 or if jpegtran is not found, mogrify (from ImageMagick) is used. scaleIfSameSize If set to 1, we scale the picture even if destination size is the same as the original picture, if set to 0 (the default), the original image is just copied if the size is correct. scaleMethod What method should be used to create scaled pictures and thumbnails ? Can be either scale or sample. sample is faster, scale is better. searchEngine If 1, generate a search page. Images can be searched on description fields set in the searchFields parameter. searchFields Space separated list of description field names used by the search engine, if searchEngine is set to 1. searchLimit Maximum results returned by the search engine, if searchEngine is set to 1. Note that if this number is too high, it can hang the browser. stripDirPrefix If 1, numbers preceding the album title, followed by an underscore, are stripped. If this parameter is set, then prefix ordering numbers on directories are removed. For example, if one has directories may, june, and august, they can be renamed 0_may, 1_june, and 2_august and they will appear in the album in the correct order. This can be overridden by the -p command line option. templateStyle Name of the template style to use. Default is swigs. Other templates provided with BINS are joi, marc, martin, petrus and satyap. Several templates can be used for different sub-album of an album, by using this parameter in the bins section of the album.xml files. See also the option which takes precedence over binsrc (but not album.xml). thumbnailBackground If set to 1, add a background colour (SUBBAR_BACK) to the thumbnail's cell in the thumbnails page so that if the top and bottom borders are wider than the image (for example, if it is in portrait mode), instead of spilling over, there is a border around the whole picture. By default, use the PAGE_BACK color. thumbnailInImageList Display thumbnails on the Image List page, set to 1 by default. thumbnailPageCycling If set to 0 next/prev-Links will be hidden if the actual page is the last/first Thumbnail page. thumbPrevNext If set to 1 (the default), display thumbnails close to the previous and next link at the bottom of the image page. thumbsPerRow Number of thumbnails (default of 4) displayed in each row in an album. titleOnThumbnail Should the title be displayed on top on the thumbnail in the thumbnails page? (defaults to 1.) treePreview If set to 1, preview thumbnails will be showed in the album tree page. This works only with joi, marc and petrus templates for now. updateOriginalPerms If set to 1, read permissions on images will be set, to ensure http deamon will be able to read them. userConfigDir Can be set in the global config file (since after the user one is read, it is too late). Defaults to ~/.bins and is processed by bsd_glob (see File::Glob for details.) xmlEncoding XML files charset encoding. image.jpg The EXIF tags are extracted from the image. Currently only the Orientation tag influences the processing, but a variety of settings are copied into the HTML file generated via the details.html template. image.jpg.xml The XML file contains an image element, which contains three child elements: description which has field children that contain per-image data. The name attribute names the tag (allowing simple extensibility, see the bins_edit flag) but bins itself currently only makes use of title description people location date event bins which works as described with the binsrc file settings, except that many of the settings are not meaningful in the context of a single picture. exif which has a cache of values copied from the EXIF tags in the image, to allow simpler processing by other tools. If a user wants to override the EXIF values and provide a replacement (such as a corrected Orientation or an Owner setting that reflects who you loaned the camera to) adding a priority attribute with a value of "1" will prevent bins from replacing it with the value in the image. album.xml This file contains an album element, which contains description and bins stanza as described for an image. The are extensible in the same manner, but bins only makes use of dirname descFileName shortdesc title sampleimage longdesc include_images.txt includes image filenames (relative to the current album, i.e. the directory where the include_images.txt file is stored.) Each filename appears on a line by itself; a line beginning with a # is a comment, and lines composed entirely of whitespace are ignored. Otherwise, the line is exactly the filename. These images are included in the order listed, and added after any that actually appear in the directory. template.html There are a number of template HTMLfiles which are used to generate the actual images. The base names of these are tree imagelist subalbum thumbnail details image The default versions of these files in /etc/bins/templates.default should show how they work, as does the HTML::Template documentation. Aside from the COLOR substitutions described above, a template can also reference BINS_VERSION ENCODING GENERATED_DATE BINS_ID SEE ALSO bins_edit (1), jpegtran (1), File::Glob, HTML::Template, imagemagick. AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others). As it is mostly derived from the &dhpackage; program itself, it is covered by the &gpl;.
bins-1.1.29/doc/album.xml0000644000175000017500000000304010303167611015705 0ustar jeromejerome00000000000000 This is my holidays pictures taken during various travels. Holidays Holidays pictures. Travel1/IMG_0005.JPG green 150 150 20 5 0 1 bins-1.1.29/doc/bins.10000644000175000017500000004775510303167611015125 0ustar jeromejerome00000000000000.TH "BINS" "1" .SH "NAME" bins \(em Generate a static HTML photo albums using XML and EXIF tags .SH "SYNOPSIS" .PP \fBbins\fR [\fB-f \fIconfig_file\fR\fP] [\fB-o \fISTR\fR\fP] [\fB-d \fISTR\fR\fP] [\fB-c \fIcolor_style\fR\fP] [\fB-s \fIstyle\fR\fP] [\fB-t \fItemplate_dir\fR\fP] [\fB-p\fP] [\fB-e\fP] [\fB-i \fIiKey,iKey...\fR\fP] [\fB-v \fIX\fR\fP] [\fB-h\fP] \fIsource_dir\fR \fItarget_dir\fR .SH "DESCRIPTION" .PP This manual page documents briefly the \fBbins\fR command. .PP This manual page was written for the \fBDebian\fP distribution because the original program does not have a manual page. Instead, it has documentation in HTML in \fB/usr/share/doc/bins/index.html\fP as well as a \fB-h\fP option. .PP \fBbins\fR is a program that takes a collection of directories and files containing JPEG images and XML descriptions, combines them with a set of HTML templates, and produces a complete photo gallery of static HTML files, rescaled images at three sizes, and thumbnails. .SH "OPTIONS" .IP "\fB-f \fIconfig_file\fR\fP" 10 use an alternative configuration file, instead of \fB~/.bins/binsrc.\fP. .IP "\fB-o \fISTR\fR\fP" 10 Tells script to use only one copy of image using HTML size specs (height, width specs in the image tag) for scaled versions (instead of generating several images, one for each size). .IP "" 10 Default is false. .IP "" 10 \fISTR\fR is an optional argument to set how the one image is generated. Possible values: .RS .IP "scaled" 10 (make scaled copy of orig in target_dir hierarchy, sized to max size). Default. .IP "copied" 10 (copy orig to web dir) .IP "custom" 10 (use copy if filesize < 1meg resize, resave, if bigger than 1 meg) .RE .IP "\fB-d \fISTR\fR\fP" 10 Determine if tags found in EXIF structure are added in desc files. .IP "" 10 \fISTR\fR is one of "always", "never" or "exist" ("exist" only adds if the desc file already exist.) Default is always. .IP "\fB-c \fIcolor_style\fR\fP" 10 Color style to use. Can be \fBblue\fP (default one), \fBgreen\fP, \fBivory\fP and \fBpink\fP or any other one defined in configuration/description files. This option is deprecated (and thus, not supported by all templates), in favor of alternate stylesheets and the \fBcustomStyleSheet\fP parameter. .IP "\fB-s \fIstyle\fR\fP" 10 Template style to use (styles provided for now are \fBjoi\fP, \fBmarc\fP, \fBmartin\fP, \fBmwolson\fP \fBpetrus\fP, \fBsatyap\fP and \fBswigs\fP). .IP "\fB-t \fItemplate_dir\fR\fP" 10 Specify location of html templates. .IP "" 10 Default is \fB~/.bins\fP, falling back to default versions in \fB/etc/bins/templates.\fIstyle\fR\fP. .IP "\fB-p\fP " 10 Numbers preceding the album title, followed by an underscore are stripped. If this option is given, then prefix ordering numbers on directories are removed. For example, if one has directories \fBmay\fP, \fBjune\fP, and \fBaugust\fP, they can be renamed \fB0_may\fP, \fB1_june\fP, and \fB2_august\fP and they will appear in the album in the correct order. .IP "\fB-e\fP" 10 Tells the script to generate an editable version of the album. If set, some more links and icons are added to directly access the \fB.xml\fP files for editing. This is for editing purposes, not for a final album. .IP "\fB-i \fIiKey,iKey...\fR\fP" 10 Sets "ignore" keywords which will be compared against the contents of the \fBignore\fP field of the album's XML file, in the \fBignore\fP field in \fBdescription\fP section. If any of the \fIiKeys\fR match those in the album's "ignore" field, that album will not be processed. See also the \fBignore\fP parameter. .IP "\fB-n \fIiKey,iKey...\fR\fP" 10 Sets "hidden" keywords which will be compared against the contents of the \fBignore\fP field of the album's XML file, in the \fBignore\fP field in \fBdescription\fP section. If any of the \fIiKeys\fR match those in the album's "ignore" field, that album will be hidden: it will not be linked anywhere. See also the \fBhidden\fP parameter. .IP "\fB-v \fIX\fR\fP " 10 \fIX\fR is the verbosity level (between 0 and 3) .IP "\fB-h\fP " 10 Show the help string this man page was originally based on. .SH "SETTINGS" .PP bins is also controlled by other files. .IP "\fB/etc/bins/binsrc\fP" 10 .IP "\fB~/.bins/binsrc\fP" 10 The \fBbinsrc\fP files are XML files with a top level \fBbins\fP tag. There are three element names with \fBbins\fP: \fBparameter\fP, \fBcolors\fP, and \fBsizes\fP. Each of these has a \fBname\fP attribute which names the data in the element content. .IP "" 10 The \fBcolors\fP element has a \fBstyle\fP attribute, that can be used with the \fBcolorStyle\fP parameter or the \fB-c\fP command line option. It contains \fBcolor\fP elements. The \fBcolor\fP elements name has one of the following values which is substituted into the template files. This tag is deprecated, in favor of alternate stylesheets and the \fBcustomStyleSheet\fP parameter. .RS .IP "" 10 PAGE_BACK .IP "" 10 PAGE_TITLE .IP "" 10 MAINBAR_BACK .IP "" 10 MAINBAR_TITLE .IP "" 10 MAINBAR_LINK .IP "" 10 MAINBAR_CURRENTPAGE .IP "" 10 SUBBAR_BACK .IP "" 10 SUBBAR_LINK .IP "" 10 SUBBAR_CURRENTPAGE .IP "" 10 SUBBAR_TITLE .RE .IP "" 10 The \fBsizes\fP element contains \fBsize\fP elements which each have a \fBname\fP attribute, a \fBshortname\fP attribute, a \fBheight\fP attribute, and a \fBwidth\fP attribute. These default to .RS .IP "" 10 Small, Sm, 40%, 40% .IP "" 10 Medium, Med, 64%, 64% .IP "" 10 Large, Lg, 100%, 100% .RE .IP "" 10 \fBname\fP and \fBshortname\fP are used in the output HTML and in generated filenames. The default values listed above are passed through \fBgettext\fP for localization; overrides in \fBbinsrc\fP files are not, and should be in the desired language. .IP "" 10 For the \fBparameter\fP elements the \fBname\fP attribute names one of the following parameters. .RS .IP "addExifToDescFile" 10 If set to 1 (the default), write EXIF data found in the image file to the image desc file (but see also the \fB-d\fP flag). .IP "albumThumbInSubAlbumPage" 10 If set to 1 (the default), display the current album thumbnail in sub-albums page if it has pictures, with links to the thumbnails page. .IP "allThumbnailsPage" 10 If set to \fB1\fP, generate a page with all thumbnails in the album and sub-albums. This is deactivated because it is an alpha feature which seems to not work properly. .IP "backgroundImage" 10 Set this to the image that should be displayed as the background of the album pages. The Image will be copied to the static files directory. This works only with joi, marc, martin and petrus templates for now. .IP "borderOnThumbnails" 10 Width of the border of the thumbnail's image in the thumbnails page, in pixels. \fB0\fP means no border. .IP "colorStyle" 10 Name of the color style to use. Default is \fBblue\fP. See also the \fB-c\fP option which takes precedence. This option is deprecated (and thus, not supported by all templates), in favor of alternate stylesheets and the \fBcustomStyleSheet\fP parameter. .IP "compactHTML" 10 If set to \fB1\fP, generated HTML code is cleaned up to reduce the size of pages and thus, speed up browsing. This reduces the size of HTML BINS files by about 30%. See \fBHTML::Clean(3)\fR to know how optimizations are performed. .IP "configFileName" 10 Can be set in the global config file, but only influences the basename of the local user config file. Defaults to \fB.binsrc\fP. .IP "createEmptyDescFields" 10 If set to 1 (the default), add empty description fields in the \fBdescription\fP section when the image description file is created to ease later manual editing. .IP "createHtaccess" 10 If \fB1\fP, create an Apache \fB.htaccess\fP file in the root dir of the album with the encoding charset bound to \fBhtml\fP and \fBhtm\fP files. This is a parameter global for the album, it can't be set in album.xml. .IP "customStyleSheet" 10 Set this to the CSS file that should be used as the stylesheet for the album pages. The CSS file will be copied to the static files directory. This works only with joi, marc, martin and petrus templates for now. .IP "dateString" 10 Specify the format of date strings. This variable accepts all formats supported by \fBdate(1)\fR. .IP "defaultSize" 10 Size to use when user clicks directly on the thumbnail in the thumbnails page instead of one of the size name. 0 is the first size (\fBSmall\fP in the default config), 1 the second (\fBMedium\fP), and so on. Set this variable to \-1 if you don't want the thumbnail to be clickable. .IP "deExifyImages" 10 If set to 1, do NOT copy exif data found in the source images to any of the generated resized images. Setting this option can yield significant space savings, especially for thumbnail and imagelist pages. .IP "emptyAlbumDesc" 10 If set to 1, and album desciption is not set, no message will be displayed (instead of the "No long/short description available" one). .IP "enlarge" 10 If set to 1, small images are enlarged in the "med" and "large" series. (defaults to 0). .IP "excludeBackgroundImage" 10 If set to 1, the image with the name given in \fBbackgroundImage\fP will be excluded from the current directory. .IP "excludeDirs" 10 Exclude directories that match this regexp (if set). Set to CVS$ in default config, so that CVS subdirs aren't processed by bins. .IP "excludeFiles" 10 Exclude image files that match this regexp (if set). No image files are excluded in default config. .IP "globalConfigDir" 10 Can't usefully be set, since it has already been used when the first config file is read. Defaults to \fB/etc/bins\fP. .IP "hidden" 10 Put here a comma separated list of keyword. If one on this keyword is found in the \fBignore\fP field in the \fBdescription\fP section of an \fBalbum.xml\fP, then this sub-album will be hidden, i.e. it will be generated but not linked anywhere. You can also use the \fB-n\fP command line option. .IP "homeURL" 10 Set this to your home page's URL. This is used for the leave button in some templates. .IP "htmlEncoding" 10 HTML pages charset encoding. .IP "ignore" 10 Put here a comma separated list of keyword. If one on this keyword is found in the \fBignore\fP field in the \fBdescription\fP section of an \fBalbum.xml\fP, then this sub-album will be ignored, i.e. it will not be processed. You can also use the \fB-i\fP command line option. .IP "imagePageCycling" 10 If set to 0 next/prev-Links will be hidden if the actual page is the last/first Image page. .IP "javaScriptPreloadImage" 10 If set to \fB1\fP, add some javascript code in image pages to preload the next image of the same size when current one is loaded, to speed up the album browsing. .IP "javaScriptPreloadThumbs" 10 If set to \fB1\fP, add some javascript code in thumbnails pages to preload thumbnails of the next page when current one is loaded, to speed up the album browsing. .IP "jpegQuality" 10 Quality of scaled jpegs (lower number = more compression, lower quality) in 1-100 range (default of 75). See imagemagick docs for more details. .IP "linkInsteadOfCopy" 10 If set to 1, we link the picture instead of copying it if possible (i.e. scaleIfSameSize is set to \fB0\fP and destination image doesn't have to be rotated: \fBrotateImages\fP is set to \fBoriginal\fP or \fBnone\fP, or orientation is already correct). Warning : if whenSrcSmaller is set to enlarge, original image can be modified. .IP "linkRelative" 10 If set to 1, we use a relative path for the link if \fBlinkInsteadOfCopy\fP is set to 1. .IP "maxAlbumsForLongSubAlbum" 10 If the number of sub albums is greater (than this value which defaults to 20), generate a short sub album page instead of the long one. (Short sub album pages appear to be unsupported at the moment; this option is disabled.) .IP "noRotation" 10 Don't perform rotation on files matching this regexp. This can used in conjunction with \fBscaleIfSameSize=0\fP and a scaled size of \fB100%x100%\fP to keep original pictures in your album. .IP "numThumbsPerPage" 10 Number of thumbnails (default of 16) displayed in each page in an album. .IP "pathImgNum" 10 If set to 1 the path in the imageview contains the number of the current image. .IP "pathShowIcon" 10 If set to 1 the path contains icons. .IP "previewMaxWidth" 10 .IP "previewMaxHeight" 10 Max thumbnail width and height (default 150x150). .IP "jpegProgressify" 10 whether to convert generated jpegs to progressive using jpegtran (if available). can be \fBnever\fP, \fBalways\fP, or \fBsmaller\fP (if the progressified file is smaller than the baseline). .IP "reverseOrder" 10 Are we reversing sorting order for pictures or directories ? 0=none, 1=dirs, 2=pix, 3=both. See also \fB-r\fP command line option. .IP "rotateImages" 10 Do we rotate images if the \fBOrientation\fP EXIF tag is found? If set to \fBoriginal\fP (the default), the original image is rotated the first time, and then it is left untouched. If set to \fBdestination\fP, this is all the scaled images and thumbnails that are rotated. This is less efficient, but the original images are preserved (and is useful if the original images are read-only). If set to \fBnone\fP, no rotation is performed. .IP "rotateWithJpegtran" 10 If set to \fB1\fP, \fBbins\fP try to use the \fBjpegtran\fP program to rotate JPEG images if it is available. \fBjpegtran\fP is faster and lossless, but some versions fail to perform rotation correctly, so it is deactivated in default config. If set to \fB0\fP or if \fBjpegtran\fP is not found, \fBmogrify\fP (from ImageMagick) is used. .IP "scaleIfSameSize" 10 If set to 1, we scale the picture even if destination size is the same as the original picture, if set to 0 (the default), the original image is just copied if the size is correct. .IP "scaleMethod" 10 What method should be used to create scaled pictures and thumbnails ? Can be either \fBscale\fP or \fBsample\fP. \fBsample\fP is \fBfaster\fP, scale is better. .IP "searchEngine" 10 If 1, generate a search page. Images can be searched on description fields set in the \fBsearchFields\fP parameter. .IP "searchFields" 10 Space separated list of description field names used by the search engine, if \fBsearchEngine\fP is set to 1. .IP "searchLimit" 10 Maximum results returned by the search engine, if \fBsearchEngine\fP is set to 1. Note that if this number is too high, it can hang the browser. .IP "stripDirPrefix" 10 If \fB1\fP, numbers preceding the album title, followed by an underscore, are stripped. If this parameter is set, then prefix ordering numbers on directories are removed. For example, if one has directories may, june, and august, they can be renamed \fB0_may\fP, \fB1_june\fP, and \fB2_august\fP and they will appear in the album in the correct order. This can be overridden by the \fB-p\fP command line option. .IP "templateStyle" 10 Name of the template style to use. Default is \fBswigs\fP. Other templates provided with BINS are \fBjoi\fP, \fBmarc\fP, \fBmartin\fP, \fBpetrus\fP and \fBsatyap\fP. Several templates can be used for different sub-album of an album, by using this parameter in the \fBbins\fP section of the \fBalbum.xml\fP files. See also the \fB-s\fP option which takes precedence over binsrc (but not album.xml). .IP "thumbnailBackground" 10 If set to 1, add a background colour (SUBBAR_BACK) to the thumbnail's cell in the thumbnails page so that if the top and bottom borders are wider than the image (for example, if it is in portrait mode), instead of spilling over, there is a border around the whole picture. By default, use the PAGE_BACK color. .IP "thumbnailInImageList" 10 Display thumbnails on the Image List page, set to 1 by default. .IP "thumbnailPageCycling" 10 If set to 0 next/prev-Links will be hidden if the actual page is the last/first Thumbnail page. .IP "thumbPrevNext" 10 If set to 1 (the default), display thumbnails close to the previous and next link at the bottom of the image page. .IP "thumbsPerRow" 10 Number of thumbnails (default of 4) displayed in each row in an album. .IP "titleOnThumbnail" 10 Should the title be displayed on top on the thumbnail in the thumbnails page? (defaults to 1.) .IP "treePreview" 10 If set to 1, preview thumbnails will be showed in the album tree page. This works only with joi, marc and petrus templates for now. .IP "updateOriginalPerms" 10 If set to 1, read permissions on images will be set, to ensure http deamon will be able to read them. .IP "userConfigDir" 10 Can be set in the global config file (since after the user one is read, it is too late). Defaults to \fB~/.bins\fP and is processed by \fBbsd_glob\fP (see \fBFile::Glob\fP for details.) .IP "xmlEncoding" 10 XML files charset encoding. .RE .IP "\fB\fIimage.jpg\fR\fP" 10 The EXIF tags are extracted from the image. Currently only the \fBOrientation\fP tag influences the processing, but a variety of settings are copied into the HTML file generated via the \fBdetails.html\fP template. .IP "\fB\fIimage.jpg\fR.xml\fP" 10 The XML file contains an \fBimage\fP element, which contains three child elements: .RS .IP "\fBdescription\fP" 10 which has \fBfield\fP children that contain per-image data. The \fBname\fP attribute names the tag (allowing simple extensibility, see the \fBbins_edit\fP \fB\-\-generic\fP flag) but \fBbins\fP itself currently only makes use of .RS .IP "" 10 title .IP "" 10 description .IP "" 10 people .IP "" 10 location .IP "" 10 date .IP "" 10 event .RE .IP "\fBbins\fP" 10 which works as described with the \fBbinsrc\fP file settings, except that many of the settings are not meaningful in the context of a single picture. .IP "\fBexif\fP" 10 which has a cache of values copied from the EXIF tags in the image, to allow simpler processing by other tools. .IP "" 10 If a user wants to override the EXIF values and provide a replacement (such as a corrected \fBOrientation\fP or an \fBOwner\fP setting that reflects who you loaned the camera to) adding a \fBpriority\fP attribute with a value of "1" will prevent \fBbins\fP from replacing it with the value in the image. .RE .IP "\fBalbum.xml\fP" 10 This file contains an \fBalbum\fP element, which contains \fBdescription\fP and \fBbins\fP stanza as described for an image. The are extensible in the same manner, but \fBbins\fP only makes use of .RS .IP "" 10 dirname .IP "" 10 descFileName .IP "" 10 shortdesc .IP "" 10 title .IP "" 10 sampleimage .IP "" 10 longdesc .RE .IP "\fBinclude_images.txt\fP" 10 includes image filenames (relative to the current album, i.e. the directory where the \fBinclude_images.txt\fP file is stored.) Each filename appears on a line by itself; a line beginning with a \fB#\fP is a comment, and lines composed entirely of whitespace are ignored. Otherwise, the line is exactly the filename. These images are included in the order listed, and added after any that actually appear in the directory. .IP "\fB\fItemplate\fR.html\fP" 10 There are a number of template HTMLfiles which are used to generate the actual images. The base names of these are .RS .IP "" 10 tree .IP "" 10 imagelist .IP "" 10 subalbum .IP "" 10 thumbnail .IP "" 10 details .IP "" 10 image .RE .IP "" 10 The default versions of these files in \fB/etc/bins/templates.default\fP should show how they work, as does the \fBHTML::Template\fP documentation. Aside from the \fBCOLOR\fP substitutions described above, a template can also reference .RS .IP "" 10 BINS_VERSION .IP "" 10 ENCODING .IP "" 10 GENERATED_DATE .IP "" 10 BINS_ID .RE .SH "SEE ALSO" .PP bins_edit (1), jpegtran (1), File::Glob, HTML::Template, imagemagick. .SH "AUTHOR" .PP This manual page was written by Mark W. Eichin eichin@thok.org for the \fBDebian\fP system (but may be used by others). As it is mostly derived from the \fBbins\fP program itself, it is covered by the GNU General Public License. .\" created by instant / docbook-to-man, Wed 24 Aug 2005, 23:31 bins-1.1.29/doc/bins_edit.10000644000175000017500000001230610303167611016112 0ustar jeromejerome00000000000000.TH "BINS" "1" .SH "NAME" bins_edit \(em Set fields in XML picture description files for BINS .SH "SYNOPSIS" .PP \fBbins_edit\fR [\fB-a\fP | \fB\-\-album\fP ] [\fB-m\fP | \fB\-\-html\fP ] [\fB-t \fItitle\fR\fP | \fB\-\-title \fItitle\fR\fP ] [\fB-e \fIevent\fR\fP | \fB\-\-event \fIevent\fR\fP ] [\fB-l \fIlocation\fR\fP | \fB\-\-location \fIlocation\fR\fP ] [\fB-p \fIpeople\fR\fP | \fB\-\-people \fIpeople\fR\fP ] [\fB-y \fIdate\fR\fP | \fB\-\-date \fIdate\fR\fP ] [\fB-d \fIdescription\fR\fP | \fB\-\-description \fIdescription\fR\fP ] [\fB\-\-longdesc \fIlongDescription\fR\fP] [\fB\-\-shortdesc \fIshortDescription\fR\fP] [\fB\-\-sample \fIpictureFileName\fR\fP] [\fB-g \fItag\fR=\fIvalue\fR\fP | \fB\-\-generic \fItag\fR=\fIvalue\fR\fP ] [\fB-h\fP | \fB\-\-help\fP ] [\fB-v\fP | \fB\-\-verbose\fP ] [\fB-q\fP | \fB\-\-quiet\fP ] [\fIfile\fR] [\fIfiles\fR \&...] .SH "DESCRIPTION" .PP This manual page documents briefly the \fBbins_edit\fR command. .PP This manual page was written for the \fBDebian\fP distribution because the original program does not have a manual page. Instead, it has documentation in HTML in \fB/usr/share/doc/bins/index.html\fP as well as a \fB\-\-help\fP option. .PP \fBbins_edit\fR sets values in the XML picture description files that \fBbins\fR(1) uses to generate galleries. .SH "OPTIONS" .PP This program follows the usual GNU command line syntax, with long options starting with two dashes (`\-'). A summary of options is included below. .IP "\fIfile\fR" 10 By default, \fIfile\fR is the filename of the XML file with the image properties. If the argument has no \fB.xml\fP suffix, it is added, so you can directly give picture names on the command line. Spaces and other special characters (even newlines) can be used in values given as parameters as long as they are enclosed between quotes. .IP "" 10 If the \fB\-\-album\fP option is given, the filename refers to the directory of images, and the \fBalbum.xml\fP in that directory will be modified instead. .IP "\fB-a\fP" 10 .IP "\fB\-\-album\fP" 10 edit album description (instead of the default of editing the image description.) In this case, the file parameter must be the source directory of the album. Only the \fB\-\-title\fP, \fB\-\-longdesc\fP, \fB\-\-shortdesc\fP and \fB\-\-sample\fP switches make sense with this option. .IP "\fB-m\fP" 10 .IP "\fB\-\-html\fP" 10 input value will be interpreted as HTML code, thus, no HTML encoding or quoting will be done. .IP "\fB-t \fItitle\fR\fP" 10 .IP "\fB\-\-title \fItitle\fR\fP" 10 Set the title (of an image.) .IP "\fB-e \fIevent\fR\fP" 10 .IP "\fB\-\-event \fIevent\fR\fP" 10 Set the event name (of an album or image.) .IP "\fB-l \fIlocation\fR\fP" 10 .IP "\fB\-\-location \fIlocation\fR\fP" 10 Set the location (of an image.) .IP "\fB-p \fIpeople\fR\fP" 10 .IP "\fB\-\-people \fIpeople\fR\fP" 10 Set the list of people (of an image.) .IP "\fB-y \fIdate\fR\fP" 10 .IP "\fB\-\-date \fIdate\fR\fP" 10 Set the date (of an image.) .IP "\fB-d \fIdescription\fR\fP" 10 .IP "\fB\-\-description \fIdescription\fR\fP" 10 Set the description (of an image.) .IP "\fB\-\-longdesc \fIlongDescription\fR\fP" 10 Set the long description (of an album.) .IP "\fB\-\-shortdesc \fIshortDescription\fR\fP" 10 Set the short description (of an album.) .IP "\fB\-\-sample \fIpictureFileName\fR\fP" 10 Select the sample picture, within this album, to be used on the album list (template \fBsubalbum.html\fP.) Note that the filename is relative to the album directory, and thus doesn't have a directory component. .IP "\fB-g \fItag\fR=\fIvalue\fR\fP" 10 .IP "\fB\-\-generic \fItag\fR=\fIvalue\fR\fP" 10 This lets you set arbitrary fields in the relevant XML file (of the image or the album.) Generic tags appear inside \fBdescription\fP which appears inside \fBimage\fP; the \fItag\fR appears as the \fBname\fP attribute of a \fBfield\fP element, and the \fIvalue\fR appears as the content of the element. .IP "\fB-h\fP" 10 .IP "\fB\-\-help\fP" 10 Gives quick help (which this man page is based on.) .IP "\fB-v\fP" 10 .IP "\fB\-\-verbose\fP" 10 This switch can appear several times to increase verbosity level. .IP "\fB-q\fP" 10 .IP "\fB\-\-quiet\fP" 10 Suppress output. .SH "EXAMPLES" .PP Set the title of the \fBImage.jpg\fP file to "My picture": .PP \fBbins_edit \-t "My picture" Image.jpg\fR .PP Set the title and location of all JPEG pictures in the directory: .PP \fBbins_edit \-\-title Holiday \-\-location Paris *.jpg\fR .PP Use of HTML values: .PP \fBbins_edit \-\-html \-\-description 'BINS is cool' file.jpg\fR .PP Set the title short description and sample image of the album in the current directory (note the dot as final parameter): .PP \fBbins_edit \-a \-t "My Album" \-\-sample image.jpg \-\-shortdesc "This is my album" .\fR .SH "SEE ALSO" .PP bins (1). .SH "AUTHOR" .PP This manual page was written by Mark W. Eichin eichin@thok.org for the \fBDebian\fP system (but may be used by others). As it is mostly derived from the \fBbins_edit\fP program itself, it is covered by the GNU General Public License. .\" created by instant / docbook-to-man, Mon 22 Aug 2005, 01:55 bins-1.1.29/doc/bins-edit-gui.10000644000175000017500000000673110303167611016617 0ustar jeromejerome00000000000000.TH "BINS" "1" .SH "NAME" bins-edit-gui \(em Set fields in XML picture description files for BINS (using a GNOME-based GUI) .SH "SYNOPSIS" .PP \fBbins-edit-gui\fR [\fIfiles\fR \&...] .SH "DESCRIPTION" .PP This manual page documents briefly the \fBbins-edit-gui\fR command. .PP \fBbins-edit-gui\fR sets values in the XML picture description files that \fBbins\fR(1) uses to generate galleries. It displays the image (scaled down to fit the window) and allows you to fill in the predefined fields (or add new ones.) For command-line editing of the same data, see \fBbins_edit\fR(1). .SH "OPTIONS" .PP This program follows the usual GNU command line syntax, with long options starting with two dashes (`\-'). A summary of options is included below. .IP "\fIfile\fR" 10 \fIfile\fR is the filename of the image itself. .IP "\fB-v\fP" 10 .IP "\fB\-\-version\fP" 10 Displays program version. .IP "\fB-v\fP" 10 .IP "\fB\-\-version\fP" 10 Displays program version. .IP "\fB-h\fP" 10 .IP "\fB\-\-help\fP" 10 Displays command-line options. .IP "\fB\-\-debug\fP" 10 Enables random developer debugging messages. .SH "COMMANDS" .IP "C-n \fBNext file\fR" 10 Save current tags set (if any changes have been made) and move on to the next image. .IP "M-Page Down \fBForward 10\fR" 10 Save current tags set (if any changes have been made) and skip forward by 10 files. .IP "C-p \fBPrevious file\fR" 10 Save current tags set (if any changes have been made) and move back to the previous image. .IP "M-Page Up \fBBack 10\fR" 10 Save current tags set (if any changes have been made) and skip backwards by 10 files. .IP "M-Home \fBStart of List\fR" 10 Save current tags set (if any changes have been made) and jump to the first file. .IP "M-End \fBEnd of List\fR" 10 Save current tags set (if any changes have been made) and jump to the last file. .IP "M-a \fBAuto-fill\fR" 10 Fill in any blank fields with the values from the most recently seen image. Particularly useful for copying a location or event across a set of images. .IP "\fBRevert\fR" 10 Reload tags from the XML file, wiping unsaved changes. .IP "C-s \fBSave\fR" 10 Save changes, if any. .IP "F2 \fBAlbum\fR" 10 Edit the album this picture is in. (Under construction, but functional.) .IP "F3 \fBOpen\fR" 10 Not yet implemented. Should provide a file browser later. .IP "> \fBRotate Right\fR" 10 Rotate image to the Right (Clockwise.) Actually sets the \fBOrientation\fP tag with \fBpriority\fP 1 so that it overrides the corresponding EXIF tag; it does not modify the image file itself. .IP "\fBCancel rotation\fR" 10 Cancels any current changes to the rotation tags (effectively, this is a "revert" function for the rotation, it doesn't to back to the original EXIF tags in the JPEG file.) .IP "< \fBRotate Left\fR" 10 Rotate image to the Left (Counter Clockwise.) Actually sets the \fBOrientation\fP tag with \fBpriority\fP 1 so that it overrides the corresponding EXIF tag; it does not modify the image file itself. .IP "C-q \fBQuit\fR" 10 Quit program, saving current changes (if any.) .IP "\fBAbout\fR" 10 Display About box. .IP "\fBLicense\fR" 10 Display License box. .SH "EXAMPLES" .PP Edit all the images in a directory: .PP \fBbins-edit-gui $(find bins-picture-dir \-name '*.jpg')\fR .SH "SEE ALSO" .PP bins (1), bins_edit (1). .SH "AUTHOR" .PP This manual page was written by Mark W. Eichin eichin@thok.org. .\" created by instant / docbook-to-man, Mon 22 Aug 2005, 01:55 bins-1.1.29/doc/contact.html0000644000175000017500000002116210303167611016411 0ustar jeromejerome00000000000000 Contact and contribution

Contact and contribution

BINS has a project page on gna!.

Contact Information

For any questions or suggestions, please use the BINS mailing list, hosted at email-lists.org. See this page for subscription information or to consult the archives. Subscription is not needed to post on the list.

Bug report

You can use the appropriate form to post a new bug. You must be registered on gna! to do so. If you don't want to register on gna!, you can post the bug on the mailing list (you don't have to subscribe to post there).

You can check if the bug is not already reported in the bug database. The bug can also be corrected in current development version (see below).

Patch submission

You can use the appropriate form to post a patch. You must be registered on gna! to do so. If you don't want to register on gna!, you can post the patch on the mailing list (you don't have to subscribe to post there).

To make your patch, it is better to use the development version (see below).

Development version

A snapshot of the current CVS version can be downloaded here (this server is occasionally down).

You can also get it via an Arch/Bazaar repository at http://arch.gna.org/bins/public. There is a main branch, to prepare the next release, and a devel branch for the experimental features. You can register it and get the latest version with the following commands:

      
      baz register-archive jerome@sautret.org--public \
        http://arch.gna.org/bins/public
      baz get jerome@sautret.org--public/bins--main
      
    

You can browse the CVS on-line here (when up) and the Arch/Bazaar repository here.

Personal contact information

If you want to contact me personally, you can send me an e-mail at , or chat with me on Jabber (my Jabber ID is jerome@myjabber.net) or on ICQ (my ICQ# is 9057913).


bins-1.1.29/doc/download.html0000644000175000017500000005303210303167611016566 0ustar jeromejerome00000000000000 Download

Download

The latest released version of BINS is 1.1.29.

To receive a mail when a new version is out, go to the BINS Freshmeat page and click on Subscribe to new releases (you must have a freshmeat account).

See ChangeLog file for differences between BINS versions.

Development version can be retrieved via the CVS or Arch/Bazaar repositories, see here.

Debian

BINS is part of Sarge (stable Debian version), Etch (testing Debian version) and Sid (unstable Debian version). Check the BINS Debian package page.

FreeBSD

BINS is available as a FreeBSD port.

It can also be found on FreshPorts.

Gentoo

BINS is available as a package for the Gentoo Linux distribution.

Mandriva

There is a Mandriva package in the contrib section of Mandriva. Follow the instructions from Cédric Thevenet's HowTo BINS for Mandrake Cooker to get the latest version using urpmi and Cooker sources.

NetBSD

A NetBSD package is available in pkgsrc/www/bins/.

Solaris

You'll have to install it from the tarball below. You can find some help in a post from Bill Clarke in the BINS mailing-list.

Ubuntu

BINS is part of the Ubuntu linux distribution (warty, hoary and breezy). You can get the according package here.

Other Systems

For other Unix-like systems, use the TAR archive below and follow the instructions of the installation page.

Warning: the description file format has changed in 1.1.0 version. See README file to convert from old .txt format to new .xml format.

A snapshot of the current CVS version can be downloaded here. Note that this version may be broken. Use links below to get stable releases.

Table 1. Source download

gzip formatbzip2 format
bins-1.1.29.tar.gz (sig) bins-1.1.29.tar.bz2 (sig)
bins-1.1.28.tar.gz (sig) bins-1.1.28.tar.bz2 (sig)
bins-1.1.27.tar.gz (sig) bins-1.1.27.tar.bz2 (sig)
bins-1.1.26.tar.gz (sig) bins-1.1.26.tar.bz2 (sig)
bins-1.1.25.tar.gz (sig) bins-1.1.25.tar.bz2 (sig)
bins-1.1.24.tar.gz (sig) bins-1.1.24.tar.bz2 (sig)
bins-1.1.23.tar.gz (sig) bins-1.1.23.tar.bz2 (sig)
bins-1.1.22.tar.gz (sig) bins-1.1.22.tar.bz2 (sig)
bins-1.1.21.tar.gz (sig) bins-1.1.21.tar.bz2 (sig)
bins-1.1.20.tar.gz (sig) bins-1.1.20.tar.bz2 (sig)
bins-1.1.19.tar.gz (sig) bins-1.1.19.tar.bz2 (sig)
bins-1.1.18.tar.gz (sig) bins-1.1.18.tar.bz2 (sig)
bins-1.1.17.tar.gz (sig) bins-1.1.17.tar.bz2 (sig)
bins-1.1.16.tar.gz (sig) bins-1.1.16.tar.bz2 (sig)
bins-1.1.15.tar.gz (sig) bins-1.1.15.tar.bz2 (sig)
bins-1.1.14.tar.gz (sig) bins-1.1.14.tar.bz2 (sig)
bins-1.1.13.tar.gz (sig) bins-1.1.13.tar.bz2 (sig)
bins-1.1.12.tar.gz (sig) bins-1.1.12.tar.bz2 (sig)
bins-1.1.11.tar.gz (sig) bins-1.1.11.tar.bz2 (sig)
bins-1.1.10.tar.gz (sig) bins-1.1.10.tar.bz2 (sig)
bins-1.1.9.tar.gz (sig) bins-1.1.9.tar.bz2 (sig)
bins-1.1.8.tar.gz (sig) bins-1.1.8.tar.bz2 (sig)
bins-1.1.7.tar.gz (sig) bins-1.1.7.tar.bz2 (sig)
bins-1.1.6.tar.gz (sig) bins-1.1.6.tar.bz2 (sig)
bins-1.1.5.tar.gz (sig) bins-1.1.5.tar.bz2 (sig)
bins-1.1.4.tar.gz (sig) bins-1.1.4.tar.bz2 (sig)
bins-1.1.3.tar.gz (sig) bins-1.1.3.tar.bz2 (sig)
bins-1.1.2.tar.gz (sig) bins-1.1.2.tar.bz2 (sig)
bins-1.1.1.tar.gz (sig) bins-1.1.1.tar.bz2 (sig)
bins-1.1.0.tar.gz (sig) bins-1.1.0.tar.bz2 (sig)
bins-1.0.4.tar.gz (sig) bins-1.0.4.tar.bz2 (sig)
bins-1.0.3.tar.gz (sig) bins-1.0.3.tar.bz2 (sig)
bins-1.0.2.tar.gz (sig) bins-1.0.2.tar.bz2 (sig)
bins-1.0.1.tar.gz (sig) bins-1.0.1.tar.bz2 (sig)
bins-1.0.0.tar.gz (sig) bins-1.0.0.tar.bz2 (sig)

Download statistics


bins-1.1.29/doc/examples.html0000644000175000017500000001772610303167611016607 0ustar jeromejerome00000000000000 Examples

Examples

Album examples

You can see some examples of albums generated by BINS by following one of this links :

  • My personal album in French, with different color and template styles in sub-albums, generated by the latest version of BINS. Go to the Album photos::Lieux::Paris sub-album to see the joi templates, which use css, javascipt and icons.

  • Joachim Kohlhammer's album, uses the joi templates. Joachim is the author of the joi templates, you can send him feedback about it. You can also browse its album with the default templates.

  • Marc Menem's album uses his own marc templates. It doesn't use tables, all positioning is done with CSS.

  • Michael Olson made the mwolson templates. His gallery illustrate this style.

  • Jason Wright's gallery has several thousands images in more than 100 albums.

  • Satya album uses the satyap style. Satya wrote the templates for this style and can be reached here.

  • Petrus's album uses the petrus template, which is based on the joi template from Joachim.

  • Andrei Emeltchenko's album uses Russian i18n. Andrei is the author of the Russian translation, you can reach him here.

  • The album of Adrian Rossiter uses some personal colors as well as some slightly modified template to fit with the look of the rest of the site. You can also check his collection of geometry related images.

  • Keith Baker's album is quite big (take a look at the tree...).

  • Sean's Photo Album is in English and doesn't use scaled images.

  • Emmanuel le Chevoir's holidays album is in French, with english i18n.

  • Photos section of Guy Santiglia's Web site uses BINS on a NetBSD box with some customized templates, with a php extensions (?!?).

  • MicroShell has an album of their work. It uses joi templates and is in French.

I'm looking for examples in other languages and/or configurations, so if you have a BINS generated album and agree I use it as an example, let me know the URL so I can add it on this page.

Screenshots

Here is a screenshot of bins-edit-gui, the gnome interface.


bins-1.1.29/doc/faq.html0000644000175000017500000003531610303167611015533 0ustar jeromejerome00000000000000 FAQ

FAQ

Frequent Asked Questions

What does BINS means ?

BINS Is Not Swigs. BINS is a fork of Swigs, which is not maintained anymore.

Does BINS run on Windows ?

I've never tried, but I don't think. It's written in Perl, which is portable, but it uses some *nix specific commands. Though it should not be so difficult to port, or maybe it can run with cygwin ?

When I visualize a big image, it don't fit in my window, I must scroll to see it, should I buy a bigger monitor ?

Yes. Or else, you can click on the big image. By default, browsers like firefox will display it automatically re-sized to your window.

How can I get bins to automatically rotate destination images ?

If your camera has a accelerometer to know which way is up, it will be done automatically. If not, you have to set manually the orientation of the images on your camera before downloading them on you computer. You can also use bins-edit-gui to set the orientation of the image. If you don't want to use the GUI, this can be done directly in the XML image description file. Put (or set if it is already there) the following tag in the <exif> section:

	
	<tag name="Orientation" priority="1">
	   left_bot
        </tag>
	
      

Adjust the left_bot to the orientation of your image (can be right_top, left_bot or bot_right).

Is it possible to give my own order number for each image ?

This can be done with two different ways.

  • You can prefix the name of images and directories with a number. You can use the add_num_prefix tool to help you. You have the possibility to choose to reverse sort with the reverseOrder option or the -r command line switch.

  • You can put an optional file album.list in your albums (a slibling file to album.xml) that lists the files in the order you want them displayed. If album.list doesn't exist in a directory the sorting by image name is done as usual.

Does BINS recreate all the albums even if I add or modify just a sub-album ?

For each picture, if it doesn't exists in destination album, it is processed. If it exists and the date of the source is greater than the date of the destination, it is also processed. If the destination is more recent, it is left unchanged. All the HTML is regenerated when bins is run.

Can I put some HTML in description fields ?

Yes, take a look at the -m option of bins_edit, see the man page.

I tried to change the color style (or e-mail, home page, other template customisation...) but I can't see any change on the generated album, is this a bug ?

Some customisation parameters are not implemented in all templates. For example, color style is not implemented in joi templates. Instead, it uses the more modern alternate stylesheets mechanism, with the customStyleSheet parameters, which is not supported by the swigs template.

How can I tell BINS to skip resizing the image (just use the default image) ?

Add this in the album.xml:

      
       <sizes>
          <size name="Full Size" shortname="Full" height="100%" width="100%">
       </sizes>
	
      

Its goes under the <bins> stanza.

Having two separate trees (source and HTML) is not efficient for my disk space usage, can I use only one tree ?

No, but you can use the linkInsteadOfCopy parameter to avoid any image file duplicate. Also, look at the linkRelative parameter. All is in the man page.

Having one description file per image is to complex to maintain, can I put all description fields for all images in just one file ?

Yes, try the bins_addtext tool.

Why special characters (like those with accents) are not correctly rendered ?

Have you copied the .htaccess in the root of your published album ? See Encoding here.

I've generated an album, but I can't find the search engine, where is it ?

For now, the search engine is only available with the swigs templates. Note that the search link will only show up with a browser supporting javascript.

The "Loading Data" screen took a bit too long to go to the search page, is this normal ?

It depends of the size of your album. You can enable compression on your web server to reduce this time. See Compression here.

Can I have several versions of an album in different languages without duplicating the pictures ?

Multi-languages albums are not handled by BINS, but you can do this manually with the mod_rewrite Apache module.

Say you have four albums trees corresponding to the same album in different languages, in four different directories named with the language code:

	/var/www/album/da/...
	/var/www/album/de/...
	/var/www/album/en/...
	/var/www/album/fr/...
      

To have only one copy of each picture, remove them from all trees except one (say en):

	find /var/www/album/{da,de,fr} \( -iname \*.JPG -o -iname \*.jpg -o \
	   -iname \*.gif -o -iname \*.png -o -iname \*.avi -o -iname \*.mpg \) \
	   -exec rm -f {} \;
      

And add a RewriteRule to your Apache configuration file to redirect all request for an image to the en tree :

	RewriteEngine on
	RewriteRule   ^/album/[^e][^n]/(.*\.(jpg|gif|png|avi|mpg))$ \
	              /album/en/$1 [NC]
      

I've put some image names in the excludeFiles parameter, but it doesn't seems to works. Can you explain how to use this stuff ?

This should be set to one regexp, so, for example, to ignore two images, the correct parameter should looks like :

      
        <parameter name="excludeFiles">
            dscn20(89|90)
        </parameter>
	
      

Why bins fails with "Assertion flags == 0 failed: file "Storable.xs", line 2336 at /usr/local/bin/bins line 4213." ?

See this post. You can find more details here.

What is the syntax used in templates ?

man HTML::Template


bins-1.1.29/doc/install_automatic.html0000644000175000017500000001433010303167611020471 0ustar jeromejerome00000000000000 Automatic installation

Automatic installation

When you are sure you have all this dependencies filled, extract the BINS archive in a directory of your choice.

You can install BINS either system wide (all users can run it) or only for one user. Note that this procedure will replace your old programs and templates, so do a backup before running it if you made some changes.

To install BINS system wide, run the install.sh script as root. This will install program in /usr/local/bin, internationalization files in /usr/local/share/locale and configuration files in /etc/bins. Note that if you want to change configuration for a particular user with this install, you just have to copy the content of /etc/bins in ~/.bins and you can then personalize BINS configuration for that user by editing files in ~/.bins.

To install BINS for just one user, run the install.sh script as this user. This will install program in ~/bin and configuration files in ~/.bins. Note that internationalization files (used to generate non-english albums) will NOT be copied, because they have to be installed in /usr/local/share/locale.


bins-1.1.29/doc/install.html0000644000175000017500000001400210303167611016417 0ustar jeromejerome00000000000000 Installation

Installation

The easiest way to get BINS working is by using a package. Check if there is one for your system on the download page. If there is no package suitable for you, use the TAR archive from the download page and follow the instructions below.

Quick procedure

for more detailed instruction, check the automatic installation page. You can also install BINS by hand.


bins-1.1.29/doc/install_manual.html0000644000175000017500000001420110303167611017755 0ustar jeromejerome00000000000000 Manual installation

Manual installation

If you don't trust the install.sh script, you can do the installation by hand.

Copy files bins & bins_edit somewhere in your PATH (/usr/local/bin sounds good, or ~/bin if you're not root). bins_edit is optional. Then, copy the content of the templates directory in /etc/bins (system wide) or ~/.bins :

    cp bins bins_edit bins-edit-gui ~/bin
    mkdir /usr/local/share/bins
    cp bins-edit-gui.glade /usr/local/share/bins
    mkdir ~/.bins
    cp templates/* ~/.bins
  

If you want to use I18N :

    mkdir -p /usr/local/share/locale/fr/LC_MESSAGES/
    cd intl
    cp fr.mo /usr/local/share/locale/fr/LC_MESSAGES/bins.mo
  

Example given is for french translation, change fr by your language code. French translation is the only one provided for the moment, contact me if you want to translate an album in your language. Be sure your $LANG and $LC_ALL variables are set to your language code if you want to use I18N. Only the strings in the generated album are translated, messages generated on the command line are still in english.


bins-1.1.29/doc/install_prerequisites.html0000644000175000017500000002445610303167611021421 0ustar jeromejerome00000000000000 Prerequisites

Prerequisites

You need Perl in order to run BINS, as well as the following Perl libraries (Mandrake and Debian package names are provided when known).

This tarball contains all these libraries in rpm format for Mandrake or as tarballs when no rpm are available (see below for information on how to install Perl library from tarball).

Table 1. Prerequisites Libraries

Perl library Debian package Mandrake 8.1 & 8.2 package
POSIX perl-baseperl-base-5.601-7mdk
IO::File perl-baseperl-base-5.601-7mdk
Getopt::Long perl-base perl-base-5.601-7mdk
File::Basename perl-modulesperl-base-5.601-7mdk
Storablelibstorable-perl 
IO:String libio-string-perl  
Image::Size libimage-size-perl perl-Image-Size-2.903-5mdk
Image::Info libimage-info-perlperl-Image-Info-1.07-1mdk
Image::Magick (with the ImageMagick tools collection) perlmagick perl-Magick-5.4.2.3-3mdk
HTML::Entities libhtml-parser-perl perl-HTML-Parser-3.25-3mdk
HTML::Template libhtml-template-perl  
HTML::Clean libhtml-clean-perl  
URI:Escape liburi-perl perl-URI-1.18-1mdk
XML::Parser::PerlSAX libxml-perl perl-libxml-perl-0.07-5mdk
XML::Grove libxml-grove-perl perl-XML-Grove-0.46alpha-2mdk
XML::Handler::YAWriter libxml-handler-yawriter-perl
Text::Iconv libtext-iconv-perl
Text::Unaccent libtext-unaccent-perl
Locale::gettext (optional if you don't want to have I18N in your album.) liblocale-gettext-perl perl-gettext-1.0-10mdk

Refer to this page to know how to install them. You can find the perl interpreter and all this Perl libraries on CPAN.

BINS need theImageMagick tools collection, which is probably already install on your system if you run one of the common GNU/Linux distribution. You can verify it by trying to run the convert (used to scale images) and mogrify (used to rotate images) programs.

If the rotateWithJpegtran parameter is set to 1 somewhere in the configuration file, BINS can also use jpegtran to rotate images when the Orientation EXIF tag is found. If it doesn't find it (or if rotateWithJpegtran is set to 0), it will use the mogrify (from ImageMagick) tool instead. The jpegtran program can perform lossless transformation and is quicker than mogify, but works only on JPEG files. Note that some systems use a version of this program that is not compatible with BINS, so the rotateWithJpegtran is set to 0 in default config. jpegtran can be found in the libjpeg-progs Debian package or in the jpegsrc tarball accessible on this FTP site.


bins-1.1.29/doc/intro.html0000644000175000017500000002331110303167611016107 0ustar jeromejerome00000000000000 Introduction

Introduction

Features

The aim of BINS is to generate static HTML photo albums. Some of the functionalities of BINS are :

  • generated album is static : it's just plain HTML/CSS/Javascript files (Javascript is not mandatory to view the album), no need of any dynamic language (php, asp, etc.) nor database on server side. Album can be burned on CD or DVD.

  • album can contains other albums (sub albums): the album can have a tree structure ;

  • generation of a thumbnail and of scaled images for each picture ;

  • generated album appearance is fully customizable by using HTML templates (5 different templates sets are currently provided) and configuration parameters: colors, number and size of thumbnails per page, number and size of scaled pictures (in pixels or percentage of the original image for the size), fields to display, etc. Those parameters can be set globally (system wide or per user), per album or sub album or per picture (for example, you can change the colors of one sub album or one just one picture page in an album by editing its description file) ;

  • several description fields (date, location, etc...) can be associated with the pictures (in text or HTML format). You can easily add or customize these fields ;

  • description fields can be set or modified via a command line interface or a GTK+/GNOME-based GUI ;

  • A search engine is included in the album : you can find some pictures by searching keywords in their description fields.

  • Album can be generated from pictures managed by Zoph.

  • speed up album browsing by performing a clean up of HTML code to reduce its size and by pre-loading thumbnails in browser cache using JavaScript code ;

  • Exif information and Digital camera support :

    • use the EXIF data structure found on some image files (usually, those produced by digital cameras) to fill automatically some fields (date and time for example).

    • BINS use the Orientation EXIF tag (which is normally set when you rotate a image on you DigiCam) to rotate the picture to correct orientation.

    • For each image, a page provides all information available on the picture and the DigiCam settings when the photo was taken.

    • Additional information are provided for Canon DigiCams.

    • Tooltips provide information about the meaning of some of the fields.

    • All EXIF information is saved in the XML description file, preventing they disappear when the image is modified ;

  • internationalization (generation of album in different languages) using gettext. Current languages supported are Catalan, Dutch, English, Esperanto, Finish, French, German, Hungarian, Italian, Japanese, Polish, Russian, Spanish and Traditional Chinese  ;

  • customizable charset encoding for HTML generation, including UTF-8 (Unicode) support by default. Generation of the Apache .htaccess file for correct encoding charset in HTTP headers ;

  • use of XML files to save user description of pictures and albums/subalbums and Exif data from image file ;

  • handle correctly file and directory names with spaces or other odd characters (excepted '/'), and create valid escaped URLs ;

  • generate valid HTML/XHTML code. The level of HTML depends of the style used. Some of the styles are valid, table free XHTML.

History

BINS (BINS Is Not SWIGS) is a modified version of SWIGS (Structured Web Image Gallery System). I've made these modifications because I need them. I tried to contact SWIGS author, but I've got no response, so I decided to publish my modified version in case someone is interested.

See ChangeLog file for differences between SWIGS and BINS and new functionalities of each version.


bins-1.1.29/doc/license.html0000644000175000017500000001001210303167611016370 0ustar jeromejerome00000000000000 License

License

BINS is free software, licensed under the GNU GPL.

BINS is Copyright © 2001-2005 Jérôme Sautret (Jerome @ Sautret.org).

Original SWIGS code is Copyright © 2000 Brendan McMahan (mcmahahb @ whitman.edu).

Initial code based on IDS 0.21 is Copyright © John Moose (moosejc @ muohio.edu).


bins-1.1.29/doc/usage_album.html0000644000175000017500000001574310303167611017252 0ustar jeromejerome00000000000000 Creating an album

Creating an album

Put all your images in a directory, say ~/images. Your images can be ordered into sub-directories. Then, create an empty directory, where the album will be created, say ~/album :

    mkdir ~/album
  

and run bins with the two directories (source and destination) as parameters :

    bins ~/images ~/album
  

This will create an HTML album, with sub-albums, thumbnails and scaled images.

To change the appearance of the HTML album, a style can be chosen with the -s command line option or via the templateStyle parameter in the configuration or description files (see Customization below for information about these files). In this case, BINS will use the HTML templates found is the subdirectory named templates.style (where style is the style name).

BINS looks for this subdirectory in the directory specified by the -t command line option, then in ~/.bins and finally in /etc/bins.

See the man page for all style names available. If someone has the artistic talent to create HTML templates for a new style, I am interested...

bins has some other command line options, type

    bins -h
  

to see them and see the bins(1) man page.


bins-1.1.29/doc/usage_custom.html0000644000175000017500000001517010303167611017456 0ustar jeromejerome00000000000000 Customization

Customization

You can customize BINS by editing the value of the parameters in the binsrc config file. One such file is provided in the distribution. If you have installed BINS as root, it should be in /etc/bins, or else in ~/.bins (you can copy it from /etc/bins to ~/.bins if you want to change configuration only for your user). See the comments in this file or the bins man page for more information about the available parameters.

You can also put these parameters (when it makes sense) in the album (album.xml) or image (image_name.jpg.xml for example) description files, in the bins section of these files (see Editing the description files in an editor), to personalize only some album, sub-album or images pages. A sample album.xml file is provided in the doc directory.

HTML albums can be personalized by these parameters, but also with new styles. You can create a new style by writing new HTML templates. If you do so, don't hesitate to send me your realization if you want them to be included with BINS.


bins-1.1.29/doc/usage_desc_cli.html0000644000175000017500000001740010303167611017707 0ustar jeromejerome00000000000000 Command line interface

Command line interface

You can use the bins_edit program to set description fields or one or several images. For example, to add the comment my picture to pic.jpg, go to the images directory (where pic.jpg is), and type:

    bins_edit -d "my picture" pic.jpg
  

The -d option stands for description. You can set other fields, like location or date. Run bins_edit --help to see all fields available and read the bins_edit(1) man page. The description text can be HTML with the --html switch. You can run bins_edit on several images, for example:

    $ bins_edit -l "Paris" -y "2001" *.jpg
  

For each album (and sub-albums), you can also set a title, a description and a sample image to be used as a thumbnail to represent the album. To do so, you can use bins_edit with the --album switch. Type bins_edit --help for more details.

After setting or changing any fields, you have to rerun bins to generate new HTML pages.


bins-1.1.29/doc/usage_desc_gui_feh.html0000644000175000017500000002121110303167611020541 0ustar jeromejerome00000000000000 BINS and feh

BINS and feh

The feh image viewer can be used to set BINS description fields with the following method, provided by Marc Menem.

Add the following two lines to the .fehrc file. :

    bins_feh -g 800x600 --caption-path tit -p -V -A "bins_edit -t \"`cat tit/%f.txt`\" -d \"`cat desc/%f.txt`\"  %f"
    bins_feh_desc -g 800x600 --caption-path desc -p -V -A "bins_edit -t \"`cat tit/%f.txt`\" -d \"`cat desc/%f.txt`\" %f"
  

Then do the following :

    cd images
    mkdir tit
    mkdir desc
    feh -Tbins_feh *.jpg
  

In feh, you can edit all the titles after going into caption mode with the c key, and update the xml files with the enter key. Then, do the following to edit the descriptions :

    feh -Tbins_feh_desc *.jpg
  

In the same way, you can edit all the descriptions after going into caption mode with the c key, and update the xml files with the enter key.


bins-1.1.29/doc/usage_desc_gui_gqview.html0000644000175000017500000002060310303167611021305 0ustar jeromejerome00000000000000 BINS in GQview

BINS in GQview

You can edit BINS description files of your images directly in GQview using bins-edit-gui. To do so, go to the Edit -> Options... menu, in the Editors tab of the GQview configuration window, and add an entry with Menu Name=BINS and Command Line=bins-edit-gui and click OK.

You can then select one or several images in GQview, right-click, and select in BINS... in the Edit sub-menu.


bins-1.1.29/doc/usage_desc_gui.html0000644000175000017500000002071210303167611017724 0ustar jeromejerome00000000000000 Graphical interface

Graphical interface

To edit the images descriptions with the GTK+/GNOME graphical user interface, run the bins-edit-gui program with the names of the images you want to comment as parameters. for example :

    bins-edit-gui *.jpg
  

After setting or changing any field, you have to rerun bins to generate new HTML pages.

See the README.gui file for installation and copyright information. Type bins-edit-gui --help and see the bins-edit-gui(1) man page for more information about this program.

bins-edit-gui was written by Mark W. Eichin .


bins-1.1.29/doc/usage_desc_gui_nautilus.html0000644000175000017500000002154010303167611021650 0ustar jeromejerome00000000000000 BINS in Nautilus

BINS in Nautilus

You can edit BINS description files of your images directly in Nautilus using bins-edit-gui. To do so, put the following shell script in the file .gnome2/nautilus-scripts/BINS (or .gnome/nautilus-scripts/BINS if you're using gnome 1.x) :

#!/bin/sh
#
# Script to edit BINS xml description files from Nautilus.
# 
# Written by crafterm at debian.org, Sun Mar 16 21:26:26 CET 2003

quoted=$(echo -e "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS" | \
    awk 'BEGIN { FS = "\n" } { printf "\"%s\" ", $1 }' | \
    sed -e s#\"\"##)

eval "bins-edit-gui $quoted"
  

Then, make the script executable by going in the file's directory and running the following command :

    chmod u+rx BINS
  

By putting that shell script there, you can use Nautilus to select all images you want to edit/add info about and then right click, scripts... and then BINS. It will then launch the gui with all the files selected, as loaded.

Thanks to Zaheer Merali for this tip and to Marcus Crafter for the script.


bins-1.1.29/doc/usage_desc.html0000644000175000017500000001655210303167611017067 0ustar jeromejerome00000000000000 Setting description fields

Setting description fields

If you want to add some comments about the albums or pictures (title, description, date, etc.), you can use either a command line interface, a GNOME graphical interface or you can edit them via other image viewers : Nautilus, GQview, feh.

You can also generate your album from Zoph. See this page for instuctions.

When you add comments to pictures, this will create an XML file per picture file, in the same directory of the source picture. Comment on album are put in a album.xml file, in the album source directory. You can also edit the XML files directly.

After adding or editing the description fields, you have to rerun bins.


bins-1.1.29/doc/usage_desc_xml.html0000644000175000017500000002024410303167611017740 0ustar jeromejerome00000000000000 Editing the XML files

Editing the XML files

bins_edit and bins-edit-gui create a XML file for each picture file commented (same name followed by .xml) and an album.xml file in each directory of an album which is commented. If you want to directly edit comments about the image, or if you want to set some parameter (see the bins section below) you can do so by editing the XML file directly with an editor (supporting Unicode if you use non-standard ASCII characters). The three main sections of this files are:

  • description: contains desciption fields (comment about the image or the album, like title, date, location, etc.).

  • bins: contains parameters to personalize the bins program behavior (and thus, the HTML album aspect). You can use here most of the parameters found in the binsrc file (see Customization section.)

  • exif: store the data found in the Exif structure of the image file. If the image file is modified and the Exif structure is lost, BINS will use the data stored in the description file (note that Exif data from the image file takes precedence on the one of the description file). album.xml files don't have this section.

After setting or changing any value in the XML files, you have to rerun bins to generate new HTML pages.

To see how you can change albums parameters, a sample album.xml file is provided in the doc directory.


bins-1.1.29/doc/usage.html0000644000175000017500000001206310303167611016062 0ustar jeromejerome00000000000000 Usage bins-1.1.29/doc/usage_httpd.html0000644000175000017500000002174110303167611017270 0ustar jeromejerome00000000000000 Web server configuration

Web server configuration

Apache Configuration

Encoding

The bins program will create automatically an .htaccess in the root directory of your album if the createHtaccess parameter is set to 1. This .htaccess is to be used by the Apache HTTP server to set the correct encoding of the HTTP header according the html pages of the album.

To allow Apache to use the .htaccess file, the following directive must be present in the Directory or VirtualHost of the Apache httpd configuration file :

	  AllowOverride All
      

Using BINS with PHP

If you want that the .html extension file to be interpreted by PHP, you have to edit the .htacces file described in Encoding section and add the following lines :

	AddHandler server-parsed .html
	AddType application/x-httpd-php .php .html
      

Thanks to Gilles Foucault for this Tip

Compression

To reduce size of HTML and Javascript files you can enable compression on the web server. This is specially useful for the search engine because the search_data.js file, containing all the search data, can be very big on important album, but it compress very well.

To enable compression on Apache 2, you have to enable mod_deflate. Then, in your virtual host configuration, add the following directives:

      
        <IfModule mod_deflate.c>
                # Compression
                AddOutputFilterByType DEFLATE text/html text/plain \
                        text/xml text/css text/javascript application/x-javascript

                # Netscape 4.x has some problems...
                BrowserMatch ^Mozilla/4 gzip-only-text/html

                # Netscape 4.06-4.08 have some more problems
                BrowserMatch ^Mozilla/4\.0[678] no-gzip

                # MSIE masquerades as Netscape, but it is fine
                #BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

                # NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
                # the above regex won't work. You can use the following
                # workaround to get the desired effect:
                BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html

                # To see how compression perform
                DeflateFilterNote Input instream
                DeflateFilterNote Output outstream
                DeflateFilterNote Ratio ratio
                LogFormat '"%r" %{outstream}n/%{instream}n (%{ratio}n%%)' deflate
                CustomLog /var/log/apache2/deflate.log deflate
        </IfModule>
	
      

See the Apache documentation for more details.


bins-1.1.29/doc/usage_tools.html0000644000175000017500000003237310303167611017310 0ustar jeromejerome00000000000000 Tools

Tools

The BINS archive contains a tools directory with some small BINS related utilities. Here is a quick documentation about these tools.

bins_cleanupgallery

The bins_cleanupgallery script can be use to remove any unused file in your HTML galleries, for example images you have removed from you source tree. Run it without argument for usage information. Note that this script is still experimental, so if it performs wrong, just re-run bins to recreate erased files.

This program was written by Jochen Schaeuble .

anti_bins

This program creates a image files tree for each image size from a BINS generated album. Edit the variables in the configuration section and run it.

Note that this program will not work if there is files or directories with space in their name in your tree.

remove_num_prefix

This script remove numeric prefixes added with add_num_prefix. See below.

add_num_prefix

add_num_prefix adds incremental numeric prefixes to files. You can use it to order the images in your albums. Note that there is an alternate method to order images and sub-albums, using the album.list file (see the FAQ).

      Usage:
      add_num_prefix start step files...
      Add a numeric prefix starting at 'start', incrementing by 'step' on 'files'.
    

For example, say that you have two sets of images, from two digicams. The images are named IMG_* for the first one, and DSC* for the second one. You want that the first set appears first in the album, and then, you want to change the order of some pictures. You start by adding a prefix on the first set:

      add_num_prefix 0100 100 IMG_*
    

The images are now named like this:

      0100_IMG_5103.JPG
      0200_IMG_5104.JPG
      0300_IMG_5105.JPG
      ....
      2500_IMG_6144.JPG
    

Then do the same on the second set (note that the last image of the first set in now named 2500_IMG_*):

      add_num_prefix 2600 100 DSC*
    

Then, you can reorder some of the pictures by changing their prefix. Just rename them with a file manager or on command line:

      mv 1400_IMG_3450.JPG 0550_IMG_3450.JPG
    

You can also change the order of several pictures with remove_num_prefix and add_num_prefix. For example, to move all pictures between 1200 (included) to 1600 (not included) after the picture number 0100, use the following commands:

      remove_num_prefix 1[2-5]*_IMG*.JPG
      add_num_prefix 0110 10 IMG*
    

This remove the prefix of the pictures you want to move, and add a new one beginning after 0100, with a small step. If you have already some XML files in your album, run also:

      remove_num_prefix 1[2-5]00_*.xml
      add_num_prefix 0110 10 IMG*
    

bins_addtext

Adrian Rossiter wrote this program. It can be used to set description fields in an alternate way. Here are the instructions from Adrian:

I build a directory tree of image albums as normal, but in each album directory I create an include_images.txt file containing a list of the album images in the order I want them. I get bins to only consider the images in the include_images.txt files by setting the excludeFiles parameter in binsrc to exclude all files (.*).

I then add comment lines to the include_images.txt files which I process with a bins_addtext to set up the album. At the beginning I add the album details, then after each image I add the title and description. bins_addtext simply calls the bins_edit program with the various details as arguments.

This is working out reasonably well as I can easily change the album, image text, order of images, etc just by editing one text file. Here is an example include_images.txt file for a one image album:

      
         #Some Album Title (1 line)
         #Long description of Some Album
         #(can be many
         #lines)
         #|Short description of Some Album (starts after the pipe symbol)
         #can be many lines, then put another pipe symbol and this is followed
         #by the sample album image)
         #|some_image.gif

         some_image.gif
         #Some Image Title (1 line)
         #Description of Some Image
         #can be many lines
         #and include html <BR>
         #but you may have to escape certain symbols for the command line e.g.
         #<A HREF=\"http://www.somesite.com\">Some Site</A>
      
    

I call the script bins_addtext. It just takes a list of directories where it looks for include_images.txt and processes it. You can use a different file by passing the name with the -f option, e.g process include_images.txt in the current directory:

        bin_addtext ./
    

Process album_desc.txt in directories some_album1 and some_album2:

      bin_addtext -f album_desc.txt some_album1 some_album2
    

bins_txt2xml

This is used to convert the old txt description files used in BINS older than 1.1.0 version to the new XML one. Run it with the directory of your image tree as parameter.


bins-1.1.29/doc/autolayout.xml0000644000175000017500000000712010303167611017016 0ustar jeromejerome00000000000000 2001-2005Jérôme SAUTRET