X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/b9ba68208ebdb250dc4d4f8866cb834f5bd8764c..c2f784d2ad08d1656e5cd7ee2054cf092bb56ce6:/doc/users/smcv/gallery.mdwn?ds=sidebyside diff --git a/doc/users/smcv/gallery.mdwn b/doc/users/smcv/gallery.mdwn index d80fc3ba1..3d40b069d 100644 --- a/doc/users/smcv/gallery.mdwn +++ b/doc/users/smcv/gallery.mdwn @@ -1,348 +1,4 @@ -This plugin has now been implemented as [[plugins/contrib/album]]; this -page has older thoughts about it. +This plugin has now been implemented as [[plugins/contrib/album]]. -## Requirements - -This plugin formats a collection of images into a photo gallery, -in the same way as many websites: good examples include the -PHP application [Gallery](http://gallery.menalto.com/), Flickr, -and Facebook's Photos "application". - -The web UI I'm trying to achieve consists of one -[HTML page of thumbnails](http://www.pseudorandom.co.uk/2008/2008-03-08-panic-cell-gig/) -as an entry point to the gallery, where each thumbnail links to -[a "viewer" HTML page](http://www.pseudorandom.co.uk/2008/2008-03-08-panic-cell-gig/img_0068/) -with a full size image, next/previous thumbnail links, and -[[plugins/comments]]. - -(The Summer of Code [[plugins/contrib/gallery]] plugin does the -next/previous UI in Javascript using Lightbox, which means that -individual photos can't be bookmarked in a meaningful way, and -the best it can do as a fallback for non-Javascript browsers -is to provide a direct link to the image.) - -Other features that would be good to have: - -* minimizing the number of separate operations needed to make a gallery - - editing one source file per gallery is acceptable, editing one - source file per photo is not - -* keeping photos outside source code control, for instance in an - underlay - -* assigning [[tags|ikiwiki/directive/tag]] to photos, providing a - superset of Facebook's "show tagged photos of this person" functionality - -* constructing galleries entirely via the web by uploading attachments - -* inserting grouping (section headings) within a gallery; as in the example - linked above, I'd like this to split up the thumbnails but not the - next/previous trail - -* rendering an `/` arrangement to display videos, and possibly - thumbnailing them in the same way as totem-video-thumbnailer - (my camera can record short videos, so some of my web photo galleries - contain them) - -My plan is to have these directives: - -* \[[!gallery]] registers the page it's on as a gallery, and displays all - photos that are part of this gallery but not part of a \[[!gallerysection]] - (below). - - All images (i.e. `*.png *.jpg *.gif`) that are attachments to the gallery page - or its subpages are considered to be part of the gallery. - - Optional arguments: - - * filter="[[ikiwiki/PageSpec]]": only consider images to be part of the - gallery if they also match this filter - - * sort="date|filename": order in which to sort the images - -* \[[!gallerysection filter="[[ikiwiki/PageSpec]]"]] displays all photos in the - gallery that match the filter - -So, -[the gallery I'm using as an example](http://www.pseudorandom.co.uk/2008/2008-03-08-panic-cell-gig/) -could look something like this: - - \[[!gallery]] - - - # Gamarra - - \[[!gallerysection filter="link(sometag)"]] - - - # Smokescreen - - \[[!gallerysection filter="link(someothertag)"]] - - - - -## Implementation ideas - -The next/previous part this plugin overlaps with [[todo/wikitrails]]. - -A \[[!galleryimg]] directive to assign metadata to images might be necessary, so -the gallery page can contain something like: - - \[[!galleryimg p1010001.jpg title="..." caption="..." tags="foo"]] - \[[!galleryimg p1010002.jpg title="..." caption="..." tags="foo bar"]] - -However, allowing other pages to push in metadata like that will make -dependency tracking difficult. - -Making the viewer pages could be rather tricky. Here are some options: -"synthesize source pages for viewers" is the one I'm leaning towards at the -moment. - -### Viewers' source page is the gallery - -One possibility is to write out the viewer pages as a side-effect of -preprocessing the \[[!gallery]] directive. The proof-of-concept implementation -below does this. However, this does mean the viewer pages can't have tags or -metadata of their own and can't be matched by [[pagespecs|ikiwiki/pagespec]] or -[[wikilinks|ikiwiki/wikilink]]. - -It might be possible to implement tagging by using \[[!galleryimg]] to assign -the metadata to the *images* instead of their viewers; however, that would -require hacking up both `IkiWiki::htmllink` and `IkiWiki::urlto` to redirect -links to the image (e.g. from the \[[!map]] on a tag page) to become links to -the viewer page. - -Modifications to the comments plugin would also be required, to make it allow -comments written to `foo/bar/comment_1._comment` even though the page foo/bar -does not really exist, and display comments on the viewer pages even though -they're not real pages. (Writing comments to `foo/bar.jpg/*._comment` is not -an option!) - -### Synthesize source pages for viewers - -(Edited to add: this is what [[plugins/contrib/album]] implements. --[[smcv]]) - -Another is to synthesize source pages for the viewers. This means they can have -tags and metadata, but trying to arrange for them to be scanned etc. correctly -without needing another refresh run is somewhat terrifying. -[[plugins/autoindex]] can safely create source pages because it runs in -the refresh hook, but I don't really like the idea of a refresh hook that scans -all source pages to see if they contain \[[!gallery]]... - -The photo galleries I have at the moment, like the Panic Cell example above, -are made by using an external script to parse XML gallery descriptions (lists -of image filenames, with metadata such as titles), and using this to write -IkiWiki markup into a directory which is then used as an underlay. This is a -hack, but it works. The use of XML is left over from a previous attempt at -solving the same problem using Django. - -Perhaps a better approach would be to have a setupfile option that names a -particular underlay directory (meeting the objective of not having large -photos under source code control) and generates a source page for each file -in that directory during the refresh hook. The source pages could be in the -underlay until they are edited (e.g. tagged), at which point they would be -copied into the source-code-controlled version in the usual way. - -> Coming back to this: a specialized web UI to mark attachments as part of -> the gallery would make this easy too - you'd put the photos in the -> underlay, then go to the CGI and say "add all". --[[smcv]] - -The synthetic source pages can be very simple, using the same trick as my -[[plugins/comments]] plugin (a dedicated [[directive|ikiwiki/directives]] -encapsulating everything the plugin needs). If the plugin automatically -gathers information like file size, pixel size, date etc. from the images, then -only the human-edited information and a filename reference need to be present -in the source page; with some clever lookup rules based on the filename of -the source page, not even the photo's filename is necessarily needed. - -> Coming back to this later: the clever lookup rules make dependency tracking -> hard, though. --[[smcv]] - - \[[!meta title="..."]] - \[[!meta date="..."]] - \[[!meta copyright="..."]] - \[[!tag ...]] - - \[[!galleryimageviewer p1010001.jpg]] - -However, this would mean that editing tags and other metadata would require -editing pages individually. Rather than trying to "fix" that, perhaps it would -be better to have a special CGI interface for bulk tagging/metadata editing. -This could even be combined with a bulk upload form (a reasonable number of -file upload controls - maybe 20 - with metadata alongside each). - -Uploading multiple images is necessarily awkward due to restrictions placed on -file upload controls by browsers for security reasons - sites like Facebook -allow whole directories to be uploaded at the same time, but they achieve this -by using a signed Java applet with privileged access to the user's filesystem. - -I've found that it's often useful to be able to force the creation time of -photos (my camera's battery isn't very reliable, and it frequently decides that -the date is 0000-00-00 00:00:00), so treating the \[[!meta date]] of the source -page and the creation date of the photo as synonymous would be useful. - -### Images are the viewer's source - special filename extension - -Making the image be the source page (and generate HTML itself) would be -possible, but I wouldn't want to generate a HTML viewer for every `.jpg` on a -site, so either the images would have to have a special extension (awkward for -uploads from Windows users) or the plugin would have to be able to change -whether HTML was generated in some way (not currently possible). - -### Images are the viewer's source - alter `ispage()` - -It might be possible to hack up `ispage()` so some, but not all, images are -considered to "be a page": - -* srcdir/not-a-photo.jpg → destdir/not-a-photo.jpg -* srcdir/gallery/photo.jpg → destdir/gallery/photo/index.html - -Perhaps one way to do this would be for the photos to appear in a particular -underlay directory, which would also fulfil the objective of having photos not -be version-controlled: - -* srcdir/not-a-photo.jpg → destdir/not-a-photo.jpg -* underlay/gallery/photo.jpg → destdir/gallery/photo/index.html - -## Proof-of-concept implementation of "viewers' source page is the gallery" - - #!/usr/bin/perl - package IkiWiki::Plugin::gallery; - - use warnings; - use strict; - use IkiWiki 2.00; - - sub import { - hook(type => "getsetup", id => "gallery", call => \&getsetup); - hook(type => "checkconfig", id => "gallery", call => \&checkconfig); - hook(type => "preprocess", id => "gallery", - call => \&preprocess_gallery, scan => 1); - hook(type => "preprocess", id => "gallerysection", - call => \&preprocess_gallerysection, scan => 1); - hook(type => "preprocess", id => "galleryimg", - call => \&preprocess_galleryimg, scan => 1); - } - - sub getsetup () { - return - plugin => { - safe => 1, - rebuild => undef, - }, - } - - sub checkconfig () { - } - - # page that is a gallery => array of images - my %galleries; - # page that is a gallery => array of filters - my %sections; - # page that is an image => page name of generated "viewer" - my %viewers; - - sub preprocess_gallery { - # \[[!gallery filter="!*/cover.jpg"]] - my %params=@_; - - my $subpage = qr/^\Q$params{page}\E\//; - - my @images; - - foreach my $page (keys %pagesources) { - # Reject anything not a subpage or attachment of this page - next unless $page =~ $subpage; - - # Reject non-images - # FIXME: hard-coded list of extensions - next unless $page =~ /\.(jpg|gif|png|mov)$/; - - # Reject according to the filter, if any - next if (exists $params{filter} && - !pagespec_match($page, $params{filter}, - location => $params{page})); - - # OK, we'll have that one - push @images, $page; - - my $viewername = $page; - $viewername =~ s/\.[^.]+$//; - $viewers{$page} = $viewername; - - my $filename = htmlpage($viewername); - will_render($params{page}, $filename); - } - - $galleries{$params{page}} = \@images; - - # If we're just scanning, don't bother producing output - return unless defined wantarray; - - # actually render the viewers - foreach my $img (@images) { - my $filename = htmlpage($viewers{$img}); - debug("rendering image viewer $filename for $img"); - writefile($filename, $config{destdir}, "# placeholder"); - } - - # display a list of "loose" images (those that are in no section); - # this works because we collected the sections' filters during the - # scan stage - - my @loose = @images; - - foreach my $filter (@{$sections{$params{page}}}) { - my $_; - @loose = grep { !pagespec_match($_, $filter, - location => $params{page}) } @loose; - } - - my $_; - my $ret = "\n"; - } - - sub preprocess_gallerysection { - # \[[!gallerysection filter="friday/*"]] - my %params=@_; - - # remember the filter for this section so the "loose images" section - # won't include these images - push @{$sections{$params{page}}}, $params{filter}; - - # If we're just scanning, don't bother producing output - return unless defined wantarray; - - # this relies on the fact that we ran preprocess_gallery once - # already, during the scan stage - my @images = @{$galleries{$params{page}}}; - @images = grep { pagespec_match($_, $params{filter}, - location => $params{page}) } @images; - - my $_; - my $ret = "\n"; - } - - sub preprocess_galleryimg { - # \[[!galleryimg p1010001.jpg title="" caption="" tags=""]] - my $file = $_[0]; - my %params=@_; - - return ""; - } - - 1 +This page's history contains some older thoughts about it; +I've deleted them in an attempt to reduce confusion.