Python, C and C++ efficiency on JPG thumbnail creation
Check out the new site at https://rkblog.dev.
4 August 2008
Comments
To create thumbnails of image files we can use few libraries like:
But there are also smaller libraries like Epeg from the development branch of Enlightment (E17) which uses only libjpeg to make thumbnails. Now which of them will be faster? And if we make Python modules from EPEG library how much slower they will be than the original C runtime?
Epeg
We can download EPEG source code and compile it without e17 (needs only libjpeg). After compile and install there will be an app called "epeg", but we will make our own, with epeg.c file like this:#include <stdlib.h>
#include <unistd.h>
#include <Epeg.h>
#define PROGRAM "ethumber"
int
main(int argc, char **argv)
{
Epeg_Image * image;
int ch, height, quality, width;
char *input, *output;
/* Default values - can be overidden */
quality = 80;
height = 125;
width = 125;
output = "thumb.jpg";
while ((ch = getopt(argc, argv, "h:i:o:q:w:")) != -1) {
switch (ch) {
case 'h':
height = atoi(optarg);
break;
case 'i':
input = optarg;
break;
case 'o':
output = optarg;
break;
case 'q':
quality = atoi(optarg);
break;
case 'w':
width = atoi(optarg);
break;
default:
exit (0);
}
}
image = epeg_file_open(input);
if (!image) {
exit (0);
}
epeg_decode_size_set(image, width, height);
epeg_quality_set (image, quality);
epeg_file_output_set(image, output);
epeg_encode(image);
epeg_close(image);
return 0;
}
gcc epeg.c -o epeg `epeg-config --cflags --libs`
And the compile "epeg" binary can be used like this:
./epeg -i file.jpg -o thumb.jpg -h heigth -w width -q quality
PIL
Python Imaging Library - the thing you would use in Python to make thumbs. It also has some filters like ANTIALIAS and SHARPEN which increase the quality of the thumbnails. Test script looks like this:from sys import argv
import Image
import ImageFilter
quality = 80
width = 125
heigth = 125
source = False
thumb = False
sharp = False
if '-q' in argv:
quality = int(argv[argv.index('-q')+1])
if '-h' in argv:
heigth = int(argv[argv.index('-h')+1])
if '-w' in argv:
width = int(argv[argv.index('-w')+1])
if '-i' in argv:
source = argv[argv.index('-i')+1]
if '-o' in argv:
thumb = argv[argv.index('-o')+1]
if '-s' in argv:
sharp = True
if source and thumb:
im = Image.open(source)
im.thumbnail((width, heigth), Image.ANTIALIAS)
if sharp:
im.filter(ImageFilter.SHARPEN)
im.save(thumb, "JPEG",quality=quality)
Benchmark settings
- I've measured time (bash/time) needed to make thumbs from 18 big JPEG files (35 MB).
- For every tested library a simple bash script was used. For imagemagick:
for plik in sources/* do convert $plik -thumbnail 250x187 -quality 80 thumbs/ithum$plik done
- EDIT: in case of imagemagick also -size param should be set so imagemagick would only read needed part of file to create the thumb, and not the whole.
- All libraries were ordered to make the same thumbs with the same settings (quality, width, heigth).
Making Python modules from EPEG in C and C++/BOOST
We can use Python standard API in C to make a Python module. The code would look like this:#include <stdlib.h>
#include <unistd.h>
#include <Python.h>
#include <Epeg.h>
static PyObject *
epg_thumbnail(PyObject *self, PyObject *args)
{
Epeg_Image * image;
int ch, height, quality, width;
char *input, *output;
if (!PyArg_ParseTuple(args, "ssiii", &input, &output, &quality, &height, &width))
return NULL;
image = epeg_file_open(input);
if (!image) {
exit (0);
}
epeg_decode_size_set(image, width, height);
epeg_quality_set (image, quality);
epeg_file_output_set(image, output);
epeg_encode(image);
epeg_close(image);
Py_BuildValue("i", 1);
}
static PyMethodDef epg_methods[] = {
{"thumbnail", (PyCFunction)epg_thumbnail, METH_VARARGS, "Funkcja epeg."},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initepg() {
Py_InitModule3("epg", epg_methods, "Miniatury z Epeg");
}
gcc -shared -I /usr/include/python2.5/ epg.c -o epg.so -fPIC `epeg-config --cflags --libs`
We can also use C++ and BOOST/Python. The code would look like this:
#include <boost/python.hpp>
#include <stdlib.h>
#include <unistd.h>
#include <Epeg.h>
int
thumbnail(char *input, char *output, int quality, int height, int width)
{
Epeg_Image * image;
int ch;
image = epeg_file_open(input);
if (!image) {
exit (0);
}
epeg_decode_size_set(image, width, height);
epeg_quality_set (image, quality);
epeg_file_output_set(image, output);
epeg_encode(image);
epeg_close(image);
return 0;
}
BOOST_PYTHON_MODULE(bstepg)
{
using namespace boost::python;
def("thumbnail", thumbnail);
}
gcc -lboost_python -shared -I /usr/include/python2.5/ bstepg.cpp -o bstepg.so -fPIC `epeg-config --cflags --libs` -I/usr/include/boost
The results
- EPEG - 4,15s
- PyEPEG C - 4,54s
- PyEPEG BOOST - 4,58s
- PIL - 11,61s
- IMAGEMAGICK - 29,32s
- IMAGEMAGICK -size - 10,9s (edit/update)

Description | Epeg | PIL | ImageMagick |
---|---|---|---|
Big image 1,3 MB, 2560x1600 |
![]() 8,5kB |
![]() 8,1kB |
![]() 10,1kB |
Small image 27 kB, 300x506 |
![]() 8,5kB |
![]() 8,5kB |
![]() 8,3kB |
RkBlog
Check out the new site at https://rkblog.dev.
Comment article