terom@30: cdef extern from "errno.h" : terom@30: extern int errno terom@30: terom@30: cdef extern from "string.h" : terom@30: char* strerror (int err) terom@30: terom@78: void* memset (void *, int, size_t) terom@78: void* memcpy (void *, void *, size_t) terom@78: terom@30: cimport stdio terom@30: cimport stdlib terom@30: cimport python_string terom@30: terom@30: cdef extern from "Python.h" : terom@30: int PyFile_Check (object p) terom@30: stdio.FILE* PyFile_AsFile (object p) terom@30: void PyFile_IncUseCount (object p) terom@30: void PyFile_DecUseCount (object p) terom@30: terom@30: cdef extern from "pngtile.h" : terom@30: struct pt_ctx : terom@30: pass terom@30: terom@30: struct pt_image : terom@30: pass terom@30: terom@30: enum pt_open_mode : terom@78: PT_OPEN_READ # 0 terom@30: PT_OPEN_UPDATE terom@30: terom@30: enum pt_cache_status : terom@78: PT_CACHE_ERROR # -1 terom@30: PT_CACHE_FRESH terom@30: PT_CACHE_NONE terom@30: PT_CACHE_STALE terom@57: PT_CACHE_INCOMPAT terom@30: terom@30: struct pt_image_info : terom@78: size_t img_width, img_height, img_bpp terom@78: int image_mtime, cache_mtime, cache_version terom@78: size_t image_bytes, cache_bytes terom@57: size_t cache_blocks terom@57: terom@57: struct pt_image_params : terom@57: int background_color[4] terom@30: terom@30: struct pt_tile_info : terom@30: size_t width, height terom@30: size_t x, y terom@34: int zoom terom@57: terom@30: int pt_image_open (pt_image **image_ptr, pt_ctx *ctx, char *png_path, int cache_mode) terom@30: int pt_image_info_func "pt_image_info" (pt_image *image, pt_image_info **info_ptr) terom@30: int pt_image_status (pt_image *image) terom@57: int pt_image_update (pt_image *image, pt_image_params *params) terom@30: int pt_image_tile_file (pt_image *image, pt_tile_info *info, stdio.FILE *out) terom@30: int pt_image_tile_mem (pt_image *image, pt_tile_info *info, char **buf_ptr, size_t *len_ptr) terom@30: void pt_image_destroy (pt_image *image) terom@30: terom@30: char* pt_strerror (int err) terom@30: terom@78: ## constants terom@78: # Image() terom@78: OPEN_READ = PT_OPEN_READ terom@78: OPEN_UPDATE = PT_OPEN_UPDATE terom@78: terom@78: # Image.status -> ... terom@78: CACHE_FRESH = PT_CACHE_FRESH terom@78: CACHE_NONE = PT_CACHE_NONE terom@78: CACHE_STALE = PT_CACHE_STALE terom@78: CACHE_INCOMPAT = PT_CACHE_INCOMPAT terom@30: terom@30: class Error (BaseException) : terom@30: pass terom@30: terom@30: cdef int trap_err (char *op, int ret) except -1 : terom@30: if ret < 0 : terom@30: raise Error("%s: %s: %s" % (op, pt_strerror(ret), strerror(errno))) terom@30: terom@30: else : terom@30: return ret terom@30: terom@30: cdef class Image : terom@78: """ terom@78: An image file on disk (.png) and an associated .cache file. terom@78: terom@78: Open the .png file at the given path using the given mode. terom@78: terom@78: path - filesystem path to .png file terom@78: mode - mode to operate cache in terom@78: OPEN_READ - read-only access to cache terom@78: OPEN_UPDATE - allow .update() terom@78: """ terom@78: terom@30: cdef pt_image *image terom@30: terom@78: terom@78: # open the pt_image terom@78: def __cinit__ (self, char *path, int mode = 0) : terom@30: trap_err("pt_image_open", terom@78: pt_image_open(&self.image, NULL, path, mode) terom@30: ) terom@78: terom@78: terom@30: def info (self) : terom@78: """ terom@78: Return a dictionary containing various information about the image. terom@78: terom@78: img_width - pixel dimensions of the source image terom@78: img_height only available if the cache was opened terom@78: img_bpp - bits per pixel for the source image terom@78: terom@78: image_mtime - last modification timestamp for source image terom@78: image_bytes - size of source image file in bytes terom@78: terom@78: cache_version - version of cache file available terom@78: cache_mtime - last modification timestamp for cache file terom@78: cache_bytes - size of cache file in bytes terom@78: cache_blocks - size of cache file in disk blocks - 512 bytes / block terom@78: """ terom@78: terom@78: cdef pt_image_info *info terom@30: terom@30: trap_err("pt_image_info", terom@78: pt_image_info_func(self.image, &info) terom@30: ) terom@30: terom@78: # return as a struct terom@78: return info[0] terom@78: terom@78: terom@30: def status (self) : terom@78: """ terom@78: Return a code describing the status of the underlying cache file. terom@78: terom@78: CACHE_FRESH - the cache file exists and is up-to-date terom@78: CACHE_NONE - the cache file does not exist terom@78: CACHE_STALE - the cache file exists, but is older than the source image terom@78: CACHE_INCOMPAT - the cache file exists, but is incompatible with this version of the library terom@78: """ terom@78: terom@30: return trap_err("pt_image_status", terom@30: pt_image_status(self.image) terom@30: ) terom@78: terom@78: terom@78: def update (self, background_color = None) : terom@78: """ terom@78: Update the underlying cache file from the source image. terom@78: terom@78: background_color - skip consecutive pixels that match this byte pattern in output terom@78: terom@78: Requires that the Image was opened using OPEN_UPDATE. terom@78: """ terom@78: terom@78: cdef pt_image_params params terom@78: cdef char *bgcolor terom@78: memset(¶ms, 0, sizeof(params)) terom@78: terom@78: # params terom@78: if background_color : terom@78: # cast terom@78: bgcolor = background_color terom@78: terom@78: if 0 >= len(bgcolor) > 4 : terom@78: raise ValueError("background_color must be a str of between 1 and 4 bytes") terom@78: terom@78: # decode terom@78: memcpy(params.background_color, bgcolor, len(bgcolor)) terom@30: terom@78: # run update terom@30: trap_err("pt_image_update", terom@78: pt_image_update(self.image, ¶ms) terom@30: ) terom@30: terom@78: terom@34: def tile_file (self, size_t width, size_t height, size_t x, size_t y, int zoom, object out) : terom@30: cdef stdio.FILE *outf terom@30: cdef pt_tile_info ti terom@30: terom@30: if not PyFile_Check(out) : terom@30: raise TypeError("out: must be a file object") terom@30: terom@30: outf = PyFile_AsFile(out) terom@30: terom@30: if not outf : terom@30: raise TypeError("out: must have a FILE*") terom@30: terom@30: ti.width = width terom@30: ti.height = height terom@30: ti.x = x terom@30: ti.y = y terom@34: ti.zoom = zoom terom@30: terom@30: trap_err("pt_image_tile_file", terom@30: pt_image_tile_file(self.image, &ti, outf) terom@30: ) terom@30: terom@78: terom@34: def tile_mem (self, size_t width, size_t height, size_t x, size_t y, int zoom) : terom@30: cdef pt_tile_info ti terom@30: cdef char *buf terom@30: cdef size_t len terom@30: terom@30: ti.width = width terom@30: ti.height = height terom@30: ti.x = x terom@30: ti.y = y terom@34: ti.zoom = zoom terom@30: terom@30: # render and return ptr to buffer terom@30: trap_err("pt_image_tile_mem", terom@30: pt_image_tile_mem(self.image, &ti, &buf, &len) terom@30: ) terom@30: terom@30: # copy buffer as str... terom@30: data = python_string.PyString_FromStringAndSize(buf, len) terom@30: terom@30: # drop buffer... terom@30: stdlib.free(buf) terom@30: terom@30: return data terom@30: terom@78: # release the pt_image terom@30: def __dealloc__ (self) : terom@30: if self.image : terom@30: pt_image_destroy(self.image) terom@30: