The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Mojolicious::Command::Author::generate::obrazi - Обраꙁи for your site – a gallery generator command

SYNOPSIS

  Usage: APPLICATION generate obrazi [OPTIONS]

  Examples:
    ./myapp.pl help generate obrazi # This help

    mojo generate obrazi --from ~/Pictures/summer-2021 \
        --to /opt/myapp/public/summer-2021

    mojo generate obrazi --from ~/Pictures/summer-2021 \
        --to /opt/some/static/site/albums/summer-2021 \
        -x 800x600 -s 96x96 -t ./some/custom_template.html.ep

  Options:
    -h, --help       Show this summary of available options
    -f, --from       Root of directory structure from which the images
                     will be taken. Defaults to ./.
        --to         Root directory where the gallery will be put. Defaults to ./.
    -x, --max        Maximum image dimesnions in pixels in format 'widthxheight'.
                     Defaults to 1000x1000.
    -s, --thumbs     Thumbnails maximal dimensions. Defaults to 100x100 pixels.
    -i, --index      Name of the CSV index file to be generated and then read
                     in the --from directory.
    -t, --template   Path to template file. Defaults to embedded template
                     obrazi.html.
    -o, --obrazec    Path to single image template file for sharing on social
                     media. Defaults to embedded template obrazec.html
    -u, --url        Url where the gallery will be published.
                     Defaults to '/obrazi.html'.

DESCRIPTION

Mojolicious::Command::Author::generate::obrazi generates a gallery from a directory structure, containing images. The produced gallery is a static html file which body content can be easily taken, modified, and embedded into a page in any site.

In addition the command generates a csv file on the first traversal of the directory structure, describing the images. This file can be edited. Titles and descriptions can be added for each image and then the command can be run again to regenerate the gallery with the modified titles and descriptions. This file can be further used by a helper — "obrazi" in Mojolicious::Plugin::Obrazi to produce and embed the HTML for the galery into a Mojolicious application. Please note that the helper is not yet implemented.

The word обраꙁъ(singular) means face, image, picture, symbol, example, template, etc. in OCS/OS/OBG language. The name of the plugin is the plural variant in nominative case (обраꙁи).

WORKFLOW

1. Images' owner and producer gives the direcory (probably zipped) to the command runner (a human yet).

2. The runner runs the command as shown in the SYNOPSIS.

3. The runner gives back the produced csv file to the images' producer. Fixes problems with ICC profiles etc. Notifies the producer for eventual naming convetions, possible problems. The producer fills in the description and titles in the comfort of LibreOffice Calc or MS Excel and returns the file to the command-runner. This may take some time.

4. The runner runs again the command with the modified csv file, reviews the produced file. Takes the HTML and puts it in a page on the Web.

5. The images' owner/producer enjoys the gallery, prise him/herself with it or goes back to the runner to report problems.

6. DONE or go to some of the previous steps.

FEATURES

Recursively traverses subdirectories and scales images (four at a time) to given width and height and produces thumbnails for those images. Thumbnail sizes can also be set.

Produces an index CSV file which can be edited to add titles and descriptions for the images.

Produces an HTML file with fully functional lightbox-like gallery, implemented only using jQuery and CSS – no jQ-plugins. Left/right keyboard buttons navigation to next and previous image.

ATTRIBUTES

Mojolicious::Command::Author::generate::obrazi inherits all attributes from Mojolicious::Command and implements the following new ones.

categories

  my $cat = $self->categories->first(sub { $_->[0] eq $img->[0] });

A Mojo::Collection instance, containing rows from the CSV file which are categories (directories). For this attribute to return meaningful data, $self->matrix must be already filled in from CSV file.

csv_filename

    my $filename = $self->csv_filename; # index.csv
    my $обраꙁи = $self->csv_filename('gallery.csv');

The name of the CSV file which will be created in "from_dir". This file, after being edited and after the images are processed, will be copied together with the images to "to_dir". Defaults to index.csv. Can be passed on the command-line via the --index argument.

defaults

    my $defaults_hashref = $обраꙁи->defaults;
    $обраꙁи->defaults->{category_title} = 'Def. Cat. title';
    $обраꙁи->defaults->{category_description} = 'Def. Cat. description.';
    $обраꙁи->defaults->{image_title} = 'Def. Image Title';
    $обраꙁи->defaults->{image_description} = 'Def. Image description.';
    $обраꙁи->defaults->{author} = 'John Smith';

These values go to the folowing columns in the produced CSV file. title, description, author. They are supposed to be replaced by editing the produced file. TODO: Maybe allow these to be passed on the command line via an argument --defaults.

description

  my $description = $обраꙁи->description;
  $self       = $обраꙁи->description('Foo');

Short description of this command, used for the application's command list.

files_per_subproc

    my $files_num = $обраꙁи->files_per_subproc;
    $self         = $обраꙁи->files_per_subproc(10);

Number of files to be processed by one subprocess. Defaults to int($number_of_images/$self->subprocs_num) +1. The last chunk of files is the remainder — usually smaller than the previous chunks.

from_dir

    $self = $обраꙁи->from_dir(path('./'));
    my $root_folder_abs_path = $обраꙁи->from_dir;

Holds a Mojo::File instance — absolute path to the directory from which the pictures will be taken. This is where the CSV file describing the directory structure will be generated too. The value is taken from the commandline argument --from_dir. Defaults to ./ — current directory — where the command is executed.

imager

    my $img = $обраꙁи->imager->read(file=>'path/to/image.jpg')
        || die $обраꙁи->imager->errstr;

    my $self = $обраꙁи->imager(Imager->new);

An Imager instance. This is the images-processing engine, used by the command.

images

  my $images     = $self->images->map(sub { [@$_] });    #copy

A Mojo::Collection instance, containing rows from the CSV file which are image files, supported by Imager and will be processed. For this attribute to return meaningful data, $self->matrix must be already filled in from CSV file.

log

    my $log = $self->log;
    my $self = $self->log(Mojo::Log->new)

A Mojo::Log instance. By default it is not the same as $self->app->log. Used to output info, warnings and errors to the terminal or the application log.

matrix

    my $matrix = $self->matrix;

    # add an image
    push @$matrix,
      [
      $category,               $path,
      $defaults->{image_title}, $defaults->{image_description},
      $defaults->{author},      $self->calculate_max_and_thumbs($path, $raw_path)
      ];

    # add a category
    push @$matrix, [
        $category, $path, "$defaults->{category_title} – $category",
        $defaults->{category_description}, $defaults->{author}, '', ''
    ];

    $matrix->each(sub{...});


    csv(in => $matrix->to_array, enc => 'UTF-8', out => \my $data, binary => 1, sep_char => ",");
    path($csv_filepath)->spurt($data);

A Mojo::Collection instance. First row contains the headers. This matrix is filled in while recursively searching in the "from_dir" for images. Then it is dumped into the index CSV file. If the CSV file is already present, the data is read directly from it.

max

    my $max_sizes = $self->max; # {width => 1000, height => 1000}
    $self = $self->max({width => 1000, height => 1000});
    $self = $self->max('1000x1000');

A hash reference with keys width and height. Defaults to {width = 1000, height => 1000}>. Can be changed via the command line argument --max.

obrazec_file

Path to template file for single html pages. Defaults to embedded template obrazec.html. Can be passed as argument on the command-line via --obrazec.

publish_url

  $обраꙁи->publish_url($string); # $self
  $обраꙁи->publish_url; # $string

String. Url path or preferably full url, where the gallery will reside. Needed for link from individual images to the common gallery page and OpenGraph meta data. Can be passed as argument on the command-line via --url. Defaults to /obrazi.html – rarely what you need.

subprocs_num

    $self->subprocs_num; #4
    $self = $self->subprocs_num(5);

Integer, used to split the number of files found into equal chunks, each of which will be processed in a separate subprocess in parallel. Defaults to 4. See also "files_per_subproc".

template_file

    my $self = $self->template_file('path/to/template.html.ep');
    my $tpl  = $self->template_file;

Path to template file to be used for generating the HTML for the gallery. Defaults to embedded template obrazi.html. Can be passed as argument on the command-line via --template.

thumbs

    my $thumbs_sizes = $self->thumbs; # {width => 100, height => 100}
    $self = $self->thumbs({width => 100, height => 100});
    $self = $self->thumbs('1000x1000');

A hash reference with keys width and height. Defaults to {width = 100, height => 100}>. Can be changed via the command line argument --thumbs.

to_dir

    $self->to_dir # path($app/public)
    $self = $self->to_dir(path('/some/folder'));

A Mojo::File instance. Directory, where the folder with the processed images will be put. Defaults to the public forlder of the current application. Can be changed via the command line argument --to_dir. It is recommended to pass this value unless all your images are into one root folder. The "to_dir" directory is the root of your images' galery.

usage

  my $usage = $обраꙁи->usage;
  $self = $обраꙁи->usage('Foo');

Usage information for this command, used for the help screen. At the bottom are shown the supported by Imager image formats.

METHODS

Mojolicious::Command::Author::generate::obrazi inherits all methods from Mojolicious::Command and implements the following new ones.

calculate_max_and_thumbs

    #   img_1000x1000.jpg, img_100x100.jpg
    my ($img_filename, $thumb_filename) = $self->calculate_max_and_thumbs($decoded_path, $raw_path);

Calculates the resized image dimensions according to the $self->max and $self->thumbs gallery constraints. Accepts the utf8 decoded path and the raw path to the file to be worked on. Returns two empty strings if there is error reading the image and warns about the error. Returns filenames for the resized image and the thumbnail image. See also "scale_calculate()" in Imager::Transformations.

run

  $обраꙁи = $обраꙁи->run(@ARGV);

Run this command.

TEMPLATES

Mojolicious::Command::Author::generate::obrazi contains four embedded templates:

    obrazi.html  — template for a single page gallery, containing all images
    obrazec.html — template for single image html pages
    obrazi.css   — template for CSS rules used in both html templates
    obrazi.js    — JavaScript (jQuery) code for handling navigation and effecs 
                   in obrazi.html

TODO: Maybe make the templates inflatable.

DEMOS

Here is a hopefully growing list of URLs of galleries produced with this software.

Творби на Марио Беров — a gallery, presenting works of the Bulgarian Orthodox icon painter Mario Berov.

SEE ALSO

Imager, Text::CSV_XS Mojolicious, Mojolicious::Guides, https://mojolicious.org,

jQuery – used for implementing the lightbox functionality,

Chota (A micro (~3kb) CSS framework) – also used for the example implementation.