Fixed image lists on Windows being NON-premultiplied.

This commit is contained in:
Pietro Gagliardi 2014-08-30 01:15:28 -04:00
parent 432a210726
commit 4f16b94388
6 changed files with 21 additions and 11 deletions

View File

@ -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]

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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;
}