Skip to content

Commit

Permalink
Experimental PNG export support for vector based projects (cf #8)
Browse files Browse the repository at this point in the history
  • Loading branch information
yohanboniface committed Jan 25, 2015
1 parent 5c1b412 commit 9ca9d53
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 12 deletions.
11 changes: 8 additions & 3 deletions src/back/GeoUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@ module.exports = {
},

zoomLatLngToXY: function (z, lat, lng) {
var xy = module.exports.zoomLatLngToFloatXY(z, lat, lng);
return [Math.floor(xy[0]), Math.floor(xy[1])];
},

zoomLatLngToFloatXY: function (z, lat, lng) {
var n = Math.pow(2.0, z),
lat_rad = lat / 180.0 * Math.PI,
y = Math.floor((1.0 - Math.log(Math.tan(lat_rad) + (1 / Math.cos(lat_rad))) / Math.PI) / 2.0 * n),
x = Math.floor(((lng + 180.0) / 360.0) * n);
return [parseInt(x, 10), parseInt(y, 10)];
y = (1.0 - Math.log(Math.tan(lat_rad) + (1 / Math.cos(lat_rad))) / Math.PI) / 2.0 * n,
x = ((lng + 180.0) / 360.0) * n;
return [x, y];
}

};
49 changes: 43 additions & 6 deletions src/plugins/base-exporters/PNG.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
var util = require('util'),
mapnik = require('mapnik'),
GeoUtils = require('../../back/GeoUtils.js'),
VectorBasedTile = require('../../back/VectorBasedTile.js').Tile,
BaseExporter = require('./Base.js').BaseExporter;

var PNGExporter = function (project, options) {
Expand All @@ -9,21 +11,56 @@ var PNGExporter = function (project, options) {
util.inherits(PNGExporter, BaseExporter);

PNGExporter.prototype.export = function (callback) {
var bounds,
scale = this.options.scale ? +this.options.scale : 2;
if (this.options.bounds) bounds = this.options.bounds.split(',').map(function (x) {return +x;})
else bounds = this.project.mml.bounds;
this.scale = this.options.scale ? +this.options.scale : 2;
if (this.options.bounds) this.bounds = this.options.bounds.split(',').map(function (x) {return +x;});
else this.bounds = this.project.mml.bounds;
if (this.project.mml.source) this.renderFromVector(callback);
else this.render(callback);
};
PNGExporter.prototype.render = function (callback) {
var self = this;
var map = new mapnik.Map(+this.options.width, +this.options.height);
map.fromString(this.project.render(), {base: this.project.root}, function render (err, map) {
var projection = new mapnik.Projection(map.srs),
im = new mapnik.Image(+self.options.width, +self.options.height);
map.zoomToBox(projection.forward(bounds));
map.render(im, {scale: scale}, function toImage (err, im) {
map.zoomToBox(projection.forward(self.bounds));
map.render(im, {scale: self.scale}, function toImage (err, im) {
if (err) throw err;
im.encode(self.options.format, callback);
});
});
};

PNGExporter.prototype.renderFromVector = function (callback) {
var self = this,
leftTop = GeoUtils.zoomLatLngToXY(this.options.zoom, this.bounds[3], this.bounds[0]),
rightBottom = GeoUtils.zoomLatLngToXY(this.options.zoom, this.bounds[1], this.bounds[2]),
floatLeftTop = GeoUtils.zoomLatLngToFloatXY(this.options.zoom, this.bounds[3], this.bounds[0]),
size = self.project.tileSize() * this.scale,
gap = [(floatLeftTop[0] - leftTop[0]) * size, (floatLeftTop[1] - leftTop[1]) * size],
map = new mapnik.Map(+this.options.width, +this.options.height),
data = [], processed = 0, toProcess = [],
commit = function () {
mapnik.blend(data, {format: 'png', width: +self.options.width, height: +self.options.height}, callback);
};
map.fromStringSync(this.project.render(), {base: this.project.root});
var processTile = function (x, y) {
var tile = new VectorBasedTile(self.options.zoom, x, y, {width: size, height: size});
return tile.render(self.project, map, function (err, im) {
if (err) throw err;
im.encode('png', function (err, buffer) {
data.push({buffer: buffer, x: (x - leftTop[0]) * size - gap[0], y: (y - leftTop[1]) * size - gap[1]});
if (toProcess[++processed]) processTile.apply(this, toProcess[processed]);
else commit();
});
});
};
for (var x = leftTop[0]; x <= rightBottom[0]; x++) {
for (var y = leftTop[1]; y <= rightBottom[1]; y++) {
toProcess.push([x, y]);
}
}
processTile.apply(this, toProcess[processed]);
};

exports.Exporter = PNGExporter;
8 changes: 5 additions & 3 deletions src/plugins/base-exporters/front/export.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,13 @@ L.K.Exporter = L.Class.extend({
this.params.width = size.x;
this.params.height = size.y;
var params = this.computeParams();
this.extentCaption.innerHTML = params.width + "px / " + params.height + "px";
this.extentCaption.innerHTML = params.width + 'px / ' + params.height + 'px';
},

getExtentSize: function () {
var topLeft = this.map.latLngToLayerPoint(this.leftTop.getLatLng()),
bottomRight = this.map.latLngToLayerPoint(this.rightBottom.getLatLng());
return L.point(Math.abs(bottomRight.x - topLeft.x), Math.abs(bottomRight.y - topLeft.y))
return L.point(Math.abs(bottomRight.x - topLeft.x), Math.abs(bottomRight.y - topLeft.y));
},

updateExtentSize: function () {
Expand All @@ -238,7 +238,7 @@ L.K.Exporter = L.Class.extend({
this.leftBottom.getLatLng().lat,
this.rightTop.getLatLng().lng,
this.rightTop.getLatLng().lat
]
];
},

computeParams: function () {
Expand All @@ -252,6 +252,8 @@ L.K.Exporter = L.Class.extend({
if (params.zoom < this.map.getZoom()) factor = 1 / factor;
params.width = params.width * factor;
params.height = params.height * factor;
} else {
params.zoom = this.map.getZoom();
}
params.width = Math.round(params.width);
params.height = Math.round(params.height);
Expand Down

0 comments on commit 9ca9d53

Please sign in to comment.