————————————#!/usr/bin/env perl
use
strict;
use
warnings;
use
Data::Dumper;
=pod
=head1 NAME
deepzoom - converting images into the DZI format
=head1 SYNOPSIS
# everything will be generated in the current directory
deepzoom holidays.png
# creating the relevant files somewhere else
deepzoom --path=/var/www/ holidays.jpg
# also renaming them
deepzoom --path=/var/www/ --prefix=vienna holidays.jpg
# converting a whole album
deepzoom day1.jpg day2.jpg day3.jpg ...
# trying this with a document
deepzoom --document=linear page1.png page2.png page3.png ...
=head1 DESCRIPTION
This program allows to convert one (large) image into a set of specifically designed image tiles, so
that the image can be viewed with DeepZoom image clients (AJAX or MS SilverLight) with varying
resolutions. Bootstrap yourself via L<http://en.wikipedia.org/wiki/Deep_Zoom>.
This program accepts image file names on the command line, and generates these tiles at a file
system location of your choice. It also generates the XML descriptor as file.
=head1 Usage
=head2 Arguments
Arguments are all names of image files. If one of them cannot be read by L<Image::Magick> then the
program will die.
=head2 Options
Following command line switches are understood:
=cut
my
%options
;
=over
=item B<prefix> (string, default: file name)
If provided, then the outgoing files (.xml and _files) will be prefixed with this. Otherwise the
file name is used. In I<document mode> (where all images are part of one larger) the prefix is
derived from the first image.
=cut
my
$prefix
;
$options
{
'prefix=s'
} = \
$prefix
;
=item B<path> (string, default: current directory)
This option controls where the files are to be generated.
=cut
use
Cwd;
my
$path
= getcwd .
'/'
;
$options
{
'path=s'
} = \
$path
;
=item B<format> (string, default: png)
This controls the format of the image pyramid.
B<NOTE>: TIFF is not yet properly supported, in that each tile currently will be stored into a separate TIFF.
=cut
my
$format
=
'png'
;
$options
{
'format=s'
} = \
$format
;
=item B<overlap> (integer, default: 4)
This specifies how much the generated tile images will overlap.
=cut
my
$overlap
= 4;
$options
{
'overlap=i'
} = \
$overlap
;
=item B<tilesize> (integer, default: 256)
The smaller the tiles, the more there will be, but the quicker each will load. The default or C<256>
works well for photos and graphics. For images containing text, a larger tile size is probably
better.
=cut
my
$tilesize
= 256;
$options
{
'tilesize=i'
} = \
$tilesize
;
=item B<loglevel> (string, default: OFF)
The log level can be set to any of the following values:
OFF
FATAL
ERROR
WARN
INFO
DEBUG
ALL
=cut
my
$loglevel
=
'OFF'
;
$options
{
'loglevel=s'
} = \
$loglevel
;
=item B<document> (undef, linear or exponential, default: undef)
In I<document mode> the program will interpret all images as images of pages of a single document. It
will produce composite images of the first pages (of the document). In I<linear mode> this is pages 1,
1-4, 1-9, 1-16, in I<exponential mode> this are pages 1, 1-4, 1-16, 1-32, 1-64.
Depending on the resolution within the DeepZoom tiling process the above composites are
consulted. The overall idea being that at some distance, one only sees the start page of a document,
and the more you zoom in, the more pages you get to see.
=cut
my
$document
=
undef
;
$options
{
'document=s'
} = \
$document
;
=item B<stretch> (integer, default: 1)
This integer stretch factor will be applied to the incoming image. It is ok to use if your image
quality is not that high, but you still want to generate larger pictures. You will see some resizing
artefacts at high resolutions.
B<NOTE>: Does not work with the document mode (yet).
=cut
my
$stretch
= 1;
$options
{
'stretch=i'
} = \
$stretch
;
=item B<help>
...does hopefully what you would expect.
=cut
my
$help
;
$options
{
'help|?|man'
} = \
$help
;
=back
=cut
#== here the fun begins ==================================================================
#-- consume the command line options -----------------------------------------------------
use
Getopt::Long;
if
(!GetOptions (
%options
) ||
$help
) {
pod2usage(
-exitstatus
=> 0,
-verbose
=> 2);
}
#-- Logging ------------------------------------------------------------------------------
Log::Log4perl->easy_init(
$ERROR
);
our
$log
= Log::Log4perl->get_logger (
"deepzoom"
);
$log
->level (
$loglevel
);
make_path (
$path
);
# assert path
my
@images
;
foreach
my
$arg
(
@ARGV
) {
# slurp in images from the comment line
my
$image
= Image::Magick->new;
$image
->Read (
$arg
) &&
$log
->logdie (
"something is wrong with '$arg'"
);
# stop right there
push
@images
,
$image
;
}
if
(
$document
) {
# document mode tiles the images
my
$pref
;
if
(
$prefix
) {
$pref
=
$prefix
;
}
else
{
(
$pref
,
undef
,
undef
) = fileparse (
$ARGV
[0],
qr/\.[^.]+$/
);
}
$Graphics::DZI::log
->level (
$loglevel
);
$Graphics::DZI::A4::log
->level (
$loglevel
);
my
$dzi
= new Graphics::DZI::A4 (
A4s
=> \
@images
,
overlap
=>
$overlap
,
tilesize
=>
$tilesize
,
path
=>
$path
.
$pref
.
'_files/'
,
prefix
=>
$pref
,
pack
=>
$document
,
'format'
=>
$format
,
);
$log
->info (
"writing descriptor to "
.
$path
.
$pref
.
'.xml'
);
write_file (
$path
.
$pref
.
'.xml'
,
$dzi
->descriptor
);
$log
->info (
"writing tiles to "
.
$path
.
$pref
.
'_files/'
);
$dzi
->iterate ();
}
else
{
no
warnings;
my
@docs
= pairwise {
{
image
=>
$a
,
file
=>
$b
,
} }
@images
,
@ARGV
;
foreach
my
$d
(
@docs
) {
my
$pref
;
if
(
$prefix
) {
$pref
=
$prefix
;
}
else
{
(
$pref
,
undef
,
undef
) = fileparse (
$d
->{file},
qr/\.[^.]+$/
);
}
$Graphics::DZI::log
->level (
$loglevel
);
$Graphics::DZI::Files::log
->level (
$loglevel
);
my
$dzi
= new Graphics::DZI::Files (
image
=>
$d
->{image},
overlap
=>
$overlap
,
tilesize
=>
$tilesize
,
scale
=>
$stretch
,
path
=>
$path
.
$pref
.
'_files/'
,
prefix
=>
$pref
,
'format'
=>
$format
,
);
$log
->info (
"writing descriptor to "
.
$path
.
$pref
.
'.xml'
);
write_file (
$path
.
$pref
.
'.xml'
,
$dzi
->descriptor);
$log
->info (
"writing tiles to "
.
$path
.
$pref
.
'_files/'
);
$dzi
->iterate ();
}
}
=head1 PITFALLS
=over
=item You are running out of memory with large maps?
=item The process takes long time?
Well, that is just so. But one wise thing is to move all newly generated stuff into the target
location when everything is finished.
=item Should not the package delete files before writing?
I do not think so, Tim. ;-)
=item Tile generation looks fine, but the tiles look completely distorted in the browser?
That happened to me when a PNG image had a "page geometry" which was different from the
picture geometry. The tiles seem to inherit the page geometry and on the client side things
get really messed up.
=back
=head1 AUTHOR
Robert Barta, C<< <drrho at cpan.org> >>
=head1 COPYRIGHT & LICENSE
Copyright 2010 Robert Barta, all rights reserved.
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=cut
our
$VERSION
=
'0.03'
;
__END__