Jithin
Jithin

Reputation: 2604

PHP ImageMagick split large image to tiles

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.

Upvotes: 0

Views: 3096

Answers (2)

jcupitt
jcupitt

Reputation: 11220

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

Upvotes: 0

emcconville
emcconville

Reputation: 24439

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");

Upvotes: 4

Related Questions