Category Archives: GitHub

PHP Image Manipulation Options Compared

I recently released SSTiles, a map tile maker which used ImageMagick (using Imagick) or GD to generate tiles. It worked great locally, but when I uploaded it to my shared hosting provider I found that the Imagick module wasn’t enabled.

When I started looking into how to enable it, I found out that I had several other options, so I decided to implement the tile creation algorithm using each of the libraries and benchmark them. You can check out the code on GitHub, and below you’ll find the results.

The Contenders

  • GD
  • Imagick (ImageMagick)
  • MagickWand (ImageMagick too)
  • convert (ImageMagick command-line binary)
  • GraphicsMagick (a fork from ImageMagick).

The Testing Setup

The machine was a ThinkPad W530 with 32 Gigs of RAM and an Intel  i7-3610QM CPU at 2.30GHz. It has a 5400rpm hard drive.

I’m running Debian Jessie, with the Linux 3.10-3-amd64 kernel. The server software was Apache 2.4.6 and PHP 5.5.4.

Xdebug was enabled to generate cachegrind files, but it’s known to have performance implications. I used XHProf to capture memory usage information. I used microtime to time each tile creation.

I ran 1000 tile create operations with each of the contenders. Each iteration does the following algorithm:

  1. Determine the dimensions of the source image.
  2. Determine the number of tiles in the requested slippy map zoom leve.
  3. Crop the specified tile out of the source image.
  4. If the tile is not square, stretch it to the appropriate dimensions.
  5. Write the image to a cache file.
  6. Print the image to the browser.

For a different server configuration or a different set of operations a different library may be faster or use less memory.

Speed

Using the ImageMagick command line tools (convert and identify) via shell_exec (or backticks) was both the fastest and the slowest method of generating thumbnails. It trended heavily towards the faster end of the spectrum though.

GD was the most consistent image library, having both least variation between tile creation rounds.

Box and Whisker Chart of Tile Making Speeds
Box and Whisker Chart of Tile Making Speeds
Fastest, Average and Slowest Runs
Fastest, Average and Slowest Runs

 

Here’s a chart showing the fastest, average and slowest run for each function. Each function was called 1000 times, and each function created the same set of 1000 tiles.

makeCacheMagickWand makeCacheGD makeCacheGM makeCacheIM makeCacheIMExec
Fastest 0.55773 0.43987 0.41371 0.60702 0.03325
Average 0.66085 0.44901 0.48161 0.64898 0.36651
Slowest 0.85648 0.47315 0.52995 0.70556 0.90478

You can also see the breakdown for each method as visualized by KCachegrind. I added the red bars to show where each method is divided.  It seems that in all cases reading the image is what takes the most time.

KCachegrind View of The Time Breakdown
KCachegrind View of The Time Breakdown

Memory

I’m not 100% sure how to interpret these XHProf memory usage results. There are two columns in the output tables: Inclusive Memory Usage and Inclusive Peak Memory Usage. I tried asking on Reddit but got no answer. I assume that someone will come along here at some point and tell me that I missed some obvious documentation somewhere.

At the moment I believe that Inclusive Memory Usage is memory managed by PHP, while Inclusive Peak Memory Usage is total memory used. This is especially important on shared hosting environments where the PHP memory limit is low but the shell memory doesn’t count.

In any case, less memory used is better so let’s take a look.

Inclusive Memory Usage
Inclusive Memory Usage
Inclusive Peak Memory
Inclusive Peak Memory Usage
Combined Memory Usage Chart
Combined Memory Usage Chart

 

 

MagickWand GD GM IM IMExec
Incl Mem Use (bytes) 21032 13592 144080 176296 7216
Incl Peak Mem Use (bytes) 22728 22920 5024 12296 28152

 

Conclusion

In my use case the tiles only need to get generated once (due to caching), but that generation needs to work without running out of memory. Since SSTiles automatically picks which method to use to create tiles, I’ve ordered those checks by which uses the least memory (Inclusive Memory Usage).

Posted in Computers, GitHub, Programming, Something Interesting | Tagged , , , , , | 3 Comments

Announcing the Stupid Simple Geocoder

Over at Moore Spatial I just announced the initial release of the Stupid Simple Geocoder.

Download it over at GitHub!

It’s written PHP and uses the Geonames geocoding service. It tries to cache geocode results in an SQLite database.

It’s stupidly simple, with a single optional parameter in the constructor and a single public method.

The parameter is an optional path to specify a location for an SQLite database.

The method is called “geocode” and takes an array of place names. It returns an array of GeoJSON Features which you can create FeatureClasses with, or use however you want.

It’s a piece of larger project I’m working on, but seemed semi-useful on its own.

Here’s an example of using it to create a feature class out of several places names in an array:

<?php
$places = Array(
  'Ironwood, MI, USA',
  'Sacramento, MG, Brazil',
  'Provo',
  'Lostlandneverfoundcity'
);

require_once('ssgeocoder.php');
$ssgeocoder = new ssgeocoder();
$features = $ssgeocoder->geocode($places);
$geojson = Array(
    'type' => 'FeatureCollection',
    'features' => $features
);

print json_encode($geojson);

Not too bad, right? You’ll see this used again in a couple of other projects I’m working on.

Posted in Computers, GitHub, Programming | Tagged , , , | Leave a comment