From 4f16b9438877d353e52870cb3631509bd0677da9 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 30 Aug 2014 01:15:28 -0400 Subject: [PATCH] Fixed image lists on Windows being NON-premultiplied. --- redo/area.go | 17 ++++++++++++----- redo/area_unix.go | 2 +- redo/area_windows.c | 2 +- redo/area_windows.go | 5 +++-- redo/imagelist_unix.go | 2 +- redo/imagelist_windows.c | 4 +++- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/redo/area.go b/redo/area.go index 9849ef5..3719b30 100644 --- a/redo/area.go +++ b/redo/area.go @@ -5,6 +5,7 @@ package ui import ( "fmt" "image" + "image/draw" "reflect" "unsafe" ) @@ -331,7 +332,7 @@ func pixelData(img *image.RGBA) *uint8 { // some platforms require pixels in ARGB order in their native endianness (because they treat the pixel array as an array of uint32s) // this does the conversion // you need to convert somewhere (Windows and cairo give us memory to use; Windows has stride==width but cairo might not) -func toARGB(i *image.RGBA, memory uintptr, memstride int) { +func toARGB(i *image.RGBA, memory uintptr, memstride int, toNRGBA bool) { var realbits []byte rbs := (*reflect.SliceHeader)(unsafe.Pointer(&realbits)) @@ -340,14 +341,20 @@ func toARGB(i *image.RGBA, memory uintptr, memstride int) { rbs.Cap = rbs.Len p := pixelDataPos(i) q := 0 + iPix := i.Pix + if toNRGBA { // for Windows image lists + j := image.NewNRGBA(i.Rect) + draw.Draw(j, j.Rect, i, i.Rect.Min, draw.Src) + iPix = j.Pix + } for y := i.Rect.Min.Y; y < i.Rect.Max.Y; y++ { nextp := p + i.Stride nextq := q + memstride for x := i.Rect.Min.X; x < i.Rect.Max.X; x++ { - argb := uint32(i.Pix[p+3]) << 24 // A - argb |= uint32(i.Pix[p+0]) << 16 // R - argb |= uint32(i.Pix[p+1]) << 8 // G - argb |= uint32(i.Pix[p+2]) // B + argb := uint32(iPix[p+3]) << 24 // A + argb |= uint32(iPix[p+0]) << 16 // R + argb |= uint32(iPix[p+1]) << 8 // G + argb |= uint32(iPix[p+2]) // B // the magic of conversion native := (*[4]byte)(unsafe.Pointer(&argb)) realbits[q+0] = native[0] diff --git a/redo/area_unix.go b/redo/area_unix.go index 1cbc4e9..3c88f52 100644 --- a/redo/area_unix.go +++ b/redo/area_unix.go @@ -223,7 +223,7 @@ func our_area_draw_callback(widget *C.GtkWidget, cr *C.cairo_t, data C.gpointer) // the flush and mark_dirty calls are required; see the cairo docs and https://git.gnome.org/browse/gtk+/tree/gdk/gdkcairo.c#n232 (thanks desrt in irc.gimp.net/#gtk+) C.cairo_surface_flush(surface) toARGB(i, uintptr(unsafe.Pointer(C.cairo_image_surface_get_data(surface))), - int(C.cairo_image_surface_get_stride(surface))) + int(C.cairo_image_surface_get_stride(surface)), false) // not NRGBA C.cairo_surface_mark_dirty(surface) C.cairo_set_source_surface(cr, surface, diff --git a/redo/area_windows.c b/redo/area_windows.c index e37538b..b8f1235 100644 --- a/redo/area_windows.c +++ b/redo/area_windows.c @@ -101,7 +101,7 @@ static void paintArea(HWND hwnd, void *data) // first, we need to load the bitmap memory, because Windows makes it for us // the pixels are arranged in RGBA order, but GDI requires BGRA // this turns out to be just ARGB in little endian; let's convert into this memory - dotoARGB(i, (void *) ppvBits); + dotoARGB(i, (void *) ppvBits, FALSE); // FALSE = not NRGBA // the second thing is... make a device context for the bitmap :| // Ninjifox just makes another compatible DC; we'll do the same diff --git a/redo/area_windows.go b/redo/area_windows.go index d2e13e4..e5e8ac0 100644 --- a/redo/area_windows.go +++ b/redo/area_windows.go @@ -118,10 +118,11 @@ func doPaint(xrect *C.RECT, hscroll C.int, vscroll C.int, data unsafe.Pointer, d } //export dotoARGB -func dotoARGB(img unsafe.Pointer, ppvBits unsafe.Pointer) { +func dotoARGB(img unsafe.Pointer, ppvBits unsafe.Pointer, toNRGBA C.BOOL) { i := (*image.RGBA)(unsafe.Pointer(img)) + t := toNRGBA != C.FALSE // the bitmap Windows gives us has a stride == width - toARGB(i, uintptr(ppvBits), i.Rect.Dx() * 4) + toARGB(i, uintptr(ppvBits), i.Rect.Dx() * 4, t) } //export areaWidthLONG diff --git a/redo/imagelist_unix.go b/redo/imagelist_unix.go index aeb7a13..246f281 100644 --- a/redo/imagelist_unix.go +++ b/redo/imagelist_unix.go @@ -37,7 +37,7 @@ func (i *imagelist) Append(img *image.RGBA) { } C.cairo_surface_flush(surface) toARGB(img, uintptr(unsafe.Pointer(C.cairo_image_surface_get_data(surface))), - int(C.cairo_image_surface_get_stride(surface))) + int(C.cairo_image_surface_get_stride(surface)), false) // not NRGBA C.cairo_surface_mark_dirty(surface) basepixbuf := C.gdk_pixbuf_get_from_surface(surface, 0, 0, C.gint(img.Rect.Dx()), C.gint(img.Rect.Dy())) if basepixbuf == nil { diff --git a/redo/imagelist_windows.c b/redo/imagelist_windows.c index 4402268..f7bddb4 100644 --- a/redo/imagelist_windows.c +++ b/redo/imagelist_windows.c @@ -22,7 +22,9 @@ HBITMAP unscaledBitmap(void *i, intptr_t dx, intptr_t dy) bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0); if (bitmap == NULL) xpanic("error creating HBITMAP for unscaled ImageList image copy", GetLastError()); - dotoARGB(i, (void *) ppvBits); + // image lists use non-premultiplied RGBA - see http://stackoverflow.com/a/25578789/3408572 + // the TRUE here does the conversion + dotoARGB(i, (void *) ppvBits, TRUE); return bitmap; }