mono / libgdiplus

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

Image drawing problem #640

Closed PreferLinux closed 4 years ago

PreferLinux commented 4 years ago

There's a problem that I've seen with drawing images in WinForms when a double-buffered control with the image is the same size as or smaller than the image itself. It does not happen with indexed or 24-bit + alpha PNGs, but does with 24-bit PNGs and JPEGs. Also doesn't happen with a PictureBox with a border. Resizing the form to (partially) cover the image that isn't drawing and then resizing it back out again will result in the covered part appearing, as does moving a control over it and back.

Changing gdip_bitmap_ensure_surface to always use CAIRO_FORMAT_ARGB32 as a debugging measure got them drawing correctly – which is weird. But interestingly, that is the format that both the PNG and JPEG codecs claim to be (and store in GpImage->cairo_format, so I'm not sure why this code chooses the Cairo format itself).

Below is a repro. I've got four test-cases there; the first row shows the custom control which is simply to have a minimum of WinForms influence, the second uses PictureBox to have BorderStyle available. The left images don't draw, the right ones do. testpic10.png testpic11.png

using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
class testform : Form {
    static void Main() {
        Application.Run(new testform());
    }

    testform() {
        var pic = new opb();
        pic.Image = Image.FromFile("testpic10.png"); // 64x64 24 bit
        pic.Size = new Size(40, 40);
        Controls.Add(pic);

        var pic2 = new opb();
        pic2.Image = Image.FromFile("testpic11.png"); // 64x64 24 bit + alpha
        pic2.SetBounds(70, 0, 40, 40);
        Controls.Add(pic2);

        var pic3 = new PictureBox();
        //pic3.BorderStyle = BorderStyle.FixedSingle;
        pic3.Image = Image.FromFile("testpic10.png"); // 64x64 24 bit
        pic3.SetBounds(0, 70, 40, 40);
        Controls.Add(pic3);

        var pic4 = new PictureBox();
        //pic4.BorderStyle = BorderStyle.FixedSingle;
        pic4.Image = Image.FromFile("testpic11.png"); // 64x64 24 bit + alpha
        pic4.SetBounds(70, 70, 40, 40);
        Controls.Add(pic4);
    }

    private class opb : Control {

        public opb() {
            SetStyle (ControlStyles.OptimizedDoubleBuffer, true);
        }

        public Image Image { get; set; }

        protected override void OnPaint(PaintEventArgs e) {
            var x = ClientRectangle.Left;
            var y = ClientRectangle.Top;
            var w = ClientSize.Width;
            var h = ClientSize.Height;
            e.Graphics.DrawLine(Pens.Black, x, y, x + w, y + h);
            //e.Graphics.DrawImage(Image, x, y, new RectangleF(0, 0, w - 1, h - 1), GraphicsUnit.Pixel); // Works OK
            e.Graphics.DrawImage(Image, 0, 0); // Doesn't work
            e.Graphics.DrawLine(Pens.Green, x + w, y, x, y + h);
        }
    }
}

Here's what I get: image (Linux (openSUSE Tumbleweed), libgdiplus is master from mid-January, Cairo 1.16.0, Pixman 0.36.0, xlib 1.6.9, Xorg server 1.20.7)

Also seen the same thing on a CentOS 8 install, libgdiplus 6.0.4, Cairo 1.15.12, Pixman 0.36.0, xlib 1.6.7, Xorg server 1.20.3

Alternatively, I tried this on my macOS + XQuartz setup, and this drew correctly (libgdiplus is master from a few days ago, Cairo 1.15.2, the rest whatever comes with XQuartz).

Just a suspicion, but the real problem here may actually be in Cairo, Pixman, or Xorg.

PreferLinux commented 4 years ago

Just tried this in a couple of Debian VMs, both have the problem. Here's version numbers: Debian 10, libgdiplus 6.0.4, Cairo 1.16.0, Pixman 0.36.0, xlib 1.6.7, Xorg 1.20.4 Debian 9, libgdiplus 6.0.4, Cairo 1.14.8, Pixman 0.34.0, xlib 1.6.4, Xorg 1.19.2

I also tried it on my Chromebook (Linux mode), and it worked correctly (Debian 9 derivative in a VM with the same versions as above, however uses XWayland + a Wayland proxy...).

So inspired by that, I tried my main system (details earlier) with Wayland, so that Mono used XWayland, and it worked correctly too.

filipnavara commented 4 years ago

Another data point: Ubuntu 18.04, libgdiplus master, Cairo 1.15.10-2ubuntu0.1, Pixman 0.34.0-2, xlib 2:1.6.4-3ubuntu0.2, VcXsrv 1.20.6 Ubuntu 18.04, libgdiplus 6.0.4, Cairo 1.15.10-2ubuntu0.1, Pixman 0.34.0-2, xlib 2:1.6.4-3ubuntu0.2, VcXsrv 1.20.6

image