Ticket #477 (closed enhancement: fixed)

Opened 7 months ago

Last modified 4 months ago

semitransparency support for png256

Reported by: mar_rud Owned by: artem
Priority: normal Milestone: 0.7.1
Component: Core Library Version: SVN Trunk
Severity: Normal Keywords:
Cc: Patch Needs Improvement: no
Needs Docmentation: no Has Patch?: yes
Design Decision Needed: no

Description

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:
- left : source image
- center : new algorithm
- 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).

Attachments

semialpha_png256.tar.gz (1.0 MB) - added by mar_rud 7 months ago.
Patch, moidified files, sample images and readme.txt
png256a_demo.1.png (10.0 kB) - added by mar_rud 7 months ago.
smooth.png/jagged.png from #202
png256a_demo.2.png (183.6 kB) - added by mar_rud 7 months ago.
real mapping sample with thin roads
png256a_demo.3.png (115.9 kB) - added by mar_rud 7 months ago.
real mapping sample with transparent area
png256a_demo.45.png (29.9 kB) - added by mar_rud 7 months ago.
Limitation of the method: limited alfa range with one-color gradient + clipping around min/max alpha values because of image size optimization.
semialpha_png256b.diff (14.5 kB) - added by mar_rud 7 months ago.
Corrected diff file after max_colors_ fix
mapnik-0.7.1.mr.hextree.diff (37.4 kB) - added by mar_rud 5 months ago.
full semitransparency support using hextree + passing parameters in format string, i.e.: "png256:c=256:m=h"
mapnik-0.7.1.mr.hextree2.diff (37.7 kB) - added by mar_rud 5 months ago.
static arrays for vc++

Change History

Changed 7 months ago by mar_rud

Patch, moidified files, sample images and readme.txt

Changed 7 months ago by mar_rud

smooth.png/jagged.png from #202

Changed 7 months ago by mar_rud

real mapping sample with thin roads

Changed 7 months ago by mar_rud

real mapping sample with transparent area

Changed 7 months ago by mar_rud

Limitation of the method: limited alfa range with one-color gradient + clipping around min/max alpha values because of image size optimization.

  Changed 7 months ago by 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 :) :
http://mapa.ump.waw.pl/ump-www/?zoom=13&lat=52.236&lon=21.00277&layers=00B000TT

Changed 7 months ago by mar_rud

Corrected diff file after max_colors_ fix

  Changed 7 months ago by 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 ;)

  Changed 7 months ago by cmarqu

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

  Changed 7 months ago by 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

  Changed 7 months ago by mar_rud

sorry, instead of

reducible_[i].push_back(root_); 

should be:

reducible_[0].push_back(root_); 

  Changed 7 months ago by springmeyer

  • status changed from new to closed
  • resolution set to fixed
  • milestone set to 0.7.0

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!

  Changed 6 months ago by 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.

follow-up: ↓ 9   Changed 6 months ago by 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.

in reply to: ↑ 8   Changed 6 months ago by springmeyer

Replying to 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

Changed 5 months ago by mar_rud

full semitransparency support using hextree + passing parameters in format string, i.e.: "png256:c=256:m=h"

  Changed 5 months ago by mar_rud

Changed 5 months ago by mar_rud

static arrays for vc++

  Changed 5 months ago by 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.

  Changed 5 months ago by springmeyer

  • status changed from closed to reopened
  • resolution fixed deleted

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

  Changed 5 months ago by springmeyer

  • milestone changed from 0.7.0 to 0.7.1

follow-up: ↓ 15   Changed 5 months ago by 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.

in reply to: ↑ 14   Changed 5 months ago by 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!

  Changed 5 months ago by springmeyer

working on porting to trunk:

There looks to be a small conflict

       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.

  Changed 5 months ago by springmeyer

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

  Changed 5 months ago by springmeyer

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

  Changed 5 months ago by mar_rud

  • status changed from reopened to closed
  • resolution set to fixed

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).

  Changed 4 months ago by albertov

  • status changed from closed to reopened
  • resolution fixed deleted

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

Alberto

  Changed 4 months ago by albertov

  • status changed from reopened to closed
  • resolution set to fixed

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

Note: See TracTickets for help on using tickets.