add missing lib/tile.*
authorTero Marttila <terom@fixme.fi>
Thu, 31 Dec 2009 14:01:37 +0200
changeset 18 f92a24ab046e
parent 17 baf3fe7c6354
child 19 ebcc49de97d0
add missing lib/tile.*
Makefile
include/pngtile.h
python/pngtile.pyx
python/setup.py
src/lib/cache.c
src/lib/error.c
src/lib/error.h
src/lib/image.c
src/lib/tile.c
src/lib/tile.h
src/util/main.c
--- a/Makefile	Tue Dec 29 16:44:48 2009 +0200
+++ b/Makefile	Thu Dec 31 14:01:37 2009 +0200
@@ -16,7 +16,7 @@
 all: depend lib/libpngtile.so bin/util
 
 lib/libpngtile.so : \
-	build/obj/lib/image.o build/obj/lib/cache.o build/obj/lib/error.o \
+	build/obj/lib/image.o build/obj/lib/cache.o build/obj/lib/tile.o build/obj/lib/error.o \
 	build/obj/shared/util.o build/obj/shared/log.o
 
 lib/pypngtile.so : \
--- a/include/pngtile.h	Tue Dec 29 16:44:48 2009 +0200
+++ b/include/pngtile.h	Thu Dec 31 14:01:37 2009 +0200
@@ -100,11 +100,23 @@
 int pt_image_update (struct pt_image *image);
 
 /**
- * Render a PNG tile to a stream.
+ * Render a PNG tile to a FILE*.
  *
  * The PNG data will be written to the given stream, which will be flushed, but not closed.
  */
-int pt_image_tile (struct pt_image *image, const struct pt_tile_info *info, FILE *out);
+int pt_image_tile_file (struct pt_image *image, const struct pt_tile_info *info, FILE *out);
+
+/**
+ * Render a PNG tile to memory.
+ *
+ * The PNG data will be written to a malloc'd buffer.
+ *
+ * @param image render from image's cache
+ * @param info tile parameters
+ * @param buf_ptr returned heap buffer
+ * @param len_ptr returned buffer length
+ */
+int pt_image_tile_mem (struct pt_image *image, const struct pt_tile_info *info, char **buf_ptr, size_t *len_ptr);
 
 /**
  * Release the given pt_image without any clean shutdown
--- a/python/pngtile.pyx	Tue Dec 29 16:44:48 2009 +0200
+++ b/python/pngtile.pyx	Thu Dec 31 14:01:37 2009 +0200
@@ -1,16 +1,16 @@
-cdef extern from "stdio.h" :
-    struct FILE :
-        pass
-
 cdef extern from "errno.h" :
     extern int errno
 
 cdef extern from "string.h" :
     char* strerror (int err)
 
+cimport stdio
+cimport stdlib
+cimport python_string
+
 cdef extern from "Python.h" :
     int PyFile_Check (object p)
-    FILE* PyFile_AsFile (object p)
+    stdio.FILE* PyFile_AsFile (object p)
     void PyFile_IncUseCount (object p)
     void PyFile_DecUseCount (object p)
 
@@ -41,7 +41,8 @@
     int pt_image_info_func "pt_image_info" (pt_image *image, pt_image_info **info_ptr)
     int pt_image_status (pt_image *image)
     int pt_image_update (pt_image *image)
-    int pt_image_tile (pt_image *image, pt_tile_info *info, FILE *out)
+    int pt_image_tile_file (pt_image *image, pt_tile_info *info, stdio.FILE *out)
+    int pt_image_tile_mem (pt_image *image, pt_tile_info *info, char **buf_ptr, size_t *len_ptr)
     void pt_image_destroy (pt_image *image)
 
     char* pt_strerror (int err)
@@ -89,8 +90,8 @@
             pt_image_update(self.image)
         )
 
-    def tile (self, size_t width, size_t height, size_t x, size_t y, object out) :
-        cdef FILE *outf
+    def tile_file (self, size_t width, size_t height, size_t x, size_t y, object out) :
+        cdef stdio.FILE *outf
         cdef pt_tile_info ti
 
         if not PyFile_Check(out) :
@@ -106,10 +107,33 @@
         ti.x = x
         ti.y = y
         
-        trap_err("pt_image_tile", 
-            pt_image_tile(self.image, &ti, outf)
+        trap_err("pt_image_tile_file", 
+            pt_image_tile_file(self.image, &ti, outf)
         )
 
+    def tile_mem (self, size_t width, size_t height, size_t x, size_t y) :
+        cdef pt_tile_info ti
+        cdef char *buf
+        cdef size_t len
+
+        ti.width = width
+        ti.height = height
+        ti.x = x
+        ti.y = y
+        
+        # render and return ptr to buffer
+        trap_err("pt_image_tile_mem", 
+            pt_image_tile_mem(self.image, &ti, &buf, &len)
+        )
+        
+        # copy buffer as str...
+        data = python_string.PyString_FromStringAndSize(buf, len)
+
+        # drop buffer...
+        stdlib.free(buf)
+
+        return data
+
     def __dealloc__ (self) :
         if self.image :
             pt_image_destroy(self.image)
--- a/python/setup.py	Tue Dec 29 16:44:48 2009 +0200
+++ b/python/setup.py	Thu Dec 31 14:01:37 2009 +0200
@@ -6,7 +6,7 @@
     name = 'pngtiles',
     cmdclass = {'build_ext': build_ext},
     ext_modules = [
-        Extension("pngtile", ["pngtile.pyx"],
+        Extension("pypngtile", ["pngtile.pyx"],
             include_dirs = ['../include'],
             library_dirs = ['../lib'],
             libraries = ['pngtile'],
--- a/src/lib/cache.c	Tue Dec 29 16:44:48 2009 +0200
+++ b/src/lib/cache.c	Thu Dec 31 14:01:37 2009 +0200
@@ -397,6 +397,7 @@
 
     // move from .tmp to .cache
     if ((err = pt_cache_create_done(cache)))
+        // XXX: pt_cache_abort?
         return err;
 
     // done!
@@ -496,15 +497,15 @@
 {
     int err;
 
+    // ensure open
+    if ((err = pt_cache_open(cache)))
+        return err;
+
     // check within bounds
     if (ti->x >= cache->header->width || ti->y >= cache->header->height)
         // completely outside
         RETURN_ERROR(PT_ERR_TILE_CLIP);
 
-    // ensure open
-    if ((err = pt_cache_open(cache)))
-        return err;
-
     // set basic info
     png_set_IHDR(png, info, ti->width, ti->height, cache->header->bit_depth, cache->header->color_type,
             PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT
--- a/src/lib/error.c	Tue Dec 29 16:44:48 2009 +0200
+++ b/src/lib/error.c	Thu Dec 31 14:01:37 2009 +0200
@@ -1,5 +1,8 @@
 #include "error.h"
 
+/*
+ * Mapping for error codes
+ */
 const char *error_names[PT_ERR_MAX] = {
     [PT_SUCCESS]                = "Success",
     [PT_ERR_MEM]                = "malloc()",
--- a/src/lib/error.h	Tue Dec 29 16:44:48 2009 +0200
+++ b/src/lib/error.h	Thu Dec 31 14:01:37 2009 +0200
@@ -1,6 +1,11 @@
 #ifndef PNGTILE_ERROR_H
 #define PNGTILE_ERROR_H
 
+/**
+ * @file
+ *
+ * Obtuse error handling
+ */
 #include "pngtile.h"
 #include <errno.h>
 
--- a/src/lib/image.c	Tue Dec 29 16:44:48 2009 +0200
+++ b/src/lib/image.c	Thu Dec 31 14:01:37 2009 +0200
@@ -1,5 +1,6 @@
 #include "image.h"
 #include "cache.h"
+#include "tile.h"
 #include "error.h"
 #include "shared/util.h"
 
@@ -101,6 +102,8 @@
  * Update the image_info field from the given png object.
  *
  * Must be called under libpng-error-trap!
+ *
+ * XXX: currently this info is not used, pulled from the cache instead
  */
 static int pt_image_update_info (struct pt_image *image, png_structp png, png_infop info)
 {
@@ -221,36 +224,49 @@
     return pt_image_update_cache(image);
 }
 
-int pt_image_tile (struct pt_image *image, const struct pt_tile_info *tile_info, FILE *out)
+int pt_image_tile_file (struct pt_image *image, const struct pt_tile_info *info, FILE *out)
 {
-    png_structp png = NULL;
-    png_infop info = NULL;
-    int err = 0;
-        
-    // open PNG writer
-    if ((png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL)
-        JUMP_SET_ERROR(err, PT_ERR_PNG_CREATE);
-    
-    if ((info = png_create_info_struct(png)) == NULL)
-        JUMP_SET_ERROR(err, PT_ERR_PNG_CREATE);
+    struct pt_tile tile;
+    int err;
 
-    // libpng error trap
-    if (setjmp(png_jmpbuf(png)))
-        JUMP_SET_ERROR(err, PT_ERR_PNG);
-    
-    // setup IO
-    png_init_io(png, out);
-    
-    // render tile
-    if ((err = pt_cache_tile_png(image->cache, png, info, tile_info)))
+    // init
+    if ((err = pt_tile_init_file(&tile, info, out)))
+        return err;
+
+    // render
+    if ((err = pt_tile_render(&tile, image->cache)))
         JUMP_ERROR(err);
 
-    // done
-    png_write_end(png, info);
+    // ok
+    return 0;
 
 error:
-    // cleanup
-    png_destroy_write_struct(&png, &info);
+    pt_tile_abort(&tile);
+
+    return err;
+}
+
+int pt_image_tile_mem (struct pt_image *image, const struct pt_tile_info *info, char **buf_ptr, size_t *len_ptr)
+{
+    struct pt_tile tile;
+    int err;
+
+    // init
+    if ((err = pt_tile_init_mem(&tile, info)))
+        return err;
+
+    // render
+    if ((err = pt_tile_render(&tile, image->cache)))
+        JUMP_ERROR(err);
+
+    // ok
+    *buf_ptr = tile.out.mem.base;
+    *len_ptr = tile.out.mem.len;
+
+    return 0;
+
+error:
+    pt_tile_abort(&tile);
 
     return err;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/tile.c	Thu Dec 31 14:01:37 2009 +0200
@@ -0,0 +1,135 @@
+#include "tile.h"
+#include "error.h"
+#include "shared/log.h" // only FATAL
+
+#include <stdlib.h>
+
+static void pt_tile_init (struct pt_tile *tile, const struct pt_tile_info *info, enum pt_tile_output out_type)
+{
+    memset(tile, 0, sizeof(*tile));
+    
+    // init
+    tile->info = *info;
+    tile->out_type = out_type;
+}
+
+
+int pt_tile_init_file (struct pt_tile *tile, const struct pt_tile_info *info, FILE *out)
+{
+    pt_tile_init(tile, info, PT_TILE_OUT_FILE);
+
+    tile->out.file = out;
+
+    return 0;
+}
+
+int pt_tile_init_mem (struct pt_tile *tile, const struct pt_tile_info *info)
+{
+    pt_tile_init(tile, info, PT_TILE_OUT_MEM);
+    
+    // init buffer
+    if ((tile->out.mem.base = malloc(PT_TILE_BUF_SIZE)) == NULL)
+        RETURN_ERROR(PT_ERR_MEM);
+
+    tile->out.mem.len = PT_TILE_BUF_SIZE;
+    tile->out.mem.off = 0;
+
+    return 0;
+}
+
+static void pt_tile_mem_write (png_structp png, png_bytep data, png_size_t length)
+{
+    struct pt_tile_mem *buf = png_get_io_ptr(png);
+    size_t buf_len = buf->len;
+
+    // grow?
+    while (buf->off + length > buf_len)
+        buf_len *= 2;
+
+    if (buf_len != buf->len) {
+        char *tmp;
+
+        if ((tmp = realloc(buf->base, buf_len)) == NULL)
+            png_error(png, "pt_tile_buf_write - realloc failed");
+
+        buf->base = tmp;
+        buf->len = buf_len;
+    }
+
+    // copy
+    memcpy(buf->base + buf->off, data, length);
+
+    buf->off += length;
+}
+
+static void pt_tile_mem_flush (png_structp png_ptr)
+{
+    // no-op
+}
+
+
+int pt_tile_render (struct pt_tile *tile, struct pt_cache *cache)
+{
+    png_structp png = NULL;
+    png_infop info = NULL;
+    int err = 0;
+
+    // open PNG writer
+    if ((png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL)
+        JUMP_SET_ERROR(err, PT_ERR_PNG_CREATE);
+    
+    if ((info = png_create_info_struct(png)) == NULL)
+        JUMP_SET_ERROR(err, PT_ERR_PNG_CREATE);
+
+    // libpng error trap
+    if (setjmp(png_jmpbuf(png)))
+        JUMP_SET_ERROR(err, PT_ERR_PNG);
+ 
+    // setup output I/O
+    switch (tile->out_type) {
+        case PT_TILE_OUT_FILE:
+            // use default FILE* operation
+            png_init_io(png, tile->out.file);
+
+            break;
+
+        case PT_TILE_OUT_MEM:
+            // use pt_tile_mem struct via pt_tile_mem_* callbacks
+            png_set_write_fn(png, &tile->out.mem, pt_tile_mem_write, pt_tile_mem_flush);
+
+            break;
+
+        default:
+            FATAL("tile->out_type: %d", tile->out_type);
+    }
+
+    // render tile
+    if ((err = pt_cache_tile_png(cache, png, info, &tile->info)))
+        JUMP_ERROR(err);
+
+    // done
+    png_write_end(png, info);
+
+error:
+    // cleanup
+    png_destroy_write_struct(&png, &info);
+
+    return err;
+}
+
+void pt_tile_abort (struct pt_tile *tile)
+{
+    // cleanup
+    switch (tile->out_type) {
+        case PT_TILE_OUT_FILE:
+            // no-op
+            break;
+
+        case PT_TILE_OUT_MEM:
+            // drop buffer
+            free(tile->out.mem.base);
+
+            break;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/tile.h	Thu Dec 31 14:01:37 2009 +0200
@@ -0,0 +1,61 @@
+#ifndef PNGTILE_TILE_H
+#define PNGTILE_TILE_H
+
+/**
+ * Generating PNG tiles from a cache
+ */
+#include "pngtile.h"
+#include "cache.h"
+
+/** Types of tile output */
+enum pt_tile_output { 
+    PT_TILE_OUT_FILE,
+    PT_TILE_OUT_MEM,
+};
+
+/** Initial size of out.mem.base, 16k */
+#define PT_TILE_BUF_SIZE (16 * 1024)
+
+
+
+/** Per-tile-render state */
+struct pt_tile {
+    /** Render spec */
+    struct pt_tile_info info;
+
+    /** Output type */
+    enum pt_tile_output out_type;
+
+    union {
+        /** Output file */
+        FILE *file;
+        
+        /** Output buffer */
+        struct pt_tile_mem {
+            char *base;
+            size_t off, len;
+        } mem;
+    } out;
+};
+
+/**
+ * Initialize to render with given params, writing output to given FILE*
+ */
+int pt_tile_init_file (struct pt_tile *tile, const struct pt_tile_info *info, FILE *out);
+
+/**
+ * Initialize to render with given params, writing output to a memory buffer
+ */
+int pt_tile_init_mem (struct pt_tile *tile, const struct pt_tile_info *info);
+
+/**
+ * Render PNG data from given cache according to parameters given to pt_tile_init_*
+ */
+int pt_tile_render (struct pt_tile *tile, struct pt_cache *cache);
+
+/**
+ * Abort any failed render process, cleaning up.
+ */
+void pt_tile_abort (struct pt_tile *tile);
+
+#endif
--- a/src/util/main.c	Tue Dec 29 16:44:48 2009 +0200
+++ b/src/util/main.c	Thu Dec 31 14:01:37 2009 +0200
@@ -151,6 +151,9 @@
             }
 
             log_info("Updated image cache");
+
+        } else {
+            log_debug("Image cache is fresh");
         }
 
         // show info
@@ -166,7 +169,7 @@
         if (ti.width && ti.height) {
             log_debug("Render tile %zux%zu@(%zu,%zu) -> stdout", ti.width, ti.height, ti.x, ti.y);
 
-            if ((err = pt_image_tile(image, &ti, stdout)))
+            if ((err = pt_image_tile_file(image, &ti, stdout)))
                 log_errno("pt_image_tile: %s: %s", img_path, pt_strerror(err));
         }