Opened 21 years ago

Closed 21 years ago

#445 closed defect (fixed)

Outlinecolor problem in label for RGB outputformat

Reported by: claude.philipona@… Owned by: warmerdam
Priority: high Milestone:
Component: GDAL Support Version: 4.0
Severity: normal Keywords:
Cc: claude.philipona@…

Description

There is a bug when OUTLINECOLOR is set with truetype label in RGB
OUTPUTFORMAT (jpeg/png24). There outline appears as "square" instaed as
"line" around the letters label.

All the where made with a simple call to a mapfile, using
Mapserver4.0/PHPMapscript. You'll find the mapfile at the end of this
message.
GD 2.0.15
Freetype 2.1.5
Gdal 1.1.9

Result with IMAGETYPE png (8bit), everything is ok, the outline is present:
http://www.camptocamp.com/~claude/mapserver/test_label_png.png

Result with IMAGETYPE png24 (24bit), no outlines, but square:
http://www.camptocamp.com/~claude/mapserver/test_label_png24.png

Result with IMAGETYPE jpeg (24bit) same as png 24 (squares instead of
outlines):
http://www.camptocamp.com/~claude/mapserver/test_label_jpg.jpg

Then I tried several configuration:
When I set POSTLABELCACHE ON and TRANSPARENCY 100 on the layer, the
OUTLINES are ok, but now (of course) label collision occurs:
http://www.camptocamp.com/~claude/mapserver/test_label__post_label_cache_transpa
rency_100_png24.png

With  POSTLABELCACHE ON or TRANSPARENCY 100 settings alone, the outlines
are not set properly either:
http://www.camptocamp.com/~claude/mapserver/test_label_transparency_100_png24.pn
g
http://www.camptocamp.com/~claude/mapserver/test_label__post_label_cache_png24.p
ng

This behaviour is quite annoying, because it is apperently impossible to
have nice OUTLINES in RGB formats without POSTLABELCACHE ON and
TRANSPARENCY 100, and often we don't want to use these two settings becaus
of the side effect.

Test mapfile:

NAME TEST
STATUS ON
SIZE 600 450

SYMBOLSET "symbols_1.sym"
EXTENT 532500 152180 534340 152880
UNITS METERS

SHAPEPATH "../shapes"
TRANSPARENT OFF

IMAGETYPE png24

IMAGECOLOR 210 190 190
FONTSET "etc/fonts.txt"
WEB
  MINSCALE 0
  MAXSCALE 40000
  IMAGEPATH "/var/www/test2/htdocs/tmp/"
  IMAGEURL "/test2/tmp/"
END # WEB

LAYER
  NAME buildings
  TYPE POLYGON
  STATUS ON
  DATA "buildings"
  TRANSPARENCY 60
  CLASS
    NAME "BAT"
    STYLE
      COLOR 50 200 50
      OUTLINECOLOR 152 227 152
      SYMBOL 0
      SIZE 1
    END
  END
END

LAYER
  NAME "roads_label"
  TYPE ANNOTATION
  STATUS ON
  DATA "roads_label.shp"
  LABELITEM "Nom"
 #POSTLABELCACHE ON
 #TRANSPARENCY 100
  CLASS
    LABEL
      TYPE truetype
      FONT "arial"
      SIZE 10
      MINDISTANCE 300
      ANTIALIAS TRUE
      POSITION cc
      ANGLE AUTO
      COLOR 100 100 100
      OUTLINECOLOR 230 230 230
    END
  END
END

END # Mapfile

Change History (3)

comment:1 by fwarmerdam, 21 years ago

Status: newassigned
Reproduced with this mapfile:

NAME TEST
STATUS ON
SIZE 600 450

#SYMBOLSET "symbols_1.sym"
EXTENT 532500 152180 534340 152880
UNITS METERS

SHAPEPATH "../shapes"
TRANSPARENT OFF

IMAGETYPE png24

IMAGECOLOR 210 190 190
FONTSET "msautotest/misc/fonts.lst"

LAYER
  NAME buildings
  TYPE POLYGON
  STATUS ON
#  DATA "buildings"
  TRANSPARENCY 60
  FEATURE
      POINTS 532900 152800 5323900 152800 5323900 152100 532900 152100 532900
152800 END
  END
  CLASS
    NAME "BAT"
    STYLE
      COLOR 50 200 50
      OUTLINECOLOR 152 227 152
      SYMBOL 0
      SIZE 1
    END
  END
END

LAYER
  NAME "roads_label"
  TYPE ANNOTATION
  STATUS DEFAULT
  FEATURE
      POINTS 533000 152500 END
      TEXT "BIG_AND_small test"
  END
#  DATA "roads_label.shp"
#  LABELITEM "Nom"
 #POSTLABELCACHE ON
 #TRANSPARENCY 100
  CLASS
    LABEL
      TYPE truetype
      FONT "default"
      SIZE 10
      MINDISTANCE 300
      ANTIALIAS TRUE
      POSITION cc
      ANGLE AUTO
      COLOR 100 100 100
      OUTLINECOLOR 230 230 230
    END
  END
END

END # Mapfile

comment:2 by fwarmerdam, 21 years ago

To: support@boutell.com


Hi,

Support contract: #30723

I am trying to use gdImageStringFT() to draw into a truecolor gdImage.
The problem is that the background areas of the text are being filled in
when we should see the underlying text through them.

An example of the results not working:
  http://www.camptocamp.com/~claude/mapserver/test_label_png24.png

Working properly:
  http://www.camptocamp.com/~claude/mapserver/test_label_png.png

Tracking through, the problem seems to be in gdft_draw_bitmap(), used to
burn the greyscale bitmap that came from freetype into the 24bit image.

In the 24bit case, level comes out of this as 0 for portions of the bitmap
that are background:

          if (bitmap.pixel_mode == ft_pixel_mode_grays)
        {
          /*
           * Scale to 128 levels of alpha for gd use.
           * alpha 0 is opacity, so be sure to invert at the end
           */
          level = (bitmap.buffer[pc] * gdAlphaMax /
               (bitmap.num_grays - 1));
        }

Later level is inverted:

          level = gdAlphaMax - level;

Then we get to this:
          if (im->alphaBlendingFlag)
            {
              *tpixel =
            gdAlphaBlend (*tpixel,
                      (level << 24) + (fg & 0xFFFFFF));
            }
          else
             {
              *tpixel = (level << 24) + (fg & 0xFFFFFF);
            }

If alpha blending is turned on, the level causes the overlay to be treated
as transparent and no change is made (good).  But if alphablending is turned
off, the output pixel is replaced by the input value even though the input
pixel is trasparent.

I *think* this is an error, but I could be mixed up about what gdft_bitmap_draw()
is really intended to do.  My perception is that the function should not copy
transparent pixels to the output bitmap.

If we look through the 8bit (not truecolor) case below we see this test:

      if (tc_key.pixel > 0)    /* if not background */

basically, background pixels are not copied to the output.  I think similar
logic should be placed in the truecolor case.   Locally I patched things
to look like this, and it worked in my case.  I am not completely confident this
is the right solution though (and it doesn't address the ft_pixel_mode_mono case).

          if (bitmap.pixel_mode == ft_pixel_mode_grays)
        {
          /*
           * Scale to 128 levels of alpha for gd use.
           * alpha 0 is opacity, so be sure to invert at the end
           */
          level = (bitmap.buffer[pc] * gdAlphaMax /
               (bitmap.num_grays - 1));

          if( level == 0 )
            continue;
        }

For my problem I will experiment with turning on alpha blending as I think
that is what I would want anyways, but I would like you to consider patching
gd for the 2.0.16 release.

Best regards,

-- 
---------------------------------------+--------------------------------------
I set the clouds in motion - turn up   | Frank Warmerdam, warmerdam@pobox.com
light and sound - activate the windows | http://pobox.com/~warmerdam
and watch the world go round - Rush    | Geospatial Programmer for Rent


comment:3 by fwarmerdam, 21 years ago

Resolution: fixed
Status: assignedclosed
I have discovered that the alpha blending flag on the gdImage was not being
set till after the outlining had been done.  While I have submitted a bug
report to the GD maintainer, it seems that practically speaking, the MapServer
solution is to move the alpha blending enable call up before the outline draws.

In my test map this seems to have resolved the problem.  Please rebuild from
CVS (you need mapgd.c:1.47) and see if the problem is resolved.

Please re-open if the problem persists. 

Note: See TracTickets for help on using tickets.