Opened 19 years ago

Last modified 15 years ago

#1243 new defect

[Performance] gdImageStringFT called multiple time in msDrawTextGD. — at Version 21

Reported by: jlacroix Owned by: jlacroix@…
Priority: high Milestone: 6.0 release
Component: MapServer C Library Version: unspecified
Severity: normal Keywords:
Cc: woodbri@…, aboudreault, tbonfort, jmckenna

Description (last modified by tbonfort)

In bug 1224, I found out that in msDrawTextGD, gdImageStringFT is called 7 times
in a row to make the outline of the text. In 4.0 there were only three call to
this function. I suppose it's for a better outlining of labels.

This cause a problem, a performance lost. It depends on the mapfiles, but in the
GMap demo (around 14 labels), it results in a 15% performance lost.

With 4.0, for 50 call to gmap75.map:
total: 6.18 sec.
in gdImageStringFT: 1.66 sec.

With 4.0:
total: 7.56
in gdImageStringFT: 2.51 sec.

Is there a way to reduce the cost of outlining?
To reduce the number of call?

Change History (25)

comment:1 by jlacroix, 19 years ago

blocked: 1224
Cc: mapserver-bugs@… added
I forgot to say that this lost is not caused by the antialiasing. The
antialiasing is expensive, but the same kind of performance lost is observed.

comment:2 by sdlime, 19 years ago

I'm all for finding a better way but I've not had any luck. I've been playing 
with this off and on for years. Ideally the outlining would be implemented 
very close to the GD/FT interface (i.e. GD should offer the effects: shadows 
and outlines, not MapServer. The additional calls are indeed for better 
outlining. With glyph caching it should not be that expensive.

Anyway, I'm open to suggestions...

Steve

comment:3 by jlacroix, 19 years ago

What is the original reason of the change from 3 to 7 calls? I did not check,
but is it possible to do less than 7 calls?

comment:4 by sdlime, 19 years ago

Status: newassigned
The reason for the change was to get better text outlines. It actually went 
from 4 to 8 calls I think. The outline is created by offsetting the text each 
of the 8 directions, used to be just 4. However, for some fonts that left gaps 
in the outline, most notably 'i' and 'l' with arial. It would probably by 
faster to render the text in the outline color once in a temporary image, then 
paste that image into the main image subsequent times. Could also try running 
a convolution filter on the temp image to achieve an effect. 

Let me play with it. May take a couple of days though.

Steve

comment:5 by jlacroix, 19 years ago

Milestone: 4.6 release
I think we should aim 4.6 with, at least to see if it's possible to gain speed
with the temporary image. I may have time to check it this week. I will assign
it to me if it's the case.

comment:6 by sdlime, 19 years ago

I have been thinking about this. The problem with a temporary image is that 
antialiasing falls apart. I think the solution lies either:

  - in modifications to GD or Freetype to allow for text effects upon initial 
rendering
  - perhaps trying to use a different font size to lay down the outline color

I've experimented with the latter before, but with older versions of Freetype, 
and found that simply scaling of labels did not work well.

Steve

comment:7 by woodbri@…, 19 years ago

Cc: woodbri@… added

comment:8 by dmorissette, 19 years ago

Using a different font size won't work unfortunately. I searched for "halo" and
freetype, and found the following post at
http://lists.gnu.org/archive/html/freetype/2004-04/msg00016.html

This is probably what we need: we could do the dilation (and antialias) in
MapServer on a pixmap that contains the rendered font, and possibly submit a
patch to boutell.com to integrate this in future versions of GD.


Re: [Freetype] Halo(?) font/effect
From: 	Peter Montgomery
Subject: 	Re: [Freetype] Halo(?) font/effect
Date: 	Tue, 13 Apr 2004 23:50:45 -0700

Ian,

> The effect (Called a 'halo font' by the end user - Not sure if that is the
correct
> term or not) results in a ring (typically white) of a pixel or two being
drawn
> all the way around each character, almost as if the character was drawn on
top
> of a larger version of itself.
<SNIP>
> So, I'm wondering if FreeType has any support for this feature, or if
anyone
> has suggestions about how to achieve this?  The best approach I've found
so far
> is to extract the curves of each character, draw them as (white) lines
with a
> thick lineweight, then proceed to draw the (black) character on top as per
usual.

You could also come at this from an image processing perspective.  Once you
have a bitmap of your string, perform a dilation of the image and then merge
that with the bitmap from Freetype.  I did a google search on the following
terms:

image dilation code

Here's a couple of hits that looked interesting:

This one has some source code:
http://www.theimagingsource.com/prod/soft/adoculos/adoculos_textbook_sc_sourcecode.htm

This one shows some images of dilation, erosion, etc:
http://rsb.info.nih.gov/ij/docs/menus/process.html


This is an open source image processing library that looked interesting and
contained various morphological functions such as dilation:
http://www.cs.rug.nl/~cosmin/tip/

    Thanks,
    PeterM

comment:9 by jlacroix, 19 years ago

While trying to test the code above I found two useful thread on the Freetype
mailing list:

[ft] Thick contours
http://lists.gnu.org/archive/html/freetype/2005-03/msg00005.html

[Freetype] using a Stroker to make a glyph border pixmap
http://lists.gnu.org/archive/html/freetype/2004-07/msg00008.html

I will give a try to the stroker stuff.

comment:10 by jlacroix, 19 years ago

Cc: steve.lime@… added
Owner: changed from sdlime to jlacroix@…
Status: assignednew
reassign to me to try the stroker stuff.

comment:11 by jlacroix, 19 years ago

Status: newassigned

comment:12 by sdlime, 19 years ago

Note that MapServer used to use the offset 4 times method described in the 
first thread, but found that insufficient, hence the 8 times now.

Steve

by jlacroix, 19 years ago

Attachment: outlines.png added

comparison between freetype outlines with stroker and current mapserver outline

comment:13 by sdlime, 19 years ago

That's good news. Can you post some examples? Also, some clarification on what 
exactly you are adding? There may be other uses... Are you changing MapServer 
(by just removing stuff) adding to GD, using new Freetype functions or what? I 
had problems getting to the URLs you referenced, on intermittent success.

Steve

comment:14 by jlacroix, 19 years ago

Sorry, there's no other real example other than what I attached to the bug. What
would you want, maybe I can quickly build an example.

Here what I changed:
Mapserver:
Remove the outlining code. Since the outlining is done by GD, we do not need
this code.

Freetype:
I updated my freetype version to use the development version (snapshot available
on their website) instead of the last stable release (freetype 2.1.9). The
stroker code is stable only in the development version. It was fixed in august
2004, and there is no official release with the fixes.

GD:
I modified the gdImageStringFTEx function in GD 2.0.33. This function is used to
draw the text in GD. At some point in this function, the glyph are loaded from
freetype. It's there, before the drawing, that we need to include the stroker
code. This code simply load the outline of the glyph and make it thick. In
short, after the line:

          /* load and transform glyph image */
          FT_Get_Glyph (slot, &image);

You include:

FT_Glyph borderimg;
FT_Stroker stroker;

FT_Glyph_Copy(image, &borderimg);

FT_Stroker_New (face->memory, &stroker);
FT_Stroker_Set (stroker,
                80,
                FT_STROKER_LINECAP_ROUND,
                FT_STROKER_LINEJOIN_ROUND,
                1);
FT_Glyph_Stroke (&borderimg, stroker, 1);

if (borderimg->format != ft_glyph_format_bitmap)
{
    err = FT_Glyph_To_Bitmap (&borderimg, ft_render_mode_normal, 0, 1);
    if (err)
    {
        gdCacheDelete (tc_cache);
        gdMutexUnlock (gdFontCacheMutex);
        return "Problem rendering glyph";
    }
}
bm = (FT_BitmapGlyph) borderimg;
gdft_draw_bitmap (tc_cache, im, 2, bm->bitmap,
                  x + (penf.x * cos_a + penf.y * sin_a)*hdpi/(METRIC_RES*64) +
bm->left,
                  y - (penf.x * sin_a - penf.y * cos_a)*vdpi/(METRIC_RES*64) -
bm->top);
FT_Done_Glyph (borderimg);


This code load the stroker (thick outline of the glyph) and draw it with the
color we want. In this example, it is hardcoded to second color in color index
(the third argument in gdft_draw_bitmap).

At the end, we draw the label 2 times.

comment:15 by sdlime, 19 years ago

It's not as good an outline as MapServer currently, but it ain't bad at all. I 
would support the changes once GD and Freetype have releases with this, but 
until then we can't yank outlining (nobody is complaining now). This can't 
happen by the 4.6 release, unless there's some conditional compilation added.

Have you contacted John Ellson who handles the Freetype support for GD?

Great fix though. I wonder what other effects this brings into play?

Steve

comment:16 by dmorissette, 19 years ago

Cc: warmerdam@… added
Milestone: 4.6 releaseFUTURE
I agree that we should wait until Freetype and GD have been released with the
required functions.

I tried to find infos about the planned date for the release of Freetype 2.1.10
and found the following post saying that it was planned for end of December
2004: http://lists.kde.org/?l=freetype-devel&m=110349526107608&w=2
But then they had some server problems in January which may have caused some
delays... the new lists are at http://savannah.nongnu.org/mail/?group=freetype
but I am unable to connect to the list server to subscribe and ask for an ETA,
so I give up.. they will release at some point I'm sure.

We'll also need to submit a patch to GD. I looked at this with Julien and it
should be possible to send a patch that integrates in the exsiting
gdImageStringFTEx() by passing the outline args via the gdFTStringExtra struct.
Julien will attach a patch to this bug and then we'll try to submit it to GD.

Frank, Steve, did you guys not have a support agreement with Boutell.com? Would
it be easier to submit the patch through you?

comment:17 by fwarmerdam, 19 years ago

The support agreement has expired now.  It was just a one year thing. 


by jlacroix, 19 years ago

Attachment: mapgd.patch added

patch to use freetype oulines

by jlacroix, 19 years ago

Attachment: gd.h.patch added

patch gd.h to use freetype outline

by jlacroix, 19 years ago

Attachment: gdft.c.patch added

patch gdft.c to use freetype outline

comment:18 by jlacroix, 19 years ago

Status: assignednew
I atached the patch to use this technology. Feel free to test/use it. It require
at least 
gd-2.0.33
freetype from september 2004
mapserver 4.5

The patch was built for GD on gd 2.0.33
and for mapserver with the 4.5 version as of 2005-05-06

comment:19 by aboudreault, 15 years ago

Pierre, a libgd maintainer, has confirmed that a similar patch will be in GD 2.1.0. He has already investigated in that patch.

comment:20 by aboudreault, 15 years ago

Cc: aboudreault added

comment:21 by tbonfort, 15 years ago

Cc: tbonfort added
Description: modified (diff)

For "historical" reasons, the AGG code uses the same behavior for 1-pixel outlines. This should probably be changed too for consistency and performance.

Note: See TracTickets for help on using tickets.