support for palette based PNGs, user 'png256' as a format parameter (see updated rundemo.py)
This commit is contained in:
parent
4586586448
commit
58f4431df1
9 changed files with 450 additions and 62 deletions
|
@ -29,6 +29,9 @@ using mapnik::ImageData32;
|
||||||
using mapnik::image_view;
|
using mapnik::image_view;
|
||||||
using mapnik::save_to_file;
|
using mapnik::save_to_file;
|
||||||
|
|
||||||
|
void (*view_to_file1)(std::string const&,std::string const&, image_view<ImageData32> const&) = mapnik::save_to_file;
|
||||||
|
void (*view_to_file2)(std::string const&, image_view<ImageData32> const&) = mapnik::save_to_file;
|
||||||
|
|
||||||
void export_image_view()
|
void export_image_view()
|
||||||
{
|
{
|
||||||
using namespace boost::python;
|
using namespace boost::python;
|
||||||
|
@ -37,5 +40,6 @@ void export_image_view()
|
||||||
.def("height",&image_view<ImageData32>::height)
|
.def("height",&image_view<ImageData32>::height)
|
||||||
;
|
;
|
||||||
|
|
||||||
//def("save_to_file",save_to_file<image_view<ImageData32> >);
|
def("save_to_file",view_to_file1);
|
||||||
|
def("save_to_file",view_to_file2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,7 +305,7 @@ m.zoom_to_box(Envelope(1405120.04127408,-247003.813399447,1706357.31328276,-2509
|
||||||
|
|
||||||
# Render two maps, one PNG, one JPEG.
|
# Render two maps, one PNG, one JPEG.
|
||||||
|
|
||||||
render_to_file(m, 'demo.png', 'png')
|
render_to_file(m, 'demo.png', 'png256') # save to palette based (max 256 colours) png
|
||||||
render_to_file(m, 'demo.jpg', 'jpeg')
|
render_to_file(m, 'demo.jpg', 'jpeg')
|
||||||
|
|
||||||
print """\n\nTwo maps have been rendered in the current directory:
|
print """\n\nTwo maps have been rendered in the current directory:
|
||||||
|
|
|
@ -57,8 +57,10 @@ namespace mapnik
|
||||||
virtual ~ImageReader() {}
|
virtual ~ImageReader() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool register_image_reader(const std::string& type,ImageReader* (*)(const std::string&));
|
bool register_image_reader(const std::string& type,ImageReader* (*)(const std::string&));
|
||||||
MAPNIK_DECL ImageReader* get_image_reader(const std::string& type,const std::string& file);
|
MAPNIK_DECL ImageReader* get_image_reader(const std::string& file,const std::string& type);
|
||||||
|
MAPNIK_DECL ImageReader* get_image_reader(const std::string& file);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //IMAGE_READER_HPP
|
#endif //IMAGE_READER_HPP
|
||||||
|
|
|
@ -31,8 +31,9 @@ namespace mapnik {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class image_view
|
class image_view
|
||||||
{
|
{
|
||||||
typedef typename T::pixel_type pixel_type;
|
public:
|
||||||
public:
|
typedef typename T::pixel_type pixel_type;
|
||||||
|
|
||||||
image_view(unsigned x, unsigned y, unsigned width, unsigned height, T const& data)
|
image_view(unsigned x, unsigned y, unsigned width, unsigned height, T const& data)
|
||||||
: x_(x),
|
: x_(x),
|
||||||
y_(y),
|
y_(y),
|
||||||
|
|
225
include/mapnik/octree.hpp
Normal file
225
include/mapnik/octree.hpp
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* This file is part of Mapnik (c++ mapping toolkit)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 Artem Pavlenko
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
//$Id$
|
||||||
|
|
||||||
|
#ifndef _OCTREE_HPP_
|
||||||
|
#define _OCTREE_HPP_
|
||||||
|
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace mapnik {
|
||||||
|
|
||||||
|
typedef uint8_t byte ;
|
||||||
|
struct rgb
|
||||||
|
{
|
||||||
|
byte r;
|
||||||
|
byte g;
|
||||||
|
byte b;
|
||||||
|
rgb(byte r_, byte b_, byte g_)
|
||||||
|
: r(r_), g(g_), b(b_) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RGBPolicy
|
||||||
|
{
|
||||||
|
const static unsigned MAX_LEVELS = 6;
|
||||||
|
inline static unsigned index_from_level(unsigned level, rgb const& c)
|
||||||
|
{
|
||||||
|
unsigned shift = 7 - level;
|
||||||
|
return (((c.r >> shift) & 1) << 2)
|
||||||
|
| (((c.g >> shift) & 1) << 1)
|
||||||
|
| ((c.b >> shift) & 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename InsertPolicy = RGBPolicy >
|
||||||
|
class octree : private boost::noncopyable
|
||||||
|
{
|
||||||
|
struct node
|
||||||
|
{
|
||||||
|
node ()
|
||||||
|
: next_node_(0),
|
||||||
|
reds(0),
|
||||||
|
greens(0),
|
||||||
|
blues(0),
|
||||||
|
count(0),
|
||||||
|
index(0)
|
||||||
|
{
|
||||||
|
memset(&children_[0],0,sizeof(children_));
|
||||||
|
}
|
||||||
|
|
||||||
|
~node ()
|
||||||
|
{
|
||||||
|
for (unsigned i = 0;i < 8; ++i) {
|
||||||
|
if (children_[i] != 0) delete children_[i],children_[i]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_leaf() const { return count != 0; }
|
||||||
|
node * children_[8];
|
||||||
|
node * next_node_;
|
||||||
|
unsigned reds;
|
||||||
|
unsigned greens;
|
||||||
|
unsigned blues;
|
||||||
|
unsigned count;
|
||||||
|
uint8_t index;
|
||||||
|
};
|
||||||
|
struct node_cmp
|
||||||
|
{
|
||||||
|
bool operator() ( const node * lhs,const node* rhs ) const
|
||||||
|
{
|
||||||
|
unsigned left_total=0;
|
||||||
|
unsigned right_total=0;
|
||||||
|
for (unsigned i=0; i<8;++i)
|
||||||
|
{
|
||||||
|
if (lhs->children_[i]) left_total+=lhs->children_[i]->count;
|
||||||
|
if (rhs->children_[i]) right_total+=rhs->children_[i]->count;
|
||||||
|
}
|
||||||
|
return lhs > rhs;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::set<node*,node_cmp> reducible_[InsertPolicy::MAX_LEVELS];
|
||||||
|
unsigned max_colors_;
|
||||||
|
unsigned colors_;
|
||||||
|
unsigned leaf_level_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit octree(unsigned max_colors=255)
|
||||||
|
: max_colors_(max_colors),
|
||||||
|
colors_(0),
|
||||||
|
leaf_level_(InsertPolicy::MAX_LEVELS),
|
||||||
|
root_(new node())
|
||||||
|
{}
|
||||||
|
|
||||||
|
~octree() { delete root_;}
|
||||||
|
|
||||||
|
void insert(T const& data)
|
||||||
|
{
|
||||||
|
unsigned level = 0;
|
||||||
|
node * cur_node = root_;
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
if ( cur_node->count > 0 || level == leaf_level_)
|
||||||
|
{
|
||||||
|
cur_node->reds += data.r;
|
||||||
|
cur_node->greens += data.g;
|
||||||
|
cur_node->blues += data.b;
|
||||||
|
cur_node->count += 1;
|
||||||
|
if (cur_node->count == 1) ++colors_;
|
||||||
|
if (colors_ >= max_colors_ - 1)
|
||||||
|
{
|
||||||
|
reduce();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned idx = InsertPolicy::index_from_level(level,data);
|
||||||
|
if (cur_node->children_[idx] == 0) {
|
||||||
|
cur_node->children_[idx] = new node();
|
||||||
|
if (level < leaf_level_-1) {
|
||||||
|
reducible_[level+1].insert(cur_node->children_[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur_node = cur_node->children_[idx];
|
||||||
|
++level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int quantize(rgb const& c) const
|
||||||
|
{
|
||||||
|
unsigned level = 0;
|
||||||
|
node * cur_node = root_;
|
||||||
|
while (cur_node)
|
||||||
|
{
|
||||||
|
if (cur_node->count != 0) return cur_node->index;
|
||||||
|
unsigned idx = InsertPolicy::index_from_level(level,c);
|
||||||
|
cur_node = cur_node->children_[idx];
|
||||||
|
++level;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_palette(std::vector<rgb> & palette) const
|
||||||
|
{
|
||||||
|
palette.reserve(colors_);
|
||||||
|
create_palette(palette, root_);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void reduce()
|
||||||
|
{
|
||||||
|
while (leaf_level_ >0 && reducible_[leaf_level_-1].size() == 0)
|
||||||
|
{
|
||||||
|
--leaf_level_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leaf_level_ < 1) return;
|
||||||
|
|
||||||
|
typename std::set<node*,node_cmp>::iterator pos = reducible_[leaf_level_-1].begin();
|
||||||
|
if (pos == reducible_[leaf_level_-1].end()) return;
|
||||||
|
|
||||||
|
node * cur_node = *pos;
|
||||||
|
unsigned num_children = 0;
|
||||||
|
for (unsigned idx=0; idx < 8; ++idx)
|
||||||
|
{
|
||||||
|
if (cur_node->children_[idx] != 0)
|
||||||
|
{
|
||||||
|
++num_children;
|
||||||
|
cur_node->reds += cur_node->children_[idx]->reds;
|
||||||
|
cur_node->greens += cur_node->children_[idx]->greens;
|
||||||
|
cur_node->blues += cur_node->children_[idx]->blues;
|
||||||
|
cur_node->count += cur_node->children_[idx]->count;
|
||||||
|
delete cur_node->children_[idx], cur_node->children_[idx]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reducible_[leaf_level_-1].erase(pos);
|
||||||
|
if (num_children > 0 )
|
||||||
|
{
|
||||||
|
colors_ -= (num_children - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_palette(std::vector<rgb> & palette, node * itr) const
|
||||||
|
{
|
||||||
|
if (itr->count != 0)
|
||||||
|
{
|
||||||
|
unsigned count = itr->count;
|
||||||
|
palette.push_back(rgb(uint8_t(itr->reds/float(count)),
|
||||||
|
uint8_t(itr->greens/float(count)),
|
||||||
|
uint8_t(itr->blues/float(count))));
|
||||||
|
itr->index = palette.size() - 1;
|
||||||
|
}
|
||||||
|
for (unsigned i=0; i < 8 ;++i)
|
||||||
|
{
|
||||||
|
if (itr->children_[i] != 0)
|
||||||
|
create_palette(palette, itr->children_[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
node * root_;
|
||||||
|
};
|
||||||
|
} // namespace mapnik
|
||||||
|
|
||||||
|
#endif /* _OCTREE_HPP_ */
|
|
@ -50,11 +50,16 @@ feature_ptr gdal_featureset::next()
|
||||||
GDALRasterBand * grey = 0;
|
GDALRasterBand * grey = 0;
|
||||||
for (int i = 0; i < dataset_.GetRasterCount() ;++i)
|
for (int i = 0; i < dataset_.GetRasterCount() ;++i)
|
||||||
{
|
{
|
||||||
GDALRasterBand * band = dataset_.GetRasterBand(i+1);
|
GDALRasterBand * band = dataset_.GetRasterBand(i+1);
|
||||||
|
//if (band->GetOverviewCount() > 0)
|
||||||
|
//{
|
||||||
|
// band = band->GetOverview(0);
|
||||||
|
//}
|
||||||
|
|
||||||
#ifdef MAPNIK_DEBUG
|
#ifdef MAPNIK_DEBUG
|
||||||
int bsx,bsy;
|
int bsx,bsy;
|
||||||
band->GetBlockSize(&bsx,&bsy);
|
band->GetBlockSize(&bsx,&bsy);
|
||||||
std::cout << boost::format("Block=%dx%d Type=%s Color=%s \n") % bsx % bsy
|
std::cout << boost::format("Block=%dx%d Type=%s Color=%s \n") % bsx % bsy
|
||||||
% GDALGetDataTypeName(band->GetRasterDataType())
|
% GDALGetDataTypeName(band->GetRasterDataType())
|
||||||
% GDALGetColorInterpretationName(band->GetColorInterpretation());
|
% GDALGetColorInterpretationName(band->GetColorInterpretation());
|
||||||
#endif
|
#endif
|
||||||
|
@ -77,30 +82,30 @@ feature_ptr gdal_featureset::next()
|
||||||
grey = band;
|
grey = band;
|
||||||
break;
|
break;
|
||||||
case GCI_PaletteIndex:
|
case GCI_PaletteIndex:
|
||||||
{
|
{
|
||||||
grey = band;
|
grey = band;
|
||||||
GDALColorTable *color_table = band->GetColorTable();
|
GDALColorTable *color_table = band->GetColorTable();
|
||||||
|
|
||||||
if ( color_table)
|
if ( color_table)
|
||||||
{
|
{
|
||||||
int count = color_table->GetColorEntryCount();
|
int count = color_table->GetColorEntryCount();
|
||||||
#ifdef MAPNIK_DEBUG
|
#ifdef MAPNIK_DEBUG
|
||||||
std::cout << "Color Table count = " << count << "\n";´
|
std::cout << "Color Table count = " << count << "\n";
|
||||||
#endif
|
#endif
|
||||||
for ( int i = 0; i < count; i++ )
|
for ( int i = 0; i < count; i++ )
|
||||||
{
|
{
|
||||||
const GDALColorEntry *ce = color_table->GetColorEntry ( i );
|
const GDALColorEntry *ce = color_table->GetColorEntry ( i );
|
||||||
if (!ce ) continue;
|
if (!ce ) continue;
|
||||||
#ifdef MAPNIK_DEBUG
|
#ifdef MAPNIK_DEBUG
|
||||||
std::cout << "color entry RGB (" << ce->c1 <<"," <<ce->c2 << "," << ce->c3 << ")\n";
|
std::cout << "color entry RGB (" << ce->c1 <<"," <<ce->c2 << "," << ce->c3 << ")\n";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GCI_Undefined:
|
case GCI_Undefined:
|
||||||
grey = band;
|
grey = band;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
;
|
;
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
//$Id: image_reader.cpp 17 2005-03-08 23:58:43Z pavlenko $
|
//$Id: image_reader.cpp 17 2005-03-08 23:58:43Z pavlenko $
|
||||||
|
|
||||||
#include <mapnik/image_reader.hpp>
|
#include <mapnik/image_reader.hpp>
|
||||||
|
#include <mapnik/image_util.hpp>
|
||||||
#include <mapnik/factory.hpp>
|
#include <mapnik/factory.hpp>
|
||||||
|
|
||||||
namespace mapnik
|
namespace mapnik
|
||||||
|
@ -36,8 +36,14 @@ namespace mapnik
|
||||||
return ImageReaderFactory::instance()->register_product(type,fun);
|
return ImageReaderFactory::instance()->register_product(type,fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageReader* get_image_reader(const std::string& type,const std::string& file)
|
ImageReader* get_image_reader(const std::string& filename,const std::string& type)
|
||||||
{
|
{
|
||||||
return ImageReaderFactory::instance()->create_object(type,file);
|
return ImageReaderFactory::instance()->create_object(type,filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImageReader* get_image_reader(const std::string& filename)
|
||||||
|
{
|
||||||
|
std::string type = type_from_filename(filename);
|
||||||
|
return ImageReaderFactory::instance()->create_object(filename,type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <mapnik/graphics.hpp>
|
#include <mapnik/graphics.hpp>
|
||||||
#include <mapnik/memory.hpp>
|
#include <mapnik/memory.hpp>
|
||||||
#include <mapnik/image_view.hpp>
|
#include <mapnik/image_view.hpp>
|
||||||
|
#include <mapnik/octree.hpp>
|
||||||
// jpeg png
|
// jpeg png
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
|
@ -52,6 +53,7 @@ namespace mapnik
|
||||||
{
|
{
|
||||||
//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(file,image);
|
||||||
|
else if (type == "png256") save_as_png256(file,image);
|
||||||
else if (type=="jpeg") save_as_jpeg(file,85,image);
|
else if (type=="jpeg") save_as_jpeg(file,85,image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,6 +125,150 @@ namespace mapnik
|
||||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void reduce_8 (T const& in, ImageData8 & out, octree<rgb> & tree)
|
||||||
|
{
|
||||||
|
unsigned width = in.width();
|
||||||
|
unsigned height = in.height();
|
||||||
|
for (unsigned y = 0; y < height; ++y)
|
||||||
|
{
|
||||||
|
mapnik::ImageData32::pixel_type const * row = in.getRow(y);
|
||||||
|
mapnik::ImageData8::pixel_type * row_out = out.getRow(y);
|
||||||
|
for (unsigned x = 0; x < width; ++x)
|
||||||
|
{
|
||||||
|
unsigned val = row[x];
|
||||||
|
mapnik::rgb c((val)&0xff, (val>>8)&0xff, (val>>16) & 0xff);
|
||||||
|
uint8_t index = tree.quantize(c);
|
||||||
|
row_out[x] = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void reduce_4 (T const& in, ImageData8 & out, octree<rgb> & tree)
|
||||||
|
{
|
||||||
|
unsigned width = in.width();
|
||||||
|
unsigned height = in.height();
|
||||||
|
|
||||||
|
for (unsigned y = 0; y < height; ++y)
|
||||||
|
{
|
||||||
|
mapnik::ImageData32::pixel_type const * row = in.getRow(y);
|
||||||
|
mapnik::ImageData8::pixel_type * row_out = out.getRow(y);
|
||||||
|
|
||||||
|
for (unsigned x = 0; x < width; ++x)
|
||||||
|
{
|
||||||
|
unsigned val = row[x];
|
||||||
|
mapnik::rgb c((val)&0xff, (val>>8)&0xff, (val>>16) & 0xff);
|
||||||
|
uint8_t index = tree.quantize(c);
|
||||||
|
if (x%2 > 0) index = index<<4;
|
||||||
|
row_out[x>>1] |= index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1-bit but only one color.
|
||||||
|
template <typename T>
|
||||||
|
void reduce_1(T const&, ImageData8 & out, octree<rgb> &)
|
||||||
|
{
|
||||||
|
out.set(0); // only one color!!!
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void save_as_png(T & file, std::vector<mapnik::rgb> & palette,
|
||||||
|
mapnik::ImageData8 const& image,
|
||||||
|
unsigned width,
|
||||||
|
unsigned height,
|
||||||
|
unsigned color_depth)
|
||||||
|
{
|
||||||
|
png_voidp error_ptr=0;
|
||||||
|
png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||||
|
error_ptr,0, 0);
|
||||||
|
|
||||||
|
if (!png_ptr) return;
|
||||||
|
|
||||||
|
// switch on optimization only if supported
|
||||||
|
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED)
|
||||||
|
png_uint_32 mask, flags;
|
||||||
|
flags = png_get_asm_flags(png_ptr);
|
||||||
|
mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
|
||||||
|
png_set_asm_flags(png_ptr, flags | mask);
|
||||||
|
#endif
|
||||||
|
png_set_filter (png_ptr, 0, PNG_FILTER_NONE);
|
||||||
|
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
if (!info_ptr)
|
||||||
|
{
|
||||||
|
png_destroy_write_struct(&png_ptr,(png_infopp)0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (setjmp(png_jmpbuf(png_ptr)))
|
||||||
|
{
|
||||||
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
png_set_write_fn (png_ptr, &file, &write_data<T>, &flush_data<T>);
|
||||||
|
|
||||||
|
png_set_IHDR(png_ptr, info_ptr,width,height,color_depth,
|
||||||
|
PNG_COLOR_TYPE_PALETTE,PNG_INTERLACE_NONE,
|
||||||
|
PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
|
||||||
|
|
||||||
|
png_set_PLTE(png_ptr,info_ptr,reinterpret_cast<png_color*>(&palette[0]),palette.size());
|
||||||
|
|
||||||
|
png_write_info(png_ptr, info_ptr);
|
||||||
|
for (unsigned i=0;i<height;i++)
|
||||||
|
{
|
||||||
|
png_write_row(png_ptr,(png_bytep)image.getRow(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
png_write_end(png_ptr, info_ptr);
|
||||||
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1,typename T2>
|
||||||
|
void save_as_png256(T1 & file, T2 const& image)
|
||||||
|
{
|
||||||
|
octree<rgb> tree(256);
|
||||||
|
unsigned width = image.width();
|
||||||
|
unsigned height = image.height();
|
||||||
|
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::rgb((val)&0xff, (val>>8)&0xff, (val>>16) & 0xff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<rgb> palette;
|
||||||
|
tree.create_palette(palette);
|
||||||
|
assert(palette.size() <= 256);
|
||||||
|
|
||||||
|
if (palette.size() > 16 )
|
||||||
|
{
|
||||||
|
// >16 && <=256 colors -> write 8-bit color depth
|
||||||
|
ImageData8 reduced_image(width,height);
|
||||||
|
reduce_8(image,reduced_image,tree);
|
||||||
|
save_as_png(file,palette,reduced_image,width,height,8);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
ImageData8 reduced_image(image_width,image_height);
|
||||||
|
reduce_1(image,reduced_image,tree);
|
||||||
|
save_as_png(file,palette,reduced_image,width,height,1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// <=16 colors -> write 4-bit color depth PNG
|
||||||
|
unsigned image_width = (int(0.5*width) + 3)&~3;
|
||||||
|
unsigned image_height = height;
|
||||||
|
ImageData8 reduced_image(image_width,image_height);
|
||||||
|
reduce_4(image,reduced_image,tree);
|
||||||
|
save_as_png(file,palette,reduced_image,width,height,4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define BUFFER_SIZE 4096
|
#define BUFFER_SIZE 4096
|
||||||
|
|
||||||
|
@ -222,7 +368,7 @@ namespace mapnik
|
||||||
template void save_to_file<image_view<ImageData32> > (std::string const&,
|
template void save_to_file<image_view<ImageData32> > (std::string const&,
|
||||||
std::string const&,
|
std::string const&,
|
||||||
image_view<ImageData32> const&);
|
image_view<ImageData32> const&);
|
||||||
|
|
||||||
template void save_to_file<image_view<ImageData32> > (std::string const&,
|
template void save_to_file<image_view<ImageData32> > (std::string const&,
|
||||||
image_view<ImageData32> const&);
|
image_view<ImageData32> const&);
|
||||||
|
|
||||||
|
|
|
@ -29,37 +29,36 @@
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
symbolizer_with_image::symbolizer_with_image(boost::shared_ptr<ImageData32> img) :
|
symbolizer_with_image::symbolizer_with_image(boost::shared_ptr<ImageData32> img) :
|
||||||
image_( img ) {}
|
image_( img ) {}
|
||||||
|
|
||||||
symbolizer_with_image::symbolizer_with_image(std::string const& file,
|
|
||||||
std::string const& type, unsigned width,unsigned height)
|
|
||||||
: image_(new ImageData32(width,height)),
|
|
||||||
image_filename_( file )
|
|
||||||
{
|
|
||||||
std::auto_ptr<ImageReader> reader(get_image_reader(type,file));
|
|
||||||
if (reader.get())
|
|
||||||
reader->read(0,0,*image_);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
symbolizer_with_image::symbolizer_with_image( symbolizer_with_image const& rhs)
|
|
||||||
: image_(rhs.image_), image_filename_(rhs.image_filename_) {}
|
|
||||||
|
|
||||||
|
|
||||||
boost::shared_ptr<ImageData32> symbolizer_with_image::get_image() const
|
|
||||||
{
|
|
||||||
return image_;
|
|
||||||
}
|
|
||||||
void symbolizer_with_image::set_image(boost::shared_ptr<ImageData32> symbol)
|
|
||||||
{
|
|
||||||
image_ = symbol;
|
|
||||||
}
|
|
||||||
const std::string & symbolizer_with_image::get_filename() const
|
|
||||||
{
|
|
||||||
return image_filename_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
symbolizer_with_image::symbolizer_with_image(std::string const& file,
|
||||||
|
std::string const& type, unsigned width,unsigned height)
|
||||||
|
: image_(new ImageData32(width,height)),
|
||||||
|
image_filename_( file )
|
||||||
|
{
|
||||||
|
std::auto_ptr<ImageReader> reader(get_image_reader(type,file));
|
||||||
|
if (reader.get())
|
||||||
|
reader->read(0,0,*image_);
|
||||||
|
}
|
||||||
|
|
||||||
|
symbolizer_with_image::symbolizer_with_image( symbolizer_with_image const& rhs)
|
||||||
|
: image_(rhs.image_), image_filename_(rhs.image_filename_) {}
|
||||||
|
|
||||||
|
|
||||||
|
boost::shared_ptr<ImageData32> symbolizer_with_image::get_image() const
|
||||||
|
{
|
||||||
|
return image_;
|
||||||
|
}
|
||||||
|
void symbolizer_with_image::set_image(boost::shared_ptr<ImageData32> symbol)
|
||||||
|
{
|
||||||
|
image_ = symbol;
|
||||||
|
}
|
||||||
|
const std::string & symbolizer_with_image::get_filename() const
|
||||||
|
{
|
||||||
|
return image_filename_;
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace mapnik
|
} // end of namespace mapnik
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue