Ticket #214 (closed defect: fixed)

Opened 11 years ago

Last modified 10 years ago

[WMS Reprojection] Problem with transparent background color of WMS layer

Reported by: dmorissette Owned by: warmerdam
Priority: high Milestone:
Component: WMS Client Version: 4.0
Severity: normal Keywords:
Cc: pspencer@…

Description

see attachment 16 in bug 211:
http://mapserver.gis.umn.edu/bugs/attachment.cgi?id=16&action=view

With MapServer 3.7, the grid layer in this mapfile ends up with an opaque black 
background but it should be transparent.  The same mapfile renders a transparent 
grid with 3.6

Change History

Changed 11 years ago by dmorissette

  • cc spencer@… added
  • owner changed from morissette@… to fwarmerdam
OK, I did more investigation this one, and I believe I found the source of the 
problem, it would be an issue with the way transparent colors coming from 
GIF/PNG and layer->offsite are handled.  However I'm really unsure what the 
right fix will be since all the color handling stuff has changed in 3.7 and I'm 
kind of lost on the implications of my changes on RGB vs 8 bits outputs.

BTW, we're using GD-1.8.4 with GIF, PNG, JPEG support.  But it seems that any 8 
bit version of GD with PNG support should do the same as well.

A quick note about WMS layers before I go any further:
In 3.6, when a WMS layer needed reprojection (via GDAL), I used to open the GIF 
returned by the remote server with gd, fetch the transparent color index, and 
then set layer->offsite to this value before calling the raster resampling code. 
 This was required because GDAL wasn't able to deal with transparent colors in 
GIFs/PNGs (or wasn't always doing the right thing).  I see that this code was 
removed in 3.7, does this mean that GDAL is able to deal with transparent 
GIF/PNG colors now?  If not then perhaps re-adding this code will fix the issue? 
I seem to have noticed that gdImages coming out of drawGDAL() carry the right 
transparent color with recent GDAL but I'm not sure.


In 3.7, when a WMS layer that needs reprojection is drawn, the following 
happens:
 - mapwmslayer.c will:
    - download the file to disk
    - create a world file with raster extents and set projection in layer
    - set layer->transform=true
    - draw the layer as a regular raster layer
 - msDrawRasterLayerLow() will see that reprojection is required and route 
   the GIF raster through msResampleGDALToMap()
 - msResampleGDALToMap() will:
    - create a temp. srcImage
    - copy palette from output image to srcImage
   ... at this point there is some code to fill the srcImage background using 
       layer->offsite color... but by default WMS layers don't carry an offsite
       color so this code is not executed...
    - then it calls drawGDAL() to read the GIF and load it into srcImage
    - copy updated srcImage palette back to output image
    - call msSimpleRasterResampler() to resample/copy srcImage -> output image

With the above, the reprojected layer has an opaque black background that hides 
all layers under it in the output image.  So this suggests a problem dealing 
with the transparent color in msSimpleRasterResampler().

I found that the following trick (hack) makes things work better, but it's not a 
good long-term fix:
  - in mapwmslayer.c: set layer->offsite = RGB:210,220,230 (or any uncommon RGB 
value)
  - this will force setting the bg of srcImage to the offsite color before the
    call to drawGDAL()
  - then my transparent WMS layer works properly _if_ I patch (fix ???) the 
    call to msSimpleRasterResampler() to pass nOffset as layer->offsite.pen 
    instead of layer->offsite.red

The problem with the above trick is that if the srcImage colors table is almost 
full, then any pixel close to the arbitrary offsite color value may end up 
transparent... which means unpredictable results.

I would think that a proper fix would involve making sure that drawGDAL() always 
returns a gdImage with a valid transparent color index _if_ the source raster 
contained transparent pixels.  Then msSimpleRasterResampler() should be modified 
to deal with the srcImage's transparent color index properly.  Once that's in 
place I'm not sure if we still need to fill the srcImage with the offsite 
color... I admit that I'm getting a bit confused.

Reassigning to Frank... hopefully this description will make sense to you.
The patch described above is in CVS, look for comments referring to bug 214.

Changed 11 years ago by fwarmerdam

  • status changed from new to assigned
I have made substantial changes to mapresample.c so that the destination
palette is no longer copied to the temporary image before the drawGDAL() call. 
Instead just one transparent color is assigned to ensure that transparent values
from the loaded image remain transparent for the resampling operation.  The
resampling operation now applies a colormap lookup transforming between the
colormap developed on the temporary image by drawGDAL() and the target image 
object. 

Note that, much like in Daniel's "hack", an arbitrary color is selected as the
transparent color in the temporary image.  However, the intention is that
msAddColorGD() will avoid mapping any allocation request to the transparent
color, even if the RGB value exactly matches.  Previosly logic was added to
perturb the value slightly.

I still have a bunch of further checking to do, but I have comitted the change
as it stands. 

NOTE: Actually currently msAddColorGD() checks only against
map->outputformat->transparent and
map->outputformat->imagecolor.{red,green,blue} to know the transparent value,
but it should also be checking the gdImagePtr's own concept of what the
transparent index is and what color value that is ... or ... the mapresample.c
code should be creating a temporary outputformat object with appropriate
transparent information on it for the local case. 

Changed 11 years ago by dmorissette

FYI I tested the latest CVS source with 3 test mapfiles that used to give 
transparency problems and they all worked fine.

Changed 11 years ago by fwarmerdam

I would add I have made some additional fixes for RGBA mode, and I am now
much more comfortable with my changes. 

I would also note, I haven't removed the hack from mapwmslayer.c.

Changed 10 years ago by dmorissette

  • status changed from assigned to closed
  • resolution set to fixed
I removed the offsite hack from mapwmslayer.c and tested again and things look 
fine.

We haven't noticed any more problems with reprojected layers since you applied 
your fixes, so I'll mark this as fixed and please reopen (Frank) if you 
were not done and you think there are still things to be addressed in this area.

Thanks for the fixes BTW!  :)
Note: See TracTickets for help on using tickets.