Opened 18 years ago
Last modified 18 years ago
#1701 reopened defect
Outline Antialiased labels eat too many colors of the palette
Reported by: | Owned by: | sdlime | |
---|---|---|---|
Priority: | high | Milestone: | |
Component: | MapServer C Library | Version: | unspecified |
Severity: | normal | Keywords: | |
Cc: | pspencer@…, arovira@… |
Description
When mapserver uses a font with antialias and outlinecolor to draw labels, many colors are allocated in the palette, and some not used at end. Problems arises when other layers with images are drawed over because the max. number of palette colors are reached. The problem is related of how mapserver renders outline fonts. It draw the label one pixel displaced in each direction with the outline color and then draws the label. When rendering this displaced labels, if antialias is on, antialias is aplicated with the background. Because the labels are drawn one over the other, different colors are allocated unnecessary. I suggest disable antialias when drawing to produce the outlined and enable it only to draw the text. Image results are very similar and the number of colors used are reduced.
Attachments (4)
Change History (19)
comment:2 by , 18 years ago
Cc: | added |
---|
Steve, I have successfully used the gd function to quantize 24bit pngs into 8bit pngs with no apparent lose of image quality using antialiased thick lines with casement styles and antialiased true type text ... loads of colours in there and there is no visible (to my poor eye) difference. This has the additional advantage of fixing the colour problems with pixmap symbol colour corruption in 8bit mode. I assume there is a performance hit but am not in a position to measure that. I have been discussing this with Assefa. Not sure how this would end up in MapServer but I would imagine it would be an option inside an outputformat object to apply the gdTrueColorToPalette function just before a save.
comment:3 by , 18 years ago
Cc: | added |
---|
I think this could make it like a format option for gd/png24 and gd/jpeg (RGB). The function to be used is gdImageCreatePaletteFromTrueColor(gdImagePtr im, int ditherFlag, int colorsWanted) so we might want to give the dithering flag and the number of colors as parameters. The change will ne done in function msSaveImageGDCtx in mapgd.c Frank : any input on this. Thanks.
comment:4 by , 18 years ago
I think it would be quite confusing to use GD/JPEG and end up with a paletted image in some other format. My suggestion is that we start just applying it to PNG format since it is easy to understand the concept of render in 24bit and switch at the last second to 8bit before writing. For now this could just be declared as FORMATOPTION. eg. FORMATOPTION "DITHER=YES" Then we can contemplate expanding this feature more widely. I do think that we will need to make some effort to explain how this differs from enabling 24 to 8 bit quantization in the raster renderer in the documentation so people don't get to confused. I'd be happy to incorporate the DITHER=YES FORMATOPTION in 4.9 if folks would like.
comment:5 by , 18 years ago
I am ok with doing it on 24bit png to start with. If we use the format option dither=yes, I am assuming the the low level gd function call would always set the dither flag to true ? Is there any advantage of setting that to false ? (the docs I have seen says soemthing like : ... "If ditherFlag is set, the image will be dithered to approximate colors better, at the expense of some obvious "speckling." ). I think clarifying this would help update the documentation too. Frank, thanks also for proposition to integrte it. Yes please do so.
comment:6 by , 18 years ago
I agree that PNG seems a place to start to try it out. It'll be interesting to see the performance hit. May be a *very* popular addition if it works well. Perhaps the discussion should be moved back to the bug Assefa created for it. ;- ) Steve
comment:7 by , 18 years ago
oops. I though It was the same bug :) You are right, there is one opened for the gd24-8bis (Bug 1690). I have updated the Bug 1690 to indicate that part of the comnversation is in this bug.
comment:8 by , 18 years ago
Implemented quantize support per Bug 1690 Please test, and consider closing this bug if that new feature addresses the problem.
comment:9 by , 18 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
I think quantize support will solve this problem and is a very good feature for mapserver. I have used it in some particular implementations via Java mapscript + gdscript and give good results. If somebody can't not use this feature and want antialiased font with outlines for readability he can tweak mapserver to disable antialias between background map and the outline line. So the code in mapgd.c if(label->outlinecolor.pen >= 0) { /* handle the outline color */ error = gdImageStringFT(img, bbox, ((label->antialias)?(label- >outlinecolor.pen):-(label->outlinecolor.pen)), font, size, angle_radians, x, y- 1, string); if(error) { if( gdImageTrueColor(img) ) gdImageAlphaBlending( img, oldAlphaBlending ); msSetError(MS_TTFERR, error, "msDrawTextGD()"); if(label->encoding != NULL) msFree(string); return(-1); } gdImageStringFT(img, bbox, ((label->antialias)?(label->outlinecolor.pen):- (label->outlinecolor.pen)), font, size, angle_radians, x, y+1, string); gdImageStringFT(img, bbox, ((label->antialias)?(label->outlinecolor.pen):- (label->outlinecolor.pen)), font, size, angle_radians, x+1, y, string); gdImageStringFT(img, bbox, ((label->antialias)?(label->outlinecolor.pen):- (label->outlinecolor.pen)), font, size, angle_radians, x-1, y, string); gdImageStringFT(img, bbox, ((label->antialias)?(label->outlinecolor.pen):- (label->outlinecolor.pen)), font, size, angle_radians, x-1, y-1, string); gdImageStringFT(img, bbox, ((label->antialias)?(label->outlinecolor.pen):- (label->outlinecolor.pen)), font, size, angle_radians, x-1, y+1, string); gdImageStringFT(img, bbox, ((label->antialias)?(label->outlinecolor.pen):- (label->outlinecolor.pen)), font, size, angle_radians, x+1, y-1, string); gdImageStringFT(img, bbox, ((label->antialias)?(label->outlinecolor.pen):- (label->outlinecolor.pen)), font, size, angle_radians, x+1, y+1, string); } will be if(label->outlinecolor.pen >= 0) { /* handle the outline color */ error = gdImageStringFT(img, bbox, -(label->outlinecolor.pen), font, size, angle_radians, x, y-1, string); if(error) { if( gdImageTrueColor(img) ) gdImageAlphaBlending( img, oldAlphaBlending ); msSetError(MS_TTFERR, error, "msDrawTextGD()"); if(label->encoding != NULL) msFree(string); return(-1); } gdImageStringFT(img, bbox, -(label->outlinecolor.pen),font, size, angle_radians, x, y+1, string); gdImageStringFT(img, bbox, -(label->outlinecolor.pen),font, size, angle_radians, x+1, y, string); gdImageStringFT(img, bbox, -(label->outlinecolor.pen),font, size, angle_radians, x-1, y, string); gdImageStringFT(img, bbox, -(label->outlinecolor.pen), font, size, angle_radians, x-1, y-1, string); gdImageStringFT(img, bbox, -(label->outlinecolor.pen), font, size, angle_radians, x-1, y+1, string); gdImageStringFT(img, bbox, -(label->outlinecolor.pen), font, size, angle_radians, x+1, y-1, string); gdImageStringFT(img, bbox, -(label->outlinecolor.pen), font, size, angle_radians, x+1, y+1, string); } Thanks, Albert.
comment:11 by , 18 years ago
Resolution: | fixed |
---|---|
Status: | closed → reopened |
I spoke too soon. Not sure if this is a solveable problem. I've got a couple of cases where it is coming up with substantially different colours even though the colour table of the resulting image is not full. Output format is: OUTPUTFORMAT NAME dithered DRIVER "GD/PNG" EXTENSION "png" MIMETYPE "image/png" IMAGEMODE RGBA TRANSPARENT OFF FORMATOPTION "QUANTIZE_FORCE=ON" FORMATOPTION "QUANTIZE_DITHER=OFF" FORMATOPTION "QUANTIZE_COLORS=256" END I tried with dither on and off and will attach samples of both.
comment:12 by , 18 years ago
Paul, I have analysed your results, and I see you are indeed getting noticably different blues in different quantized images. For instance (153,182,196) vs. (156,190,220). I have reviewed the algorithm description in gd-2.0.33/gd_topal.c and I think this is essentially inevitable. You can read the description in that source file, but basically changes in the data can result in a large or smaller box being formed for the blue, and the final color used is the "box center", not the exact color that falls in the box. I think per-tile quantization is just inappropriate for ka-map. What you really need is a way of providing a color table and force mapserver to dither the 24bit data to that color table. If you had a fixed color table you would get dependable mapping to final colors. Hmm, actually on reflection, I'm surprised the dithering doesn't mostly fix this up. In any event, I don't believe this represents a problem in mapserver. I think it is inappropriateness of per-tile quantization in a tile based viewer.
comment:13 by , 18 years ago
What is strange is that the vast majority of the incorrect tile contains the blue. Note also that the image that mapserver renders is actually 16 of those tiles and most are in the ocean. What would be needed to provide a fixed palette and dither to that? The fixed palette could easily be calculated from the colours allocated in the map file (and the colour tables of image symbols I guess).
comment:14 by , 18 years ago
Paul, At the low level version we would need to implement our own dithering modules (or reuse the dithering from GDAL already used in the mapserver raster rendering). How to collect or specify the color table is not so clear. It is especially hard to collect a colortable automatically that will address colors introduced by anti-aliasing or rasters. One approach would be to just use a fixed color cube. In combination with dithering this might give reasonable results. The other would be to allow specifying a fixed colormap in the map file somehow.
comment:15 by , 18 years ago
could the colour table be collected through colours defined in the map file when they are used? Regarding colours used by antialiasing, for the most part quantization seems to do an outstanding job of this. It just seems to be overly aggressive. When I specify 256 colours, I would expect the output image to have 256 colours if the input image has more than 256 colours, or the exact colours if the input image has less than 256 colours. My interpretation of your comment above is that this is not what is happening. Am I correct? If I have an input image with less than 256 distinct colours, I could end up with less colours in the output image than the input image? And if I have more than 256 colours, I could end up with less than 256 as well?
Note:
See TracTickets
for help on using tickets.