I created a key in Windows registry to have an option on every folder which allows me to simply right click, choose the right option and have a PDF made, either from JPGS, or PNGs, or TIFs.

My registry key is as follows:

'"C:\strawberry\perl\bin\perl.exe" "C:\Users\michal\Documents\createpdf\790024.pl" "%1"'.

The code, thanks to suggestions and some major modifications by Matt Jacob works. Dealing with paths with spaces is done by:

my $folder = $ARGV[0];
$folder =~ s|\\|/|g;
$folder =~ s|/$||;

To read files I have came up with this: my @files = <"$folder/*">;

As I am a Perl newbie, I would like to see if this is correct. It works on my system.

The whole script is as follows:


use PDF::API2;
use strict;
use warnings;

my $folder = $ARGV[0];
$folder =~ s|\\|/|g;
$folder =~ s|/$||;

my $pdf_file = $folder . '.pdf';

die "Not a folder!\n" unless -d $folder;
die "There's already a pdf of that name!\n" if -f $pdf_file;

my $pdf = PDF::API2->new;

my %dispatch = (
    jpg => sub { $pdf->image_jpeg(@_) },
    png => sub { $pdf->image_png(@_) },
    tif => sub { $pdf->image_tiff(@_) },

my @files = <"$folder/*">;

for my $ext (sort(keys(%dispatch))) {
    my $count;

    for my $file (@files) {
        next unless $file =~ /\.$ext$/;

        my $image = $dispatch{$ext}->($file);
        my $page = $pdf->page;
        $page->mediabox(0, 0, $image->width, $image->height);
        $page->trimbox(0, 0, $image->width, $image->height);
        my $gfx = $page->gfx;
        $gfx->image($image, 0, 0);


    last if $count;

if ($pdf->pages) {

I think it's fine, although my preference would be readdir over glob. (I know someone made the exact opposite suggestion on your original post, and that's alright.) I can't really articulate why, but I've never liked glob very much---I guess it just seems too magical to me. Some people would argue "why write three lines of code when you can write one?" or "readdir isn't good because you have to filter out dots" or "readdir isn't good because you have to remember to prepend the directory". OK, so put a tiny wrapper around it in your standard library or use read_dir from File::Slurp. Anyway, moving on...

I did want to comment on your comment:

Dealing with paths with spaces is done by:

my $folder = $ARGV[0];
$folder =~ s|\\|/|g;
$folder =~ s|/$||;

That code doesn't actually do anything related to handling paths with spaces. All it does is take the first command line argument to your script, replacing backslashes with forward slashes and stripping off the trailing slash. It's also unnecessary, since Perl on Windows can deal with either forward or backward slashes in paths. I would also assume that Windows is not giving you a directory path with a trailing slash on it, but I don't have access to a Windows box to confirm that.

Since you are on Windows, the shebang/hashbang line is redundant and can be removed:


Other than that, I think the rest of the code looks pretty good, but I guess it would be strange if I didn't think so, considering that I wrote some of it. When it comes to glob vs. readdir, it's mostly a matter of personal preference, although there's a good thread on Stack Overflow that examines the differences. Read it for yourself and see what you think.

  • \$\begingroup\$ Welcome to Code Review! Good job on your first answer \$\endgroup\$
    – SirPython
    Dec 21 '15 at 21:25
  • \$\begingroup\$ @Matt Jacob Thanks for this. If I understand you correctly $folder =~ s|\\|/|g; $folder =~ s|/$||; can be removed and my $folder = $ARGV[0]; is fine. I removed the above lines (except my $folder = $ARGV[0];) and everything works flawlessly. \$\endgroup\$
    – menteith
    Dec 22 '15 at 12:35
  • \$\begingroup\$ I would encourage people to use either Path::Tiny or File::Slurper for slurping now. File::Slurp is buggy and slow \$\endgroup\$ Feb 14 '16 at 8:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.