0

I am trying to split a large image to smaller tiles. I tried it using PHP ImageMagick cropImage() and I could do it successfully with the following code.

for($w = 0; $w < ($large_image_width/$tile_width); $w++){
    for($h = 0; $h < ($large_image_height/$tile_height); $h++){
        $X = $w*$tile_width;
        $Y = $h*$tile_height;

        $image = new Imagick($input_file);
        $image->cropImage($tile_width,$tile_height, $X,$Y);
        $image->writeImage("X" . ($w+1) . "Y" . ($h+1) . ".jpg");
    }
}

But it loops through each tile size and load the image again and again.

When I did more research, I found this link, which is a one liner using the command line.

convert -crop $WIDTHx$HEIGHT@ huge_file.png  tile_%d.png

I am wondering if the PHP ImageMagick extension got any function to do the same. Also I am comfortable to switch to Perl or someother library like GD.

Jithin
  • 2,594
  • 1
  • 22
  • 42

2 Answers2

4

You can reduce the $input_file I/O by loading the image once, then cloning the object.

$source_image = new Imagick($input_file);
for($w = 0; $w < ($large_image_width/$tile_width); $w++){
    for($h = 0; $h < ($large_image_height/$tile_height); $h++){
        $X = $w*$tile_width;
        $Y = $h*$tile_height;

        $image = clone $source_image;
        $image->cropImage($tile_width,$tile_height, $X,$Y);
        $image->writeImage("X" . ($w+1) . "Y" . ($h+1) . ".jpg");
    }
}

You can also optimize & reduce the for loop, or just call the one liner directly.

system("convert -crop $WIDTHx$HEIGHT@ $input_file  tile_%d.png");
emcconville
  • 23,800
  • 4
  • 50
  • 66
  • Thank you very much for the clone way. And yeah, I am aware of the system command. I meant, Is there any method in PHP ImageMagick extension itself? – Jithin Aug 12 '14 at 05:00
  • 1
    In the PECL extension itself, there is not. You can mimic the behavior by combining Imagick::cropImage & Imagick::setImagePage, but what your already doing is the easiest. – emcconville Aug 12 '14 at 13:47
0

libvips has a php binding now and it can do this task very quickly using only a little memory.

For example:

#!/usr/bin/env php
<?php

require __DIR__ . '/vendor/autoload.php';

use Jcupitt\Vips;

$im = Vips\Image::newFromFile($argv[1]);
$im->dzsave($argv[2], ["overlap" => 0, "tile-size" => 256, "depth" => "one"]);

On this laptop with a 10k x 10k jpeg image, I see:

$ time ./try260.php ~/pics/wtc.jpg x
real    0m2.262s
user    0m3.596s
sys 0m1.256s

And it's created 1369 jpeg files in x_files:

$ ls x_files/0/ | wc
   1369    1369   14319

There's a blogpost here about the dzsave operator (the libvips thing that's being used here):

http://libvips.blogspot.co.uk/2013/03/making-deepzoom-zoomify-and-google-maps.html

jcupitt
  • 10,213
  • 2
  • 23
  • 39