Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 106 additions & 6 deletions mapnik_c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,37 @@
#include <mapnik/font_engine_freetype.hpp>

#if MAPNIK_VERSION >= 300000
#include <mapnik/image.hpp>
#define mapnik_image_type mapnik::image_rgba8
#include <mapnik/image.hpp>
#define mapnik_image_type mapnik::image_rgba8
#include <mapnik/image_view_any.hpp>
#else
#include <mapnik/graphics.hpp>
#define mapnik_image_type mapnik::image_32
#include <mapnik/graphics.hpp>
#define mapnik_image_type mapnik::image_32
#endif


#include "mapnik_c_api.h"

#include <stdlib.h>

#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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<mapnik::image<mapnik::rgba8_t>>(xx, yy, xsize, ysize, *(i->i)));
#else
mapnik::image_view<mapnik::image_data_32> 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
}
Expand Down
4 changes: 3 additions & 1 deletion mapnik_c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
31 changes: 31 additions & 0 deletions test/c-api-c99-test-metatile.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

#include <stdio.h>
#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;
}
64 changes: 64 additions & 0 deletions test/lua-api-test-metatile.lua
Original file line number Diff line number Diff line change
@@ -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