merged r1661: fixed png256 for large images + improvements to palette generation: #522

This commit is contained in:
Marcin Rudowski 2010-03-06 11:13:44 +00:00
parent f4f329d3c2
commit 34578099c1
3 changed files with 57 additions and 24 deletions

View file

@ -25,6 +25,8 @@ Mapnik Trunk
- Rasterlite Plugin: Experimental support for Rasterlite, to practically use sqlite database with wavelet compressed rasters (#469)
- PNG: fixed png256 for large images and some improvements to reduce color corruptions (#522)
Mapnik 0.7.0 Release
--------------------

View file

@ -50,7 +50,7 @@ namespace mapnik {
struct RGBPolicy
{
const static unsigned MAX_LEVELS = 6;
const static unsigned MIN_LEVELS = 3;
const static unsigned MIN_LEVELS = 2;
inline static unsigned index_from_level(unsigned level, rgb const& c)
{
unsigned shift = 7 - level;
@ -70,7 +70,7 @@ namespace mapnik {
greens(0),
blues(0),
count(0),
count2(0),
count_cum(0),
children_count(0),
index(0)
{
@ -86,11 +86,12 @@ namespace mapnik {
bool is_leaf() const { return count == 0; }
node * children_[8];
unsigned reds;
unsigned greens;
unsigned blues;
boost::uint64_t reds;
boost::uint64_t greens;
boost::uint64_t blues;
unsigned count;
unsigned count2;
double reduce_cost;
unsigned count_cum;
byte children_count;
byte index;
};
@ -98,7 +99,7 @@ namespace mapnik {
{
bool operator() ( const node * lhs,const node* rhs) const
{
return lhs->count2 < rhs->count2;
return lhs->reduce_cost < rhs->reduce_cost;
}
};
@ -151,13 +152,13 @@ namespace mapnik {
unsigned level = 0;
node * cur_node = root_;
while (true) {
cur_node->count2++;
cur_node->count_cum++;
cur_node->reds += data.r;
cur_node->greens += data.g;
cur_node->blues += data.b;
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)
@ -185,7 +186,8 @@ namespace mapnik {
node * cur_node = root_;
while (cur_node)
{
if (cur_node->count != 0) return cur_node->index + offset_;
if (cur_node->children_count == 0)
return cur_node->index + offset_;
unsigned idx = InsertPolicy::index_from_level(level,c);
cur_node = cur_node->children_[idx];
++level;
@ -204,17 +206,44 @@ namespace mapnik {
palette.reserve(colors_);
create_palette(palette, root_);
}
void computeCost(node *r)
{
r->reduce_cost = 0;
if (r->children_count==0)
return;
double sum[] = {0,0,0};
for (unsigned idx=0; idx < 8; ++idx) if (r->children_[idx] != 0)
{
computeCost(r->children_[idx]);
sum[0] += r->children_[idx]->reds;
sum[1] += r->children_[idx]->greens;
sum[2] += r->children_[idx]->blues;
}
for (unsigned idx=0; idx < 8; ++idx) if (r->children_[idx] != 0)
{
r->reduce_cost += r->children_[idx]->reduce_cost;
r->reduce_cost += fabs(r->children_[idx]->reds
- sum[0] * r->children_[idx]->count_cum / r->count_cum);
r->reduce_cost += fabs(r->children_[idx]->greens
- sum[1] * r->children_[idx]->count_cum / r->count_cum);
r->reduce_cost += fabs(r->children_[idx]->blues
- sum[2] * r->children_[idx]->count_cum / r->count_cum);
}
}
void reduce()
{
computeCost(root_);
reducible_[0].push_back(root_);
// sort reducible
// sort reducible by reduce_cost
for (unsigned i=0;i<InsertPolicy::MAX_LEVELS;++i)
{
std::sort(reducible_[i].begin(), reducible_[i].end(),node_cmp());
}
while ( colors_ > max_colors_ && colors_ > 1)
{
while (leaf_level_ >0 && reducible_[leaf_level_-1].size() == 0)
@ -226,7 +255,7 @@ namespace mapnik {
// select best of all reducible:
unsigned red_idx = leaf_level_-1;
unsigned bestv = (*reducible_[red_idx].begin())->count2;
unsigned bestv = (*reducible_[red_idx].begin())->count_cum;
for(unsigned i=red_idx; i>=InsertPolicy::MIN_LEVELS; i--) if (!reducible_[i].empty()){
node *nd = *reducible_[i].begin();
unsigned gch = 0;
@ -234,8 +263,8 @@ namespace mapnik {
if (nd->children_[idx])
gch += nd->children_[idx]->children_count;
}
if (gch==0 && nd->count2<bestv){
bestv = nd->count2;
if (gch==0 && nd->count_cum<bestv){
bestv = nd->count_cum;
red_idx = i;
}
}
@ -249,10 +278,8 @@ namespace mapnik {
{
cur_node->children_count--;
++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;
//todo: case of nonleaf children, if someday sorting by reduce_cost doesn't handle it
delete cur_node->children_[idx], cur_node->children_[idx]=0;
}
}
@ -273,7 +300,7 @@ namespace mapnik {
palette.push_back(rgb(byte(itr->reds/float(count)),
byte(itr->greens/float(count)),
byte(itr->blues/float(count))));
itr->index = palette.size() - 1;
itr->index = palette.size() - 1;
}
for (unsigned i=0; i < 8 ;++i)
{

View file

@ -332,12 +332,16 @@ namespace mapnik {
unsigned divCoef = width*height-cols[0];
if (divCoef==0) divCoef = 1;
cols[0] = cols[0]>0?1:0; // fully transparent color (one or not at all)
// give chance less populated but not empty cols to have at least few colors(12)
unsigned minCols = (12+1)*divCoef/(256-cols[0]);
for(int j=1; j<TRANSPARENCY_LEVELS; j++) if (cols[j]>12 && cols[j]<minCols) {
divCoef += minCols-cols[j];
cols[j] = minCols;
}
unsigned usedColors = cols[0];
for(int j=1; j<TRANSPARENCY_LEVELS-1; j++){
unsigned oldCols = cols[j];
cols[j] = cols[j]*(256-cols[0])/divCoef;
if (oldCols>12 && cols[j]<12)
cols[j] = 12; // reserve at least 12 colors to have any effect
usedColors += cols[j];
}
// use rest for most opaque group of pixels