Skip to content

Commit

Permalink
Merge pull request #1698 from cwensley/curtis/pixelformat-without-alpha
Browse files Browse the repository at this point in the history
Fix PixelFormat.Format32bppRgb
  • Loading branch information
cwensley authored May 27, 2020
2 parents 626d6f4 + 29d5a89 commit ca76382
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 58 deletions.
10 changes: 10 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,15 @@
"console": "internalConsole",
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": "Eto.Test.WinForms",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-winforms",
"program": "${workspaceFolder}/artifacts/test/Debug/netcoreapp3.1/Eto.Test.WinForms.exe",
"args": [],
"console": "internalConsole",
"internalConsoleOptions": "openOnSessionStart"
}
]
}
14 changes: 14 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "build-winforms",
"command": "dotnet",
"type": "process",
"args": [
"build",
"/v:Minimal",
"/p:Configuration=Debug",
"/p:TargetFramework=netcoreapp3.1",
"${workspaceFolder}/test/Eto.Test.WinForms/Eto.Test.WinForms.csproj"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "restore",
"command": "dotnet",
Expand Down
163 changes: 118 additions & 45 deletions src/Eto.Gtk/Drawing/BitmapHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public class BitmapHandler : ImageHandler<Gdk.Pixbuf, Bitmap>, Bitmap.IHandler,

public bool Alpha { get; set; }

bool _isAlphaDirty;
bool _needsAlphaFixup;

public BitmapHandler()
{
}
Expand Down Expand Up @@ -81,14 +84,15 @@ public void Create(int width, int height, PixelFormat pixelFormat)
case PixelFormat.Format32bppRgb:
Control = new Gdk.Pixbuf(Gdk.Colorspace.Rgb, true, 8, width, height);
Control.Fill(0x000000FF);
_needsAlphaFixup = true;
break;
case PixelFormat.Format24bppRgb:
Control = new Gdk.Pixbuf(Gdk.Colorspace.Rgb, false, 8, width, height);
Control.Fill(0);
break;
/*case PixelFormat.Format16bppRgb555:
control = new Gdk.Pixbuf(Gdk.Colorspace.Rgb, false, 5, width, height);
break;*/
/*case PixelFormat.Format16bppRgb555:
control = new Gdk.Pixbuf(Gdk.Colorspace.Rgb, false, 5, width, height);
break;*/
default:
throw new NotSupportedException();
}
Expand Down Expand Up @@ -119,6 +123,7 @@ BitmapData InnerLock()
public void Unlock(BitmapData bitmapData)
{
sizes.Clear();
SetAlphaDirty();
}

public void Save(string fileName, ImageFormat format)
Expand Down Expand Up @@ -162,8 +167,11 @@ public override void SetImage(Gtk.Image imageView, Gtk.IconSize? iconSize)
imageView.Pixbuf = Control;
}

public void SetAlphaDirty() => _isAlphaDirty = _needsAlphaFixup;

public override void DrawImage(GraphicsHandler graphics, RectangleF source, RectangleF destination)
{
FixupAlpha();
var context = graphics.Control;
context.Save();
context.Rectangle(destination.ToCairo());
Expand Down Expand Up @@ -233,13 +241,15 @@ public Gdk.Pixbuf Pixbuf
get
{
EnsureData();
FixupAlpha();
return Control;
}
}

public Gdk.Pixbuf GetPixbuf(Size maxSize, Gdk.InterpType interpolation = Gdk.InterpType.Bilinear, bool shrink = false)
{
EnsureData();
FixupAlpha();
Gdk.Pixbuf pixbuf = Control;
if (pixbuf.Width > maxSize.Width && pixbuf.Height > maxSize.Height
|| (shrink && (maxSize.Width < pixbuf.Width || maxSize.Height < pixbuf.Height)))
Expand All @@ -257,6 +267,7 @@ public Gdk.Pixbuf GetPixbuf(Size maxSize, Gdk.InterpType interpolation = Gdk.Int
public Bitmap Clone(Rectangle? rectangle = null)
{
EnsureData();
FixupAlpha();
if (rectangle == null)
return new Bitmap(new BitmapHandler(Control.Copy()));
else
Expand Down Expand Up @@ -296,68 +307,130 @@ public Color GetPixel(int x, int y)
}
}
}

void EnsureData()
public unsafe void FixupAlpha()
{
if (Surface == null)
return;
using (var bd = InnerLock())
unsafe
if (_isAlphaDirty)
{
if (Surface != null)
{
var size = Size;
var srcrow = (byte*)Surface.DataPtr;
if (bd.BytesPerPixel == 4)
var ptr = (byte*)Surface.DataPtr;
ptr += 3; // alpha is the last byte of four
for (int y = 0; y < size.Height; y++)
{
var destrow = (byte*)bd.Data;
for (int y = 0; y < size.Height; y++)
var rowptr = (byte*)ptr;
for (int x = 0; x < size.Width; x++)
{
var src = (int*)srcrow;
var dest = (int*)destrow;
for (int x = 0; x < size.Width; x++)
{
*dest = bd.TranslateArgbToData(*src);
src++;
dest++;
}
srcrow += Surface.Stride;
destrow += bd.ScanWidth;
*rowptr = 255;
rowptr += 4;
}
ptr += Surface.Stride;
}
else if (bd.BytesPerPixel == 3)
}
else
{
using (var bd = Lock())
{
var destrow = (byte*)bd.Data;
var size = Size;
var ptr = (byte*)bd.Data;
ptr += 3; // alpha is the last byte of four
for (int y = 0; y < size.Height; y++)
{
var src = (int*)srcrow;
var dest = (byte*)destrow;
var rowptr = (byte*)ptr;
for (int x = 0; x < size.Width; x++)
{
var data = bd.TranslateArgbToData(*src);
*(dest++) = (byte)data;
data >>= 8;
*(dest++) = (byte)data;
data >>= 8;
*(dest++) = (byte)data;
src++;
*rowptr = 255;
rowptr += 4;
}
srcrow += Surface.Stride;
destrow += bd.ScanWidth;
ptr += bd.ScanWidth;
}
}
}
_isAlphaDirty = false;
}
}

unsafe void EnsureData()
{
if (Surface == null)
return;
using (var bd = InnerLock())
{
var size = Size;
var srcrow = (byte*)Surface.DataPtr;
if (bd.BytesPerPixel == 4 && _isAlphaDirty)
{
var destrow = (byte*)bd.Data;
for (int y = 0; y < size.Height; y++)
{
var src = (int*)srcrow;
var dest = (int*)destrow;
for (int x = 0; x < size.Width; x++)
{
var argb = bd.TranslateArgbToData(*src);
argb = unchecked(argb | (int)0xFF000000);
*dest = argb;
src++;
dest++;
}
srcrow += Surface.Stride;
destrow += bd.ScanWidth;
}
else
_isAlphaDirty = false;
}
if (bd.BytesPerPixel == 4)
{
var destrow = (byte*)bd.Data;
for (int y = 0; y < size.Height; y++)
{
for (int y = 0; y < size.Height; y++)
var src = (int*)srcrow;
var dest = (int*)destrow;
for (int x = 0; x < size.Width; x++)
{
var src = (int*)srcrow;
for (int x = 0; x < size.Width; x++)
{
bd.SetPixel(x, y, Color.FromArgb(*src));
src++;
}
srcrow += Surface.Stride;
*dest = bd.TranslateArgbToData(*src);
src++;
dest++;
}
srcrow += Surface.Stride;
destrow += bd.ScanWidth;
}
}
else if (bd.BytesPerPixel == 3)
{
var destrow = (byte*)bd.Data;
for (int y = 0; y < size.Height; y++)
{
var src = (int*)srcrow;
var dest = (byte*)destrow;
for (int x = 0; x < size.Width; x++)
{
var data = bd.TranslateArgbToData(*src);
*(dest++) = (byte)data;
data >>= 8;
*(dest++) = (byte)data;
data >>= 8;
*(dest++) = (byte)data;
src++;
}
srcrow += Surface.Stride;
destrow += bd.ScanWidth;
}
}
else
{
for (int y = 0; y < size.Height; y++)
{
var src = (int*)srcrow;
for (int x = 0; x < size.Width; x++)
{
bd.SetPixel(x, y, Color.FromArgb(*src));
src++;
}
srcrow += Surface.Stride;
}
}
}
((IDisposable)Surface).Dispose();
Surface = null;
}
Expand Down
5 changes: 5 additions & 0 deletions src/Eto.Gtk/Drawing/GraphicsHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public void CreateFromImage(Bitmap image)
surface = handler.Surface;
if (surface == null)
{
handler.FixupAlpha();
var format = handler.Alpha ? Cairo.Format.Argb32 : Cairo.Format.Rgb24;
surface = new Cairo.ImageSurface(format, image.Size.Width, image.Size.Height);
Control = new Cairo.Context(surface);
Expand Down Expand Up @@ -553,12 +554,16 @@ void ApplyAll()
#if !GTK2
public static bool GetClipRectangle(Cairo.Context cr, ref Gdk.Rectangle rect)
{
#if GTKCORE
return Gdk.CairoHelper.GetClipRectangle(cr, out rect);
#else
IntPtr intPtr = Marshaller.StructureToPtrAlloc(rect);
bool flag = NativeMethods.gdk_cairo_get_clip_rectangle((cr != null) ? cr.Handle : IntPtr.Zero, intPtr);
bool result = flag;
rect = (Gdk.Rectangle)Marshal.PtrToStructure(intPtr, typeof(Gdk.Rectangle));
Marshal.FreeHGlobal(intPtr);
return result;
#endif
}
#endif

Expand Down
9 changes: 8 additions & 1 deletion src/Eto.Gtk/Forms/Controls/NumericStepperHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,17 @@ public class NumericStepperHandler : GtkControl<Gtk.SpinButton, NumericStepper,
public NumericStepperHandler()
{
Control = new Gtk.SpinButton(double.MinValue, double.MaxValue, 1);
Control.WidthChars = 0;
Control.WidthChars = 5; // default to show 5 characters
Value = 0;
}

protected override void SetSize(Size size)
{
// if a width is set, we allow it to shrink as small as possible..
Control.WidthChars = size.Width > 0 ? 0 : 5;
base.SetSize(size);
}

static readonly object SuppressValueChanged_Key = new object();

int SuppressValueChanged
Expand Down
1 change: 1 addition & 0 deletions src/Eto.Gtk/Forms/GtkPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public virtual Size MinimumSize
{
Widget.Properties.Set(GtkPanel.MinimumSize_Key, value);
ContainerControl.QueueResize();
SetSize(UserPreferredSize);
}
}

Expand Down
20 changes: 18 additions & 2 deletions src/Eto.Wpf/Drawing/GraphicsHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ public void Flush()
}
}

bool Close()
unsafe bool Close()
{
CloseGroup();
if (image != null)
Expand All @@ -360,7 +360,23 @@ bool Close()
var bmp = image.ToWpf();
var newbmp = new swmi.RenderTargetBitmap(bmp.PixelWidth, bmp.PixelHeight, bmp.DpiX, bmp.DpiY, swm.PixelFormats.Pbgra32);
newbmp.RenderWithCollect(visual);
handler.SetBitmap(newbmp);
if (!bmp.Format.HasAlpha())
{
// convert to non-alpha, as RenderTargetBitmap does not support anything other than Pbgra32
var wb = new swmi.WriteableBitmap(bmp.PixelWidth, bmp.PixelWidth, bmp.DpiX, bmp.DpiY, swm.PixelFormats.Bgr32, null);
var rect = new sw.Int32Rect(0, 0, bmp.PixelWidth, bmp.PixelHeight);
var pixels = new byte[bmp.PixelHeight * wb.BackBufferStride];
newbmp.CopyPixels(rect, pixels, wb.BackBufferStride, 0);
fixed (byte* ptr = pixels)
{
wb.WritePixels(rect, (IntPtr)ptr, pixels.Length, wb.BackBufferStride, 0, 0);
}
handler.SetBitmap(wb);
}
else
{
handler.SetBitmap(newbmp);
}
return true;
}
return false;
Expand Down
9 changes: 9 additions & 0 deletions src/Eto.Wpf/WpfConversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -915,5 +915,14 @@ public static string GetName(this swm.LanguageSpecificStringDictionary nameDicti
}

public static swi.Cursor ToWpf(this Cursor cursor) => cursor?.ControlObject as swi.Cursor;

public static bool HasAlpha(this swm.PixelFormat format)
{
return format == swm.PixelFormats.Pbgra32
|| format == swm.PixelFormats.Prgba128Float
|| format == swm.PixelFormats.Prgba64
|| format == swm.PixelFormats.Rgba64
|| format == swm.PixelFormats.Rgba64;
}
}
}
Loading

0 comments on commit ca76382

Please sign in to comment.