diff --git a/mapnik_c_api.cpp b/mapnik_c_api.cpp index 9dc3db2..732d399 100644 --- a/mapnik_c_api.cpp +++ b/mapnik_c_api.cpp @@ -9,23 +9,37 @@ #include #if MAPNIK_VERSION >= 300000 -#include -#define mapnik_image_type mapnik::image_rgba8 + #include + #define mapnik_image_type mapnik::image_rgba8 + #include #else -#include -#define mapnik_image_type mapnik::image_32 + #include + #define mapnik_image_type mapnik::image_32 #endif - #include "mapnik_c_api.h" #include +#define META_MAGIC "META" +#define MIN(x,y) ((x)<(y)?(x):(y)) + #ifdef __cplusplus extern "C" { #endif +struct entry { + unsigned int offset; + unsigned int size; +}; + +struct meta_layout { + char magic[4]; + unsigned int count; // METATILE ^ 2 + unsigned int x, y, z; // lowest x,y of this metatile, plus z +}; + int mapnik_register_datasources(const char* path, char** err) { try { #if MAPNIK_VERSION >= 200200 @@ -136,7 +150,6 @@ int mapnik_map_render_to_file(mapnik_map_t * m, const char* filepath) { return -1; } - void mapnik_map_resize(mapnik_map_t *m, unsigned int width, unsigned int height) { if (m&& m->m) { m->m->resize(width, height); @@ -255,6 +268,93 @@ mapnik_image_blob_t * mapnik_image_to_png_blob(mapnik_image_t * i) { return blob; } +mapnik_image_blob_t * mapnik_image_view_to_png_blob(mapnik_image_t * i, unsigned int xx, unsigned int yy, unsigned int xsize, unsigned int ysize) { + mapnik_image_blob_t * blob = new mapnik_image_blob_t; + blob->ptr = NULL; + blob->len = 0; + if (i && i->i) { +#if MAPNIK_VERSION >= 300000 + mapnik::image_view_any vw(mapnik::image_view>(xx, yy, xsize, ysize, *(i->i))); +#else + mapnik::image_view vw(xx, yy, xsize, ysize, i->i->data()); +#endif + std::string s = save_to_string(vw, "png256"); + blob->len = s.length(); + blob->ptr = new char[blob->len]; + memcpy(blob->ptr, s.c_str(), blob->len); + } + return blob; +} + +int xyz_to_meta_offset(unsigned int x, unsigned int y, unsigned int z) { + unsigned char mask = 7; + return (x & mask) * 8 + (y & mask); +} + +mapnik_image_blob_t * mapnik_image_to_metatile(mapnik_map_t *map, mapnik_image_t * i, unsigned int z_, unsigned int x_, unsigned int y_, unsigned int ms) { + int ox, oy, limit; + ssize_t offset; + struct meta_layout m; + struct entry *offsets = new entry[ms*ms]; + mapnik_image_blob_t **tile = (mapnik_image_blob_t**)malloc((ms*ms)*sizeof(mapnik_image_blob_t*)); + mapnik_image_blob_t * blob = new mapnik_image_blob_t; + blob->ptr = NULL; + blob->len = 0; + + mapnik_map_reset_last_error(map); + + memset(&m, 0, sizeof(m)); + + // Create and write header + m.count = ms * ms; + memcpy(m.magic, META_MAGIC, strlen(META_MAGIC)); + m.x = x_; + m.y = y_; + m.z = z_; + + offset = sizeof(meta_layout) + ms*ms*sizeof(entry); + limit = ms; + memset(offsets, 0, ms*ms*sizeof(entry)); + + // Generate offset table + for (ox=0; ox < limit; ox++) { + for (oy=0; oy < limit; oy++) { + int mt = xyz_to_meta_offset(x_ + ox, y_ + oy, z_); + offsets[mt].offset = offset; + tile[mt] = mapnik_image_view_to_png_blob(i, ox*256, oy*256, 256, 256); + if(tile[mt]->ptr == NULL){ + map->err = new std::string("Cannot get image view from image"); + return NULL; + } + offsets[mt].size = tile[mt]->len; + printf("offsets[%d].offset=%ld, offsets[%d].size=%u\n", mt, offset, mt, offsets[mt].size); + offset += offsets[mt].size; + } + } + + blob->ptr = new char[offset]; + if (blob->ptr == 0) { + map->err = new std::string("Failed to write metatile. Out of memory"); + return NULL; + } + memset(blob->ptr, 0, offset); + memcpy(blob->ptr,&m,sizeof(m)); + memcpy(blob->ptr + sizeof(m), offsets, ms*ms*sizeof(entry)); + + // Write tiles + for (ox=0; ox < limit; ox++) { + for (oy=0; oy < limit; oy++) { + int mt = xyz_to_meta_offset(x_ + ox, y_ + oy, z_); + memcpy(blob->ptr + offsets[mt].offset, tile[mt]->ptr, tile[mt]->len); + mapnik_image_blob_free(tile[mt]); + } + } + delete [] offsets; + free(tile); + blob->len = offset; + + return blob; +} #ifdef __cplusplus } diff --git a/mapnik_c_api.h b/mapnik_c_api.h index 8a60a5e..f8451a6 100644 --- a/mapnik_c_api.h +++ b/mapnik_c_api.h @@ -52,7 +52,7 @@ MAPNIKCAPICALL void mapnik_image_blob_free(mapnik_image_blob_t * b); MAPNIKCAPICALL mapnik_image_blob_t * mapnik_image_to_png_blob(mapnik_image_t * i); - +MAPNIKCAPICALL mapnik_image_blob_t * mapnik_image_view_to_png_blob(mapnik_image_t * i, unsigned int xx, unsigned int yy, unsigned int xlen, unsigned int ylen); // Map typedef struct _mapnik_map_t mapnik_map_t; @@ -83,6 +83,8 @@ MAPNIKCAPICALL mapnik_projection_t * mapnik_map_projection(mapnik_map_t *m); MAPNIKCAPICALL mapnik_image_t * mapnik_map_render_to_image(mapnik_map_t * m); +MAPNIKCAPICALL mapnik_image_blob_t * mapnik_image_to_metatile(mapnik_map_t *map, mapnik_image_t * i, unsigned int z, unsigned int x, unsigned int y, unsigned int ms); + #ifdef __cplusplus } #endif diff --git a/test/c-api-c99-test-metatile.c b/test/c-api-c99-test-metatile.c new file mode 100644 index 0000000..2a1ebee --- /dev/null +++ b/test/c-api-c99-test-metatile.c @@ -0,0 +1,31 @@ + +#include +#include "mapnik_c_api.h" +#include "test/c-api-test-cfg.h" + +int main() { + mapnik_map_t * map; + mapnik_image_t * image; + mapnik_image_blob_t * metatile; + FILE * mf; + map = mapnik_map(8*256,8*256); + mapnik_register_datasources(MAPNIK_PLUGINDIR, NULL); + mapnik_map_load(map,"../sample/stylesheet.xml"); + mapnik_map_zoom_all(map); + + image = mapnik_map_render_to_image(map); + metatile = mapnik_image_to_metatile(map, image, 3, 2, 1, 8); + if( metatile == NULL || metatile->ptr == NULL) { + printf("error: %s\n", mapnik_map_last_error(map)); + return -1; + } + mf = fopen("./mapnik-c-api-c99-test-metatile.meta", "wb"); + fwrite(metatile->ptr, sizeof(char), metatile->len, mf); + fclose(mf); + printf("\x1b[1;32m ✓ (%s)\x1b[0m\n", "./mapnik-c-api-c99-test-metatile.meta"); + mapnik_image_free(image); + mapnik_image_blob_free(metatile); + mapnik_map_free(map); + printf("c99 test works\n"); + return 0; +} diff --git a/test/lua-api-test-metatile.lua b/test/lua-api-test-metatile.lua new file mode 100644 index 0000000..50feb28 --- /dev/null +++ b/test/lua-api-test-metatile.lua @@ -0,0 +1,64 @@ +local ffi = require("ffi") + +ffi.cdef[[ +int mapnik_register_datasources(const char* path); + +// Opaque class structure +typedef struct _mapnik_map_t mapnik_map_t; + +mapnik_map_t * mapnik_map( unsigned int width, unsigned int height ); + +void mapnik_map_free(mapnik_map_t * m); + +const char * mapnik_map_get_srs(mapnik_map_t * m); + +int mapnik_map_set_srs(mapnik_map_t * m, const char* srs); + +int mapnik_map_load(mapnik_map_t * m, const char* stylesheet); + +int mapnik_map_zoom_all(mapnik_map_t * m); + +int mapnik_map_render_to_file(mapnik_map_t * m, const char* filepath); + +typedef struct _mapnik_image_t mapnik_image_t; + +void mapnik_image_free(mapnik_image_t * i); + +typedef struct _mapnik_image_blob_t { + char *ptr; + unsigned int len; +} mapnik_image_blob_t; + +void mapnik_image_blob_free(mapnik_image_blob_t * b); + +mapnik_image_blob_t * mapnik_image_to_png_blob(mapnik_image_t * i); + +mapnik_image_blob_t * mapnik_image_view_to_png_blob(mapnik_image_t * i, unsigned int xx, unsigned int yy, unsigned int xlen, unsigned int ylen); + +mapnik_image_t * mapnik_map_render_to_image(mapnik_map_t * m); + +mapnik_image_blob_t * mapnik_image_to_metatile(mapnik_map_t * m, mapnik_image_t * i, unsigned int z, unsigned int x, unsigned int y, unsigned int ms); + +]] + +local m = ffi.load("../libmapnik_c.so") + +if m.mapnik_register_datasources("/usr/local/lib/mapnik/input") ~= 0 then + print("mapnik_image_to_metatile error:"..ffi.string(m.mapnik_map_last_error(map))) +else + local map = m.mapnik_map(256*8,256*8) + m.mapnik_map_load(map,"../sample/stylesheet.xml") + m.mapnik_map_zoom_all(map) + local image = m.mapnik_map_render_to_image(map) + local metatile = m.mapnik_image_to_metatile(map, image, 3, 0, 0, 8) + if metatile and metatile.ptr then + local metatile_file = io.open("lua-test-metatile.meta", "w") + metatile_file:write(ffi.string(metatile.ptr, metatile.len)) + metatile_file:close() + m.mapnik_image_blob_free(metatile) + else + print("mapnik_image_to_metatile error:"..ffi.string(m.mapnik_map_last_error(map))) + end + m.mapnik_image_free(image) + m.mapnik_map_free(map) +end