From 2b421d6d258ca7e8def83614aaedd8cdbf8640fd Mon Sep 17 00:00:00 2001 From: RamsesA Date: Tue, 3 Jul 2012 20:26:23 -0400 Subject: [PATCH 1/2] added a fast resize function Added resize_half() and resize_half_wrap() functions to composite.c and overviewer.h, to replace the call to PIL's resize function made by tileset.py. Also added "resize_half" to COverviewerMethods in main.c, so it can be called from Python. Should increase performance by 10 to 20% for the entire program. --- overviewer_core/src/composite.c | 154 ++++++++++++++++++++++++++++++- overviewer_core/src/main.c | 3 + overviewer_core/src/overviewer.h | 2 + overviewer_core/tileset.py | 9 +- 4 files changed, 165 insertions(+), 3 deletions(-) diff --git a/overviewer_core/src/composite.c b/overviewer_core/src/composite.c index 3267740..b9d1b34 100644 --- a/overviewer_core/src/composite.c +++ b/overviewer_core/src/composite.c @@ -22,7 +22,8 @@ * PIL paste if this extension is not found. */ -#include "overviewer.h" +#include "overviewer.h" +#include typedef struct { PyObject_HEAD @@ -489,3 +490,154 @@ draw_triangle(PyObject *dest, int inclusive, return dest; } + +/* scales the image to half size + */ +inline PyObject * +resize_half(PyObject *dest, PyObject *src) { + /* libImaging handles */ + Imaging imDest, imSrc; + /* alpha properties */ + int src_has_alpha, dest_has_alpha; + /* iteration variables */ + unsigned int x, y; + /* temp color variables */ + unsigned int r, g, b, a; + /* size values for source and destination */ + int src_width, src_height, dest_width, dest_height; + + imDest = imaging_python_to_c(dest); + imSrc = imaging_python_to_c(src); + + if (!imDest || !imSrc) + return NULL; + + /* check the various image modes, make sure they make sense */ + if (strcmp(imDest->mode, "RGBA") != 0) { + PyErr_SetString(PyExc_ValueError, + "given destination image does not have mode \"RGBA\""); + return NULL; + } + + if (strcmp(imSrc->mode, "RGBA") != 0 && strcmp(imSrc->mode, "RGB") != 0) { + PyErr_SetString(PyExc_ValueError, + "given source image does not have mode \"RGBA\" or \"RGB\""); + return NULL; + } + + src_width = imSrc->xsize; + src_height = imSrc->ysize; + dest_width = imDest->xsize; + dest_height = imDest->ysize; + + /* make sure destination size is 1/2 src size */ + if (src_width / 2 != dest_width || src_height / 2 != dest_height) { + PyErr_SetString(PyExc_ValueError, + "destination image size is not one-half source image size"); + return NULL; + } + + /* set up flags for the src/mask type */ + src_has_alpha = (imSrc->pixelsize == 4 ? 1 : 0); + dest_has_alpha = (imDest->pixelsize == 4 ? 1 : 0); + + /* check that there remains anything to resize */ + if (dest_width <= 0 || dest_height <= 0) { + /* nothing to do, return */ + return dest; + } + + /* set to fully opaque if source has no alpha channel */ + if(!src_has_alpha) + a = 0xFF << 2; + + for (y = 0; y < dest_height; y++) { + + UINT8 *out = (UINT8 *)imDest->image[y]; + UINT8 *in_row1 = (UINT8 *)imSrc->image[y * 2]; + UINT8 *in_row2 = (UINT8 *)imSrc->image[y * 2 + 1]; + + for (x = 0; x < dest_width; x++) { + + // read first column + r = *in_row1; + r += *in_row2; + in_row1++; + in_row2++; + g = *in_row1; + g += *in_row2; + in_row1++; + in_row2++; + b = *in_row1; + b += *in_row2; + in_row1++; + in_row2++; + + if (src_has_alpha) + { + a = *in_row1; + a += *in_row2; + in_row1++; + in_row2++; + } + + // read second column + r += *in_row1; + r += *in_row2; + in_row1++; + in_row2++; + g += *in_row1; + g += *in_row2; + in_row1++; + in_row2++; + b += *in_row1; + b += *in_row2; + in_row1++; + in_row2++; + + if (src_has_alpha) + { + a += *in_row1; + a += *in_row2; + in_row1++; + in_row2++; + } + + // write blended color + *out = (UINT8)(r >> 2); + out++; + *out = (UINT8)(g >> 2); + out++; + *out = (UINT8)(b >> 2); + out++; + + if (dest_has_alpha) + { + *out = (UINT8)(a >> 2); + out++; + } + } + } + + return dest; +} + +/* wraps resize_half so it can be called directly from python */ +PyObject * +resize_half_wrap(PyObject *self, PyObject *args) +{ + /* raw input python variables */ + PyObject *dest, *src; + /* return value: dest image on success */ + PyObject *ret; + + if (!PyArg_ParseTuple(args, "OO", &dest, &src)) + return NULL; + + ret = resize_half(dest, src); + if (ret == dest) { + /* Python needs us to own our return value */ + Py_INCREF(dest); + } + return ret; +} \ No newline at end of file diff --git a/overviewer_core/src/main.c b/overviewer_core/src/main.c index 11a12e2..7389b49 100644 --- a/overviewer_core/src/main.c +++ b/overviewer_core/src/main.c @@ -26,6 +26,9 @@ static PyMethodDef COverviewerMethods[] = { {"alpha_over", alpha_over_wrap, METH_VARARGS, "alpha over composite function"}, + {"resize_half", resize_half_wrap, METH_VARARGS, + "downscale image to half size"}, + {"render_loop", chunk_render, METH_VARARGS, "Renders stuffs"}, diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index c2d1a26..4b5a653 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -69,6 +69,8 @@ PyObject *draw_triangle(PyObject *dest, int inclusive, int x2, int y2, unsigned char r2, unsigned char g2, unsigned char b2, int tux, int tuy, int *touchups, unsigned int num_touchups); +PyObject *resize_half(PyObject *dest, PyObject *src); +PyObject *resize_half_wrap(PyObject *self, PyObject *args); /* forward declaration of RenderMode object */ typedef struct _RenderMode RenderMode; diff --git a/overviewer_core/tileset.py b/overviewer_core/tileset.py index c2a8bec..684e654 100644 --- a/overviewer_core/tileset.py +++ b/overviewer_core/tileset.py @@ -35,6 +35,7 @@ from .files import FileReplacer from .optimizeimages import optimize_image import rendermodes import c_overviewer +from c_overviewer import resize_half """ @@ -858,13 +859,17 @@ class TileSet(object): # Create the actual image now img = Image.new("RGBA", (384, 384), self.options['bgcolor']) - + # we'll use paste (NOT alpha_over) for quadtree generation because # this is just straight image stitching, not alpha blending for path in quadPath_filtered: try: - quad = Image.open(path[1]).resize((192,192), Image.ANTIALIAS) + #quad = Image.open(path[1]).resize((192,192), Image.ANTIALIAS) + src = Image.open(path[1]) + src.load() + quad = Image.new("RGBA", (192, 192), self.options['bgcolor']) + resize_half(quad, src) img.paste(quad, path[0]) except Exception, e: logging.warning("Couldn't open %s. It may be corrupt. Error was '%s'", path[1], e) From 3286b9c576538e7ddf1ea57f40ba1856256c4fd8 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Tue, 3 Jul 2012 21:07:40 -0400 Subject: [PATCH 2/2] tabs -> spaces and removed windows newline --- overviewer_core/src/composite.c | 143 ++++++++++++++++---------------- 1 file changed, 71 insertions(+), 72 deletions(-) diff --git a/overviewer_core/src/composite.c b/overviewer_core/src/composite.c index b9d1b34..6d98847 100644 --- a/overviewer_core/src/composite.c +++ b/overviewer_core/src/composite.c @@ -22,8 +22,7 @@ * PIL paste if this extension is not found. */ -#include "overviewer.h" -#include +#include "overviewer.h" typedef struct { PyObject_HEAD @@ -502,123 +501,123 @@ resize_half(PyObject *dest, PyObject *src) { /* iteration variables */ unsigned int x, y; /* temp color variables */ - unsigned int r, g, b, a; + unsigned int r, g, b, a; /* size values for source and destination */ - int src_width, src_height, dest_width, dest_height; - + int src_width, src_height, dest_width, dest_height; + imDest = imaging_python_to_c(dest); imSrc = imaging_python_to_c(src); - + if (!imDest || !imSrc) return NULL; - + /* check the various image modes, make sure they make sense */ if (strcmp(imDest->mode, "RGBA") != 0) { PyErr_SetString(PyExc_ValueError, "given destination image does not have mode \"RGBA\""); return NULL; } - + if (strcmp(imSrc->mode, "RGBA") != 0 && strcmp(imSrc->mode, "RGB") != 0) { PyErr_SetString(PyExc_ValueError, "given source image does not have mode \"RGBA\" or \"RGB\""); return NULL; } - - src_width = imSrc->xsize; - src_height = imSrc->ysize; - dest_width = imDest->xsize; - dest_height = imDest->ysize; - + + src_width = imSrc->xsize; + src_height = imSrc->ysize; + dest_width = imDest->xsize; + dest_height = imDest->ysize; + /* make sure destination size is 1/2 src size */ if (src_width / 2 != dest_width || src_height / 2 != dest_height) { PyErr_SetString(PyExc_ValueError, "destination image size is not one-half source image size"); return NULL; } - + /* set up flags for the src/mask type */ src_has_alpha = (imSrc->pixelsize == 4 ? 1 : 0); dest_has_alpha = (imDest->pixelsize == 4 ? 1 : 0); - + /* check that there remains anything to resize */ if (dest_width <= 0 || dest_height <= 0) { /* nothing to do, return */ return dest; } - + /* set to fully opaque if source has no alpha channel */ - if(!src_has_alpha) - a = 0xFF << 2; - + if(!src_has_alpha) + a = 0xFF << 2; + for (y = 0; y < dest_height; y++) { - + UINT8 *out = (UINT8 *)imDest->image[y]; UINT8 *in_row1 = (UINT8 *)imSrc->image[y * 2]; UINT8 *in_row2 = (UINT8 *)imSrc->image[y * 2 + 1]; - + for (x = 0; x < dest_width; x++) { - // read first column - r = *in_row1; - r += *in_row2; - in_row1++; - in_row2++; - g = *in_row1; - g += *in_row2; - in_row1++; - in_row2++; - b = *in_row1; - b += *in_row2; - in_row1++; - in_row2++; - + // read first column + r = *in_row1; + r += *in_row2; + in_row1++; + in_row2++; + g = *in_row1; + g += *in_row2; + in_row1++; + in_row2++; + b = *in_row1; + b += *in_row2; + in_row1++; + in_row2++; + if (src_has_alpha) - { - a = *in_row1; - a += *in_row2; - in_row1++; - in_row2++; - } - - // read second column - r += *in_row1; - r += *in_row2; - in_row1++; - in_row2++; - g += *in_row1; - g += *in_row2; - in_row1++; - in_row2++; - b += *in_row1; - b += *in_row2; - in_row1++; - in_row2++; - + { + a = *in_row1; + a += *in_row2; + in_row1++; + in_row2++; + } + + // read second column + r += *in_row1; + r += *in_row2; + in_row1++; + in_row2++; + g += *in_row1; + g += *in_row2; + in_row1++; + in_row2++; + b += *in_row1; + b += *in_row2; + in_row1++; + in_row2++; + if (src_has_alpha) - { - a += *in_row1; - a += *in_row2; - in_row1++; - in_row2++; - } - - // write blended color + { + a += *in_row1; + a += *in_row2; + in_row1++; + in_row2++; + } + + // write blended color *out = (UINT8)(r >> 2); out++; *out = (UINT8)(g >> 2); out++; *out = (UINT8)(b >> 2); out++; - + if (dest_has_alpha) { - *out = (UINT8)(a >> 2); - out++; - } + *out = (UINT8)(a >> 2); + out++; + } } } - + return dest; } @@ -630,7 +629,7 @@ resize_half_wrap(PyObject *self, PyObject *args) PyObject *dest, *src; /* return value: dest image on success */ PyObject *ret; - + if (!PyArg_ParseTuple(args, "OO", &dest, &src)) return NULL; @@ -640,4 +639,4 @@ resize_half_wrap(PyObject *self, PyObject *args) Py_INCREF(dest); } return ret; -} \ No newline at end of file +}