mono / libgdiplus

C-based implementation of the GDI+ API
http://www.mono-project.com/
MIT License
333 stars 171 forks source link

Bug with MeasureCharacterRanges on Linux, if text contains LF/CR #663

Open IshmaZX82 opened 4 years ago

IshmaZX82 commented 4 years ago

I'm using the System.Drawing.Common NuGet package. Main problem: there is a difference in how method MeasureCharacterRanges work on Windows and on Linux. On Windows this code works correctly: each char -> rectangle, CR/LF -> empty rectangle. On Linux: CR symbols disappear, the first symbols of each line after LF also disappear.

Code:

                    var g = Graphics.FromImage(new Bitmap(1, 1));
                    var font = new Font("Arial", 11f);
                    var rect = new RectangleF(0, 0, 99999, 99999);
                    var sf = new StringFormat();
                    string text = "12\r\n34\r\n56";
                    var count = text.Length;

                    CharacterRange[] cr = new CharacterRange[count];
                    for (int index = 0; index < count; index++)
                    {
                        cr[index].First = index;
                        cr[index].Length = 1;
                    }
                    sf.SetMeasurableCharacterRanges(cr);
                    Region[] ranges = g.MeasureCharacterRanges(text, font, rect, sf);

                    RectangleF?[] rects = new RectangleF?[count];
                    for (int index = 0; index < count; index++)
                    {
                        rects[index] = ranges[index].GetBounds(g);
                    }

Results on Windows:

on win

Results on Linux:

on linux

I highlighted the symbols and their rectangles in yellow.

IshmaZX82 commented 4 years ago

I have an idea where the problem might be. I analysed method cairo_MeasureCharacterRanges in libgdiplus/src/text-cairo.c This method call MeasureString and use resulting StringDetails from it. But inside MeasureString the input string is processed (CR ignored, LF to STRING_DETAIL_LF) and resulting StringDetails will be SHORTER than the input string! So now is impossible to match the input char and corresponding rectangle ....

filipnavara commented 4 years ago

The Cairo text code is known to be broken (https://github.com/mono/libgdiplus/pull/137 for some background). Newer versions of libgdiplus try to use Pango for the text layout and rendering instead.

IshmaZX82 commented 4 years ago

How can I use the newer version of libgdiplus ? The only way - to rebuild sources with --with-pango ? Or wait a few months while this will be enabled in the official build ?

filipnavara commented 4 years ago

Depending on your distro and how you acquired the libgdiplus (Mono repositories vs distro repositories) it may already be included.

IshmaZX82 commented 4 years ago

I'm a newbie to Linux and Docker, use Dockerfile:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base RUN apt-get update && \ apt-get install -y libgdiplus libc6-dev

filipnavara commented 4 years ago

I'd recommend to follow the first step from https://www.mono-project.com/download/stable/#download-lin for your particular distribution. Then apt-get install -y libgdiplus or something similar.

safern commented 4 years ago

Thanks for the help here @filipnavara. Might be good to add this URL in the repo readme.

cc: @directhex