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) - 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 Mapnik 0.7.0 Release
-------------------- --------------------

View file

@ -50,7 +50,7 @@ namespace mapnik {
struct RGBPolicy struct RGBPolicy
{ {
const static unsigned MAX_LEVELS = 6; 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) inline static unsigned index_from_level(unsigned level, rgb const& c)
{ {
unsigned shift = 7 - level; unsigned shift = 7 - level;
@ -70,7 +70,7 @@ namespace mapnik {
greens(0), greens(0),
blues(0), blues(0),
count(0), count(0),
count2(0), count_cum(0),
children_count(0), children_count(0),
index(0) index(0)
{ {
@ -86,11 +86,12 @@ namespace mapnik {
bool is_leaf() const { return count == 0; } bool is_leaf() const { return count == 0; }
node * children_[8]; node * children_[8];
unsigned reds; boost::uint64_t reds;
unsigned greens; boost::uint64_t greens;
unsigned blues; boost::uint64_t blues;
unsigned count; unsigned count;
unsigned count2; double reduce_cost;
unsigned count_cum;
byte children_count; byte children_count;
byte index; byte index;
}; };
@ -98,7 +99,7 @@ namespace mapnik {
{ {
bool operator() ( const node * lhs,const node* rhs) const 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; unsigned level = 0;
node * cur_node = root_; node * cur_node = root_;
while (true) { 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_) 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; cur_node->count += 1;
if (cur_node->count == 1) ++colors_; if (cur_node->count == 1) ++colors_;
//if (colors_ >= max_colors_ - 1) //if (colors_ >= max_colors_ - 1)
@ -185,7 +186,8 @@ namespace mapnik {
node * cur_node = root_; node * cur_node = root_;
while (cur_node) 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); unsigned idx = InsertPolicy::index_from_level(level,c);
cur_node = cur_node->children_[idx]; cur_node = cur_node->children_[idx];
++level; ++level;
@ -205,16 +207,43 @@ namespace mapnik {
create_palette(palette, root_); 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() void reduce()
{ {
computeCost(root_);
reducible_[0].push_back(root_); reducible_[0].push_back(root_);
// sort reducible // sort reducible by reduce_cost
for (unsigned i=0;i<InsertPolicy::MAX_LEVELS;++i) for (unsigned i=0;i<InsertPolicy::MAX_LEVELS;++i)
{ {
std::sort(reducible_[i].begin(), reducible_[i].end(),node_cmp()); std::sort(reducible_[i].begin(), reducible_[i].end(),node_cmp());
} }
while ( colors_ > max_colors_ && colors_ > 1) while ( colors_ > max_colors_ && colors_ > 1)
{ {
while (leaf_level_ >0 && reducible_[leaf_level_-1].size() == 0) while (leaf_level_ >0 && reducible_[leaf_level_-1].size() == 0)
@ -226,7 +255,7 @@ namespace mapnik {
// select best of all reducible: // select best of all reducible:
unsigned red_idx = leaf_level_-1; 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()){ for(unsigned i=red_idx; i>=InsertPolicy::MIN_LEVELS; i--) if (!reducible_[i].empty()){
node *nd = *reducible_[i].begin(); node *nd = *reducible_[i].begin();
unsigned gch = 0; unsigned gch = 0;
@ -234,8 +263,8 @@ namespace mapnik {
if (nd->children_[idx]) if (nd->children_[idx])
gch += nd->children_[idx]->children_count; gch += nd->children_[idx]->children_count;
} }
if (gch==0 && nd->count2<bestv){ if (gch==0 && nd->count_cum<bestv){
bestv = nd->count2; bestv = nd->count_cum;
red_idx = i; red_idx = i;
} }
} }
@ -249,10 +278,8 @@ namespace mapnik {
{ {
cur_node->children_count--; cur_node->children_count--;
++num_children; ++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; 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; delete cur_node->children_[idx], cur_node->children_[idx]=0;
} }
} }

View file

@ -332,12 +332,16 @@ namespace mapnik {
unsigned divCoef = width*height-cols[0]; unsigned divCoef = width*height-cols[0];
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)
// 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]; unsigned usedColors = cols[0];
for(int j=1; j<TRANSPARENCY_LEVELS-1; j++){ for(int j=1; j<TRANSPARENCY_LEVELS-1; j++){
unsigned oldCols = cols[j];
cols[j] = cols[j]*(256-cols[0])/divCoef; 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]; usedColors += cols[j];
} }
// use rest for most opaque group of pixels // use rest for most opaque group of pixels