github.com/as/shiny@v0.8.2/driver/windriver/windraw.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build windows 6 7 package windriver 8 9 import ( 10 "fmt" 11 "image" 12 "image/color" 13 "image/draw" 14 "syscall" 15 "unsafe" 16 17 "github.com/as/shiny/driver/win32" 18 ) 19 20 func mkbitmap(size image.Point) (syscall.Handle, *byte, error) { 21 bi := win32.BitmapInfo{ 22 Header: win32.BitmapInfoV4{ 23 Size: uint32(unsafe.Sizeof(win32.BitmapInfoV4{})), 24 Width: int32(size.X), 25 Height: -int32(size.Y), // negative height to force top-down drawing 26 Planes: 1, 27 BitCount: 32, 28 Compression: win32.BiRGB, 29 SizeImage: uint32(size.X * size.Y * 4), 30 }, 31 } 32 33 var ppvBits *byte 34 bitmap, err := win32.CreateDIBSection(0, &bi, win32.DibRGBColors, &ppvBits, 0, 0) 35 if err != nil { 36 return 0, nil, err 37 } 38 return bitmap, ppvBits, nil 39 } 40 41 var blendOverFunc = win32.BlendFunc{ 42 Op: win32.AcSrcOver, 43 Flags: 0, 44 SrcConstAlpha: 255, // only use per-pixel alphas 45 AlphaFormat: win32.AcSrcAlpha, // premultiplied 46 } 47 48 func copyBitmapToDC(dc syscall.Handle, dr image.Rectangle, src syscall.Handle, sr image.Rectangle, op draw.Op) (retErr error) { 49 memdc, err := win32.CreateCompatibleDC(dc) 50 if err != nil { 51 return err 52 } 53 defer win32.DeleteDC(memdc) 54 55 _, err = win32.SelectObject(memdc, src) 56 if err != nil { 57 return err 58 } 59 60 switch op { 61 case draw.Src: 62 return win32.StretchBlt(dc, int32(dr.Min.X), int32(dr.Min.Y), int32(dr.Dx()), int32(dr.Dy()), 63 memdc, int32(sr.Min.X), int32(sr.Min.Y), int32(sr.Dx()), int32(sr.Dy()), win32.SrcCopy) 64 case draw.Over: 65 return win32.AlphaBlend(dc, int32(dr.Min.X), int32(dr.Min.Y), int32(dr.Dx()), int32(dr.Dy()), 66 memdc, int32(sr.Min.X), int32(sr.Min.Y), int32(sr.Dx()), int32(sr.Dy()), blendOverFunc.Uintptr()) 67 default: 68 return fmt.Errorf("windriver: invalid draw operation %v", op) 69 } 70 } 71 72 func fill(dc syscall.Handle, dr image.Rectangle, c color.Color, op draw.Op) error { 73 const bgrmask = ((1 << 24) - 1) 74 cr := win32.NewColorRef(c) 75 76 if op == draw.Src { 77 brush, err := win32.CreateSolidBrush(cr & bgrmask) 78 if err != nil { 79 return err 80 } 81 defer win32.DeleteObject(brush) 82 83 return win32.FillRect(dc, &win32.Rectangle{ 84 win32.Point{int32(dr.Min.X), int32(dr.Min.Y)}, 85 win32.Point{int32(dr.Max.X), int32(dr.Max.Y)}, 86 }, brush) 87 } 88 89 // AlphaBlend will stretch the input image (using StretchBlt's 90 // COLORONCOLOR mode) to fill the output rectangle. Testing 91 // this shows that the result appears to be the same as if we had 92 // used a MxN bitmap instead. 93 sr := image.Rectangle{image.ZP, image.Point{1, 1}} 94 bitmap, bitvalues, err := mkbitmap(sr.Max) 95 if err != nil { 96 return err 97 } 98 defer win32.DeleteObject(bitmap) 99 100 *(*win32.ColorRef)(unsafe.Pointer(bitvalues)) = cr 101 102 return copyBitmapToDC(dc, dr, bitmap, sr, draw.Over) 103 }