http://qs321.pair.com?node_id=11116343

Here's a script I use all the time via the right-click menu in my file manager (Nautilus), it will shrink PDFs and images so they work better as email attachments (Update: to be a little more specific: files that are several MB or more are usually due to high-resolution images, so this script runs commands to reduce their resolution). It does require Path::Class, ImageMagick's convert, GhostScript's gs, and my modules IPC::Run3::Shell and Shell::Tools.

#!/usr/bin/env perl use Shell::Tools::Extra Shell => [qw/ :FATAL convert gs /]; use autodie ':all'; use File::stat; =head1 SYNOPSIS shrink FILENAMEs... =head1 DESCRIPTION Shrinks images and PDFs using ImageMagick resp. Ghostscript. Output files will have the same name but with F<_sm> appended, for example F<foo.jpg> becomes F<foo_sm.jpg>. This script will not overwrite existing files. Place this script in C<< ~/.local/share/nautilus/scripts/ >> for it to show up in the Nautilus right-click menu. =cut getopts('', \my %opts) or pod2usage; warn "no filenames specified\n" unless @ARGV; for my $f (@ARGV) { if (not -e -f $f) { warn "doesn't exist or isn't a file, skipping: $f\n"; next } my ($bn,undef,$ext) = fileparse $f, qr/\.[^\.]+$/; my ($mode,$of); if ( $ext=~/^\.(?:jpe?g|png|gif)$/i ) { $mode = 'img'; $of = file($f)->dir->file($bn."_sm.jpg"); } elsif ( $ext=~/^\.pdf$/ ) { $mode = 'pdf'; $of = file($f)->dir->file($bn."_sm".$ext); } else { warn "I don't handle the extension $ext, skipping: $f\n"; next } if (-e $of) { warn "output already exists, skipping: $of\n"; next } if ( $bn=~/_sm$/ ) { warn "appears to already be shrunk, skipping: $f\n"; next } if ($mode eq 'img') { convert "$f", qw{ -auto-orient -resize 1000x1000> -strip -qu +ality 95 }, "$of" } elsif ($mode eq 'pdf') { gs qw{ -q -dBATCH -dNOPAUSE -dSAFER -sDEVICE=pdfwrite -dPDFS +ETTINGS=/ebook -dAutoRotatePages=/None }, "-sOutputFile=$of", "$f" } else { die "internal error '$mode'" } chmod stat($f)->mode, $of; } =head1 AUTHOR, COPYRIGHT, AND LICENSE Copyright (c) 2017 Hauke Daempfling (haukex@zero-g.net) at the Leibniz Institute of Freshwater Ecology and Inland Fisheries (I +GB), Berlin, Germany, L<http://www.igb-berlin.de/> 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 3 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, see L<http://www.gnu.org/licenses/>. =cut

(Also, not Perl related, but I use this pretty much every day: setting up a keyboard combination such as Ctrl+Shift+F for the shell command xsel -b | xsel -ib, which causes the current clipboard buffer to be converted to text-only, which has been incredibly useful when copying formatted text that I don't want to keep the formatting of. The shell command may need to be placed into a simple script file depending on whether you can configure keyboard shortcuts to run a shell command, or if they can only run a single executable.)

My 3000th node! :-O

Replies are listed 'Best First'.
Re: Shrink Images and PDFs
by parv (Parson) on May 02, 2020 at 11:08 UTC

    I see that an image is resized to maximum of 1000 px square (input images are supposedly of larger size). For your PDF files, what does gs do or not do which reduce the PDF file size? Is it mainly ebook option?

      For your PDF files, what does gs do or not do which reduce the PDF file size? Is it mainly ebook option?

      Yes, I've found the ebook option a convenient way to downsample the resolution of the images embedded in a PDF to 150 DPI. So this script will have a significant effect on PDF files that are large due to them containing high-resolution images (like scans), and less of an effect on PDFs that are already smaller than ~1MB.

        Ah, ok. Thanks for the explanation, mainly because I had not thought of embedded images. I was thinking that ebook option might be restructuring the PDF, using common fonts and removing embedded fonts, etc.

Re: Shrink Images and PDFs
by anita2R (Scribe) on May 12, 2020 at 11:43 UTC

    Thanks for your post.

    I installed the Perl script in the scripts directory for nemo running on Mint, and although the script showed up in the context menu, it didn't run (I added some code to write to a file as a test). A bash script in the same location and with the same user/group/permissions did run OK.

    My thought was that there was an environment issue. To get the perl script to work I added a perl libraries path like this:

    use lib '/home/<myusername>/perl5/lib/perl5/';

    I don't know if this was an issue with Mint/nemo or with my installation of perl, but this may help someone else who has the same problem.

    Now shrink works from the context menu - at least for images - I haven't tried any pdf's yet.

    It was just what I had been looking for when preparing images to share with others, so much easier than opening an image manipulation program and manually having to edit and save a new file. Thanks again.

      Thanks very much for the feedback, I'm glad to hear it's helpful. As for the @INC issue, my guess would be that your local::lib configuration is set in your ~/.bashrc or ~/.profile, and that doesn't get run for these scripts. So thank you for providing a workaround for anyone who might run into the same issue.

Re: Shrink Images and PDFs
by perlfan (Vicar) on Jun 13, 2020 at 04:25 UTC
    Nice. If convert is on your system, chances are so is Image::Magick. Is there a reason to not use a pure Perl implementation rather than forking a convert process? You may want to look for a Perl interface to gs as well. I'd be surprised if a decent one didn't exist.
      If convert is on your system, chances are so is Image::Magick.

      Not in my experience; usually the Perl module has to be installed separately. How easy that is depends on what Perl you're using, for example, one could use the system Perl and just install libimage-magick-perl, but building ImageMagick (or GraphicsMagick nowadays, apparently) and its Perl module can be a can of worms.

      Is there a reason to not use a pure Perl implementation rather than forking a convert process?

      Simplicity, mostly. This was only intended for *NIX (for now), I wasn't concerned about performance, and since I'm using my own IPC::Run3::Shell module, I can be sure to avoid all the pitfalls of running external commands. Using the Perl module would be better if I was doing multiple operations on the image that are hard to do in a single command line, but the convert command line I'm using is simple enough.

        >usually the Perl module has to be installed separately

        Sorry, I meant that the Perl module comes with installing ImageMagick itself if you do it from source. From my experience installing it from source is straightforward (they make it so necessarily). Just a thought I wanted to mention since I've use gone down a similar route with image manipulation. I didn't do any shrinking, but added some watermarks to images I was serving. I also served up different "sizes". But it was all done via the Perl library, not convert itself. Anyway, I think your use of Perl is really neat here.