port r1680/r1683/r1690 from 0.7.1-dev branch to trunk
This commit is contained in:
parent
6b85a9a760
commit
d7256295ae
4 changed files with 235 additions and 61 deletions
|
@ -328,10 +328,20 @@ mapnik2.render(m, im)
|
||||||
images_ = []
|
images_ = []
|
||||||
im.save('demo.png', 'png') # true-colour RGBA
|
im.save('demo.png', 'png') # true-colour RGBA
|
||||||
images_.append('demo.png')
|
images_.append('demo.png')
|
||||||
|
|
||||||
|
# old behavior, now can do 'png8:c=256'
|
||||||
im.save('demo256.png', 'png256') # save to palette based (max 256 colours) png
|
im.save('demo256.png', 'png256') # save to palette based (max 256 colours) png
|
||||||
images_.append('demo256.png')
|
images_.append('demo256.png')
|
||||||
|
|
||||||
|
im.save('demo64_binary_transparency.png', 'png8:c=64:t=1')
|
||||||
|
images_.append('demo64_binary_transparency.png')
|
||||||
|
|
||||||
|
im.save('demo128_colors_hextree_no_alpha.png', 'png8:c=100:m=h:t=0')
|
||||||
|
images_.append('demo128_colors_hextree_no_alpha.png')
|
||||||
|
|
||||||
im.save('demo_high.jpg', 'jpeg100')
|
im.save('demo_high.jpg', 'jpeg100')
|
||||||
images_.append('demo_high.jpg')
|
images_.append('demo_high.jpg')
|
||||||
|
|
||||||
im.save('demo_low.jpg', 'jpeg50')
|
im.save('demo_low.jpg', 'jpeg50')
|
||||||
images_.append('demo_low.jpg')
|
images_.append('demo_low.jpg')
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace mapnik {
|
||||||
byte r;
|
byte r;
|
||||||
byte g;
|
byte g;
|
||||||
byte b;
|
byte b;
|
||||||
rgb(byte r_, byte b_, byte g_)
|
rgb(byte r_, byte g_, byte b_)
|
||||||
: r(r_), g(g_), b(b_) {}
|
: r(r_), g(g_), b(b_) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
//$Id$
|
//$Id$
|
||||||
#include <mapnik/global.hpp>
|
#include <mapnik/global.hpp>
|
||||||
#include <mapnik/octree.hpp>
|
#include <mapnik/octree.hpp>
|
||||||
|
#include <mapnik/hextree.hpp>
|
||||||
#include <mapnik/global.hpp>
|
#include <mapnik/global.hpp>
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
|
@ -30,10 +31,7 @@ extern "C"
|
||||||
#include <png.h>
|
#include <png.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - consider exposing this option to user
|
#define MAX_OCTREE_LEVELS 4
|
||||||
// static number of alpha ranges in png256 format
|
|
||||||
// 2 results in smallest image, 3 is minimum for semitransparency, 4 is recommended, anything else is worse
|
|
||||||
#define TRANSPARENCY_LEVELS 4
|
|
||||||
|
|
||||||
#ifdef MAPNIK_BIG_ENDIAN
|
#ifdef MAPNIK_BIG_ENDIAN
|
||||||
#define U2RED(x) (((x)>>24)&0xff)
|
#define U2RED(x) (((x)>>24)&0xff)
|
||||||
|
@ -109,7 +107,7 @@ namespace mapnik {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void reduce_8 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned limits[], std::vector<unsigned> & alpha)
|
void reduce_8 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned limits[], unsigned levels, std::vector<unsigned> & alpha)
|
||||||
{
|
{
|
||||||
unsigned width = in.width();
|
unsigned width = in.width();
|
||||||
unsigned height = in.height();
|
unsigned height = in.height();
|
||||||
|
@ -132,7 +130,7 @@ namespace mapnik {
|
||||||
mapnik::rgb c(U2RED(val), U2GREEN(val), U2BLUE(val));
|
mapnik::rgb c(U2RED(val), U2GREEN(val), U2BLUE(val));
|
||||||
byte index = 0;
|
byte index = 0;
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
for(int j=TRANSPARENCY_LEVELS-1; j>0; j--){
|
for(int j=levels-1; j>0; j--){
|
||||||
if (U2ALPHA(val)>=limits[j]) {
|
if (U2ALPHA(val)>=limits[j]) {
|
||||||
index = idx = trees[j].quantize(c);
|
index = idx = trees[j].quantize(c);
|
||||||
break;
|
break;
|
||||||
|
@ -154,7 +152,7 @@ namespace mapnik {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void reduce_4 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned limits[], std::vector<unsigned> & alpha)
|
void reduce_4 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned limits[], unsigned levels, std::vector<unsigned> & alpha)
|
||||||
{
|
{
|
||||||
unsigned width = in.width();
|
unsigned width = in.width();
|
||||||
unsigned height = in.height();
|
unsigned height = in.height();
|
||||||
|
@ -178,7 +176,7 @@ namespace mapnik {
|
||||||
mapnik::rgb c(U2RED(val), U2GREEN(val), U2BLUE(val));
|
mapnik::rgb c(U2RED(val), U2GREEN(val), U2BLUE(val));
|
||||||
byte index = 0;
|
byte index = 0;
|
||||||
int idx=-1;
|
int idx=-1;
|
||||||
for(int j=TRANSPARENCY_LEVELS-1; j>0; j--){
|
for(int j=levels-1; j>0; j--){
|
||||||
if (U2ALPHA(val)>=limits[j]) {
|
if (U2ALPHA(val)>=limits[j]) {
|
||||||
index = idx = trees[j].quantize(c);
|
index = idx = trees[j].quantize(c);
|
||||||
break;
|
break;
|
||||||
|
@ -274,8 +272,11 @@ namespace mapnik {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T1,typename T2>
|
template <typename T1,typename T2>
|
||||||
void save_as_png256(T1 & file, T2 const& image)
|
void save_as_png256(T1 & file, T2 const& image, const unsigned max_colors = 256, int trans_mode = -1)
|
||||||
{
|
{
|
||||||
|
// number of alpha ranges in png256 format; 2 results in smallest image with binary transparency
|
||||||
|
// 3 is minimum for semitransparency, 4 is recommended, anything else is worse
|
||||||
|
const unsigned TRANSPARENCY_LEVELS = (trans_mode==2||trans_mode<0)?MAX_OCTREE_LEVELS:2;
|
||||||
unsigned width = image.width();
|
unsigned width = image.width();
|
||||||
unsigned height = image.height();
|
unsigned height = image.height();
|
||||||
unsigned alphaHist[256];//transparency histogram
|
unsigned alphaHist[256];//transparency histogram
|
||||||
|
@ -287,6 +288,8 @@ namespace mapnik {
|
||||||
for (unsigned y = 0; y < height; ++y){
|
for (unsigned y = 0; y < height; ++y){
|
||||||
for (unsigned x = 0; x < width; ++x){
|
for (unsigned x = 0; x < width; ++x){
|
||||||
unsigned val = U2ALPHA((unsigned)image.getRow(y)[x]);
|
unsigned val = U2ALPHA((unsigned)image.getRow(y)[x]);
|
||||||
|
if (trans_mode==0)
|
||||||
|
val=255;
|
||||||
alphaHist[val]++;
|
alphaHist[val]++;
|
||||||
meanAlpha += val;
|
meanAlpha += val;
|
||||||
if (val>0 && val<255)
|
if (val>0 && val<255)
|
||||||
|
@ -296,16 +299,16 @@ namespace mapnik {
|
||||||
meanAlpha /= width*height;
|
meanAlpha /= width*height;
|
||||||
|
|
||||||
// transparency ranges division points
|
// transparency ranges division points
|
||||||
unsigned limits[TRANSPARENCY_LEVELS+1];
|
unsigned limits[MAX_OCTREE_LEVELS+1];
|
||||||
limits[0] = 0;
|
limits[0] = 0;
|
||||||
limits[1] = (alphaHist[0]>0)?1:0;
|
limits[1] = (alphaHist[0]>0)?1:0;
|
||||||
limits[TRANSPARENCY_LEVELS] = 256;
|
limits[TRANSPARENCY_LEVELS] = 256;
|
||||||
unsigned alphaHistSum = 0;
|
unsigned alphaHistSum = 0;
|
||||||
for(int j=1; j<TRANSPARENCY_LEVELS; j++)
|
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
|
||||||
limits[j] = limits[1];
|
limits[j] = limits[1];
|
||||||
for(int i=1; i<256; i++){
|
for(unsigned i=1; i<256; i++){
|
||||||
alphaHistSum += alphaHist[i];
|
alphaHistSum += alphaHist[i];
|
||||||
for(int j=1; j<TRANSPARENCY_LEVELS; j++){
|
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++){
|
||||||
if (alphaHistSum<semiCount*(j)/4)
|
if (alphaHistSum<semiCount*(j)/4)
|
||||||
limits[j] = i;
|
limits[j] = i;
|
||||||
}
|
}
|
||||||
|
@ -320,9 +323,9 @@ namespace mapnik {
|
||||||
limits[1]=127;
|
limits[1]=127;
|
||||||
}
|
}
|
||||||
// estimated number of colors from palette assigned to chosen ranges
|
// estimated number of colors from palette assigned to chosen ranges
|
||||||
unsigned cols[TRANSPARENCY_LEVELS];
|
unsigned cols[MAX_OCTREE_LEVELS];
|
||||||
// count colors
|
// count colors
|
||||||
for(int j=1; j<=TRANSPARENCY_LEVELS; j++) {
|
for(unsigned j=1; j<=TRANSPARENCY_LEVELS; j++) {
|
||||||
cols[j-1] = 0;
|
cols[j-1] = 0;
|
||||||
for(unsigned i=limits[j-1]; i<limits[j]; i++){
|
for(unsigned i=limits[j-1]; i<limits[j]; i++){
|
||||||
cols[j-1] += alphaHist[i];
|
cols[j-1] += alphaHist[i];
|
||||||
|
@ -333,23 +336,33 @@ namespace mapnik {
|
||||||
if (divCoef==0) divCoef = 1;
|
if (divCoef==0) divCoef = 1;
|
||||||
cols[0] = cols[0]>0?1:0; // fully transparent color (one or not at all)
|
cols[0] = cols[0]>0?1:0; // fully transparent color (one or not at all)
|
||||||
|
|
||||||
|
if (max_colors>=64) {
|
||||||
// give chance less populated but not empty cols to have at least few colors(12)
|
// give chance less populated but not empty cols to have at least few colors(12)
|
||||||
unsigned minCols = (12+1)*divCoef/(256-cols[0]);
|
unsigned minCols = (12+1)*divCoef/(max_colors-cols[0]);
|
||||||
for(int j=1; j<TRANSPARENCY_LEVELS; j++) if (cols[j]>12 && cols[j]<minCols) {
|
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++) if (cols[j]>12 && cols[j]<minCols) {
|
||||||
divCoef += minCols-cols[j];
|
divCoef += minCols-cols[j];
|
||||||
cols[j] = minCols;
|
cols[j] = minCols;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
unsigned usedColors = cols[0];
|
unsigned usedColors = cols[0];
|
||||||
for(int j=1; j<TRANSPARENCY_LEVELS-1; j++){
|
for(unsigned j=1; j<TRANSPARENCY_LEVELS-1; j++){
|
||||||
cols[j] = cols[j]*(256-cols[0])/divCoef;
|
cols[j] = cols[j]*(max_colors-cols[0])/divCoef;
|
||||||
usedColors += cols[j];
|
usedColors += cols[j];
|
||||||
}
|
}
|
||||||
// use rest for most opaque group of pixels
|
// use rest for most opaque group of pixels
|
||||||
cols[TRANSPARENCY_LEVELS-1] = 256-usedColors;
|
cols[TRANSPARENCY_LEVELS-1] = max_colors-usedColors;
|
||||||
|
|
||||||
|
//no transparency
|
||||||
|
if (trans_mode == 0)
|
||||||
|
{
|
||||||
|
limits[1] = 0;
|
||||||
|
cols[0] = 0;
|
||||||
|
cols[1] = max_colors;
|
||||||
|
}
|
||||||
|
|
||||||
// octree table for separate alpha range with 1-based index (0 is fully transparent: no color)
|
// octree table for separate alpha range with 1-based index (0 is fully transparent: no color)
|
||||||
octree<rgb> trees[TRANSPARENCY_LEVELS];
|
octree<rgb> trees[MAX_OCTREE_LEVELS];
|
||||||
for(int j=1; j<TRANSPARENCY_LEVELS; j++)
|
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
|
||||||
trees[j].setMaxColors(cols[j]);
|
trees[j].setMaxColors(cols[j]);
|
||||||
for (unsigned y = 0; y < height; ++y)
|
for (unsigned y = 0; y < height; ++y)
|
||||||
{
|
{
|
||||||
|
@ -359,7 +372,7 @@ namespace mapnik {
|
||||||
unsigned val = row[x];
|
unsigned val = row[x];
|
||||||
|
|
||||||
// insert to proper tree based on alpha range
|
// insert to proper tree based on alpha range
|
||||||
for(int j=TRANSPARENCY_LEVELS-1; j>0; j--){
|
for(unsigned j=TRANSPARENCY_LEVELS-1; j>0; j--){
|
||||||
if (cols[j]>0 && U2ALPHA(val)>=limits[j]) {
|
if (cols[j]>0 && U2ALPHA(val)>=limits[j]) {
|
||||||
trees[j].insert(mapnik::rgb(U2RED(val), U2GREEN(val), U2BLUE(val)));
|
trees[j].insert(mapnik::rgb(U2RED(val), U2GREEN(val), U2BLUE(val)));
|
||||||
break;
|
break;
|
||||||
|
@ -369,11 +382,11 @@ namespace mapnik {
|
||||||
}
|
}
|
||||||
unsigned leftovers = 0;
|
unsigned leftovers = 0;
|
||||||
std::vector<rgb> palette;
|
std::vector<rgb> palette;
|
||||||
palette.reserve(256);
|
palette.reserve(max_colors);
|
||||||
if (cols[0])
|
if (cols[0])
|
||||||
palette.push_back(rgb(0,0,0));
|
palette.push_back(rgb(0,0,0));
|
||||||
|
|
||||||
for(int j=1; j<TRANSPARENCY_LEVELS; j++) {
|
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++) {
|
||||||
if (cols[j]>0) {
|
if (cols[j]>0) {
|
||||||
if (leftovers>0) {
|
if (leftovers>0) {
|
||||||
cols[j] += leftovers;
|
cols[j] += leftovers;
|
||||||
|
@ -383,7 +396,7 @@ namespace mapnik {
|
||||||
std::vector<rgb> pal;
|
std::vector<rgb> pal;
|
||||||
trees[j].setOffset(palette.size());
|
trees[j].setOffset(palette.size());
|
||||||
trees[j].create_palette(pal);
|
trees[j].create_palette(pal);
|
||||||
assert(pal.size() <= 256);
|
assert(pal.size() <= max_colors);
|
||||||
leftovers = cols[j]-pal.size();
|
leftovers = cols[j]-pal.size();
|
||||||
cols[j] = pal.size();
|
cols[j] = pal.size();
|
||||||
for(unsigned i=0; i<pal.size(); i++){
|
for(unsigned i=0; i<pal.size(); i++){
|
||||||
|
@ -396,13 +409,14 @@ namespace mapnik {
|
||||||
//transparency values per palette index
|
//transparency values per palette index
|
||||||
std::vector<unsigned> alphaTable;
|
std::vector<unsigned> alphaTable;
|
||||||
//alphaTable.resize(palette.size());//allow semitransparency also in almost opaque range
|
//alphaTable.resize(palette.size());//allow semitransparency also in almost opaque range
|
||||||
|
if (trans_mode != 0)
|
||||||
alphaTable.resize(palette.size() - cols[TRANSPARENCY_LEVELS-1]);
|
alphaTable.resize(palette.size() - cols[TRANSPARENCY_LEVELS-1]);
|
||||||
|
|
||||||
if (palette.size() > 16 )
|
if (palette.size() > 16 )
|
||||||
{
|
{
|
||||||
// >16 && <=256 colors -> write 8-bit color depth
|
// >16 && <=256 colors -> write 8-bit color depth
|
||||||
image_data_8 reduced_image(width,height);
|
image_data_8 reduced_image(width,height);
|
||||||
reduce_8(image,reduced_image,trees, limits, alphaTable);
|
reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
|
||||||
save_as_png(file,palette,reduced_image,width,height,8,alphaTable);
|
save_as_png(file,palette,reduced_image,width,height,8,alphaTable);
|
||||||
}
|
}
|
||||||
else if (palette.size() == 1)
|
else if (palette.size() == 1)
|
||||||
|
@ -424,7 +438,96 @@ namespace mapnik {
|
||||||
unsigned image_width = (int(0.5*width) + 3)&~3;
|
unsigned image_width = (int(0.5*width) + 3)&~3;
|
||||||
unsigned image_height = height;
|
unsigned image_height = height;
|
||||||
image_data_8 reduced_image(image_width,image_height);
|
image_data_8 reduced_image(image_width,image_height);
|
||||||
reduce_4(image,reduced_image,trees, limits, alphaTable);
|
reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
|
||||||
|
save_as_png(file,palette,reduced_image,width,height,4,alphaTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1,typename T2>
|
||||||
|
void save_as_png256_hex(T1 & file, T2 const& image, int colors = 256, int trans_mode = -1, double gamma = 2.0)
|
||||||
|
{
|
||||||
|
unsigned width = image.width();
|
||||||
|
unsigned height = image.height();
|
||||||
|
|
||||||
|
// structure for color quantization
|
||||||
|
hextree<mapnik::rgba> tree(colors);
|
||||||
|
if (trans_mode >= 0)
|
||||||
|
tree.setTransMode(trans_mode);
|
||||||
|
if (gamma > 0)
|
||||||
|
tree.setGamma(gamma);
|
||||||
|
|
||||||
|
for (unsigned y = 0; y < height; ++y)
|
||||||
|
{
|
||||||
|
typename T2::pixel_type const * row = image.getRow(y);
|
||||||
|
for (unsigned x = 0; x < width; ++x)
|
||||||
|
{
|
||||||
|
unsigned val = row[x];
|
||||||
|
tree.insert(mapnik::rgba(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//transparency values per palette index
|
||||||
|
std::vector<mapnik::rgba> pal;
|
||||||
|
tree.create_palette(pal);
|
||||||
|
assert(pal.size() <= colors);
|
||||||
|
|
||||||
|
std::vector<mapnik::rgb> palette;
|
||||||
|
std::vector<unsigned> alphaTable;
|
||||||
|
for(unsigned i=0; i<pal.size(); i++)
|
||||||
|
{
|
||||||
|
palette.push_back(rgb(pal[i].r, pal[i].g, pal[i].b));
|
||||||
|
alphaTable.push_back(pal[i].a);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (palette.size() > 16 )
|
||||||
|
{
|
||||||
|
// >16 && <=256 colors -> write 8-bit color depth
|
||||||
|
image_data_8 reduced_image(width, height);
|
||||||
|
|
||||||
|
for (unsigned y = 0; y < height; ++y)
|
||||||
|
{
|
||||||
|
mapnik::image_data_32::pixel_type const * row = image.getRow(y);
|
||||||
|
mapnik::image_data_8::pixel_type * row_out = reduced_image.getRow(y);
|
||||||
|
|
||||||
|
for (unsigned x = 0; x < width; ++x)
|
||||||
|
{
|
||||||
|
unsigned val = row[x];
|
||||||
|
mapnik::rgba c(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val));
|
||||||
|
row_out[x] = tree.quantize(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
save_as_png(file, palette, reduced_image, width, height, 8, alphaTable);
|
||||||
|
}
|
||||||
|
else if (palette.size() == 1)
|
||||||
|
{
|
||||||
|
// 1 color image -> write 1-bit color depth PNG
|
||||||
|
unsigned image_width = (int(0.125*width) + 7)&~7;
|
||||||
|
unsigned image_height = height;
|
||||||
|
image_data_8 reduced_image(image_width, image_height);
|
||||||
|
reduced_image.set(0);
|
||||||
|
save_as_png(file, palette, reduced_image, width, height, 1, alphaTable);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// <=16 colors -> write 4-bit color depth PNG
|
||||||
|
unsigned image_width = (int(0.5*width) + 3)&~3;
|
||||||
|
unsigned image_height = height;
|
||||||
|
image_data_8 reduced_image(image_width, image_height);
|
||||||
|
for (unsigned y = 0; y < height; ++y)
|
||||||
|
{
|
||||||
|
mapnik::image_data_32::pixel_type const * row = image.getRow(y);
|
||||||
|
mapnik::image_data_8::pixel_type * row_out = reduced_image.getRow(y);
|
||||||
|
byte index = 0;
|
||||||
|
|
||||||
|
for (unsigned x = 0; x < width; ++x)
|
||||||
|
{
|
||||||
|
unsigned val = row[x];
|
||||||
|
mapnik::rgba c(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val));
|
||||||
|
index = tree.quantize(c);
|
||||||
|
if (x%2 == 0) index = index<<4;
|
||||||
|
row_out[x>>1] |= index;
|
||||||
|
}
|
||||||
|
}
|
||||||
save_as_png(file, palette, reduced_image, width, height, 4, alphaTable);
|
save_as_png(file, palette, reduced_image, width, height, 4, alphaTable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,9 @@ extern "C"
|
||||||
#include <mapnik/cairo_renderer.hpp>
|
#include <mapnik/cairo_renderer.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/tokenizer.hpp>
|
||||||
|
|
||||||
// stl
|
// stl
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -52,28 +55,7 @@ namespace mapnik
|
||||||
std::string const& type)
|
std::string const& type)
|
||||||
{
|
{
|
||||||
std::ostringstream ss(std::ios::out|std::ios::binary);
|
std::ostringstream ss(std::ios::out|std::ios::binary);
|
||||||
//all this should go into image_writer factory
|
save_to_stream(image, ss, type);
|
||||||
if (type=="png") save_as_png(ss,image);
|
|
||||||
else if (type == "png256") save_as_png256(ss,image);
|
|
||||||
else if (boost::algorithm::istarts_with(type,std::string("jpeg")))
|
|
||||||
{
|
|
||||||
int quality = 85;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(type.substr(4).length() != 0)
|
|
||||||
{
|
|
||||||
quality = boost::lexical_cast<int>(type.substr(4));
|
|
||||||
if(quality<1 || quality>100)
|
|
||||||
throw ImageWriterException("invalid jpeg quality: " + type.substr(4));
|
|
||||||
}
|
|
||||||
save_as_jpeg(ss,quality,image);
|
|
||||||
}
|
|
||||||
catch(boost::bad_lexical_cast &)
|
|
||||||
{
|
|
||||||
throw ImageWriterException("invalid jpeg quality: " + type.substr(4));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else throw ImageWriterException("unknown file type: " + type);
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,10 +66,89 @@ namespace mapnik
|
||||||
{
|
{
|
||||||
std::ofstream file (filename.c_str(), std::ios::out| std::ios::trunc|std::ios::binary);
|
std::ofstream file (filename.c_str(), std::ios::out| std::ios::trunc|std::ios::binary);
|
||||||
if (file)
|
if (file)
|
||||||
|
{
|
||||||
|
save_to_stream(image, file, type);
|
||||||
|
}
|
||||||
|
else throw ImageWriterException("Could not write file to " + filename );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void save_to_stream(T const& image,
|
||||||
|
std::ostream & stream,
|
||||||
|
std::string const& type)
|
||||||
|
{
|
||||||
|
if (stream)
|
||||||
{
|
{
|
||||||
//all this should go into image_writer factory
|
//all this should go into image_writer factory
|
||||||
if (type=="png") save_as_png(file,image);
|
if (type == "png") save_as_png(stream, image);
|
||||||
else if (type == "png256") save_as_png256(file,image);
|
else if (boost::algorithm::istarts_with(type, std::string("png256")) ||
|
||||||
|
boost::algorithm::istarts_with(type, std::string("png8"))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int colors = 256;
|
||||||
|
int trans_mode = -1;
|
||||||
|
double gamma = -1;
|
||||||
|
bool use_octree = true;
|
||||||
|
if (type.length() > 6){
|
||||||
|
boost::char_separator<char> sep(":");
|
||||||
|
boost::tokenizer< boost::char_separator<char> > tokens(type, sep);
|
||||||
|
BOOST_FOREACH(string t, tokens)
|
||||||
|
{
|
||||||
|
if (t == "m=h")
|
||||||
|
{
|
||||||
|
use_octree = false;
|
||||||
|
}
|
||||||
|
if (t == "m=o")
|
||||||
|
{
|
||||||
|
use_octree = true;
|
||||||
|
}
|
||||||
|
if (boost::algorithm::istarts_with(t,std::string("c=")))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
colors = boost::lexical_cast<int>(t.substr(2));
|
||||||
|
if (colors < 0 || colors > 256)
|
||||||
|
throw ImageWriterException("invalid color parameter: " + t.substr(2) + " out of bounds");
|
||||||
|
}
|
||||||
|
catch(boost::bad_lexical_cast &)
|
||||||
|
{
|
||||||
|
throw ImageWriterException("invalid color parameter: " + t.substr(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (boost::algorithm::istarts_with(t, std::string("t=")))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
trans_mode= boost::lexical_cast<int>(t.substr(2));
|
||||||
|
if (trans_mode < 0 || trans_mode > 2)
|
||||||
|
throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2) + " out of bounds");
|
||||||
|
}
|
||||||
|
catch(boost::bad_lexical_cast &)
|
||||||
|
{
|
||||||
|
throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (boost::algorithm::istarts_with(t, std::string("g=")))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
gamma= boost::lexical_cast<double>(t.substr(2));
|
||||||
|
if (gamma < 0)
|
||||||
|
throw ImageWriterException("invalid gamma parameter: " + t.substr(2) + " out of bounds");
|
||||||
|
}
|
||||||
|
catch(boost::bad_lexical_cast &)
|
||||||
|
{
|
||||||
|
throw ImageWriterException("invalid gamma parameter: " + t.substr(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (use_octree)
|
||||||
|
save_as_png256(stream, image, colors);
|
||||||
|
else
|
||||||
|
save_as_png256_hex(stream, image, colors, trans_mode, gamma);
|
||||||
|
}
|
||||||
else if (boost::algorithm::istarts_with(type,std::string("jpeg")))
|
else if (boost::algorithm::istarts_with(type,std::string("jpeg")))
|
||||||
{
|
{
|
||||||
int quality = 85;
|
int quality = 85;
|
||||||
|
@ -99,7 +160,7 @@ namespace mapnik
|
||||||
if(quality<0 || quality>100)
|
if(quality<0 || quality>100)
|
||||||
throw ImageWriterException("invalid jpeg quality: " + type.substr(4) + " out of bounds");
|
throw ImageWriterException("invalid jpeg quality: " + type.substr(4) + " out of bounds");
|
||||||
}
|
}
|
||||||
save_as_jpeg(file,quality,image);
|
save_as_jpeg(stream, quality, image);
|
||||||
}
|
}
|
||||||
catch(boost::bad_lexical_cast &)
|
catch(boost::bad_lexical_cast &)
|
||||||
{
|
{
|
||||||
|
@ -108,7 +169,7 @@ namespace mapnik
|
||||||
}
|
}
|
||||||
else throw ImageWriterException("unknown file type: " + type);
|
else throw ImageWriterException("unknown file type: " + type);
|
||||||
}
|
}
|
||||||
else throw ImageWriterException("Could not write file to " + filename );
|
else throw ImageWriterException("Could not write to empty stream" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue