Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
PerlMonks image splitter

by djw (Vicar)
on Mar 30, 2002 at 13:55 UTC ( #155428=sourcecode: print w/replies, xml ) Need Help??
Category: Web Stuff
Author/Contact Info djw
Description: Split has one purpose: crop 654x300 images into 6 equal sized smaller images that span two rows, and three columns. Html output (one page per image) is optional (on by default).

I decided to do this after I talked to a buddy of mine Chris (from the sexy about a site called

We were looking at some of the very cool art in the photo albums and saw that some people cut up a single larger picture into 6 pieces so they could fit the entire thing into one page of the album (you will have to go check out the site to see what I mean). Chris was telling me that this process can take a long time, and I mentioned I could write something to automate it.

TaDA! Split was created.

This program was written specifically for the image gallery, but it could be expanded for your own use if you feel like it. Or maybe you just need a chunk of code from it for something you are doing.

Thought I'd post it anyhow.
Sample: my car!

Thanks, djw
#!/usr/bin/perl -w
use strict;

# -----------    
# 'split' written by David Wakeman 
# and distributed using the GPL license.
# Created 03.28.2002 on planet earth.
# Use at your own risk. I am not responsible
# for any loss of data, loss of life, computer
# equipment explosion, divorce, dropped food
# or anything else that you may think happened
# because of this program.
# Enjoy!
# -----------    

use Imager;
use IO::File;
use Getopt::Long;
use File::Spec::Win32;
use File::DosGlob 'glob';
use Time::HiRes qw( gettimeofday );

# -----------    
# command-line args (html on|off and image list)
my ($hoff, @images);
GetOptions( "hoff"    => \$hoff );

if (@ARGV) { 
    foreach (@ARGV) { push(@images, $_); } 
} else {
    @images = glob "*.jpg";

my $imageCount = @images;
unless ($imageCount > 0) { print "No images found!\n\n"; &usage; }


# -----------    
# main sub

sub process {
    my $count = 0;
    my $message = "Cannot crop image";
    open(LOG, "+>splitlog.txt") || die "Can't open log: ($!)\n";

    my ($secs, $msecs) = gettimeofday;
    foreach (@images) {
        $_ =~ /(.*?).jpg/i;
        my $pic = $1;
        # -----------    
        # start our image object

        my $img = Imager->new();
        $img->open(file => "$_");
        # -----------    
        # check image size
        my $imgHeight = $img->getheight();
        my $imgWidth  = $img->getwidth();

        if ($imgHeight != 300 && $imgWidth != 654) {
            print LOG "$_ does not conform to x,y requirements - skipp
        # image is good so increment
        # -----------    
        # crop image 6 times
        my $newImage01 = $img->crop( left=>0  , right=>218, top=>0  , 
+bottom=>150 ) || die "$message: ($!)\n";
        my $newImage02 = $img->crop( left=>218, right=>437, top=>0  , 
+bottom=>150 ) || die "$message ($)): ($!)\n";
        my $newImage03 = $img->crop( left=>437, right=>654, top=>0  , 
+bottom=>150 ) || die "$message ($_): ($!)\n";
        my $newImage04 = $img->crop( left=>0  , right=>218, top=>150, 
+bottom=>300 ) || die "$message ($_): ($!)\n";
        my $newImage05 = $img->crop( left=>218, right=>437, top=>150, 
+bottom=>300 ) || die "$message ($_): ($!)\n";
        my $newImage06 = $img->crop( left=>437, right=>654, top=>150, 
+bottom=>300 ) || die "$message ($_): ($!)\n";
        # -----------    
        # write it out

        $newImage01->write(file => "$pic-01.jpg");
        $newImage02->write(file => "$pic-02.jpg");
        $newImage03->write(file => "$pic-03.jpg");
        $newImage04->write(file => "$pic-04.jpg");
        $newImage05->write(file => "$pic-05.jpg");
        $newImage06->write(file => "$pic-06.jpg");

        unless ($hoff) { &writeHTML($pic, $_); }
    my $createCount = $count * 6;    
    my ($secs2, $msecs2) = gettimeofday;
    my $stime = $secs2  - $secs;
    my $mtime = $msecs2 - $msecs;
    my $totalTime = "$stime.$mtime";

    print LOG "Files processed: $count\n";
    print LOG "Images created : $createCount\n";
    print LOG "Processing time: $totalTime seconds\n";

# -----------    
# on by default

sub writeHTML {
    my ($pic, $originalImage) = @_;
    my (%imageInfo, $kbytes, $sum);
    ($kbytes) = (stat($originalImage))[7];
    my $origSize = $kbytes / 1024;
    $origSize =~ /(\d+)\.(\d\d)/;
    my $originalImageSize = "$1.$2";
    my @newImages = ( 
    foreach (@newImages) {
        ($kbytes) = (stat($_))[7];
        my $size = $kbytes / 1024;
        $size =~ /(\d+)\.(\d\d)/;
        $imageInfo{$_} = "$1.$2";
        $sum += "$1.$2";
    open(FILE, "+>$pic.html") || die "Can't create html file: ($!)\n";
    print FILE "<html><head><title>$pic.jpg preview</title>\n";
    print FILE "<!-- \'split\' written by David Wakeman - http://perld -->\n";    
    # -----------    
    # css style tags
    print FILE "<style type=\"text/css\">\n";
    print FILE "\tBODY {\n";
    print FILE "\t\tbackground: #FFFFFF;\n";
    print FILE "\t}\n";
    print FILE "\t.imageframe {\n";
    #print FILE "\t\tborder: 1px solid black;\n";
    print FILE "\t}\n";
    print FILE "\t.titleinfo {\n";
    print FILE "\t\tborder: 1px solid black;\n";
    print FILE "\t\tcolor: #FF6600;\n";
    print FILE "\t\tfont-family: Tahoma, Verdana, sans-serif;\n";
    print FILE "\t\tfont-size: 10px;\n";
    print FILE "\t\tfont-weight: normal;\n";
    print FILE "\t\ttext-decoration: none;\n";
    print FILE "\t}\n";
    print FILE "</style>\n";
    # -----------    
    # html meat

    print FILE "</head>\n";
    print FILE "<body>\n";
    print FILE "<center>\n";

    print FILE "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\
+" width=\"200\">\n";
    print FILE "<tr>\n";
    print FILE " <td class=\"titleinfo\" align=\"center\"><b>File Info
    print FILE "</tr>\n";
    print FILE "<tr>\n";
    print FILE "<td class=\"titleinfo\">\n";
    print FILE "<b>Original size</b>: $originalImageSize KB<br>\n";
    print FILE "<b>Combined size</b>: $sum KB\n";
    print FILE "<ul>\n";
    foreach (@newImages) {
        print FILE "<b>$_</b>: $imageInfo{$_} KB <br>\n";
    print FILE "</ul></td></tr>\n";
    print FILE "</table>\n<br>\n";
    # -----------    
    # image table
    print FILE "<table border=\"0\" cellpadding=\"0\" cellspacing=\"4\
    print FILE "<tr>\n";
    # -----------    
    # first set of images across (row 1)
    print FILE " <td class=\"imageframe\"><img src=\"$pic-01.jpg\" bor
    print FILE " <td class=\"imageframe\"><img src=\"$pic-02.jpg\" bor
    print FILE " <td class=\"imageframe\"><img src=\"$pic-03.jpg\" bor

    print FILE "</tr><tr>\n";

    # -----------
    # second set of images across (row 2)
    print FILE " <td class=\"imageframe\"><img src=\"$pic-04.jpg\" bor
    print FILE " <td class=\"imageframe\"><img src=\"$pic-05.jpg\" bor
    print FILE " <td class=\"imageframe\"><img src=\"$pic-06.jpg\" bor

    print FILE "</tr></table>\n";
    print FILE "</center>\n";
    print FILE "</body>\n";
    print FILE "</html>\n";


# -----------    
# called by command-line option
# or if it can't find any jpg's
# in current dir.

sub usage {
    print "\nusage: -hoff [ [filename 1] [filename 2] ]\n\n";
    print " By default with no arguments will attempt to\n";
    print " process every jpg file in the current directory, and will\
    print " produce an html page per image 'set' so you can view outpu
    print " and see file size information.\n\n";
    print "\t' foo.jpg bar.jpg foobar.jpg'\n";
    print "\t\tor\n";
    print "\t' -hoff foo.jpg bar.jpg foobar.jpg'\n\n";

    print " The first method allows you to specify certain images and\
    print " the second turns off html output and specifies only certai
    print " images to be processed.  The html off option can be called
    print " by itself.\n\n";
    print " Please read the readme.txt associated with this program fo
    print " more info.\n";
Replies are listed 'Best First'.
•Re: image splitter
by merlyn (Sage) on Mar 30, 2002 at 17:30 UTC
    my $newImage01 = $img->crop( left=>0 , right=>218, to +p=>0 , bottom=>150 ) || die "$message: ($!)\n"; my $newImage02 = $img->crop( left=>218, right=>437, to +p=>0 , bottom=>150 ) || die "$message ($)): ($!)\n"; my $newImage03 = $img->crop( left=>437, right=>654, to +p=>0 , bottom=>150 ) || die "$message ($_): ($!)\n"; my $newImage04 = $img->crop( left=>0 , right=>218, to +p=>150, bottom=>300 ) || die "$message ($_): ($!)\n"; my $newImage05 = $img->crop( left=>218, right=>437, to +p=>150, bottom=>300 ) || die "$message ($_): ($!)\n"; my $newImage06 = $img->crop( left=>437, right=>654, to +p=>150, bottom=>300 ) || die "$message ($_): ($!)\n";
    Unless I'm misreading Imager's docs, or it works in some bizarre ways, you're duplicating a thin line of pixels at each border. I think you want top 0, bottom 149 in one picture, and top 150, bottom 300 in the other. Similarly for left and right.

    On a more general note, since you'll be now editing this portion of the code anyway {grin}, I'd get rid of that complex series of constants and use a computed loop anyway.

    -- Randal L. Schwartz, Perl hacker

      Originally I thought as you did and only went to 149 in the first block, and same goes for the width. But when I took the images into photoshop, I noticed that they were no longer each 218x150. They were all missing one pixel depending on which row they were in (eg 217x150 or 218x149).

      If I do as you say then I lose pixel data from 149-150 on the grid and that isn't a good thing =) I think it helps if you think of the picture as a grid.

      I joined the picture back up (of my car - the sample image) and it doesn't seem to be duplicating any part of the image, but I could be wrong because its hard to tell. Maybe I'll join it again and switch my desktop resolution to 640x480 so I can see for sure.

      As for the chunk you mentioned above, yeah I should put that into a loop. I wrote the imager part seperate from the rest of the program and added it later - the code you posted was a quick test of Imager. I'll do that right away - I plan on making this a bit more flexible so you can adjust the croping etc.

        Originally I thought as you did and only went to 149 in the first block, and same goes for the width. But when I took the images into photoshop, I noticed that they were no longer each 218x150. They were all missing one pixel depending on which row they were in (eg 217x150 or 218x149).
        Sounds like a bug in either Imager or its docs. {grin}

        -- Randal L. Schwartz, Perl hacker

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: sourcecode [id://155428]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (9)
As of 2017-01-24 04:28 GMT
Find Nodes?
    Voting Booth?
    Do you watch meteor showers?

    Results (202 votes). Check out past polls.