Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

semitransparency support for png256 #477

Closed
artemp opened this issue Oct 11, 2011 · 20 comments
Closed

semitransparency support for png256 #477

artemp opened this issue Oct 11, 2011 · 20 comments
Milestone

Comments

@artemp
Copy link
Member

artemp commented Oct 11, 2011

Current png256 format allows only full opacity or full transparency pixels. Discussion about it can be found in http://trac.mapnik.org/ticket/202#comment:5. Now I'm presenting patch implementing mentioned solution: using 3 octrees, one per alpha range. Boundaries and assigned color numbers are computed based on image alpha distribution.
This allows more smooth transparency changes and eliminates jagged edges.

In attachment, beside patch and fixed files, there are: readme.txt with more info, some sample images for testing different cases and little program, that can be used to test png256 without need to compile all mapnik libraries. I used it while writing this fix to test different approaches.

In image attachments below You can see effects in different cases. Those images are divided to 3 columns:[[BR]]

  • left : source image[[BR]]
  • center : new algorithm[[BR]]
  • right : previous algorithm

Codes are prepared against 0.7 branch (including latest fix to #445, #447).
I suggest testing in different scenarios before committing. It isn't perfect, but in most situations should be enough, without much cputime or image size trade off (only 10% longer time and bigger image).

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[mar_rud] After more extensive testing, I found that bug in octree.h can lead to infinite loop. Problem occurred while creating palette in octree::reduce() for very low max_colors_ values (< 8). Fixed this by correcting octree.h (missing line and corrected while conditions) and also corrected png_io.h to increase to at least 12 estimated max_colors_, because when using i.e. 4, effect isn't good anyway (not enough colors produced visible outline instead of smooth edge).

In this form my server is already generating hybrid layer in png256 format :) :[[BR]]
http://mapa.ump.waw.pl/ump-www/?zoom=13&lat=52.236&lon=21.00277&layers=00B000TT

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[mar_rud] One issue with IE worth mentioning: If using png256 format with transparency, avoid changing opacity of displayed images in browser using css, as under IE (even IE8) there is bug and all semitransparent pixels will be fully opaque and this looks very bad. If css style is not set (in OpenLayers no 'opacity' parameter for Layer), at least in IE7, IE8 everything goes back to normal. Any nonIE browser I checked doesn't have such problems: Firefox, Safari, Chrome, Opera, Konqueror.

Unfortunately I use opacity:0.7 in my OpenLayers init script and now I can rewrite my mapnik xml's to make forests and other polygons semitransparent or just ignore IE ugly rendering ;)

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[cmarqu] Oh, thanks very much for that hint, the problem had bitten me too!

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[springmeyer] Marcin,

When compiling with semialpha_png256b.diff I get:

{{{
include/mapnik/octree.hpp: In member function 'void mapnik::octree<T, InsertPolicy>::reduce()':
include/mapnik/octree.hpp:211: error: 'i' was not declared in this scope
scons: *** [src/image_util.os] Error 1
Install file: "include/mapnik/octree.hpp" as "/usr/local/include/mapnik/octree.hpp"
scons: building terminated because of errors.
springmeyer:seven spring$ coda include/mapnik/octree.hpp
}}}

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[mar_rud] sorry, instead of
{{{
reducible_[i].push_back(root_);
}}}
should be:
{{{
reducible_[0].push_back(root_);
}}}

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[springmeyer] Tested on a variety of mapfiles and confirmed that there is no visible change in non-transparent png256, while semi-transparency now looks excellent. Really excellent write-up and patch Marcin :)

I also tested with #define TRANSPARENCY_LEVELS 2 which looks slightly more jaggy (and is smaller) but is still higher quality than before the patch. I think there may be scenarios where users could desire that sharper edge (or binary transparency) and I think we should raise the issue in another ticket of how to allow users to pass more image options in future revisions of Mapnik.

But, as is this patch is a great improvement and I've added in r1509. Will also port to trunk in r1510.

Thanks Marcin!

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[springmeyer] Marcin,

Would it be possible for you to amend this patch to allow for the option of maintaining binary transparency? I'm running into a snag where an application using GD requires it otherwise the semitransparent background becomes fully black.

Setting {{{#define TRANSPARENCY_LEVELS 1}}} results in zero-division errors, but perhaps there is an easy way for you to consider restoring the binary option pre r1509. I realize that it was a limitation previously, but in this case also a feature.

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[mar_rud] TRANSPARENCY_LEVELS 2 should do the trick, because 2 levels would be: full opacity + full transparency, and division point is alpha value: 127. This wouldn't work only if image has one semitransparent color, and this is needed (added one line), to set correct meanAlpha for that case:
{{{
if (TRANSPARENCY_LEVELS==2) {
limits[1]=127;
meanAlpha=(meanAlpha>127)?255:0;
}
}}}

Default TRANSPARENCY_LEVELS 4 means additional 2 semitransparent ranges, but number of semitransparent levels could be more, depending on color->alpha correlation, see:
http://trac.mapnik.org/attachment/ticket/477/png256a_demo.45.png
for extreme cases with TRANSPARENCY_LEVELS 4.

In #202 I suggested using ie: "png256:colors=16:transparency=full" or "jpg:quality=95" for controlling image saving behaviour using format string. This would need parsing and passing parameters to png_io.h and also making TRANSPARENCY_LEVELS a variable, same as magic value 256/255 colors, if less would be required.

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[springmeyer] Replying to [comment:8 mar_rud]:

TRANSPARENCY_LEVELS 2 should do the trick, because 2 levels would be: full opacity + full transparency, and division point is alpha value: 127.

Great, good to know. Thats what I originally assumed. As it turns out I botched my testing, I was recompiling with level=2 but not seeing an affect because I was not using png256 at all, /sigh. So, sorry about that. I was using the OGCServer which defaults to standard PNG, which I had forgotten about. As it turns out any transparency level works in the application using GD! All GD needed was a paletted image.

That said, I'm happy for my mistake as your extra info is great :).

This wouldn't work only if image has one semitransparent color, and this is needed (added one line), to set correct meanAlpha for that case:

{{{
if (TRANSPARENCY_LEVELS==2) {
limits[1]=127;
meanAlpha=(meanAlpha>127)?255:0;
}
}}}

Okay, do you think we should add this?

Default TRANSPARENCY_LEVELS 4 means additional 2 semitransparent ranges, but number of semitransparent levels could be more, depending on color->alpha correlation, see:
http://trac.mapnik.org/attachment/ticket/477/png256a_demo.45.png
for extreme cases with TRANSPARENCY_LEVELS 4.

Great, good to know.

In #202 I suggested using ie: "png256:colors=16:transparency=full" or "jpg:quality=95" for controlling image saving behaviour using format string. This would need parsing and passing parameters to png_io.h and also making TRANSPARENCY_LEVELS a variable, same as magic value 256/255 colors, if less would be required.

Yes, this is a good idea. We need this. We should discuss more on mapnik-devel about what people would like to see exposed and add functionality to trunk.

Thanks!

Dane

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[mar_rud] More details about last patch: http://lists.berlios.de/pipermail/mapnik-devel/2010-March/001081.html

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[springmeyer] great, I'm supportive of extra hextree+parameter fix going into 0.7.1 as long as compiler issues seem resolved. Will be a good way to get feedback on extra options by users so we can refine in trunk. I've not had a chance to play with the patch yet so I don't have any more distinct thoughts. Will try to later today or tomorrow.

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[springmeyer] Okay, I've had a quick chance to test and I don't see anything too risky here, so applying to 0.7.1 seems great and I've done so in r1680, along with a few additions to rundemo.py and a tweak to allow passing options to octree/hextree by doing e.g. png:c=64:t=1 in addition to png256:c=64:t=1. Does that sound good?

I am going to re-open this ticket however, for 2 reasons:

  1. I need to test against PPC arch tonight, to make sure current behavior is maintained.
  2. We need to port to trunk

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[mar_rud] r1680 was missing new file: hextree.hpp. I added it + updated CHANGELOG (r1683), with some basic description of new changes, but I think it needs some cleaning (i.e. first position is redundant).

Not sure about "png:c=64:t=1", but added also png8 as discussed on mapnik-devel.

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[springmeyer] thanks for adding missing file! - funny how svn needs second add like that after patch.

I agree about "png:c=64:t=1" being potentially confusing ( what would png:t=1 mean since it only applies when colors are also reduced), so I rolled that back in r1690 - for now png256/png8 prefix sounds fine for exposing.

Also, I have just tested on PPC (mac os x 10.5) and works great!

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[springmeyer] working on porting to trunk:

There looks to be a small conflict
{{{
#!diff
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
    
  •  for(unsigned j=1; j<TRANSPARENCY_LEVELS-1; j++){
    
  •     cols[j] = cols[j]*(max_colors-cols[0])/divCoef;
      usedColors += cols[j];
    
    }
    }}}

so, I'll attach trunk patch next for review and commit by mar_rud, then we can close.

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[springmeyer] hmm, nm I think on this conflict, my svn trunk co was not up to date...

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[springmeyer] Okay, applied to trunk in r1691, please take a look marcin, and close if the port looks correct.

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[mar_rud] Looks fine, except for missing unfortunate hextree.hpp :) that I added (r1693) so I'm closing this ticket.

I left CHANGELOG alone, because probably it would be better to sync it after 0.7.1 release as next: "Mapnik 0.7.1 Release" paragraph with those changes, that were ported (#524).

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[albertov] I've noticed same edge cases where transparency is not handled correctly. Please take a look at #539 and #540.

Alberto

@artemp
Copy link
Member Author

artemp commented Oct 11, 2011

[albertov] Closing since these issues are already tracked at their own tickets.

@artemp artemp closed this as completed Oct 11, 2011
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant