diff --git a/.travis.yml b/.travis.yml index f190013..27edb20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,31 @@ language: go -os: -- linux -- osx -go: -- 1.10.x -- 1.11.x -- master matrix: + include: + - os: linux + dist: xenial + go: 1.10.x + - os: linux + dist: xenial + go: 1.11.x + - os: linux + dist: xenial + go: master + - os: osx + go: 1.10.x + - os: osx + go: 1.11.x + - os: osx + go: master allow_failures: - go: master fast_finish: true go_import_path: github.com/liamg/aminal before_install: - if [[ $TRAVIS_OS_NAME == 'linux' ]]; then sudo apt-get install -y xorg-dev libgl1-mesa-dev - gcc-multilib gcc-mingw-w64-x86-64 && go get github.com/mitchellh/gox; fi + gcc-multilib gcc-mingw-w64-x86-64 xvfb vttest && go get github.com/mitchellh/gox; fi script: -- make test +- go get +- if [[ $TRAVIS_OS_NAME == 'linux' ]]; then xvfb-run --server-args="-screen 0 1024x768x24" make test; else make test; fi - if [[ $TRAVIS_OS_NAME == 'osx' ]]; then make build-darwin-native-travis; fi - if [[ $TRAVIS_OS_NAME == 'linux' ]]; then make build-linux-travis; fi - if [[ $TRAVIS_OS_NAME == 'linux' ]]; then make windows-cross-compile-travis; fi diff --git a/buffer/buffer.go b/buffer/buffer.go index 81dcb58..d4deadd 100644 --- a/buffer/buffer.go +++ b/buffer/buffer.go @@ -1,8 +1,11 @@ package buffer import ( + "bytes" "fmt" + "io/ioutil" "net/url" + "os" "time" ) @@ -1050,3 +1053,30 @@ func (buffer *Buffer) getMaxLines() uint64 { return result } + +func (buffer *Buffer) Save(path string) { + f, err := os.Create(path) + if err != nil { + panic(err) + } + defer f.Close() + + for _, line := range buffer.lines { + f.WriteString(line.String()) + } +} + +func (buffer *Buffer) Compare(path string) bool { + f, err := ioutil.ReadFile(path) + if err != nil { + panic(err) + } + + bufferContent := []byte{} + for _, line := range buffer.lines { + lineBytes := []byte(line.String()) + bufferContent = append(bufferContent, lineBytes...) + } + return bytes.Equal(f, bufferContent) +} + diff --git a/gui/gui.go b/gui/gui.go index 2a4fb4d..e6fca8a 100644 --- a/gui/gui.go +++ b/gui/gui.go @@ -2,6 +2,9 @@ package gui import ( "fmt" + "image" + "image/png" + "os" "os/exec" "runtime" "strconv" @@ -17,6 +20,7 @@ import ( "github.com/liamg/aminal/version" "go.uber.org/zap" "unsafe" + "github.com/kbinani/screenshot" ) type GUI struct { @@ -587,3 +591,17 @@ func (gui *GUI) SwapBuffers() { UpdateNSGLContext(gui.window) gui.window.SwapBuffers() } + +func (gui *GUI) Screenshot(path string) { + x, y := gui.window.GetPos() + w, h := gui.window.GetSize() + + img, err := screenshot.CaptureRect(image.Rectangle{ Min: image.Point{ X: x, Y: y }, + Max: image.Point{ X: x + w, Y: y + h}}) + if err != nil { + panic(err) + } + file, _ := os.Create(path) + defer file.Close() + png.Encode(file, img) +} diff --git a/gui/vendor/github.com/kbinani/screenshot/LICENSE b/gui/vendor/github.com/kbinani/screenshot/LICENSE new file mode 100644 index 0000000..4babaeb --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 kbinani + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/gui/vendor/github.com/kbinani/screenshot/README.md b/gui/vendor/github.com/kbinani/screenshot/README.md new file mode 100644 index 0000000..e02654a --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/README.md @@ -0,0 +1,75 @@ +screenshot +========== + +[![Build Status](https://travis-ci.org/kbinani/screenshot.svg?branch=master)](https://travis-ci.org/kbinani/screenshot) +[![](https://img.shields.io/badge/godoc-reference-5272B4.svg)](https://godoc.org/github.com/kbinani/screenshot) +[![](https://img.shields.io/badge/license-MIT-428F7E.svg?style=flat)](https://github.com/kbinani/screenshot/blob/master/LICENSE) +[![Go Report Card](https://goreportcard.com/badge/github.com/kbinani/screenshot)](https://goreportcard.com/report/github.com/kbinani/screenshot) + +* Go library to capture desktop screen. +* Support Windows, Mac, Linux, FreeBSD, OpenBSD, NetBSD, and Solaris environment. +* Multiple display supported. +* `cgo` free for Windows, Linux, FreeBSD, OpenBSD, NetBSD, and Solaris. + +example +======= + +* sample program `main.go` + + ```go + package main + + import ( + "github.com/kbinani/screenshot" + "image/png" + "os" + "fmt" + ) + + func main() { + n := screenshot.NumActiveDisplays() + + for i := 0; i < n; i++ { + bounds := screenshot.GetDisplayBounds(i) + + img, err := screenshot.CaptureRect(bounds) + if err != nil { + panic(err) + } + fileName := fmt.Sprintf("%d_%dx%d.png", i, bounds.Dx(), bounds.Dy()) + file, _ := os.Create(fileName) + defer file.Close() + png.Encode(file, img) + + fmt.Printf("#%d : %v \"%s\"\n", i, bounds, fileName) + } + } + ``` + +* output example + + ```bash + $ go run main.go + #0 : (0,0)-(1280,800) "0_1280x800.png" + #1 : (-293,-1440)-(2267,0) "1_2560x1440.png" + #2 : (-1373,-1812)-(-293,108) "2_1080x1920.png" + $ ls -1 + 0_1280x800.png + 1_2560x1440.png + 2_1080x1920.png + main.go + ``` + +coordinate +================= +Y-axis is downward direction in this library. The origin of coordinate is upper-left corner of main display. This means coordinate system is similar to Windows OS + +license +======= + +MIT Licence + +author +====== + +kbinani diff --git a/gui/vendor/github.com/kbinani/screenshot/example/main.go b/gui/vendor/github.com/kbinani/screenshot/example/main.go new file mode 100644 index 0000000..1cb725e --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/example/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + "github.com/kbinani/screenshot" + "image" + "image/png" + "os" +) + +// save *image.RGBA to filePath with PNG format. +func save(img *image.RGBA, filePath string) { + file, err := os.Create(filePath) + if err != nil { + panic(err) + } + defer file.Close() + png.Encode(file, img) +} + +func main() { + // Capture each displays. + n := screenshot.NumActiveDisplays() + if n <= 0 { + panic("Active display not found") + } + + var all image.Rectangle = image.Rect(0, 0, 0, 0) + + for i := 0; i < n; i++ { + bounds := screenshot.GetDisplayBounds(i) + all = bounds.Union(all) + + img, err := screenshot.CaptureRect(bounds) + if err != nil { + panic(err) + } + fileName := fmt.Sprintf("%d_%dx%d.png", i, bounds.Dx(), bounds.Dy()) + save(img, fileName) + + fmt.Printf("#%d : %v \"%s\"\n", i, bounds, fileName) + } + + // Capture all desktop region into an image. + fmt.Printf("%v\n", all) + img, err := screenshot.Capture(all.Min.X, all.Min.Y, all.Dx(), all.Dy()) + if err != nil { + panic(err) + } + save(img, "all.png") +} diff --git a/gui/vendor/github.com/kbinani/screenshot/internal/util/util.go b/gui/vendor/github.com/kbinani/screenshot/internal/util/util.go new file mode 100644 index 0000000..042be9f --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/internal/util/util.go @@ -0,0 +1,22 @@ +package util + +import ( + "errors" + "image" +) + +func CreateImage(rect image.Rectangle) (img *image.RGBA, e error) { + img = nil + e = errors.New("Cannot create image.RGBA") + + defer func() { + err := recover() + if err == nil { + e = nil + } + }() + // image.NewRGBA may panic if rect is too large. + img = image.NewRGBA(rect) + + return img, e +} diff --git a/gui/vendor/github.com/kbinani/screenshot/internal/xwindow/xwindow.go b/gui/vendor/github.com/kbinani/screenshot/internal/xwindow/xwindow.go new file mode 100644 index 0000000..1ec5551 --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/internal/xwindow/xwindow.go @@ -0,0 +1,193 @@ +package xwindow + +import ( + "errors" + "fmt" + "image" + "image/color" + + "github.com/BurntSushi/xgb" + mshm "github.com/BurntSushi/xgb/shm" + "github.com/BurntSushi/xgb/xinerama" + "github.com/BurntSushi/xgb/xproto" + "github.com/gen2brain/shm" + "github.com/kbinani/screenshot/internal/util" +) + +func Capture(x, y, width, height int) (img *image.RGBA, e error) { + defer func() { + err := recover() + if err != nil { + img = nil + e = errors.New(fmt.Sprintf("%v", err)) + } + }() + c, err := xgb.NewConn() + if err != nil { + return nil, err + } + defer c.Close() + + err = xinerama.Init(c) + reply, err := xinerama.QueryScreens(c).Reply() + if err != nil { + return nil, err + } + + primary := reply.ScreenInfo[0] + x0 := int(primary.XOrg) + y0 := int(primary.YOrg) + + useShm := true + err = mshm.Init(c) + if err != nil { + useShm = false + } + + screen := xproto.Setup(c).DefaultScreen(c) + wholeScreenBounds := image.Rect(0, 0, int(screen.WidthInPixels), int(screen.HeightInPixels)) + targetBounds := image.Rect(x+x0, y+y0, x+x0+width, y+y0+height) + intersect := wholeScreenBounds.Intersect(targetBounds) + + rect := image.Rect(0, 0, width, height) + img, err = util.CreateImage(rect) + if err != nil { + return nil, err + } + + // Paint with opaque black + index := 0 + for iy := 0; iy < height; iy++ { + j := index + for ix := 0; ix < width; ix++ { + img.Pix[j+3] = 255 + j += 4 + } + index += img.Stride + } + + if !intersect.Empty() { + var data []byte + + if useShm { + shmSize := intersect.Dx() * intersect.Dy() * 4 + shmId, err := shm.Get(shm.IPC_PRIVATE, shmSize, shm.IPC_CREAT|0777) + if err != nil { + return nil, err + } + + seg, err := mshm.NewSegId(c) + if err != nil { + return nil, err + } + + data, err = shm.At(shmId, 0, 0) + if err != nil { + return nil, err + } + + mshm.Attach(c, seg, uint32(shmId), false) + + defer mshm.Detach(c, seg) + defer shm.Rm(shmId) + defer shm.Dt(data) + + _, err = mshm.GetImage(c, xproto.Drawable(screen.Root), + int16(intersect.Min.X), int16(intersect.Min.Y), + uint16(intersect.Dx()), uint16(intersect.Dy()), 0xffffffff, + byte(xproto.ImageFormatZPixmap), seg, 0).Reply() + if err != nil { + return nil, err + } + } else { + xImg, err := xproto.GetImage(c, xproto.ImageFormatZPixmap, xproto.Drawable(screen.Root), + int16(intersect.Min.X), int16(intersect.Min.Y), + uint16(intersect.Dx()), uint16(intersect.Dy()), 0xffffffff).Reply() + if err != nil { + return nil, err + } + + data = xImg.Data + } + + // BitBlt by hand + offset := 0 + for iy := intersect.Min.Y; iy < intersect.Max.Y; iy++ { + for ix := intersect.Min.X; ix < intersect.Max.X; ix++ { + r := data[offset+2] + g := data[offset+1] + b := data[offset] + img.SetRGBA(ix-(x+x0), iy-(y+y0), color.RGBA{r, g, b, 255}) + offset += 4 + } + } + } + + return img, e +} + +func NumActiveDisplays() (num int) { + defer func() { + e := recover() + if e != nil { + num = 0 + } + }() + + c, err := xgb.NewConn() + if err != nil { + return 0 + } + defer c.Close() + + err = xinerama.Init(c) + if err != nil { + return 0 + } + + reply, err := xinerama.QueryScreens(c).Reply() + if err != nil { + return 0 + } + + num = int(reply.Number) + return num +} + +func GetDisplayBounds(displayIndex int) (rect image.Rectangle) { + defer func() { + e := recover() + if e != nil { + rect = image.ZR + } + }() + + c, err := xgb.NewConn() + if err != nil { + return image.ZR + } + defer c.Close() + + err = xinerama.Init(c) + + reply, err := xinerama.QueryScreens(c).Reply() + if err != nil { + return image.ZR + } + + if displayIndex >= int(reply.Number) { + return image.ZR + } + + primary := reply.ScreenInfo[0] + x0 := int(primary.XOrg) + y0 := int(primary.YOrg) + + screen := reply.ScreenInfo[displayIndex] + x := int(screen.XOrg) - x0 + y := int(screen.YOrg) - y0 + w := int(screen.Width) + h := int(screen.Height) + rect = image.Rect(x, y, x+w, y+h) + return rect +} diff --git a/gui/vendor/github.com/kbinani/screenshot/screenshot.go b/gui/vendor/github.com/kbinani/screenshot/screenshot.go new file mode 100644 index 0000000..84407f0 --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/screenshot.go @@ -0,0 +1,18 @@ +// Package screenshot captures screen-shot image as image.RGBA. +// Mac, Windows, Linux, FreeBSD, OpenBSD, NetBSD, and Solaris are supported. +package screenshot + +import ( + "image" +) + +// CaptureDisplay captures whole region of displayIndex'th display. +func CaptureDisplay(displayIndex int) (*image.RGBA, error) { + rect := GetDisplayBounds(displayIndex) + return CaptureRect(rect) +} + +// CaptureRect captures specified region of desktop. +func CaptureRect(rect image.Rectangle) (*image.RGBA, error) { + return Capture(rect.Min.X, rect.Min.Y, rect.Dx(), rect.Dy()) +} diff --git a/gui/vendor/github.com/kbinani/screenshot/screenshot_darwin.go b/gui/vendor/github.com/kbinani/screenshot/screenshot_darwin.go new file mode 100644 index 0000000..0918417 --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/screenshot_darwin.go @@ -0,0 +1,215 @@ +// +build go1.10 + +package screenshot + +/* +#cgo LDFLAGS: -framework CoreGraphics -framework CoreFoundation +#include + +void* CompatCGDisplayCreateImageForRect(CGDirectDisplayID display, CGRect rect) { + return CGDisplayCreateImageForRect(display, rect); +} + +void CompatCGImageRelease(void* image) { + CGImageRelease(image); +} + +void* CompatCGImageCreateCopyWithColorSpace(void* image, CGColorSpaceRef space) { + return CGImageCreateCopyWithColorSpace((CGImageRef)image, space); +} + +void CompatCGContextDrawImage(CGContextRef c, CGRect rect, void* image) { + CGContextDrawImage(c, rect, (CGImageRef)image); +} +*/ +import "C" + +import ( + "errors" + "image" + "unsafe" + + "github.com/kbinani/screenshot/internal/util" +) + +func Capture(x, y, width, height int) (*image.RGBA, error) { + if width <= 0 || height <= 0 { + return nil, errors.New("width or height should be > 0") + } + + rect := image.Rect(0, 0, width, height) + img, err := util.CreateImage(rect) + if err != nil { + return nil, err + } + + // cg: CoreGraphics coordinate (origin: lower-left corner of primary display, x-axis: rightward, y-axis: upward) + // win: Windows coordinate (origin: upper-left corner of primary display, x-axis: rightward, y-axis: downward) + // di: Display local coordinate (origin: upper-left corner of the display, x-axis: rightward, y-axis: downward) + + cgMainDisplayBounds := getCoreGraphicsCoordinateOfDisplay(C.CGMainDisplayID()) + + winBottomLeft := C.CGPointMake(C.CGFloat(x), C.CGFloat(y+height)) + cgBottomLeft := getCoreGraphicsCoordinateFromWindowsCoordinate(winBottomLeft, cgMainDisplayBounds) + cgCaptureBounds := C.CGRectMake(cgBottomLeft.x, cgBottomLeft.y, C.CGFloat(width), C.CGFloat(height)) + + ids := activeDisplayList() + + ctx := createBitmapContext(width, height, (*C.uint32_t)(unsafe.Pointer(&img.Pix[0])), img.Stride) + if ctx == 0 { + return nil, errors.New("cannot create bitmap context") + } + + colorSpace := createColorspace() + if colorSpace == 0 { + return nil, errors.New("cannot create colorspace") + } + defer C.CGColorSpaceRelease(colorSpace) + + for _, id := range ids { + cgBounds := getCoreGraphicsCoordinateOfDisplay(id) + cgIntersect := C.CGRectIntersection(cgBounds, cgCaptureBounds) + if C.CGRectIsNull(cgIntersect) { + continue + } + if cgIntersect.size.width <= 0 || cgIntersect.size.height <= 0 { + continue + } + + // CGDisplayCreateImageForRect potentially fail in case width/height is odd number. + if int(cgIntersect.size.width)%2 != 0 { + cgIntersect.size.width = C.CGFloat(int(cgIntersect.size.width) + 1) + } + if int(cgIntersect.size.height)%2 != 0 { + cgIntersect.size.height = C.CGFloat(int(cgIntersect.size.height) + 1) + } + + diIntersectDisplayLocal := C.CGRectMake(cgIntersect.origin.x-cgBounds.origin.x, + cgBounds.origin.y+cgBounds.size.height-(cgIntersect.origin.y+cgIntersect.size.height), + cgIntersect.size.width, cgIntersect.size.height) + captured := C.CompatCGDisplayCreateImageForRect(id, diIntersectDisplayLocal) + if captured == nil { + return nil, errors.New("cannot capture display") + } + defer C.CompatCGImageRelease(captured) + + image := C.CompatCGImageCreateCopyWithColorSpace(captured, colorSpace) + if image == nil { + return nil, errors.New("failed copying captured image") + } + defer C.CompatCGImageRelease(image) + + cgDrawRect := C.CGRectMake(cgIntersect.origin.x-cgCaptureBounds.origin.x, cgIntersect.origin.y-cgCaptureBounds.origin.y, + cgIntersect.size.width, cgIntersect.size.height) + C.CompatCGContextDrawImage(ctx, cgDrawRect, image) + } + + i := 0 + for iy := 0; iy < height; iy++ { + j := i + for ix := 0; ix < width; ix++ { + // ARGB => RGBA, and set A to 255 + img.Pix[j], img.Pix[j+1], img.Pix[j+2], img.Pix[j+3] = img.Pix[j+1], img.Pix[j+2], img.Pix[j+3], 255 + j += 4 + } + i += img.Stride + } + + return img, nil +} + +func NumActiveDisplays() int { + var count C.uint32_t = 0 + if C.CGGetActiveDisplayList(0, nil, &count) == C.kCGErrorSuccess { + return int(count) + } else { + return 0 + } +} + +func GetDisplayBounds(displayIndex int) image.Rectangle { + id := getDisplayId(displayIndex) + main := C.CGMainDisplayID() + + var rect image.Rectangle + + bounds := getCoreGraphicsCoordinateOfDisplay(id) + rect.Min.X = int(bounds.origin.x) + if main == id { + rect.Min.Y = 0 + } else { + mainBounds := getCoreGraphicsCoordinateOfDisplay(main) + mainHeight := mainBounds.size.height + rect.Min.Y = int(mainHeight - (bounds.origin.y + bounds.size.height)) + } + rect.Max.X = rect.Min.X + int(bounds.size.width) + rect.Max.Y = rect.Min.Y + int(bounds.size.height) + + return rect +} + +func getDisplayId(displayIndex int) C.CGDirectDisplayID { + main := C.CGMainDisplayID() + if displayIndex == 0 { + return main + } else { + n := NumActiveDisplays() + ids := make([]C.CGDirectDisplayID, n) + if C.CGGetActiveDisplayList(C.uint32_t(n), (*C.CGDirectDisplayID)(unsafe.Pointer(&ids[0])), nil) != C.kCGErrorSuccess { + return 0 + } + index := 0 + for i := 0; i < n; i++ { + if ids[i] == main { + continue + } + index++ + if index == displayIndex { + return ids[i] + } + } + } + + return 0 +} + +func getCoreGraphicsCoordinateOfDisplay(id C.CGDirectDisplayID) C.CGRect { + main := C.CGDisplayBounds(C.CGMainDisplayID()) + r := C.CGDisplayBounds(id) + return C.CGRectMake(r.origin.x, -r.origin.y-r.size.height+main.size.height, + r.size.width, r.size.height) +} + +func getCoreGraphicsCoordinateFromWindowsCoordinate(p C.CGPoint, mainDisplayBounds C.CGRect) C.CGPoint { + return C.CGPointMake(p.x, mainDisplayBounds.size.height-p.y) +} + +func createBitmapContext(width int, height int, data *C.uint32_t, bytesPerRow int) C.CGContextRef { + colorSpace := createColorspace() + if colorSpace == 0 { + return 0 + } + defer C.CGColorSpaceRelease(colorSpace) + + return C.CGBitmapContextCreate(unsafe.Pointer(data), + C.size_t(width), + C.size_t(height), + 8, // bits per component + C.size_t(bytesPerRow), + colorSpace, + C.kCGImageAlphaNoneSkipFirst) +} + +func createColorspace() C.CGColorSpaceRef { + return C.CGColorSpaceCreateWithName(C.kCGColorSpaceSRGB) +} + +func activeDisplayList() []C.CGDirectDisplayID { + count := C.uint32_t(NumActiveDisplays()) + ret := make([]C.CGDirectDisplayID, count) + if C.CGGetActiveDisplayList(count, (*C.CGDirectDisplayID)(unsafe.Pointer(&ret[0])), nil) == C.kCGErrorSuccess { + return ret + } else { + return make([]C.CGDirectDisplayID, 0) + } +} diff --git a/gui/vendor/github.com/kbinani/screenshot/screenshot_freebsd.go b/gui/vendor/github.com/kbinani/screenshot/screenshot_freebsd.go new file mode 120000 index 0000000..059e88b --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/screenshot_freebsd.go @@ -0,0 +1 @@ +screenshot_linux.go \ No newline at end of file diff --git a/gui/vendor/github.com/kbinani/screenshot/screenshot_go1.9_or_earlier_darwin.go b/gui/vendor/github.com/kbinani/screenshot/screenshot_go1.9_or_earlier_darwin.go new file mode 100644 index 0000000..11d1f16 --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/screenshot_go1.9_or_earlier_darwin.go @@ -0,0 +1,197 @@ +// +build darwin,!go1.10 + +package screenshot + +// #cgo LDFLAGS: -framework CoreGraphics -framework CoreFoundation +// #include +import "C" + +import ( + "errors" + "image" + "unsafe" + + "github.com/kbinani/screenshot/internal/util" +) + +func Capture(x, y, width, height int) (*image.RGBA, error) { + if width <= 0 || height <= 0 { + return nil, errors.New("width or height should be > 0") + } + + rect := image.Rect(0, 0, width, height) + img, err := util.CreateImage(rect) + if err != nil { + return nil, err + } + + // cg: CoreGraphics coordinate (origin: lower-left corner of primary display, x-axis: rightward, y-axis: upward) + // win: Windows coordinate (origin: upper-left corner of primary display, x-axis: rightward, y-axis: downward) + // di: Display local coordinate (origin: upper-left corner of the display, x-axis: rightward, y-axis: downward) + + cgMainDisplayBounds := getCoreGraphicsCoordinateOfDisplay(C.CGMainDisplayID()) + + winBottomLeft := C.CGPointMake(C.CGFloat(x), C.CGFloat(y+height)) + cgBottomLeft := getCoreGraphicsCoordinateFromWindowsCoordinate(winBottomLeft, cgMainDisplayBounds) + cgCaptureBounds := C.CGRectMake(cgBottomLeft.x, cgBottomLeft.y, C.CGFloat(width), C.CGFloat(height)) + + ids := activeDisplayList() + + ctx := createBitmapContext(width, height, (*C.uint32_t)(unsafe.Pointer(&img.Pix[0])), img.Stride) + if ctx == nil { + return nil, errors.New("cannot create bitmap context") + } + + colorSpace := createColorspace() + if colorSpace == nil { + return nil, errors.New("cannot create colorspace") + } + defer C.CGColorSpaceRelease(colorSpace) + + for _, id := range ids { + cgBounds := getCoreGraphicsCoordinateOfDisplay(id) + cgIntersect := C.CGRectIntersection(cgBounds, cgCaptureBounds) + if C.CGRectIsNull(cgIntersect) { + continue + } + if cgIntersect.size.width <= 0 || cgIntersect.size.height <= 0 { + continue + } + + // CGDisplayCreateImageForRect potentially fail in case width/height is odd number. + if int(cgIntersect.size.width)%2 != 0 { + cgIntersect.size.width = C.CGFloat(int(cgIntersect.size.width) + 1) + } + if int(cgIntersect.size.height)%2 != 0 { + cgIntersect.size.height = C.CGFloat(int(cgIntersect.size.height) + 1) + } + + diIntersectDisplayLocal := C.CGRectMake(cgIntersect.origin.x-cgBounds.origin.x, + cgBounds.origin.y+cgBounds.size.height-(cgIntersect.origin.y+cgIntersect.size.height), + cgIntersect.size.width, cgIntersect.size.height) + captured := C.CGDisplayCreateImageForRect(id, diIntersectDisplayLocal) + if captured == nil { + return nil, errors.New("cannot capture display") + } + defer C.CGImageRelease(captured) + + image := C.CGImageCreateCopyWithColorSpace(captured, colorSpace) + if image == nil { + return nil, errors.New("failed copying captured image") + } + defer C.CGImageRelease(image) + + cgDrawRect := C.CGRectMake(cgIntersect.origin.x-cgCaptureBounds.origin.x, cgIntersect.origin.y-cgCaptureBounds.origin.y, + cgIntersect.size.width, cgIntersect.size.height) + C.CGContextDrawImage(ctx, cgDrawRect, image) + } + + i := 0 + for iy := 0; iy < height; iy++ { + j := i + for ix := 0; ix < width; ix++ { + // ARGB => RGBA, and set A to 255 + img.Pix[j], img.Pix[j+1], img.Pix[j+2], img.Pix[j+3] = img.Pix[j+1], img.Pix[j+2], img.Pix[j+3], 255 + j += 4 + } + i += img.Stride + } + + return img, nil +} + +func NumActiveDisplays() int { + var count C.uint32_t = 0 + if C.CGGetActiveDisplayList(0, nil, &count) == C.kCGErrorSuccess { + return int(count) + } else { + return 0 + } +} + +func GetDisplayBounds(displayIndex int) image.Rectangle { + id := getDisplayId(displayIndex) + main := C.CGMainDisplayID() + + var rect image.Rectangle + + bounds := getCoreGraphicsCoordinateOfDisplay(id) + rect.Min.X = int(bounds.origin.x) + if main == id { + rect.Min.Y = 0 + } else { + mainBounds := getCoreGraphicsCoordinateOfDisplay(main) + mainHeight := mainBounds.size.height + rect.Min.Y = int(mainHeight - (bounds.origin.y + bounds.size.height)) + } + rect.Max.X = rect.Min.X + int(bounds.size.width) + rect.Max.Y = rect.Min.Y + int(bounds.size.height) + + return rect +} + +func getDisplayId(displayIndex int) C.CGDirectDisplayID { + main := C.CGMainDisplayID() + if displayIndex == 0 { + return main + } else { + n := NumActiveDisplays() + ids := make([]C.CGDirectDisplayID, n) + if C.CGGetActiveDisplayList(C.uint32_t(n), (*C.CGDirectDisplayID)(unsafe.Pointer(&ids[0])), nil) != C.kCGErrorSuccess { + return 0 + } + index := 0 + for i := 0; i < n; i++ { + if ids[i] == main { + continue + } + index++ + if index == displayIndex { + return ids[i] + } + } + } + + return 0 +} + +func getCoreGraphicsCoordinateOfDisplay(id C.CGDirectDisplayID) C.CGRect { + main := C.CGDisplayBounds(C.CGMainDisplayID()) + r := C.CGDisplayBounds(id) + return C.CGRectMake(r.origin.x, -r.origin.y-r.size.height+main.size.height, + r.size.width, r.size.height) +} + +func getCoreGraphicsCoordinateFromWindowsCoordinate(p C.CGPoint, mainDisplayBounds C.CGRect) C.CGPoint { + return C.CGPointMake(p.x, mainDisplayBounds.size.height-p.y) +} + +func createBitmapContext(width int, height int, data *C.uint32_t, bytesPerRow int) C.CGContextRef { + colorSpace := createColorspace() + if colorSpace == nil { + return nil + } + defer C.CGColorSpaceRelease(colorSpace) + + return C.CGBitmapContextCreate(unsafe.Pointer(data), + C.size_t(width), + C.size_t(height), + 8, // bits per component + C.size_t(bytesPerRow), + colorSpace, + C.kCGImageAlphaNoneSkipFirst) +} + +func createColorspace() C.CGColorSpaceRef { + return C.CGColorSpaceCreateWithName(C.kCGColorSpaceSRGB) +} + +func activeDisplayList() []C.CGDirectDisplayID { + count := C.uint32_t(NumActiveDisplays()) + ret := make([]C.CGDirectDisplayID, count) + if C.CGGetActiveDisplayList(count, (*C.CGDirectDisplayID)(unsafe.Pointer(&ret[0])), nil) == C.kCGErrorSuccess { + return ret + } else { + return make([]C.CGDirectDisplayID, 0) + } +} diff --git a/gui/vendor/github.com/kbinani/screenshot/screenshot_linux.go b/gui/vendor/github.com/kbinani/screenshot/screenshot_linux.go new file mode 100644 index 0000000..a21661d --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/screenshot_linux.go @@ -0,0 +1,24 @@ +package screenshot + +import ( + "github.com/kbinani/screenshot/internal/xwindow" + "image" +) + +// Capture returns screen capture of specified desktop region. +// x and y represent distance from the upper-left corner of main display. +// Y-axis is downward direction. This means coordinates system is similar to Windows OS. +func Capture(x, y, width, height int) (*image.RGBA, error) { + return xwindow.Capture(x, y, width, height) +} + +// NumActiveDisplays returns the number of active displays. +func NumActiveDisplays() int { + return xwindow.NumActiveDisplays() +} + +// GetDisplayBounds returns the bounds of displayIndex'th display. +// The main display is displayIndex = 0. +func GetDisplayBounds(displayIndex int) image.Rectangle { + return xwindow.GetDisplayBounds(displayIndex) +} diff --git a/gui/vendor/github.com/kbinani/screenshot/screenshot_netbsd.go b/gui/vendor/github.com/kbinani/screenshot/screenshot_netbsd.go new file mode 120000 index 0000000..059e88b --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/screenshot_netbsd.go @@ -0,0 +1 @@ +screenshot_linux.go \ No newline at end of file diff --git a/gui/vendor/github.com/kbinani/screenshot/screenshot_openbsd.go b/gui/vendor/github.com/kbinani/screenshot/screenshot_openbsd.go new file mode 120000 index 0000000..059e88b --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/screenshot_openbsd.go @@ -0,0 +1 @@ +screenshot_linux.go \ No newline at end of file diff --git a/gui/vendor/github.com/kbinani/screenshot/screenshot_solaris.go b/gui/vendor/github.com/kbinani/screenshot/screenshot_solaris.go new file mode 120000 index 0000000..059e88b --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/screenshot_solaris.go @@ -0,0 +1 @@ +screenshot_linux.go \ No newline at end of file diff --git a/gui/vendor/github.com/kbinani/screenshot/screenshot_windows.go b/gui/vendor/github.com/kbinani/screenshot/screenshot_windows.go new file mode 100644 index 0000000..135742c --- /dev/null +++ b/gui/vendor/github.com/kbinani/screenshot/screenshot_windows.go @@ -0,0 +1,150 @@ +package screenshot + +import ( + "errors" + "github.com/kbinani/screenshot/internal/util" + win "github.com/lxn/win" + "image" + "syscall" + "unsafe" +) + +var ( + libUser32, _ = syscall.LoadLibrary("user32.dll") + funcGetDesktopWindow, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "GetDesktopWindow") + funcEnumDisplayMonitors, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "EnumDisplayMonitors") +) + +func Capture(x, y, width, height int) (*image.RGBA, error) { + rect := image.Rect(0, 0, width, height) + img, err := util.CreateImage(rect) + if err != nil { + return nil, err + } + + hwnd := getDesktopWindow() + hdc := win.GetDC(hwnd) + if hdc == 0 { + return nil, errors.New("GetDC failed") + } + defer win.ReleaseDC(hwnd, hdc) + + memory_device := win.CreateCompatibleDC(hdc) + if memory_device == 0 { + return nil, errors.New("CreateCompatibleDC failed") + } + defer win.DeleteDC(memory_device) + + bitmap := win.CreateCompatibleBitmap(hdc, int32(width), int32(height)) + if bitmap == 0 { + return nil, errors.New("CreateCompatibleBitmap failed") + } + defer win.DeleteObject(win.HGDIOBJ(bitmap)) + + var header win.BITMAPINFOHEADER + header.BiSize = uint32(unsafe.Sizeof(header)) + header.BiPlanes = 1 + header.BiBitCount = 32 + header.BiWidth = int32(width) + header.BiHeight = int32(-height) + header.BiCompression = win.BI_RGB + header.BiSizeImage = 0 + + // GetDIBits balks at using Go memory on some systems. The MSDN example uses + // GlobalAlloc, so we'll do that too. See: + // https://docs.microsoft.com/en-gb/windows/desktop/gdi/capturing-an-image + bitmapDataSize := uintptr(((int64(width)*int64(header.BiBitCount) + 31) / 32) * 4 * int64(height)) + hmem := win.GlobalAlloc(win.GMEM_MOVEABLE, bitmapDataSize) + defer win.GlobalFree(hmem) + memptr := win.GlobalLock(hmem) + defer win.GlobalUnlock(hmem) + + old := win.SelectObject(memory_device, win.HGDIOBJ(bitmap)) + if old == 0 { + return nil, errors.New("SelectObject failed") + } + defer win.SelectObject(memory_device, old) + + if !win.BitBlt(memory_device, 0, 0, int32(width), int32(height), hdc, int32(x), int32(y), win.SRCCOPY) { + return nil, errors.New("BitBlt failed") + } + + if win.GetDIBits(hdc, bitmap, 0, uint32(height), (*uint8)(memptr), (*win.BITMAPINFO)(unsafe.Pointer(&header)), win.DIB_RGB_COLORS) == 0 { + return nil, errors.New("GetDIBits failed") + } + + i := 0 + src := uintptr(memptr) + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + v0 := *(*uint8)(unsafe.Pointer(src)) + v1 := *(*uint8)(unsafe.Pointer(src + 1)) + v2 := *(*uint8)(unsafe.Pointer(src + 2)) + + // BGRA => RGBA, and set A to 255 + img.Pix[i], img.Pix[i+1], img.Pix[i+2], img.Pix[i+3] = v2, v1, v0, 255 + + i += 4 + src += 4 + } + } + + return img, nil +} + +func NumActiveDisplays() int { + var count int = 0 + enumDisplayMonitors(win.HDC(0), nil, syscall.NewCallback(countupMonitorCallback), uintptr(unsafe.Pointer(&count))) + return count +} + +func GetDisplayBounds(displayIndex int) image.Rectangle { + var ctx getMonitorBoundsContext + ctx.Index = displayIndex + ctx.Count = 0 + enumDisplayMonitors(win.HDC(0), nil, syscall.NewCallback(getMonitorBoundsCallback), uintptr(unsafe.Pointer(&ctx))) + return image.Rect( + int(ctx.Rect.Left), int(ctx.Rect.Top), + int(ctx.Rect.Right), int(ctx.Rect.Bottom)) +} + +func getDesktopWindow() win.HWND { + ret, _, _ := syscall.Syscall(funcGetDesktopWindow, 0, 0, 0, 0) + return win.HWND(ret) +} + +func enumDisplayMonitors(hdc win.HDC, lprcClip *win.RECT, lpfnEnum uintptr, dwData uintptr) bool { + ret, _, _ := syscall.Syscall6(funcEnumDisplayMonitors, 4, + uintptr(hdc), + uintptr(unsafe.Pointer(lprcClip)), + lpfnEnum, + dwData, + 0, + 0) + return int(ret) != 0 +} + +func countupMonitorCallback(hMonitor win.HMONITOR, hdcMonitor win.HDC, lprcMonitor *win.RECT, dwData uintptr) uintptr { + var count *int + count = (*int)(unsafe.Pointer(dwData)) + *count = *count + 1 + return uintptr(1) +} + +type getMonitorBoundsContext struct { + Index int + Rect win.RECT + Count int +} + +func getMonitorBoundsCallback(hMonitor win.HMONITOR, hdcMonitor win.HDC, lprcMonitor *win.RECT, dwData uintptr) uintptr { + var ctx *getMonitorBoundsContext + ctx = (*getMonitorBoundsContext)(unsafe.Pointer(dwData)) + if ctx.Count == ctx.Index { + ctx.Rect = *lprcMonitor + return uintptr(0) + } else { + ctx.Count = ctx.Count + 1 + return uintptr(1) + } +} diff --git a/gui/vendor/github.com/lxn/win/AUTHORS b/gui/vendor/github.com/lxn/win/AUTHORS new file mode 100644 index 0000000..e93ff83 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/AUTHORS @@ -0,0 +1,31 @@ +# This is the official list of 'win' authors for copyright purposes. + +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# Please keep the list sorted. + +# Contributors +# ============ + +Alexander Neumann +Aman Gupta +Anton Lahti +Benny Siegert +Bruno Bigras +Carl Kittelberger +Carlos Cobo +Cary Cherng +David Porter +gonutz +Hill +Joseph Watson +Kevin Pors +ktye +mycaosf +ryujimiya +Tiago Carvalho +wsf01 +gonutz +Cory Redmond diff --git a/gui/vendor/github.com/lxn/win/LICENSE b/gui/vendor/github.com/lxn/win/LICENSE new file mode 100644 index 0000000..2bd706b --- /dev/null +++ b/gui/vendor/github.com/lxn/win/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2010 The win Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/gui/vendor/github.com/lxn/win/README.mdown b/gui/vendor/github.com/lxn/win/README.mdown new file mode 100644 index 0000000..33d81ff --- /dev/null +++ b/gui/vendor/github.com/lxn/win/README.mdown @@ -0,0 +1,15 @@ +About win +========= + +win is a Windows API wrapper package for Go. + +Originally part of [walk](https://github.com/lxn/walk), it is now a separate +project. + +Setup +===== + +Make sure you have a working Go installation. +See [Getting Started](http://golang.org/doc/install.html) + +Now run `go get github.com/lxn/win` diff --git a/gui/vendor/github.com/lxn/win/advapi32.go b/gui/vendor/github.com/lxn/win/advapi32.go new file mode 100644 index 0000000..31e4ffe --- /dev/null +++ b/gui/vendor/github.com/lxn/win/advapi32.go @@ -0,0 +1,136 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +const KEY_READ REGSAM = 0x20019 +const KEY_WRITE REGSAM = 0x20006 + +const ( + HKEY_CLASSES_ROOT HKEY = 0x80000000 + HKEY_CURRENT_USER HKEY = 0x80000001 + HKEY_LOCAL_MACHINE HKEY = 0x80000002 + HKEY_USERS HKEY = 0x80000003 + HKEY_PERFORMANCE_DATA HKEY = 0x80000004 + HKEY_CURRENT_CONFIG HKEY = 0x80000005 + HKEY_DYN_DATA HKEY = 0x80000006 +) + +const ( + ERROR_NO_MORE_ITEMS = 259 +) + +type ( + ACCESS_MASK uint32 + HKEY HANDLE + REGSAM ACCESS_MASK +) + +const ( + REG_NONE uint64 = 0 // No value type + REG_SZ = 1 // Unicode nul terminated string + REG_EXPAND_SZ = 2 // Unicode nul terminated string + // (with environment variable references) + REG_BINARY = 3 // Free form binary + REG_DWORD = 4 // 32-bit number + REG_DWORD_LITTLE_ENDIAN = 4 // 32-bit number (same as REG_DWORD) + REG_DWORD_BIG_ENDIAN = 5 // 32-bit number + REG_LINK = 6 // Symbolic Link (unicode) + REG_MULTI_SZ = 7 // Multiple Unicode strings + REG_RESOURCE_LIST = 8 // Resource list in the resource map + REG_FULL_RESOURCE_DESCRIPTOR = 9 // Resource list in the hardware description + REG_RESOURCE_REQUIREMENTS_LIST = 10 + REG_QWORD = 11 // 64-bit number + REG_QWORD_LITTLE_ENDIAN = 11 // 64-bit number (same as REG_QWORD) + +) + +var ( + // Library + libadvapi32 uintptr + + // Functions + regCloseKey uintptr + regOpenKeyEx uintptr + regQueryValueEx uintptr + regEnumValue uintptr + regSetValueEx uintptr +) + +func init() { + // Library + libadvapi32 = MustLoadLibrary("advapi32.dll") + + // Functions + regCloseKey = MustGetProcAddress(libadvapi32, "RegCloseKey") + regOpenKeyEx = MustGetProcAddress(libadvapi32, "RegOpenKeyExW") + regQueryValueEx = MustGetProcAddress(libadvapi32, "RegQueryValueExW") + regEnumValue = MustGetProcAddress(libadvapi32, "RegEnumValueW") + regSetValueEx = MustGetProcAddress(libadvapi32, "RegSetValueExW") +} + +func RegCloseKey(hKey HKEY) int32 { + ret, _, _ := syscall.Syscall(regCloseKey, 1, + uintptr(hKey), + 0, + 0) + + return int32(ret) +} + +func RegOpenKeyEx(hKey HKEY, lpSubKey *uint16, ulOptions uint32, samDesired REGSAM, phkResult *HKEY) int32 { + ret, _, _ := syscall.Syscall6(regOpenKeyEx, 5, + uintptr(hKey), + uintptr(unsafe.Pointer(lpSubKey)), + uintptr(ulOptions), + uintptr(samDesired), + uintptr(unsafe.Pointer(phkResult)), + 0) + + return int32(ret) +} + +func RegQueryValueEx(hKey HKEY, lpValueName *uint16, lpReserved, lpType *uint32, lpData *byte, lpcbData *uint32) int32 { + ret, _, _ := syscall.Syscall6(regQueryValueEx, 6, + uintptr(hKey), + uintptr(unsafe.Pointer(lpValueName)), + uintptr(unsafe.Pointer(lpReserved)), + uintptr(unsafe.Pointer(lpType)), + uintptr(unsafe.Pointer(lpData)), + uintptr(unsafe.Pointer(lpcbData))) + + return int32(ret) +} + +func RegEnumValue(hKey HKEY, index uint32, lpValueName *uint16, lpcchValueName *uint32, lpReserved, lpType *uint32, lpData *byte, lpcbData *uint32) int32 { + ret, _, _ := syscall.Syscall9(regEnumValue, 8, + uintptr(hKey), + uintptr(index), + uintptr(unsafe.Pointer(lpValueName)), + uintptr(unsafe.Pointer(lpcchValueName)), + uintptr(unsafe.Pointer(lpReserved)), + uintptr(unsafe.Pointer(lpType)), + uintptr(unsafe.Pointer(lpData)), + uintptr(unsafe.Pointer(lpcbData)), + 0) + return int32(ret) +} + +func RegSetValueEx(hKey HKEY, lpValueName *uint16, lpReserved, lpDataType uint64, lpData *byte, cbData uint32) int32 { + ret, _, _ := syscall.Syscall6(regSetValueEx, 6, + uintptr(hKey), + uintptr(unsafe.Pointer(lpValueName)), + uintptr(lpReserved), + uintptr(lpDataType), + uintptr(unsafe.Pointer(lpData)), + uintptr(cbData)) + return int32(ret) +} diff --git a/gui/vendor/github.com/lxn/win/combobox.go b/gui/vendor/github.com/lxn/win/combobox.go new file mode 100644 index 0000000..3fdc782 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/combobox.go @@ -0,0 +1,86 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +// ComboBox return values +const ( + CB_OKAY = 0 + CB_ERR = ^uintptr(0) // -1 + CB_ERRSPACE = ^uintptr(1) // -2 +) + +// ComboBox notifications +const ( + CBN_ERRSPACE = -1 + CBN_SELCHANGE = 1 + CBN_DBLCLK = 2 + CBN_SETFOCUS = 3 + CBN_KILLFOCUS = 4 + CBN_EDITCHANGE = 5 + CBN_EDITUPDATE = 6 + CBN_DROPDOWN = 7 + CBN_CLOSEUP = 8 + CBN_SELENDOK = 9 + CBN_SELENDCANCEL = 10 +) + +// ComboBox styles +const ( + CBS_SIMPLE = 0x0001 + CBS_DROPDOWN = 0x0002 + CBS_DROPDOWNLIST = 0x0003 + CBS_OWNERDRAWFIXED = 0x0010 + CBS_OWNERDRAWVARIABLE = 0x0020 + CBS_AUTOHSCROLL = 0x0040 + CBS_OEMCONVERT = 0x0080 + CBS_SORT = 0x0100 + CBS_HASSTRINGS = 0x0200 + CBS_NOINTEGRALHEIGHT = 0x0400 + CBS_DISABLENOSCROLL = 0x0800 + CBS_UPPERCASE = 0x2000 + CBS_LOWERCASE = 0x4000 +) + +// ComboBox messages +const ( + CB_GETEDITSEL = 0x0140 + CB_LIMITTEXT = 0x0141 + CB_SETEDITSEL = 0x0142 + CB_ADDSTRING = 0x0143 + CB_DELETESTRING = 0x0144 + CB_DIR = 0x0145 + CB_GETCOUNT = 0x0146 + CB_GETCURSEL = 0x0147 + CB_GETLBTEXT = 0x0148 + CB_GETLBTEXTLEN = 0x0149 + CB_INSERTSTRING = 0x014A + CB_RESETCONTENT = 0x014B + CB_FINDSTRING = 0x014C + CB_SELECTSTRING = 0x014D + CB_SETCURSEL = 0x014E + CB_SHOWDROPDOWN = 0x014F + CB_GETITEMDATA = 0x0150 + CB_SETITEMDATA = 0x0151 + CB_GETDROPPEDCONTROLRECT = 0x0152 + CB_SETITEMHEIGHT = 0x0153 + CB_GETITEMHEIGHT = 0x0154 + CB_SETEXTENDEDUI = 0x0155 + CB_GETEXTENDEDUI = 0x0156 + CB_GETDROPPEDSTATE = 0x0157 + CB_FINDSTRINGEXACT = 0x0158 + CB_SETLOCALE = 0x0159 + CB_GETLOCALE = 0x015A + CB_GETTOPINDEX = 0x015b + CB_SETTOPINDEX = 0x015c + CB_GETHORIZONTALEXTENT = 0x015d + CB_SETHORIZONTALEXTENT = 0x015e + CB_GETDROPPEDWIDTH = 0x015f + CB_SETDROPPEDWIDTH = 0x0160 + CB_INITSTORAGE = 0x0161 + CB_MULTIPLEADDSTRING = 0x0163 + CB_GETCOMBOBOXINFO = 0x0164 +) diff --git a/gui/vendor/github.com/lxn/win/comctl32.go b/gui/vendor/github.com/lxn/win/comctl32.go new file mode 100644 index 0000000..3e204a2 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/comctl32.go @@ -0,0 +1,343 @@ +// Copyright 2016 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +// Button control messages +const ( + BCM_FIRST = 0x1600 + BCM_GETIDEALSIZE = BCM_FIRST + 0x0001 + BCM_SETIMAGELIST = BCM_FIRST + 0x0002 + BCM_GETIMAGELIST = BCM_FIRST + 0x0003 + BCM_SETTEXTMARGIN = BCM_FIRST + 0x0004 + BCM_GETTEXTMARGIN = BCM_FIRST + 0x0005 + BCM_SETDROPDOWNSTATE = BCM_FIRST + 0x0006 + BCM_SETSPLITINFO = BCM_FIRST + 0x0007 + BCM_GETSPLITINFO = BCM_FIRST + 0x0008 + BCM_SETNOTE = BCM_FIRST + 0x0009 + BCM_GETNOTE = BCM_FIRST + 0x000A + BCM_GETNOTELENGTH = BCM_FIRST + 0x000B + BCM_SETSHIELD = BCM_FIRST + 0x000C +) + +const ( + CCM_FIRST = 0x2000 + CCM_LAST = CCM_FIRST + 0x200 + CCM_SETBKCOLOR = 8193 + CCM_SETCOLORSCHEME = 8194 + CCM_GETCOLORSCHEME = 8195 + CCM_GETDROPTARGET = 8196 + CCM_SETUNICODEFORMAT = 8197 + CCM_GETUNICODEFORMAT = 8198 + CCM_SETVERSION = 0x2007 + CCM_GETVERSION = 0x2008 + CCM_SETNOTIFYWINDOW = 0x2009 + CCM_SETWINDOWTHEME = 0x200b + CCM_DPISCALE = 0x200c +) + +// Common controls styles +const ( + CCS_TOP = 1 + CCS_NOMOVEY = 2 + CCS_BOTTOM = 3 + CCS_NORESIZE = 4 + CCS_NOPARENTALIGN = 8 + CCS_ADJUSTABLE = 32 + CCS_NODIVIDER = 64 + CCS_VERT = 128 + CCS_LEFT = 129 + CCS_NOMOVEX = 130 + CCS_RIGHT = 131 +) + +// InitCommonControlsEx flags +const ( + ICC_LISTVIEW_CLASSES = 1 + ICC_TREEVIEW_CLASSES = 2 + ICC_BAR_CLASSES = 4 + ICC_TAB_CLASSES = 8 + ICC_UPDOWN_CLASS = 16 + ICC_PROGRESS_CLASS = 32 + ICC_HOTKEY_CLASS = 64 + ICC_ANIMATE_CLASS = 128 + ICC_WIN95_CLASSES = 255 + ICC_DATE_CLASSES = 256 + ICC_USEREX_CLASSES = 512 + ICC_COOL_CLASSES = 1024 + ICC_INTERNET_CLASSES = 2048 + ICC_PAGESCROLLER_CLASS = 4096 + ICC_NATIVEFNTCTL_CLASS = 8192 + INFOTIPSIZE = 1024 + ICC_STANDARD_CLASSES = 0x00004000 + ICC_LINK_CLASS = 0x00008000 +) + +// WM_NOTITY messages +const ( + NM_FIRST = 0 + NM_OUTOFMEMORY = ^uint32(0) // NM_FIRST - 1 + NM_CLICK = ^uint32(1) // NM_FIRST - 2 + NM_DBLCLK = ^uint32(2) // NM_FIRST - 3 + NM_RETURN = ^uint32(3) // NM_FIRST - 4 + NM_RCLICK = ^uint32(4) // NM_FIRST - 5 + NM_RDBLCLK = ^uint32(5) // NM_FIRST - 6 + NM_SETFOCUS = ^uint32(6) // NM_FIRST - 7 + NM_KILLFOCUS = ^uint32(7) // NM_FIRST - 8 + NM_CUSTOMDRAW = ^uint32(11) // NM_FIRST - 12 + NM_HOVER = ^uint32(12) // NM_FIRST - 13 + NM_NCHITTEST = ^uint32(13) // NM_FIRST - 14 + NM_KEYDOWN = ^uint32(14) // NM_FIRST - 15 + NM_RELEASEDCAPTURE = ^uint32(15) // NM_FIRST - 16 + NM_SETCURSOR = ^uint32(16) // NM_FIRST - 17 + NM_CHAR = ^uint32(17) // NM_FIRST - 18 + NM_TOOLTIPSCREATED = ^uint32(18) // NM_FIRST - 19 + NM_LAST = ^uint32(98) // NM_FIRST - 99 + TRBN_THUMBPOSCHANGING = 0xfffffa22 // TRBN_FIRST - 1 +) + +// ProgressBar messages +const ( + PBM_SETPOS = WM_USER + 2 + PBM_DELTAPOS = WM_USER + 3 + PBM_SETSTEP = WM_USER + 4 + PBM_STEPIT = WM_USER + 5 + PBM_SETMARQUEE = WM_USER + 10 + PBM_SETRANGE32 = 1030 + PBM_GETRANGE = 1031 + PBM_GETPOS = 1032 + PBM_SETBARCOLOR = 1033 + PBM_SETBKCOLOR = CCM_SETBKCOLOR +) + +// ProgressBar styles +const ( + PBS_SMOOTH = 0x01 + PBS_VERTICAL = 0x04 + PBS_MARQUEE = 0x08 +) + +// TrackBar (Slider) messages +const ( + TBM_GETPOS = WM_USER + TBM_GETRANGEMIN = WM_USER + 1 + TBM_GETRANGEMAX = WM_USER + 2 + TBM_SETPOS = WM_USER + 5 + TBM_SETRANGEMIN = WM_USER + 7 + TBM_SETRANGEMAX = WM_USER + 8 +) + +// TrackBar (Slider) styles +const ( + TBS_VERT = 0x002 + TBS_TOOLTIPS = 0x100 +) + +// ImageList creation flags +const ( + ILC_MASK = 0x00000001 + ILC_COLOR = 0x00000000 + ILC_COLORDDB = 0x000000FE + ILC_COLOR4 = 0x00000004 + ILC_COLOR8 = 0x00000008 + ILC_COLOR16 = 0x00000010 + ILC_COLOR24 = 0x00000018 + ILC_COLOR32 = 0x00000020 + ILC_PALETTE = 0x00000800 + ILC_MIRROR = 0x00002000 + ILC_PERITEMMIRROR = 0x00008000 +) + +// LoadIconMetric flags +const ( + LIM_SMALL = 0 + LIM_LARGE = 1 +) + +const ( + CDDS_PREPAINT = 0x00000001 + CDDS_POSTPAINT = 0x00000002 + CDDS_PREERASE = 0x00000003 + CDDS_POSTERASE = 0x00000004 + CDDS_ITEM = 0x00010000 + CDDS_ITEMPREPAINT = CDDS_ITEM | CDDS_PREPAINT + CDDS_ITEMPOSTPAINT = CDDS_ITEM | CDDS_POSTPAINT + CDDS_ITEMPREERASE = CDDS_ITEM | CDDS_PREERASE + CDDS_ITEMPOSTERASE = CDDS_ITEM | CDDS_POSTERASE + CDDS_SUBITEM = 0x00020000 +) + +const ( + CDIS_SELECTED = 0x0001 + CDIS_GRAYED = 0x0002 + CDIS_DISABLED = 0x0004 + CDIS_CHECKED = 0x0008 + CDIS_FOCUS = 0x0010 + CDIS_DEFAULT = 0x0020 + CDIS_HOT = 0x0040 + CDIS_MARKED = 0x0080 + CDIS_INDETERMINATE = 0x0100 + CDIS_SHOWKEYBOARDCUES = 0x0200 + CDIS_NEARHOT = 0x0400 + CDIS_OTHERSIDEHOT = 0x0800 + CDIS_DROPHILITED = 0x1000 +) + +const ( + CDRF_DODEFAULT = 0x00000000 + CDRF_NEWFONT = 0x00000002 + CDRF_SKIPDEFAULT = 0x00000004 + CDRF_DOERASE = 0x00000008 + CDRF_NOTIFYPOSTPAINT = 0x00000010 + CDRF_NOTIFYITEMDRAW = 0x00000020 + CDRF_NOTIFYSUBITEMDRAW = 0x00000020 + CDRF_NOTIFYPOSTERASE = 0x00000040 + CDRF_SKIPPOSTPAINT = 0x00000100 +) + +const ( + LPSTR_TEXTCALLBACK = ^uintptr(0) + I_CHILDRENCALLBACK = -1 +) + +type HIMAGELIST HANDLE + +type INITCOMMONCONTROLSEX struct { + DwSize, DwICC uint32 +} + +type NMCUSTOMDRAW struct { + Hdr NMHDR + DwDrawStage uint32 + Hdc HDC + Rc RECT + DwItemSpec uintptr + UItemState uint32 + LItemlParam uintptr +} + +var ( + // Library + libcomctl32 uintptr + + // Functions + imageList_Add uintptr + imageList_AddMasked uintptr + imageList_Create uintptr + imageList_Destroy uintptr + imageList_ReplaceIcon uintptr + initCommonControlsEx uintptr + loadIconMetric uintptr + loadIconWithScaleDown uintptr +) + +func init() { + // Library + libcomctl32 = MustLoadLibrary("comctl32.dll") + + // Functions + imageList_Add = MustGetProcAddress(libcomctl32, "ImageList_Add") + imageList_AddMasked = MustGetProcAddress(libcomctl32, "ImageList_AddMasked") + imageList_Create = MustGetProcAddress(libcomctl32, "ImageList_Create") + imageList_Destroy = MustGetProcAddress(libcomctl32, "ImageList_Destroy") + imageList_ReplaceIcon = MustGetProcAddress(libcomctl32, "ImageList_ReplaceIcon") + initCommonControlsEx = MustGetProcAddress(libcomctl32, "InitCommonControlsEx") + loadIconMetric = MaybeGetProcAddress(libcomctl32, "LoadIconMetric") + loadIconWithScaleDown = MaybeGetProcAddress(libcomctl32, "LoadIconWithScaleDown") + + // Initialize the common controls we support + var initCtrls INITCOMMONCONTROLSEX + initCtrls.DwSize = uint32(unsafe.Sizeof(initCtrls)) + initCtrls.DwICC = ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | ICC_PROGRESS_CLASS | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES + + InitCommonControlsEx(&initCtrls) +} + +func ImageList_Add(himl HIMAGELIST, hbmImage, hbmMask HBITMAP) int32 { + ret, _, _ := syscall.Syscall(imageList_Add, 3, + uintptr(himl), + uintptr(hbmImage), + uintptr(hbmMask)) + + return int32(ret) +} + +func ImageList_AddMasked(himl HIMAGELIST, hbmImage HBITMAP, crMask COLORREF) int32 { + ret, _, _ := syscall.Syscall(imageList_AddMasked, 3, + uintptr(himl), + uintptr(hbmImage), + uintptr(crMask)) + + return int32(ret) +} + +func ImageList_Create(cx, cy int32, flags uint32, cInitial, cGrow int32) HIMAGELIST { + ret, _, _ := syscall.Syscall6(imageList_Create, 5, + uintptr(cx), + uintptr(cy), + uintptr(flags), + uintptr(cInitial), + uintptr(cGrow), + 0) + + return HIMAGELIST(ret) +} + +func ImageList_Destroy(hIml HIMAGELIST) bool { + ret, _, _ := syscall.Syscall(imageList_Destroy, 1, + uintptr(hIml), + 0, + 0) + + return ret != 0 +} + +func ImageList_ReplaceIcon(himl HIMAGELIST, i int32, hicon HICON) int32 { + ret, _, _ := syscall.Syscall(imageList_ReplaceIcon, 3, + uintptr(himl), + uintptr(i), + uintptr(hicon)) + + return int32(ret) +} + +func InitCommonControlsEx(lpInitCtrls *INITCOMMONCONTROLSEX) bool { + ret, _, _ := syscall.Syscall(initCommonControlsEx, 1, + uintptr(unsafe.Pointer(lpInitCtrls)), + 0, + 0) + + return ret != 0 +} + +func LoadIconMetric(hInstance HINSTANCE, lpIconName *uint16, lims int32, hicon *HICON) HRESULT { + ret, _, _ := syscall.Syscall6(loadIconMetric, 4, + uintptr(hInstance), + uintptr(unsafe.Pointer(lpIconName)), + uintptr(lims), + uintptr(unsafe.Pointer(hicon)), + 0, + 0) + + return HRESULT(ret) +} + +func LoadIconWithScaleDown(hInstance HINSTANCE, lpIconName *uint16, w int32, h int32, hicon *HICON) HRESULT { + ret, _, _ := syscall.Syscall6(loadIconWithScaleDown, 5, + uintptr(hInstance), + uintptr(unsafe.Pointer(lpIconName)), + uintptr(w), + uintptr(h), + uintptr(unsafe.Pointer(hicon)), + 0) + + return HRESULT(ret) +} diff --git a/gui/vendor/github.com/lxn/win/comdlg32.go b/gui/vendor/github.com/lxn/win/comdlg32.go new file mode 100644 index 0000000..6ba9d05 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/comdlg32.go @@ -0,0 +1,299 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +// Common error codes +const ( + CDERR_DIALOGFAILURE = 0xFFFF + CDERR_FINDRESFAILURE = 0x0006 + CDERR_INITIALIZATION = 0x0002 + CDERR_LOADRESFAILURE = 0x0007 + CDERR_LOADSTRFAILURE = 0x0005 + CDERR_LOCKRESFAILURE = 0x0008 + CDERR_MEMALLOCFAILURE = 0x0009 + CDERR_MEMLOCKFAILURE = 0x000A + CDERR_NOHINSTANCE = 0x0004 + CDERR_NOHOOK = 0x000B + CDERR_NOTEMPLATE = 0x0003 + CDERR_REGISTERMSGFAIL = 0x000C + CDERR_STRUCTSIZE = 0x0001 +) + +// CHOOSECOLOR flags +const ( + CC_ANYCOLOR = 0x00000100 + CC_ENABLEHOOK = 0x00000010 + CC_ENABLETEMPLATE = 0x00000020 + CC_ENABLETEMPLATEHANDLE = 0x00000040 + CC_FULLOPEN = 0x00000002 + CC_PREVENTFULLOPEN = 0x00000004 + CC_RGBINIT = 0x00000001 + CC_SHOWHELP = 0x00000008 + CC_SOLIDCOLOR = 0x00000080 +) + +type CHOOSECOLOR struct { + LStructSize uint32 + HwndOwner HWND + HInstance HWND + RgbResult COLORREF + LpCustColors *[16]COLORREF + Flags uint32 + LCustData uintptr + LpfnHook uintptr + LpTemplateName *uint16 +} + +// PrintDlg specific error codes +const ( + PDERR_CREATEICFAILURE = 0x100A + PDERR_DEFAULTDIFFERENT = 0x100C + PDERR_DNDMMISMATCH = 0x1009 + PDERR_GETDEVMODEFAIL = 0x1005 + PDERR_INITFAILURE = 0x1006 + PDERR_LOADDRVFAILURE = 0x1004 + PDERR_NODEFAULTPRN = 0x1008 + PDERR_NODEVICES = 0x1007 + PDERR_PARSEFAILURE = 0x1002 + PDERR_PRINTERNOTFOUND = 0x100B + PDERR_RETDEFFAILURE = 0x1003 + PDERR_SETUPFAILURE = 0x1001 +) + +// ChooseFont specific error codes +const ( + CFERR_MAXLESSTHANMIN = 0x2002 + CFERR_NOFONTS = 0x2001 +) + +// GetOpenFileName and GetSaveFileName specific error codes +const ( + FNERR_BUFFERTOOSMALL = 0x3003 + FNERR_INVALIDFILENAME = 0x3002 + FNERR_SUBCLASSFAILURE = 0x3001 +) + +// FindText and ReplaceText specific error codes +const ( + FRERR_BUFFERLENGTHZERO = 0x4001 +) + +// GetOpenFileName and GetSaveFileName flags +const ( + OFN_ALLOWMULTISELECT = 0x00000200 + OFN_CREATEPROMPT = 0x00002000 + OFN_DONTADDTORECENT = 0x02000000 + OFN_ENABLEHOOK = 0x00000020 + OFN_ENABLEINCLUDENOTIFY = 0x00400000 + OFN_ENABLESIZING = 0x00800000 + OFN_ENABLETEMPLATE = 0x00000040 + OFN_ENABLETEMPLATEHANDLE = 0x00000080 + OFN_EXPLORER = 0x00080000 + OFN_EXTENSIONDIFFERENT = 0x00000400 + OFN_FILEMUSTEXIST = 0x00001000 + OFN_FORCESHOWHIDDEN = 0x10000000 + OFN_HIDEREADONLY = 0x00000004 + OFN_LONGNAMES = 0x00200000 + OFN_NOCHANGEDIR = 0x00000008 + OFN_NODEREFERENCELINKS = 0x00100000 + OFN_NOLONGNAMES = 0x00040000 + OFN_NONETWORKBUTTON = 0x00020000 + OFN_NOREADONLYRETURN = 0x00008000 + OFN_NOTESTFILECREATE = 0x00010000 + OFN_NOVALIDATE = 0x00000100 + OFN_OVERWRITEPROMPT = 0x00000002 + OFN_PATHMUSTEXIST = 0x00000800 + OFN_READONLY = 0x00000001 + OFN_SHAREAWARE = 0x00004000 + OFN_SHOWHELP = 0x00000010 +) + +// GetOpenFileName and GetSaveFileName extended flags +const ( + OFN_EX_NOPLACESBAR = 0x00000001 +) + +// PrintDlg[Ex] result actions +const ( + PD_RESULT_APPLY = 2 + PD_RESULT_CANCEL = 0 + PD_RESULT_PRINT = 1 +) + +// PrintDlg[Ex] flags +const ( + PD_ALLPAGES = 0x00000000 + PD_COLLATE = 0x00000010 + PD_CURRENTPAGE = 0x00400000 + PD_DISABLEPRINTTOFILE = 0x00080000 + PD_ENABLEPRINTTEMPLATE = 0x00004000 + PD_ENABLEPRINTTEMPLATEHANDLE = 0x00010000 + PD_EXCLUSIONFLAGS = 0x01000000 + PD_HIDEPRINTTOFILE = 0x00100000 + PD_NOCURRENTPAGE = 0x00800000 + PD_NOPAGENUMS = 0x00000008 + PD_NOSELECTION = 0x00000004 + PD_NOWARNING = 0x00000080 + PD_PAGENUMS = 0x00000002 + PD_PRINTTOFILE = 0x00000020 + PD_RETURNDC = 0x00000100 + PD_RETURNDEFAULT = 0x00000400 + PD_RETURNIC = 0x00000200 + PD_SELECTION = 0x00000001 + PD_USEDEVMODECOPIES = 0x00040000 + PD_USEDEVMODECOPIESANDCOLLATE = 0x00040000 + PD_USELARGETEMPLATE = 0x10000000 +) + +// PrintDlgEx exclusion flags +const ( + PD_EXCL_COPIESANDCOLLATE = DM_COPIES | DM_COLLATE +) + +const START_PAGE_GENERAL = 0xffffffff + +type ( + LPOFNHOOKPROC uintptr + HPROPSHEETPAGE HANDLE + LPUNKNOWN uintptr +) + +type OPENFILENAME struct { + LStructSize uint32 + HwndOwner HWND + HInstance HINSTANCE + LpstrFilter *uint16 + LpstrCustomFilter *uint16 + NMaxCustFilter uint32 + NFilterIndex uint32 + LpstrFile *uint16 + NMaxFile uint32 + LpstrFileTitle *uint16 + NMaxFileTitle uint32 + LpstrInitialDir *uint16 + LpstrTitle *uint16 + Flags uint32 + NFileOffset uint16 + NFileExtension uint16 + LpstrDefExt *uint16 + LCustData uintptr + LpfnHook LPOFNHOOKPROC + LpTemplateName *uint16 + PvReserved unsafe.Pointer + DwReserved uint32 + FlagsEx uint32 +} + +type PRINTPAGERANGE struct { + NFromPage uint32 + NToPage uint32 +} + +type DEVNAMES struct { + WDriverOffset uint16 + WDeviceOffset uint16 + WOutputOffset uint16 + WDefault uint16 +} + +type PRINTDLGEX struct { + LStructSize uint32 + HwndOwner HWND + HDevMode HGLOBAL + HDevNames HGLOBAL + HDC HDC + Flags uint32 + Flags2 uint32 + ExclusionFlags uint32 + NPageRanges uint32 + NMaxPageRanges uint32 + LpPageRanges *PRINTPAGERANGE + NMinPage uint32 + NMaxPage uint32 + NCopies uint32 + HInstance HINSTANCE + LpPrintTemplateName *uint16 + LpCallback LPUNKNOWN + NPropertyPages uint32 + LphPropertyPages *HPROPSHEETPAGE + NStartPage uint32 + DwResultAction uint32 +} + +var ( + // Library + libcomdlg32 uintptr + + // Functions + chooseColor uintptr + commDlgExtendedError uintptr + getOpenFileName uintptr + getSaveFileName uintptr + printDlgEx uintptr +) + +func init() { + // Library + libcomdlg32 = MustLoadLibrary("comdlg32.dll") + + // Functions + chooseColor = MustGetProcAddress(libcomdlg32, "ChooseColorW") + commDlgExtendedError = MustGetProcAddress(libcomdlg32, "CommDlgExtendedError") + getOpenFileName = MustGetProcAddress(libcomdlg32, "GetOpenFileNameW") + getSaveFileName = MustGetProcAddress(libcomdlg32, "GetSaveFileNameW") + printDlgEx = MustGetProcAddress(libcomdlg32, "PrintDlgExW") +} + +func ChooseColor(lpcc *CHOOSECOLOR) bool { + ret, _, _ := syscall.Syscall(chooseColor, 1, + uintptr(unsafe.Pointer(lpcc)), + 0, + 0) + + return ret != 0 +} + +func CommDlgExtendedError() uint32 { + ret, _, _ := syscall.Syscall(commDlgExtendedError, 0, + 0, + 0, + 0) + + return uint32(ret) +} + +func GetOpenFileName(lpofn *OPENFILENAME) bool { + ret, _, _ := syscall.Syscall(getOpenFileName, 1, + uintptr(unsafe.Pointer(lpofn)), + 0, + 0) + + return ret != 0 +} + +func GetSaveFileName(lpofn *OPENFILENAME) bool { + ret, _, _ := syscall.Syscall(getSaveFileName, 1, + uintptr(unsafe.Pointer(lpofn)), + 0, + 0) + + return ret != 0 +} + +func PrintDlgEx(lppd *PRINTDLGEX) HRESULT { + ret, _, _ := syscall.Syscall(printDlgEx, 1, + uintptr(unsafe.Pointer(lppd)), + 0, + 0) + + return HRESULT(ret) +} diff --git a/gui/vendor/github.com/lxn/win/datetimepicker.go b/gui/vendor/github.com/lxn/win/datetimepicker.go new file mode 100644 index 0000000..07a6532 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/datetimepicker.go @@ -0,0 +1,96 @@ +// Copyright 2011 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +const DTM_FIRST = 0x1000 +const DTN_FIRST = ^uint32(739) // -740 +const DTN_FIRST2 = ^uint32(752) // -753 + +const ( + GDTR_MIN = 0x0001 + GDTR_MAX = 0x0002 +) + +const ( + GDT_ERROR = -1 + GDT_VALID = 0 + GDT_NONE = 1 +) + +// Messages +const ( + DTM_GETSYSTEMTIME = DTM_FIRST + 1 + DTM_SETSYSTEMTIME = DTM_FIRST + 2 + DTM_GETRANGE = DTM_FIRST + 3 + DTM_SETRANGE = DTM_FIRST + 4 + DTM_SETFORMAT = DTM_FIRST + 50 + DTM_SETMCCOLOR = DTM_FIRST + 6 + DTM_GETMCCOLOR = DTM_FIRST + 7 + DTM_GETMONTHCAL = DTM_FIRST + 8 + DTM_SETMCFONT = DTM_FIRST + 9 + DTM_GETMCFONT = DTM_FIRST + 10 +) + +// Styles +const ( + DTS_UPDOWN = 0x0001 + DTS_SHOWNONE = 0x0002 + DTS_SHORTDATEFORMAT = 0x0000 + DTS_LONGDATEFORMAT = 0x0004 + DTS_SHORTDATECENTURYFORMAT = 0x000C + DTS_TIMEFORMAT = 0x0009 + DTS_APPCANPARSE = 0x0010 + DTS_RIGHTALIGN = 0x0020 +) + +// Notifications +const ( + DTN_DATETIMECHANGE = DTN_FIRST2 - 6 + DTN_USERSTRING = DTN_FIRST - 5 + DTN_WMKEYDOWN = DTN_FIRST - 4 + DTN_FORMAT = DTN_FIRST - 3 + DTN_FORMATQUERY = DTN_FIRST - 2 + DTN_DROPDOWN = DTN_FIRST2 - 1 + DTN_CLOSEUP = DTN_FIRST2 +) + +// Structs +type ( + NMDATETIMECHANGE struct { + Nmhdr NMHDR + DwFlags uint32 + St SYSTEMTIME + } + + NMDATETIMESTRING struct { + Nmhdr NMHDR + PszUserString *uint16 + St SYSTEMTIME + DwFlags uint32 + } + + NMDATETIMEWMKEYDOWN struct { + Nmhdr NMHDR + NVirtKey int + PszFormat *uint16 + St SYSTEMTIME + } + + NMDATETIMEFORMAT struct { + Nmhdr NMHDR + PszFormat *uint16 + St SYSTEMTIME + PszDisplay *uint16 + SzDisplay [64]uint16 + } + + NMDATETIMEFORMATQUERY struct { + Nmhdr NMHDR + PszFormat *uint16 + SzMax SIZE + } +) diff --git a/gui/vendor/github.com/lxn/win/edit.go b/gui/vendor/github.com/lxn/win/edit.go new file mode 100644 index 0000000..38509cf --- /dev/null +++ b/gui/vendor/github.com/lxn/win/edit.go @@ -0,0 +1,84 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +// Edit styles +const ( + ES_LEFT = 0x0000 + ES_CENTER = 0x0001 + ES_RIGHT = 0x0002 + ES_MULTILINE = 0x0004 + ES_UPPERCASE = 0x0008 + ES_LOWERCASE = 0x0010 + ES_PASSWORD = 0x0020 + ES_AUTOVSCROLL = 0x0040 + ES_AUTOHSCROLL = 0x0080 + ES_NOHIDESEL = 0x0100 + ES_OEMCONVERT = 0x0400 + ES_READONLY = 0x0800 + ES_WANTRETURN = 0x1000 + ES_NUMBER = 0x2000 +) + +// Edit notifications +const ( + EN_SETFOCUS = 0x0100 + EN_KILLFOCUS = 0x0200 + EN_CHANGE = 0x0300 + EN_UPDATE = 0x0400 + EN_ERRSPACE = 0x0500 + EN_MAXTEXT = 0x0501 + EN_HSCROLL = 0x0601 + EN_VSCROLL = 0x0602 + EN_ALIGN_LTR_EC = 0x0700 + EN_ALIGN_RTL_EC = 0x0701 +) + +// Edit messages +const ( + EM_GETSEL = 0x00B0 + EM_SETSEL = 0x00B1 + EM_GETRECT = 0x00B2 + EM_SETRECT = 0x00B3 + EM_SETRECTNP = 0x00B4 + EM_SCROLL = 0x00B5 + EM_LINESCROLL = 0x00B6 + EM_SCROLLCARET = 0x00B7 + EM_GETMODIFY = 0x00B8 + EM_SETMODIFY = 0x00B9 + EM_GETLINECOUNT = 0x00BA + EM_LINEINDEX = 0x00BB + EM_SETHANDLE = 0x00BC + EM_GETHANDLE = 0x00BD + EM_GETTHUMB = 0x00BE + EM_LINELENGTH = 0x00C1 + EM_REPLACESEL = 0x00C2 + EM_GETLINE = 0x00C4 + EM_LIMITTEXT = 0x00C5 + EM_CANUNDO = 0x00C6 + EM_UNDO = 0x00C7 + EM_FMTLINES = 0x00C8 + EM_LINEFROMCHAR = 0x00C9 + EM_SETTABSTOPS = 0x00CB + EM_SETPASSWORDCHAR = 0x00CC + EM_EMPTYUNDOBUFFER = 0x00CD + EM_GETFIRSTVISIBLELINE = 0x00CE + EM_SETREADONLY = 0x00CF + EM_SETWORDBREAKPROC = 0x00D0 + EM_GETWORDBREAKPROC = 0x00D1 + EM_GETPASSWORDCHAR = 0x00D2 + EM_SETMARGINS = 0x00D3 + EM_GETMARGINS = 0x00D4 + EM_SETLIMITTEXT = EM_LIMITTEXT + EM_GETLIMITTEXT = 0x00D5 + EM_POSFROMCHAR = 0x00D6 + EM_CHARFROMPOS = 0x00D7 + EM_SETIMESTATUS = 0x00D8 + EM_GETIMESTATUS = 0x00D9 + EM_SETCUEBANNER = 0x1501 + EM_GETCUEBANNER = 0x1502 +) diff --git a/gui/vendor/github.com/lxn/win/gdi32.go b/gui/vendor/github.com/lxn/win/gdi32.go new file mode 100644 index 0000000..f438853 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/gdi32.go @@ -0,0 +1,1935 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +// GetDeviceCaps index constants +const ( + DRIVERVERSION = 0 + TECHNOLOGY = 2 + HORZSIZE = 4 + VERTSIZE = 6 + HORZRES = 8 + VERTRES = 10 + LOGPIXELSX = 88 + LOGPIXELSY = 90 + BITSPIXEL = 12 + PLANES = 14 + NUMBRUSHES = 16 + NUMPENS = 18 + NUMFONTS = 22 + NUMCOLORS = 24 + NUMMARKERS = 20 + ASPECTX = 40 + ASPECTY = 42 + ASPECTXY = 44 + PDEVICESIZE = 26 + CLIPCAPS = 36 + SIZEPALETTE = 104 + NUMRESERVED = 106 + COLORRES = 108 + PHYSICALWIDTH = 110 + PHYSICALHEIGHT = 111 + PHYSICALOFFSETX = 112 + PHYSICALOFFSETY = 113 + SCALINGFACTORX = 114 + SCALINGFACTORY = 115 + VREFRESH = 116 + DESKTOPHORZRES = 118 + DESKTOPVERTRES = 117 + BLTALIGNMENT = 119 + SHADEBLENDCAPS = 120 + COLORMGMTCAPS = 121 + RASTERCAPS = 38 + CURVECAPS = 28 + LINECAPS = 30 + POLYGONALCAPS = 32 + TEXTCAPS = 34 +) + +// GetDeviceCaps TECHNOLOGY constants +const ( + DT_PLOTTER = 0 + DT_RASDISPLAY = 1 + DT_RASPRINTER = 2 + DT_RASCAMERA = 3 + DT_CHARSTREAM = 4 + DT_METAFILE = 5 + DT_DISPFILE = 6 +) + +// GetDeviceCaps SHADEBLENDCAPS constants +const ( + SB_NONE = 0x00 + SB_CONST_ALPHA = 0x01 + SB_PIXEL_ALPHA = 0x02 + SB_PREMULT_ALPHA = 0x04 + SB_GRAD_RECT = 0x10 + SB_GRAD_TRI = 0x20 +) + +// GetDeviceCaps COLORMGMTCAPS constants +const ( + CM_NONE = 0x00 + CM_DEVICE_ICM = 0x01 + CM_GAMMA_RAMP = 0x02 + CM_CMYK_COLOR = 0x04 +) + +// GetDeviceCaps RASTERCAPS constants +const ( + RC_BANDING = 2 + RC_BITBLT = 1 + RC_BITMAP64 = 8 + RC_DI_BITMAP = 128 + RC_DIBTODEV = 512 + RC_FLOODFILL = 4096 + RC_GDI20_OUTPUT = 16 + RC_PALETTE = 256 + RC_SCALING = 4 + RC_STRETCHBLT = 2048 + RC_STRETCHDIB = 8192 + RC_DEVBITS = 0x8000 + RC_OP_DX_OUTPUT = 0x4000 +) + +// GetDeviceCaps CURVECAPS constants +const ( + CC_NONE = 0 + CC_CIRCLES = 1 + CC_PIE = 2 + CC_CHORD = 4 + CC_ELLIPSES = 8 + CC_WIDE = 16 + CC_STYLED = 32 + CC_WIDESTYLED = 64 + CC_INTERIORS = 128 + CC_ROUNDRECT = 256 +) + +// GetDeviceCaps LINECAPS constants +const ( + LC_NONE = 0 + LC_POLYLINE = 2 + LC_MARKER = 4 + LC_POLYMARKER = 8 + LC_WIDE = 16 + LC_STYLED = 32 + LC_WIDESTYLED = 64 + LC_INTERIORS = 128 +) + +// GetDeviceCaps POLYGONALCAPS constants +const ( + PC_NONE = 0 + PC_POLYGON = 1 + PC_POLYPOLYGON = 256 + PC_PATHS = 512 + PC_RECTANGLE = 2 + PC_WINDPOLYGON = 4 + PC_SCANLINE = 8 + PC_TRAPEZOID = 4 + PC_WIDE = 16 + PC_STYLED = 32 + PC_WIDESTYLED = 64 + PC_INTERIORS = 128 +) + +// GetDeviceCaps TEXTCAPS constants +const ( + TC_OP_CHARACTER = 1 + TC_OP_STROKE = 2 + TC_CP_STROKE = 4 + TC_CR_90 = 8 + TC_CR_ANY = 16 + TC_SF_X_YINDEP = 32 + TC_SA_DOUBLE = 64 + TC_SA_INTEGER = 128 + TC_SA_CONTIN = 256 + TC_EA_DOUBLE = 512 + TC_IA_ABLE = 1024 + TC_UA_ABLE = 2048 + TC_SO_ABLE = 4096 + TC_RA_ABLE = 8192 + TC_VA_ABLE = 16384 + TC_RESERVED = 32768 + TC_SCROLLBLT = 65536 +) + +// Brush styles +const ( + BS_SOLID = 0 + BS_NULL = 1 + BS_HOLLOW = BS_NULL + BS_HATCHED = 2 + BS_PATTERN = 3 + BS_INDEXED = 4 + BS_DIBPATTERN = 5 + BS_DIBPATTERNPT = 6 + BS_PATTERN8X8 = 7 + BS_DIBPATTERN8X8 = 8 + BS_MONOPATTERN = 9 +) + +// Hatch styles +const ( + HS_HORIZONTAL = 0 + HS_VERTICAL = 1 + HS_FDIAGONAL = 2 + HS_BDIAGONAL = 3 + HS_CROSS = 4 + HS_DIAGCROSS = 5 +) + +// Pen types +const ( + PS_COSMETIC = 0x00000000 + PS_GEOMETRIC = 0x00010000 + PS_TYPE_MASK = 0x000F0000 +) + +// Pen styles +const ( + PS_SOLID = 0 + PS_DASH = 1 + PS_DOT = 2 + PS_DASHDOT = 3 + PS_DASHDOTDOT = 4 + PS_NULL = 5 + PS_INSIDEFRAME = 6 + PS_USERSTYLE = 7 + PS_ALTERNATE = 8 + PS_STYLE_MASK = 0x0000000F +) + +// Pen cap types +const ( + PS_ENDCAP_ROUND = 0x00000000 + PS_ENDCAP_SQUARE = 0x00000100 + PS_ENDCAP_FLAT = 0x00000200 + PS_ENDCAP_MASK = 0x00000F00 +) + +// Pen join types +const ( + PS_JOIN_ROUND = 0x00000000 + PS_JOIN_BEVEL = 0x00001000 + PS_JOIN_MITER = 0x00002000 + PS_JOIN_MASK = 0x0000F000 +) + +// Print constants +const ( + PRF_NONCLIENT = 0x00000002 + PRF_CLIENT = 0x00000004 + PRF_ERASEBKGND = 0x00000008 + PRF_CHILDREN = 0x00000010 + PRF_OWNED = 0x00000020 +) + +// Stock logical objects +const ( + WHITE_BRUSH = 0 + LTGRAY_BRUSH = 1 + GRAY_BRUSH = 2 + DKGRAY_BRUSH = 3 + BLACK_BRUSH = 4 + NULL_BRUSH = 5 + HOLLOW_BRUSH = NULL_BRUSH + WHITE_PEN = 6 + BLACK_PEN = 7 + NULL_PEN = 8 + OEM_FIXED_FONT = 10 + ANSI_FIXED_FONT = 11 + ANSI_VAR_FONT = 12 + SYSTEM_FONT = 13 + DEVICE_DEFAULT_FONT = 14 + DEFAULT_PALETTE = 15 + SYSTEM_FIXED_FONT = 16 + DEFAULT_GUI_FONT = 17 + DC_BRUSH = 18 + DC_PEN = 19 +) + +const LF_FACESIZE = 32 + +// Font weight constants +const ( + FW_DONTCARE = 0 + FW_THIN = 100 + FW_EXTRALIGHT = 200 + FW_ULTRALIGHT = FW_EXTRALIGHT + FW_LIGHT = 300 + FW_NORMAL = 400 + FW_REGULAR = 400 + FW_MEDIUM = 500 + FW_SEMIBOLD = 600 + FW_DEMIBOLD = FW_SEMIBOLD + FW_BOLD = 700 + FW_EXTRABOLD = 800 + FW_ULTRABOLD = FW_EXTRABOLD + FW_HEAVY = 900 + FW_BLACK = FW_HEAVY +) + +// Charset constants +const ( + ANSI_CHARSET = 0 + DEFAULT_CHARSET = 1 + SYMBOL_CHARSET = 2 + SHIFTJIS_CHARSET = 128 + HANGEUL_CHARSET = 129 + HANGUL_CHARSET = 129 + GB2312_CHARSET = 134 + CHINESEBIG5_CHARSET = 136 + GREEK_CHARSET = 161 + TURKISH_CHARSET = 162 + HEBREW_CHARSET = 177 + ARABIC_CHARSET = 178 + BALTIC_CHARSET = 186 + RUSSIAN_CHARSET = 204 + THAI_CHARSET = 222 + EASTEUROPE_CHARSET = 238 + OEM_CHARSET = 255 + JOHAB_CHARSET = 130 + VIETNAMESE_CHARSET = 163 + MAC_CHARSET = 77 +) + +// Font output precision constants +const ( + OUT_DEFAULT_PRECIS = 0 + OUT_STRING_PRECIS = 1 + OUT_CHARACTER_PRECIS = 2 + OUT_STROKE_PRECIS = 3 + OUT_TT_PRECIS = 4 + OUT_DEVICE_PRECIS = 5 + OUT_RASTER_PRECIS = 6 + OUT_TT_ONLY_PRECIS = 7 + OUT_OUTLINE_PRECIS = 8 + OUT_PS_ONLY_PRECIS = 10 +) + +// Font clipping precision constants +const ( + CLIP_DEFAULT_PRECIS = 0 + CLIP_CHARACTER_PRECIS = 1 + CLIP_STROKE_PRECIS = 2 + CLIP_MASK = 15 + CLIP_LH_ANGLES = 16 + CLIP_TT_ALWAYS = 32 + CLIP_EMBEDDED = 128 +) + +// Font output quality constants +const ( + DEFAULT_QUALITY = 0 + DRAFT_QUALITY = 1 + PROOF_QUALITY = 2 + NONANTIALIASED_QUALITY = 3 + ANTIALIASED_QUALITY = 4 + CLEARTYPE_QUALITY = 5 +) + +// Font pitch constants +const ( + DEFAULT_PITCH = 0 + FIXED_PITCH = 1 + VARIABLE_PITCH = 2 +) + +// Font family constants +const ( + FF_DECORATIVE = 80 + FF_DONTCARE = 0 + FF_MODERN = 48 + FF_ROMAN = 16 + FF_SCRIPT = 64 + FF_SWISS = 32 +) + +// DeviceCapabilities capabilities +const ( + DC_FIELDS = 1 + DC_PAPERS = 2 + DC_PAPERSIZE = 3 + DC_MINEXTENT = 4 + DC_MAXEXTENT = 5 + DC_BINS = 6 + DC_DUPLEX = 7 + DC_SIZE = 8 + DC_EXTRA = 9 + DC_VERSION = 10 + DC_DRIVER = 11 + DC_BINNAMES = 12 + DC_ENUMRESOLUTIONS = 13 + DC_FILEDEPENDENCIES = 14 + DC_TRUETYPE = 15 + DC_PAPERNAMES = 16 + DC_ORIENTATION = 17 + DC_COPIES = 18 + DC_BINADJUST = 19 + DC_EMF_COMPLIANT = 20 + DC_DATATYPE_PRODUCED = 21 + DC_COLLATE = 22 + DC_MANUFACTURER = 23 + DC_MODEL = 24 + DC_PERSONALITY = 25 + DC_PRINTRATE = 26 + DC_PRINTRATEUNIT = 27 + DC_PRINTERMEM = 28 + DC_MEDIAREADY = 29 + DC_STAPLE = 30 + DC_PRINTRATEPPM = 31 + DC_COLORDEVICE = 32 + DC_NUP = 33 + DC_MEDIATYPENAMES = 34 + DC_MEDIATYPES = 35 +) + +const ( + CCHDEVICENAME = 32 + CCHFORMNAME = 32 +) + +const ( + DM_UPDATE = 1 + DM_COPY = 2 + DM_PROMPT = 4 + DM_MODIFY = 8 + DM_IN_BUFFER = DM_MODIFY + DM_IN_PROMPT = DM_PROMPT + DM_OUT_BUFFER = DM_COPY + DM_OUT_DEFAULT = DM_UPDATE +) + +// DEVMODE field selection bits +const ( + DM_ORIENTATION = 0x00000001 + DM_PAPERSIZE = 0x00000002 + DM_PAPERLENGTH = 0x00000004 + DM_PAPERWIDTH = 0x00000008 + DM_SCALE = 0x00000010 + DM_POSITION = 0x00000020 + DM_NUP = 0x00000040 + DM_DISPLAYORIENTATION = 0x00000080 + DM_COPIES = 0x00000100 + DM_DEFAULTSOURCE = 0x00000200 + DM_PRINTQUALITY = 0x00000400 + DM_COLOR = 0x00000800 + DM_DUPLEX = 0x00001000 + DM_YRESOLUTION = 0x00002000 + DM_TTOPTION = 0x00004000 + DM_COLLATE = 0x00008000 + DM_FORMNAME = 0x00010000 + DM_LOGPIXELS = 0x00020000 + DM_BITSPERPEL = 0x00040000 + DM_PELSWIDTH = 0x00080000 + DM_PELSHEIGHT = 0x00100000 + DM_DISPLAYFLAGS = 0x00200000 + DM_DISPLAYFREQUENCY = 0x00400000 + DM_ICMMETHOD = 0x00800000 + DM_ICMINTENT = 0x01000000 + DM_MEDIATYPE = 0x02000000 + DM_DITHERTYPE = 0x04000000 + DM_PANNINGWIDTH = 0x08000000 + DM_PANNINGHEIGHT = 0x10000000 + DM_DISPLAYFIXEDOUTPUT = 0x20000000 +) + +// Orientation constants +const ( + DMORIENT_PORTRAIT = 1 + DMORIENT_LANDSCAPE = 2 +) + +// Paper sizes +const ( + DMPAPER_FIRST = DMPAPER_LETTER + DMPAPER_LETTER = 1 /* Letter 8 1/2 x 11 in */ + DMPAPER_LETTERSMALL = 2 /* Letter Small 8 1/2 x 11 in */ + DMPAPER_TABLOID = 3 /* Tabloid 11 x 17 in */ + DMPAPER_LEDGER = 4 /* Ledger 17 x 11 in */ + DMPAPER_LEGAL = 5 /* Legal 8 1/2 x 14 in */ + DMPAPER_STATEMENT = 6 /* Statement 5 1/2 x 8 1/2 in */ + DMPAPER_EXECUTIVE = 7 /* Executive 7 1/4 x 10 1/2 in */ + DMPAPER_A3 = 8 /* A3 297 x 420 mm */ + DMPAPER_A4 = 9 /* A4 210 x 297 mm */ + DMPAPER_A4SMALL = 10 /* A4 Small 210 x 297 mm */ + DMPAPER_A5 = 11 /* A5 148 x 210 mm */ + DMPAPER_B4 = 12 /* B4 (JIS) 250 x 354 */ + DMPAPER_B5 = 13 /* B5 (JIS) 182 x 257 mm */ + DMPAPER_FOLIO = 14 /* Folio 8 1/2 x 13 in */ + DMPAPER_QUARTO = 15 /* Quarto 215 x 275 mm */ + DMPAPER_10X14 = 16 /* 10x14 in */ + DMPAPER_11X17 = 17 /* 11x17 in */ + DMPAPER_NOTE = 18 /* Note 8 1/2 x 11 in */ + DMPAPER_ENV_9 = 19 /* Envelope #9 3 7/8 x 8 7/8 */ + DMPAPER_ENV_10 = 20 /* Envelope #10 4 1/8 x 9 1/2 */ + DMPAPER_ENV_11 = 21 /* Envelope #11 4 1/2 x 10 3/8 */ + DMPAPER_ENV_12 = 22 /* Envelope #12 4 \276 x 11 */ + DMPAPER_ENV_14 = 23 /* Envelope #14 5 x 11 1/2 */ + DMPAPER_CSHEET = 24 /* C size sheet */ + DMPAPER_DSHEET = 25 /* D size sheet */ + DMPAPER_ESHEET = 26 /* E size sheet */ + DMPAPER_ENV_DL = 27 /* Envelope DL 110 x 220mm */ + DMPAPER_ENV_C5 = 28 /* Envelope C5 162 x 229 mm */ + DMPAPER_ENV_C3 = 29 /* Envelope C3 324 x 458 mm */ + DMPAPER_ENV_C4 = 30 /* Envelope C4 229 x 324 mm */ + DMPAPER_ENV_C6 = 31 /* Envelope C6 114 x 162 mm */ + DMPAPER_ENV_C65 = 32 /* Envelope C65 114 x 229 mm */ + DMPAPER_ENV_B4 = 33 /* Envelope B4 250 x 353 mm */ + DMPAPER_ENV_B5 = 34 /* Envelope B5 176 x 250 mm */ + DMPAPER_ENV_B6 = 35 /* Envelope B6 176 x 125 mm */ + DMPAPER_ENV_ITALY = 36 /* Envelope 110 x 230 mm */ + DMPAPER_ENV_MONARCH = 37 /* Envelope Monarch 3.875 x 7.5 in */ + DMPAPER_ENV_PERSONAL = 38 /* 6 3/4 Envelope 3 5/8 x 6 1/2 in */ + DMPAPER_FANFOLD_US = 39 /* US Std Fanfold 14 7/8 x 11 in */ + DMPAPER_FANFOLD_STD_GERMAN = 40 /* German Std Fanfold 8 1/2 x 12 in */ + DMPAPER_FANFOLD_LGL_GERMAN = 41 /* German Legal Fanfold 8 1/2 x 13 in */ + DMPAPER_ISO_B4 = 42 /* B4 (ISO) 250 x 353 mm */ + DMPAPER_JAPANESE_POSTCARD = 43 /* Japanese Postcard 100 x 148 mm */ + DMPAPER_9X11 = 44 /* 9 x 11 in */ + DMPAPER_10X11 = 45 /* 10 x 11 in */ + DMPAPER_15X11 = 46 /* 15 x 11 in */ + DMPAPER_ENV_INVITE = 47 /* Envelope Invite 220 x 220 mm */ + DMPAPER_RESERVED_48 = 48 /* RESERVED--DO NOT USE */ + DMPAPER_RESERVED_49 = 49 /* RESERVED--DO NOT USE */ + DMPAPER_LETTER_EXTRA = 50 /* Letter Extra 9 \275 x 12 in */ + DMPAPER_LEGAL_EXTRA = 51 /* Legal Extra 9 \275 x 15 in */ + DMPAPER_TABLOID_EXTRA = 52 /* Tabloid Extra 11.69 x 18 in */ + DMPAPER_A4_EXTRA = 53 /* A4 Extra 9.27 x 12.69 in */ + DMPAPER_LETTER_TRANSVERSE = 54 /* Letter Transverse 8 \275 x 11 in */ + DMPAPER_A4_TRANSVERSE = 55 /* A4 Transverse 210 x 297 mm */ + DMPAPER_LETTER_EXTRA_TRANSVERSE = 56 /* Letter Extra Transverse 9\275 x 12 in */ + DMPAPER_A_PLUS = 57 /* SuperA/SuperA/A4 227 x 356 mm */ + DMPAPER_B_PLUS = 58 /* SuperB/SuperB/A3 305 x 487 mm */ + DMPAPER_LETTER_PLUS = 59 /* Letter Plus 8.5 x 12.69 in */ + DMPAPER_A4_PLUS = 60 /* A4 Plus 210 x 330 mm */ + DMPAPER_A5_TRANSVERSE = 61 /* A5 Transverse 148 x 210 mm */ + DMPAPER_B5_TRANSVERSE = 62 /* B5 (JIS) Transverse 182 x 257 mm */ + DMPAPER_A3_EXTRA = 63 /* A3 Extra 322 x 445 mm */ + DMPAPER_A5_EXTRA = 64 /* A5 Extra 174 x 235 mm */ + DMPAPER_B5_EXTRA = 65 /* B5 (ISO) Extra 201 x 276 mm */ + DMPAPER_A2 = 66 /* A2 420 x 594 mm */ + DMPAPER_A3_TRANSVERSE = 67 /* A3 Transverse 297 x 420 mm */ + DMPAPER_A3_EXTRA_TRANSVERSE = 68 /* A3 Extra Transverse 322 x 445 mm */ + DMPAPER_DBL_JAPANESE_POSTCARD = 69 /* Japanese Double Postcard 200 x 148 mm */ + DMPAPER_A6 = 70 /* A6 105 x 148 mm */ + DMPAPER_JENV_KAKU2 = 71 /* Japanese Envelope Kaku #2 */ + DMPAPER_JENV_KAKU3 = 72 /* Japanese Envelope Kaku #3 */ + DMPAPER_JENV_CHOU3 = 73 /* Japanese Envelope Chou #3 */ + DMPAPER_JENV_CHOU4 = 74 /* Japanese Envelope Chou #4 */ + DMPAPER_LETTER_ROTATED = 75 /* Letter Rotated 11 x 8 1/2 11 in */ + DMPAPER_A3_ROTATED = 76 /* A3 Rotated 420 x 297 mm */ + DMPAPER_A4_ROTATED = 77 /* A4 Rotated 297 x 210 mm */ + DMPAPER_A5_ROTATED = 78 /* A5 Rotated 210 x 148 mm */ + DMPAPER_B4_JIS_ROTATED = 79 /* B4 (JIS) Rotated 364 x 257 mm */ + DMPAPER_B5_JIS_ROTATED = 80 /* B5 (JIS) Rotated 257 x 182 mm */ + DMPAPER_JAPANESE_POSTCARD_ROTATED = 81 /* Japanese Postcard Rotated 148 x 100 mm */ + DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED = 82 /* Double Japanese Postcard Rotated 148 x 200 mm */ + DMPAPER_A6_ROTATED = 83 /* A6 Rotated 148 x 105 mm */ + DMPAPER_JENV_KAKU2_ROTATED = 84 /* Japanese Envelope Kaku #2 Rotated */ + DMPAPER_JENV_KAKU3_ROTATED = 85 /* Japanese Envelope Kaku #3 Rotated */ + DMPAPER_JENV_CHOU3_ROTATED = 86 /* Japanese Envelope Chou #3 Rotated */ + DMPAPER_JENV_CHOU4_ROTATED = 87 /* Japanese Envelope Chou #4 Rotated */ + DMPAPER_B6_JIS = 88 /* B6 (JIS) 128 x 182 mm */ + DMPAPER_B6_JIS_ROTATED = 89 /* B6 (JIS) Rotated 182 x 128 mm */ + DMPAPER_12X11 = 90 /* 12 x 11 in */ + DMPAPER_JENV_YOU4 = 91 /* Japanese Envelope You #4 */ + DMPAPER_JENV_YOU4_ROTATED = 92 /* Japanese Envelope You #4 Rotated*/ + DMPAPER_P16K = 93 /* PRC 16K 146 x 215 mm */ + DMPAPER_P32K = 94 /* PRC 32K 97 x 151 mm */ + DMPAPER_P32KBIG = 95 /* PRC 32K(Big) 97 x 151 mm */ + DMPAPER_PENV_1 = 96 /* PRC Envelope #1 102 x 165 mm */ + DMPAPER_PENV_2 = 97 /* PRC Envelope #2 102 x 176 mm */ + DMPAPER_PENV_3 = 98 /* PRC Envelope #3 125 x 176 mm */ + DMPAPER_PENV_4 = 99 /* PRC Envelope #4 110 x 208 mm */ + DMPAPER_PENV_5 = 100 /* PRC Envelope #5 110 x 220 mm */ + DMPAPER_PENV_6 = 101 /* PRC Envelope #6 120 x 230 mm */ + DMPAPER_PENV_7 = 102 /* PRC Envelope #7 160 x 230 mm */ + DMPAPER_PENV_8 = 103 /* PRC Envelope #8 120 x 309 mm */ + DMPAPER_PENV_9 = 104 /* PRC Envelope #9 229 x 324 mm */ + DMPAPER_PENV_10 = 105 /* PRC Envelope #10 324 x 458 mm */ + DMPAPER_P16K_ROTATED = 106 /* PRC 16K Rotated */ + DMPAPER_P32K_ROTATED = 107 /* PRC 32K Rotated */ + DMPAPER_P32KBIG_ROTATED = 108 /* PRC 32K(Big) Rotated */ + DMPAPER_PENV_1_ROTATED = 109 /* PRC Envelope #1 Rotated 165 x 102 mm */ + DMPAPER_PENV_2_ROTATED = 110 /* PRC Envelope #2 Rotated 176 x 102 mm */ + DMPAPER_PENV_3_ROTATED = 111 /* PRC Envelope #3 Rotated 176 x 125 mm */ + DMPAPER_PENV_4_ROTATED = 112 /* PRC Envelope #4 Rotated 208 x 110 mm */ + DMPAPER_PENV_5_ROTATED = 113 /* PRC Envelope #5 Rotated 220 x 110 mm */ + DMPAPER_PENV_6_ROTATED = 114 /* PRC Envelope #6 Rotated 230 x 120 mm */ + DMPAPER_PENV_7_ROTATED = 115 /* PRC Envelope #7 Rotated 230 x 160 mm */ + DMPAPER_PENV_8_ROTATED = 116 /* PRC Envelope #8 Rotated 309 x 120 mm */ + DMPAPER_PENV_9_ROTATED = 117 /* PRC Envelope #9 Rotated 324 x 229 mm */ + DMPAPER_PENV_10_ROTATED = 118 /* PRC Envelope #10 Rotated 458 x 324 mm */ + DMPAPER_LAST = DMPAPER_PENV_10_ROTATED + DMPAPER_USER = 256 +) + +// Bin constants +const ( + DMBIN_FIRST = DMBIN_UPPER + DMBIN_UPPER = 1 + DMBIN_ONLYONE = 1 + DMBIN_LOWER = 2 + DMBIN_MIDDLE = 3 + DMBIN_MANUAL = 4 + DMBIN_ENVELOPE = 5 + DMBIN_ENVMANUAL = 6 + DMBIN_AUTO = 7 + DMBIN_TRACTOR = 8 + DMBIN_SMALLFMT = 9 + DMBIN_LARGEFMT = 10 + DMBIN_LARGECAPACITY = 11 + DMBIN_CASSETTE = 14 + DMBIN_FORMSOURCE = 15 + DMBIN_LAST = DMBIN_FORMSOURCE + DMBIN_USER = 256 +) + +// Quality constants +const ( + DMRES_DRAFT = -1 + DMRES_LOW = -2 + DMRES_MEDIUM = -3 + DMRES_HIGH = -4 +) + +// Color/monochrome constants +const ( + DMCOLOR_MONOCHROME = 1 + DMCOLOR_COLOR = 2 +) + +// Duplex constants +const ( + DMDUP_SIMPLEX = 1 + DMDUP_VERTICAL = 2 + DMDUP_HORIZONTAL = 3 +) + +// TrueType constants +const ( + DMTT_BITMAP = 1 + DMTT_DOWNLOAD = 2 + DMTT_SUBDEV = 3 + DMTT_DOWNLOAD_OUTLINE = 4 +) + +// Collation constants +const ( + DMCOLLATE_FALSE = 0 + DMCOLLATE_TRUE = 1 +) + +// Background modes +const ( + TRANSPARENT = 1 + OPAQUE = 2 +) + +// Ternary raster operations +const ( + SRCCOPY = 0x00CC0020 + SRCPAINT = 0x00EE0086 + SRCAND = 0x008800C6 + SRCINVERT = 0x00660046 + SRCERASE = 0x00440328 + NOTSRCCOPY = 0x00330008 + NOTSRCERASE = 0x001100A6 + MERGECOPY = 0x00C000CA + MERGEPAINT = 0x00BB0226 + PATCOPY = 0x00F00021 + PATPAINT = 0x00FB0A09 + PATINVERT = 0x005A0049 + DSTINVERT = 0x00550009 + BLACKNESS = 0x00000042 + WHITENESS = 0x00FF0062 + NOMIRRORBITMAP = 0x80000000 + CAPTUREBLT = 0x40000000 +) + +// StretchBlt modes +const ( + BLACKONWHITE = 1 + WHITEONBLACK = 2 + COLORONCOLOR = 3 + HALFTONE = 4 + MAXSTRETCHBLTMODE = 4 + STRETCH_ANDSCANS = BLACKONWHITE + STRETCH_ORSCANS = WHITEONBLACK + STRETCH_DELETESCANS = COLORONCOLOR + STRETCH_HALFTONE = HALFTONE +) + +// Bitmap compression constants +const ( + BI_RGB = 0 + BI_RLE8 = 1 + BI_RLE4 = 2 + BI_BITFIELDS = 3 + BI_JPEG = 4 + BI_PNG = 5 +) + +// Bitmap color table usage +const ( + DIB_RGB_COLORS = 0 + DIB_PAL_COLORS = 1 +) + +const CBM_INIT = 4 + +const CLR_INVALID = 0xFFFFFFFF + +const ( + /* pixel types */ + PFD_TYPE_RGBA = 0 + PFD_TYPE_COLORINDEX = 1 + + /* layer types */ + PFD_MAIN_PLANE = 0 + PFD_OVERLAY_PLANE = 1 + PFD_UNDERLAY_PLANE = (-1) + + /* PIXELFORMATDESCRIPTOR flags */ + PFD_DOUBLEBUFFER = 0x00000001 + PFD_STEREO = 0x00000002 + PFD_DRAW_TO_WINDOW = 0x00000004 + PFD_DRAW_TO_BITMAP = 0x00000008 + PFD_SUPPORT_GDI = 0x00000010 + PFD_SUPPORT_OPENGL = 0x00000020 + PFD_GENERIC_FORMAT = 0x00000040 + PFD_NEED_PALETTE = 0x00000080 + PFD_NEED_SYSTEM_PALETTE = 0x00000100 + PFD_SWAP_EXCHANGE = 0x00000200 + PFD_SWAP_COPY = 0x00000400 + PFD_SWAP_LAYER_BUFFERS = 0x00000800 + PFD_GENERIC_ACCELERATED = 0x00001000 + PFD_SUPPORT_DIRECTDRAW = 0x00002000 + + /* PIXELFORMATDESCRIPTOR flags for use in ChoosePixelFormat only */ + PFD_DEPTH_DONTCARE = 0x20000000 + PFD_DOUBLEBUFFER_DONTCARE = 0x40000000 + PFD_STEREO_DONTCARE = 0x80000000 +) + +// GradientFill constants +const ( + GRADIENT_FILL_RECT_H = 0x00 + GRADIENT_FILL_RECT_V = 0x01 + GRADIENT_FILL_TRIANGLE = 0x02 +) + +// Region Combine Modes +const ( + RGN_AND = 1 + RGN_OR = 2 + RGN_XOR = 3 + RGN_DIFF = 4 + RGN_COPY = 5 +) + +// Region Types +const ( + REGIONERROR = 0 + NULLREGION = 1 + SIMPLEREGION = 2 + COMPLEXREGION = 3 +) + +// AlphaBlend operations +const ( + AC_SRC_ALPHA = 0x1 +) + +// AddFontResourceEx flags +const ( + FR_PRIVATE = 0x10 + FR_NOT_ENUM = 0x20 +) + +type ( + COLORREF uint32 + HBITMAP HGDIOBJ + HBRUSH HGDIOBJ + HDC HANDLE + HFONT HGDIOBJ + HGDIOBJ HANDLE + HENHMETAFILE HANDLE + HPALETTE HGDIOBJ + HPEN HGDIOBJ + HRGN HGDIOBJ +) + +type PIXELFORMATDESCRIPTOR struct { + NSize uint16 + NVersion uint16 + DwFlags uint32 + IPixelType byte + CColorBits byte + CRedBits byte + CRedShift byte + CGreenBits byte + CGreenShift byte + CBlueBits byte + CBlueShift byte + CAlphaBits byte + CAlphaShift byte + CAccumBits byte + CAccumRedBits byte + CAccumGreenBits byte + CAccumBlueBits byte + CAccumAlphaBits byte + CDepthBits byte + CStencilBits byte + CAuxBuffers byte + ILayerType byte + BReserved byte + DwLayerMask uint32 + DwVisibleMask uint32 + DwDamageMask uint32 +} + +type LOGFONT struct { + LfHeight int32 + LfWidth int32 + LfEscapement int32 + LfOrientation int32 + LfWeight int32 + LfItalic byte + LfUnderline byte + LfStrikeOut byte + LfCharSet byte + LfOutPrecision byte + LfClipPrecision byte + LfQuality byte + LfPitchAndFamily byte + LfFaceName [LF_FACESIZE]uint16 +} + +type TEXTMETRIC struct { + TmHeight int32 + TmAscent int32 + TmDescent int32 + TmInternalLeading int32 + TmExternalLeading int32 + TmAveCharWidth int32 + TmMaxCharWidth int32 + TmWeight int32 + TmOverhang int32 + TmDigitizedAspectX int32 + TmDigitizedAspectY int32 + TmFirstChar uint16 + TmLastChar uint16 + TmDefaultChar uint16 + TmBreakChar uint16 + TmItalic byte + TmUnderlined byte + TmStruckOut byte + TmPitchAndFamily byte + TmCharSet byte +} + +type DEVMODE struct { + DmDeviceName [CCHDEVICENAME]uint16 + DmSpecVersion uint16 + DmDriverVersion uint16 + DmSize uint16 + DmDriverExtra uint16 + DmFields uint32 + DmOrientation int16 + DmPaperSize int16 + DmPaperLength int16 + DmPaperWidth int16 + DmScale int16 + DmCopies int16 + DmDefaultSource int16 + DmPrintQuality int16 + DmColor int16 + DmDuplex int16 + DmYResolution int16 + DmTTOption int16 + DmCollate int16 + DmFormName [CCHFORMNAME]uint16 + DmLogPixels uint16 + DmBitsPerPel uint32 + DmPelsWidth uint32 + DmPelsHeight uint32 + DmDisplayFlags uint32 + DmDisplayFrequency uint32 + DmICMMethod uint32 + DmICMIntent uint32 + DmMediaType uint32 + DmDitherType uint32 + DmReserved1 uint32 + DmReserved2 uint32 + DmPanningWidth uint32 + DmPanningHeight uint32 +} + +type POINT struct { + X, Y int32 +} + +type RECT struct { + Left, Top, Right, Bottom int32 +} + +type SIZE struct { + CX, CY int32 +} + +type DOCINFO struct { + CbSize int32 + LpszDocName *uint16 + LpszOutput *uint16 + LpszDatatype *uint16 + FwType uint32 +} + +type LOGBRUSH struct { + LbStyle uint32 + LbColor COLORREF + LbHatch uintptr +} + +type CIEXYZ struct { + CiexyzX, CiexyzY, CiexyzZ int32 // FXPT2DOT30 +} + +type CIEXYZTRIPLE struct { + CiexyzRed, CiexyzGreen, CiexyzBlue CIEXYZ +} + +type BITMAPINFOHEADER struct { + BiSize uint32 + BiWidth int32 + BiHeight int32 + BiPlanes uint16 + BiBitCount uint16 + BiCompression uint32 + BiSizeImage uint32 + BiXPelsPerMeter int32 + BiYPelsPerMeter int32 + BiClrUsed uint32 + BiClrImportant uint32 +} + +type BITMAPV4HEADER struct { + BITMAPINFOHEADER + BV4RedMask uint32 + BV4GreenMask uint32 + BV4BlueMask uint32 + BV4AlphaMask uint32 + BV4CSType uint32 + BV4Endpoints CIEXYZTRIPLE + BV4GammaRed uint32 + BV4GammaGreen uint32 + BV4GammaBlue uint32 +} + +type BITMAPV5HEADER struct { + BITMAPV4HEADER + BV5Intent uint32 + BV5ProfileData uint32 + BV5ProfileSize uint32 + BV5Reserved uint32 +} + +type RGBQUAD struct { + RgbBlue byte + RgbGreen byte + RgbRed byte + RgbReserved byte +} + +type BITMAPINFO struct { + BmiHeader BITMAPINFOHEADER + BmiColors *RGBQUAD +} + +type BITMAP struct { + BmType int32 + BmWidth int32 + BmHeight int32 + BmWidthBytes int32 + BmPlanes uint16 + BmBitsPixel uint16 + BmBits unsafe.Pointer +} + +type DIBSECTION struct { + DsBm BITMAP + DsBmih BITMAPINFOHEADER + DsBitfields [3]uint32 + DshSection HANDLE + DsOffset uint32 +} + +type ENHMETAHEADER struct { + IType uint32 + NSize uint32 + RclBounds RECT + RclFrame RECT + DSignature uint32 + NVersion uint32 + NBytes uint32 + NRecords uint32 + NHandles uint16 + SReserved uint16 + NDescription uint32 + OffDescription uint32 + NPalEntries uint32 + SzlDevice SIZE + SzlMillimeters SIZE + CbPixelFormat uint32 + OffPixelFormat uint32 + BOpenGL uint32 + SzlMicrometers SIZE +} + +type TRIVERTEX struct { + X int32 + Y int32 + Red uint16 + Green uint16 + Blue uint16 + Alpha uint16 +} + +type GRADIENT_RECT struct { + UpperLeft uint32 + LowerRight uint32 +} + +type GRADIENT_TRIANGLE struct { + Vertex1 uint32 + Vertex2 uint32 + Vertex3 uint32 +} + +type BLENDFUNCTION struct { + BlendOp byte + BlendFlags byte + SourceConstantAlpha byte + AlphaFormat byte +} + +var ( + // Library + libgdi32 uintptr + libmsimg32 uintptr + + // Functions + abortDoc uintptr + addFontResourceEx uintptr + alphaBlend uintptr + bitBlt uintptr + choosePixelFormat uintptr + closeEnhMetaFile uintptr + combineRgn uintptr + copyEnhMetaFile uintptr + createBitmap uintptr + createCompatibleBitmap uintptr + createBrushIndirect uintptr + createCompatibleDC uintptr + createDC uintptr + createDIBSection uintptr + createFontIndirect uintptr + createEnhMetaFile uintptr + createIC uintptr + createPatternBrush uintptr + createRectRgn uintptr + deleteDC uintptr + deleteEnhMetaFile uintptr + deleteObject uintptr + ellipse uintptr + endDoc uintptr + endPage uintptr + excludeClipRect uintptr + extCreatePen uintptr + fillRgn uintptr + gdiFlush uintptr + getBkColor uintptr + getDeviceCaps uintptr + getDIBits uintptr + getEnhMetaFile uintptr + getEnhMetaFileHeader uintptr + getObject uintptr + getPixel uintptr + getRgnBox uintptr + getStockObject uintptr + getTextColor uintptr + getTextExtentExPoint uintptr + getTextExtentPoint32 uintptr + getTextMetrics uintptr + getViewportOrgEx uintptr + gradientFill uintptr + intersectClipRect uintptr + lineTo uintptr + moveToEx uintptr + playEnhMetaFile uintptr + polyline uintptr + rectangle uintptr + removeFontResourceEx uintptr + resetDC uintptr + restoreDC uintptr + roundRect uintptr + selectObject uintptr + setBkColor uintptr + setBkMode uintptr + setBrushOrgEx uintptr + setDIBits uintptr + setPixel uintptr + setPixelFormat uintptr + setStretchBltMode uintptr + setTextColor uintptr + setViewportOrgEx uintptr + saveDC uintptr + startDoc uintptr + startPage uintptr + stretchBlt uintptr + swapBuffers uintptr + textOut uintptr + transparentBlt uintptr +) + +func init() { + // Library + libgdi32 = MustLoadLibrary("gdi32.dll") + libmsimg32 = MustLoadLibrary("msimg32.dll") + + // Functions + abortDoc = MustGetProcAddress(libgdi32, "AbortDoc") + addFontResourceEx = MustGetProcAddress(libgdi32, "AddFontResourceExW") + bitBlt = MustGetProcAddress(libgdi32, "BitBlt") + choosePixelFormat = MustGetProcAddress(libgdi32, "ChoosePixelFormat") + closeEnhMetaFile = MustGetProcAddress(libgdi32, "CloseEnhMetaFile") + combineRgn = MustGetProcAddress(libgdi32, "CombineRgn") + copyEnhMetaFile = MustGetProcAddress(libgdi32, "CopyEnhMetaFileW") + createBitmap = MustGetProcAddress(libgdi32, "CreateBitmap") + createCompatibleBitmap = MustGetProcAddress(libgdi32, "CreateCompatibleBitmap") + createBrushIndirect = MustGetProcAddress(libgdi32, "CreateBrushIndirect") + createCompatibleDC = MustGetProcAddress(libgdi32, "CreateCompatibleDC") + createDC = MustGetProcAddress(libgdi32, "CreateDCW") + createDIBSection = MustGetProcAddress(libgdi32, "CreateDIBSection") + createEnhMetaFile = MustGetProcAddress(libgdi32, "CreateEnhMetaFileW") + createFontIndirect = MustGetProcAddress(libgdi32, "CreateFontIndirectW") + createIC = MustGetProcAddress(libgdi32, "CreateICW") + createPatternBrush = MustGetProcAddress(libgdi32, "CreatePatternBrush") + createRectRgn = MustGetProcAddress(libgdi32, "CreateRectRgn") + deleteDC = MustGetProcAddress(libgdi32, "DeleteDC") + deleteEnhMetaFile = MustGetProcAddress(libgdi32, "DeleteEnhMetaFile") + deleteObject = MustGetProcAddress(libgdi32, "DeleteObject") + ellipse = MustGetProcAddress(libgdi32, "Ellipse") + endDoc = MustGetProcAddress(libgdi32, "EndDoc") + endPage = MustGetProcAddress(libgdi32, "EndPage") + excludeClipRect = MustGetProcAddress(libgdi32, "ExcludeClipRect") + extCreatePen = MustGetProcAddress(libgdi32, "ExtCreatePen") + fillRgn = MustGetProcAddress(libgdi32, "FillRgn") + gdiFlush = MustGetProcAddress(libgdi32, "GdiFlush") + getBkColor = MustGetProcAddress(libgdi32, "GetBkColor") + getDeviceCaps = MustGetProcAddress(libgdi32, "GetDeviceCaps") + getDIBits = MustGetProcAddress(libgdi32, "GetDIBits") + getEnhMetaFile = MustGetProcAddress(libgdi32, "GetEnhMetaFileW") + getEnhMetaFileHeader = MustGetProcAddress(libgdi32, "GetEnhMetaFileHeader") + getObject = MustGetProcAddress(libgdi32, "GetObjectW") + getPixel = MustGetProcAddress(libgdi32, "GetPixel") + getRgnBox = MustGetProcAddress(libgdi32, "GetRgnBox") + getStockObject = MustGetProcAddress(libgdi32, "GetStockObject") + getTextColor = MustGetProcAddress(libgdi32, "GetTextColor") + getTextExtentExPoint = MustGetProcAddress(libgdi32, "GetTextExtentExPointW") + getTextExtentPoint32 = MustGetProcAddress(libgdi32, "GetTextExtentPoint32W") + getTextMetrics = MustGetProcAddress(libgdi32, "GetTextMetricsW") + getViewportOrgEx = MustGetProcAddress(libgdi32, "GetViewportOrgEx") + intersectClipRect = MustGetProcAddress(libgdi32, "IntersectClipRect") + lineTo = MustGetProcAddress(libgdi32, "LineTo") + moveToEx = MustGetProcAddress(libgdi32, "MoveToEx") + playEnhMetaFile = MustGetProcAddress(libgdi32, "PlayEnhMetaFile") + polyline = MustGetProcAddress(libgdi32, "Polyline") + rectangle = MustGetProcAddress(libgdi32, "Rectangle") + removeFontResourceEx = MustGetProcAddress(libgdi32, "RemoveFontResourceExW") + resetDC = MustGetProcAddress(libgdi32, "ResetDCW") + restoreDC = MustGetProcAddress(libgdi32, "RestoreDC") + roundRect = MustGetProcAddress(libgdi32, "RoundRect") + saveDC = MustGetProcAddress(libgdi32, "SaveDC") + selectObject = MustGetProcAddress(libgdi32, "SelectObject") + setBkColor = MustGetProcAddress(libgdi32, "SetBkColor") + setBkMode = MustGetProcAddress(libgdi32, "SetBkMode") + setBrushOrgEx = MustGetProcAddress(libgdi32, "SetBrushOrgEx") + setDIBits = MustGetProcAddress(libgdi32, "SetDIBits") + setPixel = MustGetProcAddress(libgdi32, "SetPixel") + setPixelFormat = MustGetProcAddress(libgdi32, "SetPixelFormat") + setStretchBltMode = MustGetProcAddress(libgdi32, "SetStretchBltMode") + setTextColor = MustGetProcAddress(libgdi32, "SetTextColor") + setViewportOrgEx = MustGetProcAddress(libgdi32, "SetViewportOrgEx") + startDoc = MustGetProcAddress(libgdi32, "StartDocW") + startPage = MustGetProcAddress(libgdi32, "StartPage") + stretchBlt = MustGetProcAddress(libgdi32, "StretchBlt") + swapBuffers = MustGetProcAddress(libgdi32, "SwapBuffers") + textOut = MustGetProcAddress(libgdi32, "TextOutW") + + alphaBlend = MustGetProcAddress(libmsimg32, "AlphaBlend") + gradientFill = MustGetProcAddress(libmsimg32, "GradientFill") + transparentBlt = MustGetProcAddress(libmsimg32, "TransparentBlt") +} + +func AbortDoc(hdc HDC) int32 { + ret, _, _ := syscall.Syscall(abortDoc, 1, + uintptr(hdc), + 0, + 0) + + return int32(ret) +} + +func AddFontResourceEx(lpszFilename *uint16, fl uint32, pdv unsafe.Pointer) int32 { + ret, _, _ := syscall.Syscall(addFontResourceEx, 3, + uintptr(unsafe.Pointer(lpszFilename)), + uintptr(fl), + uintptr(pdv)) + + return int32(ret) +} + +func AlphaBlend(hdcDest HDC, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest int32, hdcSrc HDC, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc int32, ftn BLENDFUNCTION) bool { + ret, _, _ := syscall.Syscall12(alphaBlend, 11, + uintptr(hdcDest), + uintptr(nXOriginDest), + uintptr(nYOriginDest), + uintptr(nWidthDest), + uintptr(nHeightDest), + uintptr(hdcSrc), + uintptr(nXOriginSrc), + uintptr(nYOriginSrc), + uintptr(nWidthSrc), + uintptr(nHeightSrc), + uintptr(*(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(&ftn))))), + 0) + + return ret != 0 +} + +func BitBlt(hdcDest HDC, nXDest, nYDest, nWidth, nHeight int32, hdcSrc HDC, nXSrc, nYSrc int32, dwRop uint32) bool { + ret, _, _ := syscall.Syscall9(bitBlt, 9, + uintptr(hdcDest), + uintptr(nXDest), + uintptr(nYDest), + uintptr(nWidth), + uintptr(nHeight), + uintptr(hdcSrc), + uintptr(nXSrc), + uintptr(nYSrc), + uintptr(dwRop)) + + return ret != 0 +} + +func ChoosePixelFormat(hdc HDC, ppfd *PIXELFORMATDESCRIPTOR) int32 { + ret, _, _ := syscall.Syscall(choosePixelFormat, 2, + uintptr(hdc), + uintptr(unsafe.Pointer(ppfd)), + 0) + + return int32(ret) +} + +func CloseEnhMetaFile(hdc HDC) HENHMETAFILE { + ret, _, _ := syscall.Syscall(closeEnhMetaFile, 1, + uintptr(hdc), + 0, + 0) + + return HENHMETAFILE(ret) +} + +func CombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2 HRGN, fnCombineMode int32) int32 { + ret, _, _ := syscall.Syscall6(combineRgn, 4, + uintptr(hrgnDest), + uintptr(hrgnSrc1), + uintptr(hrgnSrc2), + uintptr(fnCombineMode), + 0, + 0) + + return int32(ret) +} + +func CopyEnhMetaFile(hemfSrc HENHMETAFILE, lpszFile *uint16) HENHMETAFILE { + ret, _, _ := syscall.Syscall(copyEnhMetaFile, 2, + uintptr(hemfSrc), + uintptr(unsafe.Pointer(lpszFile)), + 0) + + return HENHMETAFILE(ret) +} + +func CreateBitmap(nWidth, nHeight int32, cPlanes, cBitsPerPel uint32, lpvBits unsafe.Pointer) HBITMAP { + ret, _, _ := syscall.Syscall6(createBitmap, 5, + uintptr(nWidth), + uintptr(nHeight), + uintptr(cPlanes), + uintptr(cBitsPerPel), + uintptr(lpvBits), + 0) + + return HBITMAP(ret) +} + +func CreateCompatibleBitmap(hdc HDC, nWidth, nHeight int32) HBITMAP { + ret, _, _ := syscall.Syscall(createCompatibleBitmap, 3, + uintptr(hdc), + uintptr(nWidth), + uintptr(nHeight)) + + return HBITMAP(ret) +} + +func CreateBrushIndirect(lplb *LOGBRUSH) HBRUSH { + ret, _, _ := syscall.Syscall(createBrushIndirect, 1, + uintptr(unsafe.Pointer(lplb)), + 0, + 0) + + return HBRUSH(ret) +} + +func CreateCompatibleDC(hdc HDC) HDC { + ret, _, _ := syscall.Syscall(createCompatibleDC, 1, + uintptr(hdc), + 0, + 0) + + return HDC(ret) +} + +func CreateDC(lpszDriver, lpszDevice, lpszOutput *uint16, lpInitData *DEVMODE) HDC { + ret, _, _ := syscall.Syscall6(createDC, 4, + uintptr(unsafe.Pointer(lpszDriver)), + uintptr(unsafe.Pointer(lpszDevice)), + uintptr(unsafe.Pointer(lpszOutput)), + uintptr(unsafe.Pointer(lpInitData)), + 0, + 0) + + return HDC(ret) +} + +func CreateDIBSection(hdc HDC, pbmih *BITMAPINFOHEADER, iUsage uint32, ppvBits *unsafe.Pointer, hSection HANDLE, dwOffset uint32) HBITMAP { + ret, _, _ := syscall.Syscall6(createDIBSection, 6, + uintptr(hdc), + uintptr(unsafe.Pointer(pbmih)), + uintptr(iUsage), + uintptr(unsafe.Pointer(ppvBits)), + uintptr(hSection), + uintptr(dwOffset)) + + return HBITMAP(ret) +} + +func CreateEnhMetaFile(hdcRef HDC, lpFilename *uint16, lpRect *RECT, lpDescription *uint16) HDC { + ret, _, _ := syscall.Syscall6(createEnhMetaFile, 4, + uintptr(hdcRef), + uintptr(unsafe.Pointer(lpFilename)), + uintptr(unsafe.Pointer(lpRect)), + uintptr(unsafe.Pointer(lpDescription)), + 0, + 0) + + return HDC(ret) +} + +func CreateFontIndirect(lplf *LOGFONT) HFONT { + ret, _, _ := syscall.Syscall(createFontIndirect, 1, + uintptr(unsafe.Pointer(lplf)), + 0, + 0) + + return HFONT(ret) +} + +func CreateIC(lpszDriver, lpszDevice, lpszOutput *uint16, lpdvmInit *DEVMODE) HDC { + ret, _, _ := syscall.Syscall6(createIC, 4, + uintptr(unsafe.Pointer(lpszDriver)), + uintptr(unsafe.Pointer(lpszDevice)), + uintptr(unsafe.Pointer(lpszOutput)), + uintptr(unsafe.Pointer(lpdvmInit)), + 0, + 0) + + return HDC(ret) +} + +func CreatePatternBrush(hbmp HBITMAP) HBRUSH { + ret, _, _ := syscall.Syscall(createPatternBrush, 1, + uintptr(hbmp), + 0, + 0) + + return HBRUSH(ret) +} + +func CreateRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect int32) HRGN { + ret, _, _ := syscall.Syscall6(createRectRgn, 4, + uintptr(nLeftRect), + uintptr(nTopRect), + uintptr(nRightRect), + uintptr(nBottomRect), + 0, + 0) + + return HRGN(ret) +} + +func DeleteDC(hdc HDC) bool { + ret, _, _ := syscall.Syscall(deleteDC, 1, + uintptr(hdc), + 0, + 0) + + return ret != 0 +} + +func DeleteEnhMetaFile(hemf HENHMETAFILE) bool { + ret, _, _ := syscall.Syscall(deleteEnhMetaFile, 1, + uintptr(hemf), + 0, + 0) + + return ret != 0 +} + +func DeleteObject(hObject HGDIOBJ) bool { + ret, _, _ := syscall.Syscall(deleteObject, 1, + uintptr(hObject), + 0, + 0) + + return ret != 0 +} + +func Ellipse(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int32) bool { + ret, _, _ := syscall.Syscall6(ellipse, 5, + uintptr(hdc), + uintptr(nLeftRect), + uintptr(nTopRect), + uintptr(nRightRect), + uintptr(nBottomRect), + 0) + + return ret != 0 +} + +func EndDoc(hdc HDC) int32 { + ret, _, _ := syscall.Syscall(endDoc, 1, + uintptr(hdc), + 0, + 0) + + return int32(ret) +} + +func EndPage(hdc HDC) int32 { + ret, _, _ := syscall.Syscall(endPage, 1, + uintptr(hdc), + 0, + 0) + + return int32(ret) +} + +func ExcludeClipRect(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int32) int32 { + ret, _, _ := syscall.Syscall6(excludeClipRect, 5, + uintptr(hdc), + uintptr(nLeftRect), + uintptr(nTopRect), + uintptr(nRightRect), + uintptr(nBottomRect), + 0) + + return int32(ret) +} + +func ExtCreatePen(dwPenStyle, dwWidth uint32, lplb *LOGBRUSH, dwStyleCount uint32, lpStyle *uint32) HPEN { + ret, _, _ := syscall.Syscall6(extCreatePen, 5, + uintptr(dwPenStyle), + uintptr(dwWidth), + uintptr(unsafe.Pointer(lplb)), + uintptr(dwStyleCount), + uintptr(unsafe.Pointer(lpStyle)), + 0) + + return HPEN(ret) +} + +func FillRgn(hdc HDC, hrgn HRGN, hbr HBRUSH) bool { + ret, _, _ := syscall.Syscall(fillRgn, 3, + uintptr(hdc), + uintptr(hrgn), + uintptr(hbr)) + + return ret != 0 +} + +func GdiFlush() bool { + ret, _, _ := syscall.Syscall(gdiFlush, 0, + 0, + 0, + 0) + + return ret != 0 +} + +func GetBkColor(hdc HDC) COLORREF { + ret, _, _ := syscall.Syscall(getBkColor, 1, + uintptr(hdc), + 0, + 0) + + return COLORREF(ret) +} + +func GetDeviceCaps(hdc HDC, nIndex int32) int32 { + ret, _, _ := syscall.Syscall(getDeviceCaps, 2, + uintptr(hdc), + uintptr(nIndex), + 0) + + return int32(ret) +} + +func GetDIBits(hdc HDC, hbmp HBITMAP, uStartScan uint32, cScanLines uint32, lpvBits *byte, lpbi *BITMAPINFO, uUsage uint32) int32 { + ret, _, _ := syscall.Syscall9(getDIBits, 7, + uintptr(hdc), + uintptr(hbmp), + uintptr(uStartScan), + uintptr(cScanLines), + uintptr(unsafe.Pointer(lpvBits)), + uintptr(unsafe.Pointer(lpbi)), + uintptr(uUsage), + 0, + 0) + return int32(ret) +} + +func GetEnhMetaFile(lpszMetaFile *uint16) HENHMETAFILE { + ret, _, _ := syscall.Syscall(getEnhMetaFile, 1, + uintptr(unsafe.Pointer(lpszMetaFile)), + 0, + 0) + + return HENHMETAFILE(ret) +} + +func GetEnhMetaFileHeader(hemf HENHMETAFILE, cbBuffer uint32, lpemh *ENHMETAHEADER) uint32 { + ret, _, _ := syscall.Syscall(getEnhMetaFileHeader, 3, + uintptr(hemf), + uintptr(cbBuffer), + uintptr(unsafe.Pointer(lpemh))) + + return uint32(ret) +} + +func GetObject(hgdiobj HGDIOBJ, cbBuffer uintptr, lpvObject unsafe.Pointer) int32 { + ret, _, _ := syscall.Syscall(getObject, 3, + uintptr(hgdiobj), + uintptr(cbBuffer), + uintptr(lpvObject)) + + return int32(ret) +} + +func GetPixel(hdc HDC, nXPos, nYPos int32) COLORREF { + ret, _, _ := syscall.Syscall(getPixel, 3, + uintptr(hdc), + uintptr(nXPos), + uintptr(nYPos)) + + return COLORREF(ret) +} + +func GetRgnBox(hrgn HRGN, lprc *RECT) int32 { + ret, _, _ := syscall.Syscall(getRgnBox, 2, + uintptr(hrgn), + uintptr(unsafe.Pointer(lprc)), + 0) + + return int32(ret) +} + +func GetStockObject(fnObject int32) HGDIOBJ { + ret, _, _ := syscall.Syscall(getStockObject, 1, + uintptr(fnObject), + 0, + 0) + + return HGDIOBJ(ret) +} + +func GetTextColor(hdc HDC) COLORREF { + ret, _, _ := syscall.Syscall(getTextColor, 1, + uintptr(hdc), + 0, + 0) + + return COLORREF(ret) +} + +func GetTextExtentExPoint(hdc HDC, lpszStr *uint16, cchString, nMaxExtent int32, lpnFit, alpDx *int32, lpSize *SIZE) bool { + ret, _, _ := syscall.Syscall9(getTextExtentExPoint, 7, + uintptr(hdc), + uintptr(unsafe.Pointer(lpszStr)), + uintptr(cchString), + uintptr(nMaxExtent), + uintptr(unsafe.Pointer(lpnFit)), + uintptr(unsafe.Pointer(alpDx)), + uintptr(unsafe.Pointer(lpSize)), + 0, + 0) + + return ret != 0 +} + +func GetTextExtentPoint32(hdc HDC, lpString *uint16, c int32, lpSize *SIZE) bool { + ret, _, _ := syscall.Syscall6(getTextExtentPoint32, 4, + uintptr(hdc), + uintptr(unsafe.Pointer(lpString)), + uintptr(c), + uintptr(unsafe.Pointer(lpSize)), + 0, + 0) + + return ret != 0 +} + +func GetTextMetrics(hdc HDC, lptm *TEXTMETRIC) bool { + ret, _, _ := syscall.Syscall(getTextMetrics, 2, + uintptr(hdc), + uintptr(unsafe.Pointer(lptm)), + 0) + + return ret != 0 +} + +func GetViewportOrgEx(hdc HDC, lpPoint *POINT) bool { + ret, _, _ := syscall.Syscall(getViewportOrgEx, 2, + uintptr(hdc), + uintptr(unsafe.Pointer(lpPoint)), + 0) + + return ret != 0 +} + +func GradientFill(hdc HDC, pVertex *TRIVERTEX, nVertex uint32, pMesh unsafe.Pointer, nMesh, ulMode uint32) bool { + ret, _, _ := syscall.Syscall6(gradientFill, 6, + uintptr(hdc), + uintptr(unsafe.Pointer(pVertex)), + uintptr(nVertex), + uintptr(pMesh), + uintptr(nMesh), + uintptr(ulMode)) + + return ret != 0 +} + +func IntersectClipRect(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int32) int32 { + ret, _, _ := syscall.Syscall6(intersectClipRect, 5, + uintptr(hdc), + uintptr(nLeftRect), + uintptr(nTopRect), + uintptr(nRightRect), + uintptr(nBottomRect), + 0) + + return int32(ret) +} + +func LineTo(hdc HDC, nXEnd, nYEnd int32) bool { + ret, _, _ := syscall.Syscall(lineTo, 3, + uintptr(hdc), + uintptr(nXEnd), + uintptr(nYEnd)) + + return ret != 0 +} + +func MoveToEx(hdc HDC, x, y int, lpPoint *POINT) bool { + ret, _, _ := syscall.Syscall6(moveToEx, 4, + uintptr(hdc), + uintptr(x), + uintptr(y), + uintptr(unsafe.Pointer(lpPoint)), + 0, + 0) + + return ret != 0 +} + +func PlayEnhMetaFile(hdc HDC, hemf HENHMETAFILE, lpRect *RECT) bool { + ret, _, _ := syscall.Syscall(playEnhMetaFile, 3, + uintptr(hdc), + uintptr(hemf), + uintptr(unsafe.Pointer(lpRect))) + + return ret != 0 +} + +func Polyline(hdc HDC, lppt unsafe.Pointer, cPoints int32) bool { + ret, _, _ := syscall.Syscall(polyline, 3, + uintptr(hdc), + uintptr(lppt), + uintptr(cPoints)) + + return ret != 0 +} + +func Rectangle_(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int32) bool { + ret, _, _ := syscall.Syscall6(rectangle, 5, + uintptr(hdc), + uintptr(nLeftRect), + uintptr(nTopRect), + uintptr(nRightRect), + uintptr(nBottomRect), + 0) + + return ret != 0 +} + +func RemoveFontResourceEx(lpszFilename *uint16, fl uint32, pdv unsafe.Pointer) bool { + ret, _, _ := syscall.Syscall(removeFontResourceEx, 3, + uintptr(unsafe.Pointer(lpszFilename)), + uintptr(fl), + uintptr(pdv)) + + return ret != 0 +} + +func ResetDC(hdc HDC, lpInitData *DEVMODE) HDC { + ret, _, _ := syscall.Syscall(resetDC, 2, + uintptr(hdc), + uintptr(unsafe.Pointer(lpInitData)), + 0) + + return HDC(ret) +} + +func RestoreDC(hdc HDC, nSaveDC int32) bool { + ret, _, _ := syscall.Syscall(restoreDC, 2, + uintptr(hdc), + uintptr(nSaveDC), + 0) + return ret != 0 +} + +func RoundRect(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect, nWidth, nHeight int32) bool { + ret, _, _ := syscall.Syscall9(roundRect, 7, + uintptr(hdc), + uintptr(nLeftRect), + uintptr(nTopRect), + uintptr(nRightRect), + uintptr(nBottomRect), + uintptr(nWidth), + uintptr(nHeight), + 0, + 0) + + return ret != 0 +} + +func SaveDC(hdc HDC) int32 { + ret, _, _ := syscall.Syscall(saveDC, 1, + uintptr(hdc), + 0, + 0) + return int32(ret) +} + +func SelectObject(hdc HDC, hgdiobj HGDIOBJ) HGDIOBJ { + ret, _, _ := syscall.Syscall(selectObject, 2, + uintptr(hdc), + uintptr(hgdiobj), + 0) + + return HGDIOBJ(ret) +} + +func SetBkColor(hdc HDC, crColor COLORREF) COLORREF { + ret, _, _ := syscall.Syscall(setBkColor, 2, + uintptr(hdc), + uintptr(crColor), + 0) + + return COLORREF(ret) +} + +func SetBkMode(hdc HDC, iBkMode int32) int32 { + ret, _, _ := syscall.Syscall(setBkMode, 2, + uintptr(hdc), + uintptr(iBkMode), + 0) + + return int32(ret) +} + +func SetBrushOrgEx(hdc HDC, nXOrg, nYOrg int32, lppt *POINT) bool { + ret, _, _ := syscall.Syscall6(setBrushOrgEx, 4, + uintptr(hdc), + uintptr(nXOrg), + uintptr(nYOrg), + uintptr(unsafe.Pointer(lppt)), + 0, + 0) + + return ret != 0 +} + +func SetDIBits(hdc HDC, hbmp HBITMAP, uStartScan, cScanLines uint32, lpvBits *byte, lpbmi *BITMAPINFO, fuColorUse uint32) int32 { + ret, _, _ := syscall.Syscall9(setDIBits, 7, + uintptr(hdc), + uintptr(hbmp), + uintptr(uStartScan), + uintptr(cScanLines), + uintptr(unsafe.Pointer(lpvBits)), + uintptr(unsafe.Pointer(lpbmi)), + uintptr(fuColorUse), + 0, + 0) + + return int32(ret) +} + +func SetPixel(hdc HDC, X, Y int32, crColor COLORREF) COLORREF { + ret, _, _ := syscall.Syscall6(setPixel, 4, + uintptr(hdc), + uintptr(X), + uintptr(Y), + uintptr(crColor), + 0, + 0) + + return COLORREF(ret) +} + +func SetPixelFormat(hdc HDC, iPixelFormat int32, ppfd *PIXELFORMATDESCRIPTOR) bool { + ret, _, _ := syscall.Syscall(setPixelFormat, 3, + uintptr(hdc), + uintptr(iPixelFormat), + uintptr(unsafe.Pointer(ppfd))) + + return ret != 0 +} + +func SetStretchBltMode(hdc HDC, iStretchMode int32) int32 { + ret, _, _ := syscall.Syscall(setStretchBltMode, 2, + uintptr(hdc), + uintptr(iStretchMode), + 0) + + return int32(ret) +} + +func SetTextColor(hdc HDC, crColor COLORREF) COLORREF { + ret, _, _ := syscall.Syscall(setTextColor, 2, + uintptr(hdc), + uintptr(crColor), + 0) + + return COLORREF(ret) +} + +func SetViewportOrgEx(hdc HDC, x, y int32, lpPoint *POINT) COLORREF { + ret, _, _ := syscall.Syscall6(setViewportOrgEx, 4, + uintptr(hdc), + uintptr(x), + uintptr(y), + uintptr(unsafe.Pointer(lpPoint)), + 0, + 0) + + return COLORREF(ret) +} + +func StartDoc(hdc HDC, lpdi *DOCINFO) int32 { + ret, _, _ := syscall.Syscall(startDoc, 2, + uintptr(hdc), + uintptr(unsafe.Pointer(lpdi)), + 0) + + return int32(ret) +} + +func StartPage(hdc HDC) int32 { + ret, _, _ := syscall.Syscall(startPage, 1, + uintptr(hdc), + 0, + 0) + + return int32(ret) +} + +func StretchBlt(hdcDest HDC, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest int32, hdcSrc HDC, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc int32, dwRop uint32) bool { + ret, _, _ := syscall.Syscall12(stretchBlt, 11, + uintptr(hdcDest), + uintptr(nXOriginDest), + uintptr(nYOriginDest), + uintptr(nWidthDest), + uintptr(nHeightDest), + uintptr(hdcSrc), + uintptr(nXOriginSrc), + uintptr(nYOriginSrc), + uintptr(nWidthSrc), + uintptr(nHeightSrc), + uintptr(dwRop), + 0) + + return ret != 0 +} + +func SwapBuffers(hdc HDC) bool { + ret, _, _ := syscall.Syscall(swapBuffers, 1, + uintptr(hdc), + 0, + 0) + + return ret != 0 +} + +func TextOut(hdc HDC, nXStart, nYStart int32, lpString *uint16, cchString int32) bool { + ret, _, _ := syscall.Syscall6(textOut, 5, + uintptr(hdc), + uintptr(nXStart), + uintptr(nYStart), + uintptr(unsafe.Pointer(lpString)), + uintptr(cchString), + 0) + return ret != 0 +} + +func TransparentBlt(hdcDest HDC, xoriginDest, yoriginDest, wDest, hDest int32, hdcSrc HDC, xoriginSrc, yoriginSrc, wSrc, hSrc int32, crTransparent uint32) bool { + ret, _, _ := syscall.Syscall12(transparentBlt, 11, + uintptr(hdcDest), + uintptr(xoriginDest), + uintptr(yoriginDest), + uintptr(wDest), + uintptr(hDest), + uintptr(hdcSrc), + uintptr(xoriginSrc), + uintptr(yoriginSrc), + uintptr(wSrc), + uintptr(hSrc), + uintptr(crTransparent), + 0) + + return ret != 0 +} diff --git a/gui/vendor/github.com/lxn/win/gdiplus.go b/gui/vendor/github.com/lxn/win/gdiplus.go new file mode 100644 index 0000000..1752262 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/gdiplus.go @@ -0,0 +1,223 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +type GpStatus int32 + +const ( + Ok GpStatus = 0 + GenericError GpStatus = 1 + InvalidParameter GpStatus = 2 + OutOfMemory GpStatus = 3 + ObjectBusy GpStatus = 4 + InsufficientBuffer GpStatus = 5 + NotImplemented GpStatus = 6 + Win32Error GpStatus = 7 + WrongState GpStatus = 8 + Aborted GpStatus = 9 + FileNotFound GpStatus = 10 + ValueOverflow GpStatus = 11 + AccessDenied GpStatus = 12 + UnknownImageFormat GpStatus = 13 + FontFamilyNotFound GpStatus = 14 + FontStyleNotFound GpStatus = 15 + NotTrueTypeFont GpStatus = 16 + UnsupportedGdiplusVersion GpStatus = 17 + GdiplusNotInitialized GpStatus = 18 + PropertyNotFound GpStatus = 19 + PropertyNotSupported GpStatus = 20 + ProfileNotFound GpStatus = 21 +) + +func (s GpStatus) String() string { + switch s { + case Ok: + return "Ok" + + case GenericError: + return "GenericError" + + case InvalidParameter: + return "InvalidParameter" + + case OutOfMemory: + return "OutOfMemory" + + case ObjectBusy: + return "ObjectBusy" + + case InsufficientBuffer: + return "InsufficientBuffer" + + case NotImplemented: + return "NotImplemented" + + case Win32Error: + return "Win32Error" + + case WrongState: + return "WrongState" + + case Aborted: + return "Aborted" + + case FileNotFound: + return "FileNotFound" + + case ValueOverflow: + return "ValueOverflow" + + case AccessDenied: + return "AccessDenied" + + case UnknownImageFormat: + return "UnknownImageFormat" + + case FontFamilyNotFound: + return "FontFamilyNotFound" + + case FontStyleNotFound: + return "FontStyleNotFound" + + case NotTrueTypeFont: + return "NotTrueTypeFont" + + case UnsupportedGdiplusVersion: + return "UnsupportedGdiplusVersion" + + case GdiplusNotInitialized: + return "GdiplusNotInitialized" + + case PropertyNotFound: + return "PropertyNotFound" + + case PropertyNotSupported: + return "PropertyNotSupported" + + case ProfileNotFound: + return "ProfileNotFound" + } + + return "Unknown Status Value" +} + +type GdiplusStartupInput struct { + GdiplusVersion uint32 + DebugEventCallback uintptr + SuppressBackgroundThread BOOL + SuppressExternalCodecs BOOL +} + +type GdiplusStartupOutput struct { + NotificationHook uintptr + NotificationUnhook uintptr +} + +type GpImage struct{} + +type GpBitmap GpImage + +type ARGB uint32 + +var ( + // Library + libgdiplus uintptr + + // Functions + gdipCreateBitmapFromFile uintptr + gdipCreateBitmapFromHBITMAP uintptr + gdipCreateHBITMAPFromBitmap uintptr + gdipDisposeImage uintptr + gdiplusShutdown uintptr + gdiplusStartup uintptr +) + +var ( + token uintptr +) + +func init() { + // Library + libgdiplus = MustLoadLibrary("gdiplus.dll") + + // Functions + gdipCreateBitmapFromFile = MustGetProcAddress(libgdiplus, "GdipCreateBitmapFromFile") + gdipCreateBitmapFromHBITMAP = MustGetProcAddress(libgdiplus, "GdipCreateBitmapFromHBITMAP") + gdipCreateHBITMAPFromBitmap = MustGetProcAddress(libgdiplus, "GdipCreateHBITMAPFromBitmap") + gdipDisposeImage = MustGetProcAddress(libgdiplus, "GdipDisposeImage") + gdiplusShutdown = MustGetProcAddress(libgdiplus, "GdiplusShutdown") + gdiplusStartup = MustGetProcAddress(libgdiplus, "GdiplusStartup") +} + +func GdipCreateBitmapFromFile(filename *uint16, bitmap **GpBitmap) GpStatus { + ret, _, _ := syscall.Syscall(gdipCreateBitmapFromFile, 2, + uintptr(unsafe.Pointer(filename)), + uintptr(unsafe.Pointer(bitmap)), + 0) + + return GpStatus(ret) +} + +func GdipCreateBitmapFromHBITMAP(hbm HBITMAP, hpal HPALETTE, bitmap **GpBitmap) GpStatus { + ret, _, _ := syscall.Syscall(gdipCreateBitmapFromHBITMAP, 3, + uintptr(hbm), + uintptr(hpal), + uintptr(unsafe.Pointer(bitmap))) + + return GpStatus(ret) +} + +func GdipCreateHBITMAPFromBitmap(bitmap *GpBitmap, hbmReturn *HBITMAP, background ARGB) GpStatus { + ret, _, _ := syscall.Syscall(gdipCreateHBITMAPFromBitmap, 3, + uintptr(unsafe.Pointer(bitmap)), + uintptr(unsafe.Pointer(hbmReturn)), + uintptr(background)) + + return GpStatus(ret) +} + +func GdipDisposeImage(image *GpImage) GpStatus { + ret, _, _ := syscall.Syscall(gdipDisposeImage, 1, + uintptr(unsafe.Pointer(image)), + 0, + 0) + + return GpStatus(ret) +} + +func GdiplusShutdown() { + syscall.Syscall(gdiplusShutdown, 1, + token, + 0, + 0) +} + +func GdiplusStartup(input *GdiplusStartupInput, output *GdiplusStartupOutput) GpStatus { + ret, _, _ := syscall.Syscall(gdiplusStartup, 3, + uintptr(unsafe.Pointer(&token)), + uintptr(unsafe.Pointer(input)), + uintptr(unsafe.Pointer(output))) + + return GpStatus(ret) +} + +/*GdipSaveImageToFile(image *GpImage, filename *uint16, clsidEncoder *CLSID, encoderParams *EncoderParameters) GpStatus { + ret, _, _ := syscall.Syscall6(gdipSaveImageToFile, 4, + uintptr(unsafe.Pointer(image)), + uintptr(unsafe.Pointer(filename)), + uintptr(unsafe.Pointer(clsidEncoder)), + uintptr(unsafe.Pointer(encoderParams)), + 0, + 0) + + return GpStatus(ret) +}*/ diff --git a/gui/vendor/github.com/lxn/win/header.go b/gui/vendor/github.com/lxn/win/header.go new file mode 100644 index 0000000..7f67505 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/header.go @@ -0,0 +1,136 @@ +// Copyright 2012 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +const ( + HDS_NOSIZING = 0x0800 +) + +type HDITEM struct { + Mask uint32 + Cxy int32 + PszText *uint16 + Hbm HBITMAP + CchTextMax int32 + Fmt int32 + LParam uintptr + IImage int32 + IOrder int32 + Type uint32 + PvFilter uintptr +} + +type HDLAYOUT struct { + Prc *RECT + Pwpos *WINDOWPOS +} + +const ( + HDI_WIDTH = 0x0001 + HDI_HEIGHT = HDI_WIDTH + HDI_TEXT = 0x0002 + HDI_FORMAT = 0x0004 + HDI_LPARAM = 0x0008 + HDI_BITMAP = 0x0010 + HDI_IMAGE = 0x0020 + HDI_DI_SETITEM = 0x0040 + HDI_ORDER = 0x0080 + HDI_FILTER = 0x0100 + HDI_STATE = 0x0200 +) + +const ( + HDF_LEFT = 0x0000 + HDF_RIGHT = 0x0001 + HDF_CENTER = 0x0002 + HDF_JUSTIFYMASK = 0x0003 + HDF_RTLREADING = 0x0004 + HDF_CHECKBOX = 0x0040 + HDF_CHECKED = 0x0080 + HDF_FIXEDWIDTH = 0x0100 + HDF_SORTDOWN = 0x0200 + HDF_SORTUP = 0x0400 + HDF_IMAGE = 0x0800 + HDF_BITMAP_ON_RIGHT = 0x1000 + HDF_BITMAP = 0x2000 + HDF_STRING = 0x4000 + HDF_OWNERDRAW = 0x8000 + HDF_SPLITBUTTON = 0x1000000 +) + +const ( + HDIS_FOCUSED = 0x00000001 +) + +const ( + HDM_FIRST = 0x1200 + HDM_GETITEMCOUNT = HDM_FIRST + 0 + HDM_DELETEITEM = HDM_FIRST + 2 + HDM_LAYOUT = HDM_FIRST + 5 + HDM_HITTEST = HDM_FIRST + 6 + HDM_GETITEMRECT = HDM_FIRST + 7 + HDM_SETIMAGELIST = HDM_FIRST + 8 + HDM_GETIMAGELIST = HDM_FIRST + 9 + HDM_INSERTITEM = HDM_FIRST + 10 + HDM_GETITEM = HDM_FIRST + 11 + HDM_SETITEM = HDM_FIRST + 12 + HDM_ORDERTOINDEX = HDM_FIRST + 15 + HDM_CREATEDRAGIMAGE = HDM_FIRST + 16 + HDM_GETORDERARRAY = HDM_FIRST + 17 + HDM_SETORDERARRAY = HDM_FIRST + 18 + HDM_SETHOTDIVIDER = HDM_FIRST + 19 + HDM_SETBITMAPMARGIN = HDM_FIRST + 20 + HDM_GETBITMAPMARGIN = HDM_FIRST + 21 + HDM_SETFILTERCHANGETIMEOUT = HDM_FIRST + 22 + HDM_EDITFILTER = HDM_FIRST + 23 + HDM_CLEARFILTER = HDM_FIRST + 24 + HDM_GETITEMDROPDOWNRECT = HDM_FIRST + 25 + HDM_GETOVERFLOWRECT = HDM_FIRST + 26 + HDM_GETFOCUSEDITEM = HDM_FIRST + 27 + HDM_SETFOCUSEDITEM = HDM_FIRST + 28 + HDM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT + HDM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT +) + +const ( + HHT_NOWHERE = 0x0001 + HHT_ONHEADER = 0x0002 + HHT_ONDIVIDER = 0x0004 + HHT_ONDIVOPEN = 0x0008 + HHT_ONFILTER = 0x0010 + HHT_ONFILTERBUTTON = 0x0020 + HHT_ABOVE = 0x0100 + HHT_BELOW = 0x0200 + HHT_TORIGHT = 0x0400 + HHT_TOLEFT = 0x0800 + HHT_ONITEMSTATEICON = 0x1000 + HHT_ONDROPDOWN = 0x2000 + HHT_ONOVERFLOW = 0x4000 +) + +const ( + HDN_FIRST = ^uint32(300) + HDN_BEGINDRAG = HDN_FIRST - 10 + HDN_ENDDRAG = HDN_FIRST - 11 + HDN_FILTERCHANGE = HDN_FIRST - 12 + HDN_FILTERBTNCLICK = HDN_FIRST - 13 + HDN_BEGINFILTEREDIT = HDN_FIRST - 14 + HDN_ENDFILTEREDIT = HDN_FIRST - 15 + HDN_ITEMSTATEICONCLICK = HDN_FIRST - 16 + HDN_ITEMKEYDOWN = HDN_FIRST - 17 + HDN_DROPDOWN = HDN_FIRST - 18 + HDN_OVERFLOWCLICK = HDN_FIRST - 19 + HDN_ITEMCHANGING = HDN_FIRST - 20 + HDN_ITEMCHANGED = HDN_FIRST - 21 + HDN_ITEMCLICK = HDN_FIRST - 22 + HDN_ITEMDBLCLICK = HDN_FIRST - 23 + HDN_DIVIDERDBLCLICK = HDN_FIRST - 25 + HDN_BEGINTRACK = HDN_FIRST - 26 + HDN_ENDTRACK = HDN_FIRST - 27 + HDN_TRACK = HDN_FIRST - 28 + HDN_GETDISPINFO = HDN_FIRST - 29 +) diff --git a/gui/vendor/github.com/lxn/win/kernel32.go b/gui/vendor/github.com/lxn/win/kernel32.go new file mode 100644 index 0000000..33c9c36 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/kernel32.go @@ -0,0 +1,390 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +const MAX_PATH = 260 + +// Error codes +const ( + ERROR_SUCCESS = 0 + ERROR_INVALID_FUNCTION = 1 + ERROR_FILE_NOT_FOUND = 2 + ERROR_INVALID_PARAMETER = 87 + ERROR_INSUFFICIENT_BUFFER = 122 + ERROR_MORE_DATA = 234 +) + +// GlobalAlloc flags +const ( + GHND = 0x0042 + GMEM_FIXED = 0x0000 + GMEM_MOVEABLE = 0x0002 + GMEM_ZEROINIT = 0x0040 + GPTR = 0x004 +) + +// Predefined locale ids +const ( + LOCALE_CUSTOM_DEFAULT LCID = 0x0c00 + LOCALE_CUSTOM_UI_DEFAULT LCID = 0x1400 + LOCALE_CUSTOM_UNSPECIFIED LCID = 0x1000 + LOCALE_INVARIANT LCID = 0x007f + LOCALE_USER_DEFAULT LCID = 0x0400 + LOCALE_SYSTEM_DEFAULT LCID = 0x0800 +) + +// LCTYPE constants +const ( + LOCALE_SDECIMAL LCTYPE = 14 + LOCALE_STHOUSAND LCTYPE = 15 + LOCALE_SISO3166CTRYNAME LCTYPE = 0x5a + LOCALE_SISO3166CTRYNAME2 LCTYPE = 0x68 + LOCALE_SISO639LANGNAME LCTYPE = 0x59 + LOCALE_SISO639LANGNAME2 LCTYPE = 0x67 +) + +var ( + // Library + libkernel32 uintptr + + // Functions + activateActCtx uintptr + closeHandle uintptr + createActCtx uintptr + fileTimeToSystemTime uintptr + getConsoleTitle uintptr + getConsoleWindow uintptr + getLastError uintptr + getLocaleInfo uintptr + getLogicalDriveStrings uintptr + getModuleHandle uintptr + getNumberFormat uintptr + getPhysicallyInstalledSystemMemory uintptr + getProfileString uintptr + getThreadLocale uintptr + getThreadUILanguage uintptr + getVersion uintptr + globalAlloc uintptr + globalFree uintptr + globalLock uintptr + globalUnlock uintptr + moveMemory uintptr + mulDiv uintptr + setLastError uintptr + systemTimeToFileTime uintptr +) + +type ( + ATOM uint16 + HANDLE uintptr + HGLOBAL HANDLE + HINSTANCE HANDLE + LCID uint32 + LCTYPE uint32 + LANGID uint16 + HMODULE uintptr +) + +type FILETIME struct { + DwLowDateTime uint32 + DwHighDateTime uint32 +} + +type NUMBERFMT struct { + NumDigits uint32 + LeadingZero uint32 + Grouping uint32 + LpDecimalSep *uint16 + LpThousandSep *uint16 + NegativeOrder uint32 +} + +type SYSTEMTIME struct { + WYear uint16 + WMonth uint16 + WDayOfWeek uint16 + WDay uint16 + WHour uint16 + WMinute uint16 + WSecond uint16 + WMilliseconds uint16 +} + +type ACTCTX struct { + size uint32 + Flags uint32 + Source *uint16 // UTF-16 string + ProcessorArchitecture uint16 + LangID uint16 + AssemblyDirectory *uint16 // UTF-16 string + ResourceName *uint16 // UTF-16 string + ApplicationName *uint16 // UTF-16 string + Module HMODULE +} + +func init() { + // Library + libkernel32 = MustLoadLibrary("kernel32.dll") + + // Functions + activateActCtx = MustGetProcAddress(libkernel32, "ActivateActCtx") + closeHandle = MustGetProcAddress(libkernel32, "CloseHandle") + createActCtx = MustGetProcAddress(libkernel32, "CreateActCtxW") + fileTimeToSystemTime = MustGetProcAddress(libkernel32, "FileTimeToSystemTime") + getConsoleTitle = MustGetProcAddress(libkernel32, "GetConsoleTitleW") + getConsoleWindow = MustGetProcAddress(libkernel32, "GetConsoleWindow") + getLastError = MustGetProcAddress(libkernel32, "GetLastError") + getLocaleInfo = MustGetProcAddress(libkernel32, "GetLocaleInfoW") + getLogicalDriveStrings = MustGetProcAddress(libkernel32, "GetLogicalDriveStringsW") + getModuleHandle = MustGetProcAddress(libkernel32, "GetModuleHandleW") + getNumberFormat = MustGetProcAddress(libkernel32, "GetNumberFormatW") + getPhysicallyInstalledSystemMemory, _ = syscall.GetProcAddress(syscall.Handle(libkernel32), "GetPhysicallyInstalledSystemMemory") + getProfileString = MustGetProcAddress(libkernel32, "GetProfileStringW") + getThreadLocale = MustGetProcAddress(libkernel32, "GetThreadLocale") + getThreadUILanguage, _ = syscall.GetProcAddress(syscall.Handle(libkernel32), "GetThreadUILanguage") + getVersion = MustGetProcAddress(libkernel32, "GetVersion") + globalAlloc = MustGetProcAddress(libkernel32, "GlobalAlloc") + globalFree = MustGetProcAddress(libkernel32, "GlobalFree") + globalLock = MustGetProcAddress(libkernel32, "GlobalLock") + globalUnlock = MustGetProcAddress(libkernel32, "GlobalUnlock") + moveMemory = MustGetProcAddress(libkernel32, "RtlMoveMemory") + mulDiv = MustGetProcAddress(libkernel32, "MulDiv") + setLastError = MustGetProcAddress(libkernel32, "SetLastError") + systemTimeToFileTime = MustGetProcAddress(libkernel32, "SystemTimeToFileTime") +} + +func ActivateActCtx(ctx HANDLE) (uintptr, bool) { + var cookie uintptr + ret, _, _ := syscall.Syscall(activateActCtx, 2, + uintptr(ctx), + uintptr(unsafe.Pointer(&cookie)), + 0) + return cookie, ret != 0 +} + +func CloseHandle(hObject HANDLE) bool { + ret, _, _ := syscall.Syscall(closeHandle, 1, + uintptr(hObject), + 0, + 0) + + return ret != 0 +} + +func CreateActCtx(ctx *ACTCTX) HANDLE { + if ctx != nil { + ctx.size = uint32(unsafe.Sizeof(*ctx)) + } + ret, _, _ := syscall.Syscall( + createActCtx, + 1, + uintptr(unsafe.Pointer(ctx)), + 0, + 0) + return HANDLE(ret) +} + +func FileTimeToSystemTime(lpFileTime *FILETIME, lpSystemTime *SYSTEMTIME) bool { + ret, _, _ := syscall.Syscall(fileTimeToSystemTime, 2, + uintptr(unsafe.Pointer(lpFileTime)), + uintptr(unsafe.Pointer(lpSystemTime)), + 0) + + return ret != 0 +} + +func GetConsoleTitle(lpConsoleTitle *uint16, nSize uint32) uint32 { + ret, _, _ := syscall.Syscall(getConsoleTitle, 2, + uintptr(unsafe.Pointer(lpConsoleTitle)), + uintptr(nSize), + 0) + + return uint32(ret) +} + +func GetConsoleWindow() HWND { + ret, _, _ := syscall.Syscall(getConsoleWindow, 0, + 0, + 0, + 0) + + return HWND(ret) +} + +func GetLastError() uint32 { + ret, _, _ := syscall.Syscall(getLastError, 0, + 0, + 0, + 0) + + return uint32(ret) +} + +func GetLocaleInfo(Locale LCID, LCType LCTYPE, lpLCData *uint16, cchData int32) int32 { + ret, _, _ := syscall.Syscall6(getLocaleInfo, 4, + uintptr(Locale), + uintptr(LCType), + uintptr(unsafe.Pointer(lpLCData)), + uintptr(cchData), + 0, + 0) + + return int32(ret) +} + +func GetLogicalDriveStrings(nBufferLength uint32, lpBuffer *uint16) uint32 { + ret, _, _ := syscall.Syscall(getLogicalDriveStrings, 2, + uintptr(nBufferLength), + uintptr(unsafe.Pointer(lpBuffer)), + 0) + + return uint32(ret) +} + +func GetModuleHandle(lpModuleName *uint16) HINSTANCE { + ret, _, _ := syscall.Syscall(getModuleHandle, 1, + uintptr(unsafe.Pointer(lpModuleName)), + 0, + 0) + + return HINSTANCE(ret) +} + +func GetNumberFormat(Locale LCID, dwFlags uint32, lpValue *uint16, lpFormat *NUMBERFMT, lpNumberStr *uint16, cchNumber int32) int32 { + ret, _, _ := syscall.Syscall6(getNumberFormat, 6, + uintptr(Locale), + uintptr(dwFlags), + uintptr(unsafe.Pointer(lpValue)), + uintptr(unsafe.Pointer(lpFormat)), + uintptr(unsafe.Pointer(lpNumberStr)), + uintptr(cchNumber)) + + return int32(ret) +} + +func GetPhysicallyInstalledSystemMemory(totalMemoryInKilobytes *uint64) bool { + ret, _, _ := syscall.Syscall(getPhysicallyInstalledSystemMemory, 1, + uintptr(unsafe.Pointer(totalMemoryInKilobytes)), + 0, + 0) + + return ret != 0 +} + +func GetProfileString(lpAppName, lpKeyName, lpDefault *uint16, lpReturnedString uintptr, nSize uint32) bool { + ret, _, _ := syscall.Syscall6(getProfileString, 5, + uintptr(unsafe.Pointer(lpAppName)), + uintptr(unsafe.Pointer(lpKeyName)), + uintptr(unsafe.Pointer(lpDefault)), + lpReturnedString, + uintptr(nSize), + 0) + return ret != 0 +} + +func GetThreadLocale() LCID { + ret, _, _ := syscall.Syscall(getThreadLocale, 0, + 0, + 0, + 0) + + return LCID(ret) +} + +func GetThreadUILanguage() LANGID { + if getThreadUILanguage == 0 { + return 0 + } + + ret, _, _ := syscall.Syscall(getThreadUILanguage, 0, + 0, + 0, + 0) + + return LANGID(ret) +} + +func GetVersion() int64 { + ret, _, _ := syscall.Syscall(getVersion, 0, + 0, + 0, + 0) + return int64(ret) +} + +func GlobalAlloc(uFlags uint32, dwBytes uintptr) HGLOBAL { + ret, _, _ := syscall.Syscall(globalAlloc, 2, + uintptr(uFlags), + dwBytes, + 0) + + return HGLOBAL(ret) +} + +func GlobalFree(hMem HGLOBAL) HGLOBAL { + ret, _, _ := syscall.Syscall(globalFree, 1, + uintptr(hMem), + 0, + 0) + + return HGLOBAL(ret) +} + +func GlobalLock(hMem HGLOBAL) unsafe.Pointer { + ret, _, _ := syscall.Syscall(globalLock, 1, + uintptr(hMem), + 0, + 0) + + return unsafe.Pointer(ret) +} + +func GlobalUnlock(hMem HGLOBAL) bool { + ret, _, _ := syscall.Syscall(globalUnlock, 1, + uintptr(hMem), + 0, + 0) + + return ret != 0 +} + +func MoveMemory(destination, source unsafe.Pointer, length uintptr) { + syscall.Syscall(moveMemory, 3, + uintptr(unsafe.Pointer(destination)), + uintptr(source), + uintptr(length)) +} + +func MulDiv(nNumber, nNumerator, nDenominator int32) int32 { + ret, _, _ := syscall.Syscall(mulDiv, 3, + uintptr(nNumber), + uintptr(nNumerator), + uintptr(nDenominator)) + + return int32(ret) +} + +func SetLastError(dwErrorCode uint32) { + syscall.Syscall(setLastError, 1, + uintptr(dwErrorCode), + 0, + 0) +} + +func SystemTimeToFileTime(lpSystemTime *SYSTEMTIME, lpFileTime *FILETIME) bool { + ret, _, _ := syscall.Syscall(systemTimeToFileTime, 2, + uintptr(unsafe.Pointer(lpSystemTime)), + uintptr(unsafe.Pointer(lpFileTime)), + 0) + + return ret != 0 +} diff --git a/gui/vendor/github.com/lxn/win/listbox.go b/gui/vendor/github.com/lxn/win/listbox.go new file mode 100644 index 0000000..abb872b --- /dev/null +++ b/gui/vendor/github.com/lxn/win/listbox.go @@ -0,0 +1,87 @@ +// Copyright 2012 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +// ListBox style +const ( + LBS_NOTIFY = 0x0001 + LBS_SORT = 0x0002 + LBS_NOREDRAW = 0x0004 + LBS_MULTIPLESEL = 0x0008 + LBS_OWNERDRAWFIXED = 0x0010 + LBS_OWNERDRAWVARIABLE = 0x0020 + LBS_HASSTRINGS = 0x0040 + LBS_USETABSTOPS = 0x0080 + LBS_NOINTEGRALHEIGHT = 0x0100 + LBS_MULTICOLUMN = 0x0200 + LBS_WANTKEYBOARDINPUT = 0x0400 + LBS_EXTENDEDSEL = 0x0800 + LBS_DISABLENOSCROLL = 0x1000 + LBS_NODATA = 0x2000 + LBS_NOSEL = 0x4000 + LBS_COMBOBOX = 0x8000 + LBS_STANDARD = LBS_NOTIFY | LBS_SORT | WS_BORDER | WS_VSCROLL +) + +// ListBox messages +const ( + LB_ADDSTRING = 0x0180 + LB_INSERTSTRING = 0x0181 + LB_DELETESTRING = 0x0182 + LB_SELITEMRANGEEX = 0x0183 + LB_RESETCONTENT = 0x0184 + LB_SETSEL = 0x0185 + LB_SETCURSEL = 0x0186 + LB_GETSEL = 0x0187 + LB_GETCURSEL = 0x0188 + LB_GETTEXT = 0x0189 + LB_GETTEXTLEN = 0x018A + LB_GETCOUNT = 0x018B + LB_SELECTSTRING = 0x018C + LB_DIR = 0x018D + LB_GETTOPINDEX = 0x018E + LB_FINDSTRING = 0x018F + LB_GETSELCOUNT = 0x0190 + LB_GETSELITEMS = 0x0191 + LB_SETTABSTOPS = 0x0192 + LB_GETHORIZONTALEXTENT = 0x0193 + LB_SETHORIZONTALEXTENT = 0x0194 + LB_SETCOLUMNWIDTH = 0x0195 + LB_ADDFILE = 0x0196 + LB_SETTOPINDEX = 0x0197 + LB_GETITEMRECT = 0x0198 + LB_GETITEMDATA = 0x0199 + LB_SETITEMDATA = 0x019A + LB_SELITEMRANGE = 0x019B + LB_SETANCHORINDEX = 0x019C + LB_GETANCHORINDEX = 0x019D + LB_SETCARETINDEX = 0x019E + LB_GETCARETINDEX = 0x019F + LB_SETITEMHEIGHT = 0x01A0 + LB_GETITEMHEIGHT = 0x01A1 + LB_FINDSTRINGEXACT = 0x01A2 + LB_SETLOCALE = 0x01A5 + LB_GETLOCALE = 0x01A6 + LB_SETCOUNT = 0x01A7 + LB_INITSTORAGE = 0x01A8 + LB_ITEMFROMPOINT = 0x01A9 + LB_MULTIPLEADDSTRING = 0x01B1 +) + +//Listbox Notification Codes +const ( + LBN_ERRSPACE = -2 + LBN_SELCHANGE = 1 + LBN_DBLCLK = 2 + LBN_SELCANCEL = 3 + LBN_SETFOCUS = 4 + LBN_KILLFOCUS = 5 +) +const ( + LB_ERR = -1 + LB_ERRSPACE = -2 +) diff --git a/gui/vendor/github.com/lxn/win/listview.go b/gui/vendor/github.com/lxn/win/listview.go new file mode 100644 index 0000000..a705534 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/listview.go @@ -0,0 +1,376 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +const ( + LVSCW_AUTOSIZE = ^uintptr(0) + LVSCW_AUTOSIZE_USEHEADER = ^uintptr(1) +) + +// LVM_SETITEMCOUNT flags +const ( + LVSICF_NOINVALIDATEALL = 0x0001 + LVSICF_NOSCROLL = 0x0002 +) + +// ListView messages +const ( + LVM_FIRST = 0x1000 + LVM_SETIMAGELIST = LVM_FIRST + 3 + LVM_GETITEM = LVM_FIRST + 75 + LVM_SETITEM = LVM_FIRST + 76 + LVM_INSERTITEM = LVM_FIRST + 77 + LVM_DELETEITEM = LVM_FIRST + 8 + LVM_DELETEALLITEMS = LVM_FIRST + 9 + LVM_GETCALLBACKMASK = LVM_FIRST + 10 + LVM_SETCALLBACKMASK = LVM_FIRST + 11 + LVM_GETNEXTITEM = LVM_FIRST + 12 + LVM_FINDITEM = LVM_FIRST + 83 + LVM_GETITEMRECT = LVM_FIRST + 14 + LVM_GETSTRINGWIDTH = LVM_FIRST + 87 + LVM_HITTEST = LVM_FIRST + 18 + LVM_ENSUREVISIBLE = LVM_FIRST + 19 + LVM_SCROLL = LVM_FIRST + 20 + LVM_REDRAWITEMS = LVM_FIRST + 21 + LVM_ARRANGE = LVM_FIRST + 22 + LVM_EDITLABEL = LVM_FIRST + 118 + LVM_GETEDITCONTROL = LVM_FIRST + 24 + LVM_GETCOLUMN = LVM_FIRST + 95 + LVM_SETCOLUMN = LVM_FIRST + 96 + LVM_INSERTCOLUMN = LVM_FIRST + 97 + LVM_DELETECOLUMN = LVM_FIRST + 28 + LVM_GETCOLUMNWIDTH = LVM_FIRST + 29 + LVM_SETCOLUMNWIDTH = LVM_FIRST + 30 + LVM_GETHEADER = LVM_FIRST + 31 + LVM_CREATEDRAGIMAGE = LVM_FIRST + 33 + LVM_GETVIEWRECT = LVM_FIRST + 34 + LVM_GETTEXTCOLOR = LVM_FIRST + 35 + LVM_SETTEXTCOLOR = LVM_FIRST + 36 + LVM_GETTEXTBKCOLOR = LVM_FIRST + 37 + LVM_SETTEXTBKCOLOR = LVM_FIRST + 38 + LVM_GETTOPINDEX = LVM_FIRST + 39 + LVM_GETCOUNTPERPAGE = LVM_FIRST + 40 + LVM_GETORIGIN = LVM_FIRST + 41 + LVM_UPDATE = LVM_FIRST + 42 + LVM_SETITEMSTATE = LVM_FIRST + 43 + LVM_GETITEMSTATE = LVM_FIRST + 44 + LVM_GETITEMTEXT = LVM_FIRST + 115 + LVM_SETITEMTEXT = LVM_FIRST + 116 + LVM_SETITEMCOUNT = LVM_FIRST + 47 + LVM_SORTITEMS = LVM_FIRST + 48 + LVM_SETITEMPOSITION32 = LVM_FIRST + 49 + LVM_GETSELECTEDCOUNT = LVM_FIRST + 50 + LVM_GETITEMSPACING = LVM_FIRST + 51 + LVM_GETISEARCHSTRING = LVM_FIRST + 117 + LVM_SETICONSPACING = LVM_FIRST + 53 + LVM_SETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 54 + LVM_GETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 55 + LVM_GETSUBITEMRECT = LVM_FIRST + 56 + LVM_SUBITEMHITTEST = LVM_FIRST + 57 + LVM_SETCOLUMNORDERARRAY = LVM_FIRST + 58 + LVM_GETCOLUMNORDERARRAY = LVM_FIRST + 59 + LVM_SETHOTITEM = LVM_FIRST + 60 + LVM_GETHOTITEM = LVM_FIRST + 61 + LVM_SETHOTCURSOR = LVM_FIRST + 62 + LVM_GETHOTCURSOR = LVM_FIRST + 63 + LVM_APPROXIMATEVIEWRECT = LVM_FIRST + 64 + LVM_SETWORKAREAS = LVM_FIRST + 65 + LVM_GETWORKAREAS = LVM_FIRST + 70 + LVM_GETNUMBEROFWORKAREAS = LVM_FIRST + 73 + LVM_GETSELECTIONMARK = LVM_FIRST + 66 + LVM_SETSELECTIONMARK = LVM_FIRST + 67 + LVM_SETHOVERTIME = LVM_FIRST + 71 + LVM_GETHOVERTIME = LVM_FIRST + 72 + LVM_SETTOOLTIPS = LVM_FIRST + 74 + LVM_GETTOOLTIPS = LVM_FIRST + 78 + LVM_SORTITEMSEX = LVM_FIRST + 81 + LVM_SETBKIMAGE = LVM_FIRST + 138 + LVM_GETBKIMAGE = LVM_FIRST + 139 + LVM_SETSELECTEDCOLUMN = LVM_FIRST + 140 + LVM_SETVIEW = LVM_FIRST + 142 + LVM_GETVIEW = LVM_FIRST + 143 + LVM_INSERTGROUP = LVM_FIRST + 145 + LVM_SETGROUPINFO = LVM_FIRST + 147 + LVM_GETGROUPINFO = LVM_FIRST + 149 + LVM_REMOVEGROUP = LVM_FIRST + 150 + LVM_MOVEGROUP = LVM_FIRST + 151 + LVM_GETGROUPCOUNT = LVM_FIRST + 152 + LVM_GETGROUPINFOBYINDEX = LVM_FIRST + 153 + LVM_MOVEITEMTOGROUP = LVM_FIRST + 154 + LVM_GETGROUPRECT = LVM_FIRST + 98 + LVM_SETGROUPMETRICS = LVM_FIRST + 155 + LVM_GETGROUPMETRICS = LVM_FIRST + 156 + LVM_ENABLEGROUPVIEW = LVM_FIRST + 157 + LVM_SORTGROUPS = LVM_FIRST + 158 + LVM_INSERTGROUPSORTED = LVM_FIRST + 159 + LVM_REMOVEALLGROUPS = LVM_FIRST + 160 + LVM_HASGROUP = LVM_FIRST + 161 + LVM_GETGROUPSTATE = LVM_FIRST + 92 + LVM_GETFOCUSEDGROUP = LVM_FIRST + 93 + LVM_SETTILEVIEWINFO = LVM_FIRST + 162 + LVM_GETTILEVIEWINFO = LVM_FIRST + 163 + LVM_SETTILEINFO = LVM_FIRST + 164 + LVM_GETTILEINFO = LVM_FIRST + 165 + LVM_SETINSERTMARK = LVM_FIRST + 166 + LVM_GETINSERTMARK = LVM_FIRST + 167 + LVM_INSERTMARKHITTEST = LVM_FIRST + 168 + LVM_GETINSERTMARKRECT = LVM_FIRST + 169 + LVM_SETINSERTMARKCOLOR = LVM_FIRST + 170 + LVM_GETINSERTMARKCOLOR = LVM_FIRST + 171 + LVM_SETINFOTIP = LVM_FIRST + 173 + LVM_GETSELECTEDCOLUMN = LVM_FIRST + 174 + LVM_ISGROUPVIEWENABLED = LVM_FIRST + 175 + LVM_GETOUTLINECOLOR = LVM_FIRST + 176 + LVM_SETOUTLINECOLOR = LVM_FIRST + 177 + LVM_CANCELEDITLABEL = LVM_FIRST + 179 + LVM_MAPINDEXTOID = LVM_FIRST + 180 + LVM_MAPIDTOINDEX = LVM_FIRST + 181 + LVM_ISITEMVISIBLE = LVM_FIRST + 182 + LVM_GETNEXTITEMINDEX = LVM_FIRST + 211 +) + +// ListView notifications +const ( + LVN_FIRST = ^uint32(99) // -100 + + LVN_ITEMCHANGING = LVN_FIRST - 0 + LVN_ITEMCHANGED = LVN_FIRST - 1 + LVN_INSERTITEM = LVN_FIRST - 2 + LVN_DELETEITEM = LVN_FIRST - 3 + LVN_DELETEALLITEMS = LVN_FIRST - 4 + LVN_BEGINLABELEDIT = LVN_FIRST - 75 + LVN_ENDLABELEDIT = LVN_FIRST - 76 + LVN_COLUMNCLICK = LVN_FIRST - 8 + LVN_BEGINDRAG = LVN_FIRST - 9 + LVN_BEGINRDRAG = LVN_FIRST - 11 + LVN_ODCACHEHINT = LVN_FIRST - 13 + LVN_ODFINDITEM = LVN_FIRST - 79 + LVN_ITEMACTIVATE = LVN_FIRST - 14 + LVN_ODSTATECHANGED = LVN_FIRST - 15 + LVN_HOTTRACK = LVN_FIRST - 21 + LVN_GETDISPINFO = LVN_FIRST - 77 + LVN_SETDISPINFO = LVN_FIRST - 78 + LVN_KEYDOWN = LVN_FIRST - 55 + LVN_MARQUEEBEGIN = LVN_FIRST - 56 + LVN_GETINFOTIP = LVN_FIRST - 58 + LVN_INCREMENTALSEARCH = LVN_FIRST - 63 + LVN_BEGINSCROLL = LVN_FIRST - 80 + LVN_ENDSCROLL = LVN_FIRST - 81 +) + +// ListView LVNI constants +const ( + LVNI_ALL = 0 + LVNI_FOCUSED = 1 + LVNI_SELECTED = 2 + LVNI_CUT = 4 + LVNI_DROPHILITED = 8 + LVNI_ABOVE = 256 + LVNI_BELOW = 512 + LVNI_TOLEFT = 1024 + LVNI_TORIGHT = 2048 +) + +// ListView styles +const ( + LVS_ICON = 0x0000 + LVS_REPORT = 0x0001 + LVS_SMALLICON = 0x0002 + LVS_LIST = 0x0003 + LVS_TYPEMASK = 0x0003 + LVS_SINGLESEL = 0x0004 + LVS_SHOWSELALWAYS = 0x0008 + LVS_SORTASCENDING = 0x0010 + LVS_SORTDESCENDING = 0x0020 + LVS_SHAREIMAGELISTS = 0x0040 + LVS_NOLABELWRAP = 0x0080 + LVS_AUTOARRANGE = 0x0100 + LVS_EDITLABELS = 0x0200 + LVS_OWNERDATA = 0x1000 + LVS_NOSCROLL = 0x2000 + LVS_TYPESTYLEMASK = 0xfc00 + LVS_ALIGNTOP = 0x0000 + LVS_ALIGNLEFT = 0x0800 + LVS_ALIGNMASK = 0x0c00 + LVS_OWNERDRAWFIXED = 0x0400 + LVS_NOCOLUMNHEADER = 0x4000 + LVS_NOSORTHEADER = 0x8000 +) + +// ListView extended styles +const ( + LVS_EX_GRIDLINES = 0x00000001 + LVS_EX_SUBITEMIMAGES = 0x00000002 + LVS_EX_CHECKBOXES = 0x00000004 + LVS_EX_TRACKSELECT = 0x00000008 + LVS_EX_HEADERDRAGDROP = 0x00000010 + LVS_EX_FULLROWSELECT = 0x00000020 + LVS_EX_ONECLICKACTIVATE = 0x00000040 + LVS_EX_TWOCLICKACTIVATE = 0x00000080 + LVS_EX_FLATSB = 0x00000100 + LVS_EX_REGIONAL = 0x00000200 + LVS_EX_INFOTIP = 0x00000400 + LVS_EX_UNDERLINEHOT = 0x00000800 + LVS_EX_UNDERLINECOLD = 0x00001000 + LVS_EX_MULTIWORKAREAS = 0x00002000 + LVS_EX_LABELTIP = 0x00004000 + LVS_EX_BORDERSELECT = 0x00008000 + LVS_EX_DOUBLEBUFFER = 0x00010000 + LVS_EX_HIDELABELS = 0x00020000 + LVS_EX_SINGLEROW = 0x00040000 + LVS_EX_SNAPTOGRID = 0x00080000 + LVS_EX_SIMPLESELECT = 0x00100000 +) + +// ListView column flags +const ( + LVCF_FMT = 0x0001 + LVCF_WIDTH = 0x0002 + LVCF_TEXT = 0x0004 + LVCF_SUBITEM = 0x0008 + LVCF_IMAGE = 0x0010 + LVCF_ORDER = 0x0020 +) + +// ListView column format constants +const ( + LVCFMT_LEFT = 0x0000 + LVCFMT_RIGHT = 0x0001 + LVCFMT_CENTER = 0x0002 + LVCFMT_JUSTIFYMASK = 0x0003 + LVCFMT_IMAGE = 0x0800 + LVCFMT_BITMAP_ON_RIGHT = 0x1000 + LVCFMT_COL_HAS_IMAGES = 0x8000 +) + +// ListView item flags +const ( + LVIF_TEXT = 0x00000001 + LVIF_IMAGE = 0x00000002 + LVIF_PARAM = 0x00000004 + LVIF_STATE = 0x00000008 + LVIF_INDENT = 0x00000010 + LVIF_NORECOMPUTE = 0x00000800 + LVIF_GROUPID = 0x00000100 + LVIF_COLUMNS = 0x00000200 +) + +// ListView item states +const ( + LVIS_FOCUSED = 1 + LVIS_SELECTED = 2 + LVIS_CUT = 4 + LVIS_DROPHILITED = 8 + LVIS_OVERLAYMASK = 0xF00 + LVIS_STATEIMAGEMASK = 0xF000 +) + +// ListView hit test constants +const ( + LVHT_NOWHERE = 0x00000001 + LVHT_ONITEMICON = 0x00000002 + LVHT_ONITEMLABEL = 0x00000004 + LVHT_ONITEMSTATEICON = 0x00000008 + LVHT_ONITEM = LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON + + LVHT_ABOVE = 0x00000008 + LVHT_BELOW = 0x00000010 + LVHT_TORIGHT = 0x00000020 + LVHT_TOLEFT = 0x00000040 +) + +// ListView image list types +const ( + LVSIL_NORMAL = 0 + LVSIL_SMALL = 1 + LVSIL_STATE = 2 + LVSIL_GROUPHEADER = 3 +) + +type LVCOLUMN struct { + Mask uint32 + Fmt int32 + Cx int32 + PszText *uint16 + CchTextMax int32 + ISubItem int32 + IImage int32 + IOrder int32 +} + +type LVITEM struct { + Mask uint32 + IItem int32 + ISubItem int32 + State uint32 + StateMask uint32 + PszText *uint16 + CchTextMax int32 + IImage int32 + LParam uintptr + IIndent int32 + IGroupId int32 + CColumns uint32 + PuColumns uint32 +} + +type LVHITTESTINFO struct { + Pt POINT + Flags uint32 + IItem int32 + ISubItem int32 + IGroup int32 +} + +type NMITEMACTIVATE struct { + Hdr NMHDR + IItem int32 + ISubItem int32 + UNewState uint32 + UOldState uint32 + UChanged uint32 + PtAction POINT + LParam uintptr + UKeyFlags uint32 +} + +type NMLISTVIEW struct { + Hdr NMHDR + IItem int32 + ISubItem int32 + UNewState uint32 + UOldState uint32 + UChanged uint32 + PtAction POINT + LParam uintptr +} + +type NMLVCUSTOMDRAW struct { + Nmcd NMCUSTOMDRAW + ClrText COLORREF + ClrTextBk COLORREF + ISubItem int32 + DwItemType uint32 + ClrFace COLORREF + IIconEffect int32 + IIconPhase int32 + IPartId int32 + IStateId int32 + RcText RECT + UAlign uint32 +} + +type NMLVDISPINFO struct { + Hdr NMHDR + Item LVITEM +} + +type NMLVSCROLL struct { + Hdr NMHDR + Dx int32 + Dy int32 +} diff --git a/gui/vendor/github.com/lxn/win/menu.go b/gui/vendor/github.com/lxn/win/menu.go new file mode 100644 index 0000000..0773f29 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/menu.go @@ -0,0 +1,110 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +// Constants for MENUITEMINFO.fMask +const ( + MIIM_STATE = 1 + MIIM_ID = 2 + MIIM_SUBMENU = 4 + MIIM_CHECKMARKS = 8 + MIIM_TYPE = 16 + MIIM_DATA = 32 + MIIM_STRING = 64 + MIIM_BITMAP = 128 + MIIM_FTYPE = 256 +) + +// Constants for MENUITEMINFO.fType +const ( + MFT_BITMAP = 4 + MFT_MENUBARBREAK = 32 + MFT_MENUBREAK = 64 + MFT_OWNERDRAW = 256 + MFT_RADIOCHECK = 512 + MFT_RIGHTJUSTIFY = 0x4000 + MFT_SEPARATOR = 0x800 + MFT_RIGHTORDER = 0x2000 + MFT_STRING = 0 +) + +// Constants for MENUITEMINFO.fState +const ( + MFS_CHECKED = 8 + MFS_DEFAULT = 4096 + MFS_DISABLED = 3 + MFS_ENABLED = 0 + MFS_GRAYED = 3 + MFS_HILITE = 128 + MFS_UNCHECKED = 0 + MFS_UNHILITE = 0 +) + +// Constants for MENUITEMINFO.hbmp* +const ( + HBMMENU_CALLBACK = -1 + HBMMENU_SYSTEM = 1 + HBMMENU_MBAR_RESTORE = 2 + HBMMENU_MBAR_MINIMIZE = 3 + HBMMENU_MBAR_CLOSE = 5 + HBMMENU_MBAR_CLOSE_D = 6 + HBMMENU_MBAR_MINIMIZE_D = 7 + HBMMENU_POPUP_CLOSE = 8 + HBMMENU_POPUP_RESTORE = 9 + HBMMENU_POPUP_MAXIMIZE = 10 + HBMMENU_POPUP_MINIMIZE = 11 +) + +// MENUINFO mask constants +const ( + MIM_APPLYTOSUBMENUS = 0x80000000 + MIM_BACKGROUND = 0x00000002 + MIM_HELPID = 0x00000004 + MIM_MAXHEIGHT = 0x00000001 + MIM_MENUDATA = 0x00000008 + MIM_STYLE = 0x00000010 +) + +// MENUINFO style constants +const ( + MNS_AUTODISMISS = 0x10000000 + MNS_CHECKORBMP = 0x04000000 + MNS_DRAGDROP = 0x20000000 + MNS_MODELESS = 0x40000000 + MNS_NOCHECK = 0x80000000 + MNS_NOTIFYBYPOS = 0x08000000 +) + +const ( + MF_BYCOMMAND = 0x00000000 + MF_BYPOSITION = 0x00000400 +) + +type MENUITEMINFO struct { + CbSize uint32 + FMask uint32 + FType uint32 + FState uint32 + WID uint32 + HSubMenu HMENU + HbmpChecked HBITMAP + HbmpUnchecked HBITMAP + DwItemData uintptr + DwTypeData *uint16 + Cch uint32 + HbmpItem HBITMAP +} + +type MENUINFO struct { + CbSize uint32 + FMask uint32 + DwStyle uint32 + CyMax uint32 + HbrBack HBRUSH + DwContextHelpID uint32 + DwMenuData uintptr +} diff --git a/gui/vendor/github.com/lxn/win/ole32.go b/gui/vendor/github.com/lxn/win/ole32.go new file mode 100644 index 0000000..d75dee7 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/ole32.go @@ -0,0 +1,500 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +const ( + CLSCTX_INPROC_SERVER = 0x1 + CLSCTX_INPROC_HANDLER = 0x2 + CLSCTX_LOCAL_SERVER = 0x4 + CLSCTX_INPROC_SERVER16 = 0x8 + CLSCTX_REMOTE_SERVER = 0x10 + CLSCTX_INPROC_HANDLER16 = 0x20 + CLSCTX_RESERVED1 = 0x40 + CLSCTX_RESERVED2 = 0x80 + CLSCTX_RESERVED3 = 0x100 + CLSCTX_RESERVED4 = 0x200 + CLSCTX_NO_CODE_DOWNLOAD = 0x400 + CLSCTX_RESERVED5 = 0x800 + CLSCTX_NO_CUSTOM_MARSHAL = 0x1000 + CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000 + CLSCTX_NO_FAILURE_LOG = 0x4000 + CLSCTX_DISABLE_AAA = 0x8000 + CLSCTX_ENABLE_AAA = 0x10000 + CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000 + CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000 + CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000 + CLSCTX_ENABLE_CLOAKING = 0x100000 + CLSCTX_PS_DLL = 0x80000000 + CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER +) + +// Verbs for IOleObject.DoVerb +const ( + OLEIVERB_PRIMARY = 0 + OLEIVERB_SHOW = -1 + OLEIVERB_OPEN = -2 + OLEIVERB_HIDE = -3 + OLEIVERB_UIACTIVATE = -4 + OLEIVERB_INPLACEACTIVATE = -5 + OLEIVERB_DISCARDUNDOSTATE = -6 +) + +// OLECLOSE constants +const ( + OLECLOSE_SAVEIFDIRTY = 0 + OLECLOSE_NOSAVE = 1 + OLECLOSE_PROMPTSAVE = 2 +) + +type IID syscall.GUID +type CLSID syscall.GUID +type REFIID *IID +type REFCLSID *CLSID + +var ( + IID_IClassFactory = IID{0x00000001, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} + IID_IConnectionPointContainer = IID{0xB196B284, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}} + IID_IOleClientSite = IID{0x00000118, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} + IID_IOleInPlaceObject = IID{0x00000113, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} + IID_IOleInPlaceSite = IID{0x00000119, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} + IID_IOleObject = IID{0x00000112, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} + IID_IUnknown = IID{0x00000000, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} +) + +func EqualREFIID(a, b REFIID) bool { + if a == b { + return true + } + if a == nil || b == nil { + return false + } + + if a.Data1 != b.Data1 || a.Data2 != b.Data2 || a.Data3 != b.Data3 { + return false + } + + for i := 0; i < 8; i++ { + if a.Data4[i] != b.Data4[i] { + return false + } + } + + return true +} + +type IClassFactoryVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + CreateInstance uintptr + LockServer uintptr +} + +type IClassFactory struct { + LpVtbl *IClassFactoryVtbl +} + +func (cf *IClassFactory) Release() uint32 { + ret, _, _ := syscall.Syscall(cf.LpVtbl.Release, 1, + uintptr(unsafe.Pointer(cf)), + 0, + 0) + + return uint32(ret) +} + +func (cf *IClassFactory) CreateInstance(pUnkOuter *IUnknown, riid REFIID, ppvObject *unsafe.Pointer) HRESULT { + ret, _, _ := syscall.Syscall6(cf.LpVtbl.CreateInstance, 4, + uintptr(unsafe.Pointer(cf)), + uintptr(unsafe.Pointer(pUnkOuter)), + uintptr(unsafe.Pointer(riid)), + uintptr(unsafe.Pointer(ppvObject)), + 0, + 0) + + return HRESULT(ret) +} + +type IConnectionPointVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + GetConnectionInterface uintptr + GetConnectionPointContainer uintptr + Advise uintptr + Unadvise uintptr + EnumConnections uintptr +} + +type IConnectionPoint struct { + LpVtbl *IConnectionPointVtbl +} + +func (cp *IConnectionPoint) Release() uint32 { + ret, _, _ := syscall.Syscall(cp.LpVtbl.Release, 1, + uintptr(unsafe.Pointer(cp)), + 0, + 0) + + return uint32(ret) +} + +func (cp *IConnectionPoint) Advise(pUnkSink unsafe.Pointer, pdwCookie *uint32) HRESULT { + ret, _, _ := syscall.Syscall(cp.LpVtbl.Advise, 3, + uintptr(unsafe.Pointer(cp)), + uintptr(pUnkSink), + uintptr(unsafe.Pointer(pdwCookie))) + + return HRESULT(ret) +} + +type IConnectionPointContainerVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + EnumConnectionPoints uintptr + FindConnectionPoint uintptr +} + +type IConnectionPointContainer struct { + LpVtbl *IConnectionPointContainerVtbl +} + +func (cpc *IConnectionPointContainer) Release() uint32 { + ret, _, _ := syscall.Syscall(cpc.LpVtbl.Release, 1, + uintptr(unsafe.Pointer(cpc)), + 0, + 0) + + return uint32(ret) +} + +func (cpc *IConnectionPointContainer) FindConnectionPoint(riid REFIID, ppCP **IConnectionPoint) HRESULT { + ret, _, _ := syscall.Syscall(cpc.LpVtbl.FindConnectionPoint, 3, + uintptr(unsafe.Pointer(cpc)), + uintptr(unsafe.Pointer(riid)), + uintptr(unsafe.Pointer(ppCP))) + + return HRESULT(ret) +} + +type IOleClientSiteVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + SaveObject uintptr + GetMoniker uintptr + GetContainer uintptr + ShowObject uintptr + OnShowWindow uintptr + RequestNewObjectLayout uintptr +} + +type IOleClientSite struct { + LpVtbl *IOleClientSiteVtbl +} + +type IOleInPlaceFrameVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + GetWindow uintptr + ContextSensitiveHelp uintptr + GetBorder uintptr + RequestBorderSpace uintptr + SetBorderSpace uintptr + SetActiveObject uintptr + InsertMenus uintptr + SetMenu uintptr + RemoveMenus uintptr + SetStatusText uintptr + EnableModeless uintptr + TranslateAccelerator uintptr +} + +type IOleInPlaceFrame struct { + LpVtbl *IOleInPlaceFrameVtbl +} + +type IOleInPlaceObjectVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + GetWindow uintptr + ContextSensitiveHelp uintptr + InPlaceDeactivate uintptr + UIDeactivate uintptr + SetObjectRects uintptr + ReactivateAndUndo uintptr +} + +type IOleInPlaceObject struct { + LpVtbl *IOleInPlaceObjectVtbl +} + +func (obj *IOleInPlaceObject) Release() uint32 { + ret, _, _ := syscall.Syscall(obj.LpVtbl.Release, 1, + uintptr(unsafe.Pointer(obj)), + 0, + 0) + + return uint32(ret) +} + +func (obj *IOleInPlaceObject) SetObjectRects(lprcPosRect, lprcClipRect *RECT) HRESULT { + ret, _, _ := syscall.Syscall(obj.LpVtbl.SetObjectRects, 3, + uintptr(unsafe.Pointer(obj)), + uintptr(unsafe.Pointer(lprcPosRect)), + uintptr(unsafe.Pointer(lprcClipRect))) + + return HRESULT(ret) +} + +type IOleInPlaceSiteVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + GetWindow uintptr + ContextSensitiveHelp uintptr + CanInPlaceActivate uintptr + OnInPlaceActivate uintptr + OnUIActivate uintptr + GetWindowContext uintptr + Scroll uintptr + OnUIDeactivate uintptr + OnInPlaceDeactivate uintptr + DiscardUndoState uintptr + DeactivateAndUndo uintptr + OnPosRectChange uintptr +} + +type IOleInPlaceSite struct { + LpVtbl *IOleInPlaceSiteVtbl +} + +type IOleObjectVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + SetClientSite uintptr + GetClientSite uintptr + SetHostNames uintptr + Close uintptr + SetMoniker uintptr + GetMoniker uintptr + InitFromData uintptr + GetClipboardData uintptr + DoVerb uintptr + EnumVerbs uintptr + Update uintptr + IsUpToDate uintptr + GetUserClassID uintptr + GetUserType uintptr + SetExtent uintptr + GetExtent uintptr + Advise uintptr + Unadvise uintptr + EnumAdvise uintptr + GetMiscStatus uintptr + SetColorScheme uintptr +} + +type IOleObject struct { + LpVtbl *IOleObjectVtbl +} + +func (obj *IOleObject) QueryInterface(riid REFIID, ppvObject *unsafe.Pointer) HRESULT { + ret, _, _ := syscall.Syscall(obj.LpVtbl.QueryInterface, 3, + uintptr(unsafe.Pointer(obj)), + uintptr(unsafe.Pointer(riid)), + uintptr(unsafe.Pointer(ppvObject))) + + return HRESULT(ret) +} + +func (obj *IOleObject) Release() uint32 { + ret, _, _ := syscall.Syscall(obj.LpVtbl.Release, 1, + uintptr(unsafe.Pointer(obj)), + 0, + 0) + + return uint32(ret) +} + +func (obj *IOleObject) SetClientSite(pClientSite *IOleClientSite) HRESULT { + ret, _, _ := syscall.Syscall(obj.LpVtbl.SetClientSite, 2, + uintptr(unsafe.Pointer(obj)), + uintptr(unsafe.Pointer(pClientSite)), + 0) + + return HRESULT(ret) +} + +func (obj *IOleObject) SetHostNames(szContainerApp, szContainerObj *uint16) HRESULT { + ret, _, _ := syscall.Syscall(obj.LpVtbl.SetHostNames, 3, + uintptr(unsafe.Pointer(obj)), + uintptr(unsafe.Pointer(szContainerApp)), + uintptr(unsafe.Pointer(szContainerObj))) + + return HRESULT(ret) +} + +func (obj *IOleObject) Close(dwSaveOption uint32) HRESULT { + ret, _, _ := syscall.Syscall(obj.LpVtbl.Close, 2, + uintptr(unsafe.Pointer(obj)), + uintptr(dwSaveOption), + 0) + + return HRESULT(ret) +} + +func (obj *IOleObject) DoVerb(iVerb int32, lpmsg *MSG, pActiveSite *IOleClientSite, lindex int32, hwndParent HWND, lprcPosRect *RECT) HRESULT { + ret, _, _ := syscall.Syscall9(obj.LpVtbl.DoVerb, 7, + uintptr(unsafe.Pointer(obj)), + uintptr(iVerb), + uintptr(unsafe.Pointer(lpmsg)), + uintptr(unsafe.Pointer(pActiveSite)), + uintptr(lindex), + uintptr(hwndParent), + uintptr(unsafe.Pointer(lprcPosRect)), + 0, + 0) + + return HRESULT(ret) +} + +type IUnknownVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr +} + +type IUnknown struct { + LpVtbl *IUnknownVtbl +} + +type OLEINPLACEFRAMEINFO struct { + Cb uint32 + FMDIApp BOOL + HwndFrame HWND + Haccel HACCEL + CAccelEntries uint32 +} + +type COAUTHIDENTITY struct { + User *uint16 + UserLength uint32 + Domain *uint16 + DomainLength uint32 + Password *uint16 + PasswordLength uint32 + Flags uint32 +} + +type COAUTHINFO struct { + dwAuthnSvc uint32 + dwAuthzSvc uint32 + pwszServerPrincName *uint16 + dwAuthnLevel uint32 + dwImpersonationLevel uint32 + pAuthIdentityData *COAUTHIDENTITY + dwCapabilities uint32 +} + +type COSERVERINFO struct { + dwReserved1 uint32 + pwszName *uint16 + pAuthInfo *COAUTHINFO + dwReserved2 uint32 +} + +var ( + // Library + libole32 uintptr + + // Functions + coCreateInstance uintptr + coGetClassObject uintptr + coTaskMemFree uintptr + oleInitialize uintptr + oleSetContainedObject uintptr + oleUninitialize uintptr +) + +func init() { + // Library + libole32 = MustLoadLibrary("ole32.dll") + + // Functions + coCreateInstance = MustGetProcAddress(libole32, "CoCreateInstance") + coGetClassObject = MustGetProcAddress(libole32, "CoGetClassObject") + coTaskMemFree = MustGetProcAddress(libole32, "CoTaskMemFree") + oleInitialize = MustGetProcAddress(libole32, "OleInitialize") + oleSetContainedObject = MustGetProcAddress(libole32, "OleSetContainedObject") + oleUninitialize = MustGetProcAddress(libole32, "OleUninitialize") +} + +func CoCreateInstance(rclsid REFCLSID, pUnkOuter *IUnknown, dwClsContext uint32, riid REFIID, ppv *unsafe.Pointer) HRESULT { + ret, _, _ := syscall.Syscall6(coCreateInstance, 5, + uintptr(unsafe.Pointer(rclsid)), + uintptr(unsafe.Pointer(pUnkOuter)), + uintptr(dwClsContext), + uintptr(unsafe.Pointer(riid)), + uintptr(unsafe.Pointer(ppv)), + 0) + + return HRESULT(ret) +} + +func CoGetClassObject(rclsid REFCLSID, dwClsContext uint32, pServerInfo *COSERVERINFO, riid REFIID, ppv *unsafe.Pointer) HRESULT { + ret, _, _ := syscall.Syscall6(coGetClassObject, 5, + uintptr(unsafe.Pointer(rclsid)), + uintptr(dwClsContext), + uintptr(unsafe.Pointer(pServerInfo)), + uintptr(unsafe.Pointer(riid)), + uintptr(unsafe.Pointer(ppv)), + 0) + + return HRESULT(ret) +} + +func CoTaskMemFree(pv uintptr) { + syscall.Syscall(coTaskMemFree, 1, + pv, + 0, + 0) +} + +func OleInitialize() HRESULT { + ret, _, _ := syscall.Syscall(oleInitialize, 1, // WTF, why does 0 not work here? + 0, + 0, + 0) + + return HRESULT(ret) +} + +func OleSetContainedObject(pUnknown *IUnknown, fContained bool) HRESULT { + ret, _, _ := syscall.Syscall(oleSetContainedObject, 2, + uintptr(unsafe.Pointer(pUnknown)), + uintptr(BoolToBOOL(fContained)), + 0) + + return HRESULT(ret) +} + +func OleUninitialize() { + syscall.Syscall(oleUninitialize, 0, + 0, + 0, + 0) +} diff --git a/gui/vendor/github.com/lxn/win/oleaut32.go b/gui/vendor/github.com/lxn/win/oleaut32.go new file mode 100644 index 0000000..9d0e016 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/oleaut32.go @@ -0,0 +1,462 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "fmt" + "syscall" + "unsafe" +) + +type DISPID int32 + +const ( + DISPID_BEFORENAVIGATE DISPID = 100 + DISPID_NAVIGATECOMPLETE DISPID = 101 + DISPID_STATUSTEXTCHANGE DISPID = 102 + DISPID_QUIT DISPID = 103 + DISPID_DOWNLOADCOMPLETE DISPID = 104 + DISPID_COMMANDSTATECHANGE DISPID = 105 + DISPID_DOWNLOADBEGIN DISPID = 106 + DISPID_NEWWINDOW DISPID = 107 + DISPID_PROGRESSCHANGE DISPID = 108 + DISPID_WINDOWMOVE DISPID = 109 + DISPID_WINDOWRESIZE DISPID = 110 + DISPID_WINDOWACTIVATE DISPID = 111 + DISPID_PROPERTYCHANGE DISPID = 112 + DISPID_TITLECHANGE DISPID = 113 + DISPID_TITLEICONCHANGE DISPID = 114 + DISPID_FRAMEBEFORENAVIGATE DISPID = 200 + DISPID_FRAMENAVIGATECOMPLETE DISPID = 201 + DISPID_FRAMENEWWINDOW DISPID = 204 + DISPID_BEFORENAVIGATE2 DISPID = 250 + DISPID_NEWWINDOW2 DISPID = 251 + DISPID_NAVIGATECOMPLETE2 DISPID = 252 + DISPID_ONQUIT DISPID = 253 + DISPID_ONVISIBLE DISPID = 254 + DISPID_ONTOOLBAR DISPID = 255 + DISPID_ONMENUBAR DISPID = 256 + DISPID_ONSTATUSBAR DISPID = 257 + DISPID_ONFULLSCREEN DISPID = 258 + DISPID_DOCUMENTCOMPLETE DISPID = 259 + DISPID_ONTHEATERMODE DISPID = 260 + DISPID_ONADDRESSBAR DISPID = 261 + DISPID_WINDOWSETRESIZABLE DISPID = 262 + DISPID_WINDOWCLOSING DISPID = 263 + DISPID_WINDOWSETLEFT DISPID = 264 + DISPID_WINDOWSETTOP DISPID = 265 + DISPID_WINDOWSETWIDTH DISPID = 266 + DISPID_WINDOWSETHEIGHT DISPID = 267 + DISPID_CLIENTTOHOSTWINDOW DISPID = 268 + DISPID_SETSECURELOCKICON DISPID = 269 + DISPID_FILEDOWNLOAD DISPID = 270 + DISPID_NAVIGATEERROR DISPID = 271 + DISPID_PRIVACYIMPACTEDSTATECHANGE DISPID = 272 + DISPID_NEWWINDOW3 DISPID = 273 +) + +var ( + IID_IDispatch = IID{0x00020400, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} +) + +const ( + DISP_E_MEMBERNOTFOUND = 0x80020003 +) + +const ( + CSC_UPDATECOMMANDS = ^0x0 + CSC_NAVIGATEFORWARD = 0x1 + CSC_NAVIGATEBACK = 0x2 +) + +type IDispatchVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + GetTypeInfoCount uintptr + GetTypeInfo uintptr + GetIDsOfNames uintptr + Invoke uintptr +} + +type IDispatch struct { + LpVtbl *IDispatchVtbl +} + +type VARTYPE uint16 + +const ( + VT_EMPTY VARTYPE = 0 + VT_NULL VARTYPE = 1 + VT_I2 VARTYPE = 2 + VT_I4 VARTYPE = 3 + VT_R4 VARTYPE = 4 + VT_R8 VARTYPE = 5 + VT_CY VARTYPE = 6 + VT_DATE VARTYPE = 7 + VT_BSTR VARTYPE = 8 + VT_DISPATCH VARTYPE = 9 + VT_ERROR VARTYPE = 10 + VT_BOOL VARTYPE = 11 + VT_VARIANT VARTYPE = 12 + VT_UNKNOWN VARTYPE = 13 + VT_DECIMAL VARTYPE = 14 + VT_I1 VARTYPE = 16 + VT_UI1 VARTYPE = 17 + VT_UI2 VARTYPE = 18 + VT_UI4 VARTYPE = 19 + VT_I8 VARTYPE = 20 + VT_UI8 VARTYPE = 21 + VT_INT VARTYPE = 22 + VT_UINT VARTYPE = 23 + VT_VOID VARTYPE = 24 + VT_HRESULT VARTYPE = 25 + VT_PTR VARTYPE = 26 + VT_SAFEARRAY VARTYPE = 27 + VT_CARRAY VARTYPE = 28 + VT_USERDEFINED VARTYPE = 29 + VT_LPSTR VARTYPE = 30 + VT_LPWSTR VARTYPE = 31 + VT_RECORD VARTYPE = 36 + VT_INT_PTR VARTYPE = 37 + VT_UINT_PTR VARTYPE = 38 + VT_FILETIME VARTYPE = 64 + VT_BLOB VARTYPE = 65 + VT_STREAM VARTYPE = 66 + VT_STORAGE VARTYPE = 67 + VT_STREAMED_OBJECT VARTYPE = 68 + VT_STORED_OBJECT VARTYPE = 69 + VT_BLOB_OBJECT VARTYPE = 70 + VT_CF VARTYPE = 71 + VT_CLSID VARTYPE = 72 + VT_VERSIONED_STREAM VARTYPE = 73 + VT_BSTR_BLOB VARTYPE = 0xfff + VT_VECTOR VARTYPE = 0x1000 + VT_ARRAY VARTYPE = 0x2000 + VT_BYREF VARTYPE = 0x4000 + VT_RESERVED VARTYPE = 0x8000 + VT_ILLEGAL VARTYPE = 0xffff + VT_ILLEGALMASKED VARTYPE = 0xfff + VT_TYPEMASK VARTYPE = 0xfff +) + +type VARIANTARG struct { + VARIANT +} + +type VARIANT_BOOL int16 + +const ( + VARIANT_TRUE VARIANT_BOOL = -1 + VARIANT_FALSE VARIANT_BOOL = 0 +) + +type SAFEARRAYBOUND struct { + CElements uint32 + LLbound int32 +} + +type SAFEARRAY struct { + CDims uint16 + FFeatures uint16 + CbElements uint32 + CLocks uint32 + PvData uintptr + Rgsabound [1]SAFEARRAYBOUND +} + +//type BSTR *uint16 + +func StringToBSTR(value string) *uint16 /*BSTR*/ { + // IMPORTANT: Don't forget to free the BSTR value when no longer needed! + return SysAllocString(value) +} + +func BSTRToString(value *uint16 /*BSTR*/) string { + // ISSUE: Is this really ok? + bstrArrPtr := (*[200000000]uint16)(unsafe.Pointer(value)) + + bstrSlice := make([]uint16, SysStringLen(value)) + copy(bstrSlice, bstrArrPtr[:]) + + return syscall.UTF16ToString(bstrSlice) +} + +func IntToVariantI4(value int32) *VAR_I4 { + return &VAR_I4{vt: VT_I4, lVal: value} +} + +func VariantI4ToInt(value *VAR_I4) int32 { + return value.lVal +} + +func BoolToVariantBool(value bool) *VAR_BOOL { + return &VAR_BOOL{vt: VT_BOOL, boolVal: VARIANT_BOOL(BoolToBOOL(value))} +} + +func VariantBoolToBool(value *VAR_BOOL) bool { + return value.boolVal != 0 +} + +func StringToVariantBSTR(value string) *VAR_BSTR { + // IMPORTANT: Don't forget to free the BSTR value when no longer needed! + return &VAR_BSTR{vt: VT_BSTR, bstrVal: StringToBSTR(value)} +} + +func VariantBSTRToString(value *VAR_BSTR) string { + return BSTRToString(value.bstrVal) +} + +func (v *VARIANT) MustLong() int32 { + value, err := v.Long() + if err != nil { + panic(err) + } + return value +} + +func (v *VARIANT) Long() (int32, error) { + if v.Vt != VT_I4 { + return 0, fmt.Errorf("Error: Long() v.Vt != VT_I4, ptr=%p, value=%+v", v, v) + } + p := (*VAR_I4)(unsafe.Pointer(v)) + return p.lVal, nil +} + +func (v *VARIANT) SetLong(value int32) { + v.Vt = VT_I4 + p := (*VAR_I4)(unsafe.Pointer(v)) + p.lVal = value +} + +func (v *VARIANT) MustULong() uint32 { + value, err := v.ULong() + if err != nil { + panic(err) + } + return value +} + +func (v *VARIANT) ULong() (uint32, error) { + if v.Vt != VT_UI4 { + return 0, fmt.Errorf("Error: ULong() v.Vt != VT_UI4, ptr=%p, value=%+v", v, v) + } + p := (*VAR_UI4)(unsafe.Pointer(v)) + return p.ulVal, nil +} + +func (v *VARIANT) SetULong(value uint32) { + v.Vt = VT_UI4 + p := (*VAR_UI4)(unsafe.Pointer(v)) + p.ulVal = value +} + +func (v *VARIANT) MustBool() VARIANT_BOOL { + value, err := v.Bool() + if err != nil { + panic(err) + } + return value +} + +func (v *VARIANT) Bool() (VARIANT_BOOL, error) { + if v.Vt != VT_BOOL { + return VARIANT_FALSE, fmt.Errorf("Error: Bool() v.Vt != VT_BOOL, ptr=%p, value=%+v", v, v) + } + p := (*VAR_BOOL)(unsafe.Pointer(v)) + return p.boolVal, nil +} + +func (v *VARIANT) SetBool(value VARIANT_BOOL) { + v.Vt = VT_BOOL + p := (*VAR_BOOL)(unsafe.Pointer(v)) + p.boolVal = value +} + +func (v *VARIANT) MustBSTR() *uint16 { + value, err := v.BSTR() + if err != nil { + panic(err) + } + return value +} + +func (v *VARIANT) BSTR() (*uint16, error) { + if v.Vt != VT_BSTR { + return nil, fmt.Errorf("Error: BSTR() v.Vt != VT_BSTR, ptr=%p, value=%+v", v, v) + } + p := (*VAR_BSTR)(unsafe.Pointer(v)) + return p.bstrVal, nil +} + +func (v *VARIANT) SetBSTR(value *uint16) { + v.Vt = VT_BSTR + p := (*VAR_BSTR)(unsafe.Pointer(v)) + p.bstrVal = value +} + +func (v *VARIANT) MustPDispatch() *IDispatch { + value, err := v.PDispatch() + if err != nil { + panic(err) + } + return value +} + +func (v *VARIANT) PDispatch() (*IDispatch, error) { + if v.Vt != VT_DISPATCH { + return nil, fmt.Errorf("Error: PDispatch() v.Vt != VT_DISPATCH, ptr=%p, value=%+v", v, v) + } + p := (*VAR_PDISP)(unsafe.Pointer(v)) + return p.pdispVal, nil +} + +func (v *VARIANT) SetPDispatch(value *IDispatch) { + v.Vt = VT_DISPATCH + p := (*VAR_PDISP)(unsafe.Pointer(v)) + p.pdispVal = value +} + +func (v *VARIANT) MustPVariant() *VARIANT { + value, err := v.PVariant() + if err != nil { + panic(err) + } + return value +} + +func (v *VARIANT) PVariant() (*VARIANT, error) { + if v.Vt != VT_BYREF|VT_VARIANT { + return nil, fmt.Errorf("Error: PVariant() v.Vt != VT_BYREF|VT_VARIANT, ptr=%p, value=%+v", v, v) + } + p := (*VAR_PVAR)(unsafe.Pointer(v)) + return p.pvarVal, nil +} + +func (v *VARIANT) SetPVariant(value *VARIANT) { + v.Vt = VT_BYREF | VT_VARIANT + p := (*VAR_PVAR)(unsafe.Pointer(v)) + p.pvarVal = value +} + +func (v *VARIANT) MustPBool() *VARIANT_BOOL { + value, err := v.PBool() + if err != nil { + panic(err) + } + return value +} + +func (v *VARIANT) PBool() (*VARIANT_BOOL, error) { + if v.Vt != VT_BYREF|VT_BOOL { + return nil, fmt.Errorf("Error: PBool() v.Vt != VT_BYREF|VT_BOOL, ptr=%p, value=%+v", v, v) + } + p := (*VAR_PBOOL)(unsafe.Pointer(v)) + return p.pboolVal, nil +} + +func (v *VARIANT) SetPBool(value *VARIANT_BOOL) { + v.Vt = VT_BYREF | VT_BOOL + p := (*VAR_PBOOL)(unsafe.Pointer(v)) + p.pboolVal = value +} + +func (v *VARIANT) MustPPDispatch() **IDispatch { + value, err := v.PPDispatch() + if err != nil { + panic(err) + } + return value +} + +func (v *VARIANT) PPDispatch() (**IDispatch, error) { + if v.Vt != VT_BYREF|VT_DISPATCH { + return nil, fmt.Errorf("PPDispatch() v.Vt != VT_BYREF|VT_DISPATCH, ptr=%p, value=%+v", v, v) + } + p := (*VAR_PPDISP)(unsafe.Pointer(v)) + return p.ppdispVal, nil +} + +func (v *VARIANT) SetPPDispatch(value **IDispatch) { + v.Vt = VT_BYREF | VT_DISPATCH + p := (*VAR_PPDISP)(unsafe.Pointer(v)) + p.ppdispVal = value +} + +func (v *VARIANT) MustPSafeArray() *SAFEARRAY { + value, err := v.PSafeArray() + if err != nil { + panic(err) + } + return value +} + +func (v *VARIANT) PSafeArray() (*SAFEARRAY, error) { + if (v.Vt & VT_ARRAY) != VT_ARRAY { + return nil, fmt.Errorf("Error: PSafeArray() (v.Vt & VT_ARRAY) != VT_ARRAY, ptr=%p, value=%+v", v, v) + } + p := (*VAR_PSAFEARRAY)(unsafe.Pointer(v)) + return p.parray, nil +} + +func (v *VARIANT) SetPSafeArray(value *SAFEARRAY, elementVt VARTYPE) { + v.Vt = VT_ARRAY | elementVt + p := (*VAR_PSAFEARRAY)(unsafe.Pointer(v)) + p.parray = value +} + +type DISPPARAMS struct { + Rgvarg *VARIANTARG + RgdispidNamedArgs *DISPID + CArgs int32 + CNamedArgs int32 +} + +var ( + // Library + liboleaut32 uintptr + + // Functions + sysAllocString uintptr + sysFreeString uintptr + sysStringLen uintptr +) + +func init() { + // Library + liboleaut32 = MustLoadLibrary("oleaut32.dll") + + // Functions + sysAllocString = MustGetProcAddress(liboleaut32, "SysAllocString") + sysFreeString = MustGetProcAddress(liboleaut32, "SysFreeString") + sysStringLen = MustGetProcAddress(liboleaut32, "SysStringLen") +} + +func SysAllocString(s string) *uint16 /*BSTR*/ { + ret, _, _ := syscall.Syscall(sysAllocString, 1, + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(s))), + 0, + 0) + + return (*uint16) /*BSTR*/ (unsafe.Pointer(ret)) +} + +func SysFreeString(bstr *uint16 /*BSTR*/) { + syscall.Syscall(sysFreeString, 1, + uintptr(unsafe.Pointer(bstr)), + 0, + 0) +} + +func SysStringLen(bstr *uint16 /*BSTR*/) uint32 { + ret, _, _ := syscall.Syscall(sysStringLen, 1, + uintptr(unsafe.Pointer(bstr)), + 0, + 0) + + return uint32(ret) +} diff --git a/gui/vendor/github.com/lxn/win/oleaut32_386.go b/gui/vendor/github.com/lxn/win/oleaut32_386.go new file mode 100644 index 0000000..5f3ce1f --- /dev/null +++ b/gui/vendor/github.com/lxn/win/oleaut32_386.go @@ -0,0 +1,75 @@ +// Copyright 2012 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +type VARIANT struct { + Vt VARTYPE + reserved [14]byte +} + +type VAR_I4 struct { + vt VARTYPE + reserved1 [6]byte + lVal int32 + reserved2 [4]byte +} + +type VAR_UI4 struct { + vt VARTYPE + reserved1 [6]byte + ulVal uint32 + reserved2 [4]byte +} + +type VAR_BOOL struct { + vt VARTYPE + reserved1 [6]byte + boolVal VARIANT_BOOL + reserved2 [6]byte +} + +type VAR_BSTR struct { + vt VARTYPE + reserved1 [6]byte + bstrVal *uint16 /*BSTR*/ + reserved2 [4]byte +} + +type VAR_PDISP struct { + vt VARTYPE + reserved1 [6]byte + pdispVal *IDispatch + reserved2 [4]byte +} + +type VAR_PSAFEARRAY struct { + vt VARTYPE + reserved1 [6]byte + parray *SAFEARRAY + reserved2 [4]byte +} + +type VAR_PVAR struct { + vt VARTYPE + reserved1 [6]byte + pvarVal *VARIANT + reserved2 [4]byte +} + +type VAR_PBOOL struct { + vt VARTYPE + reserved1 [6]byte + pboolVal *VARIANT_BOOL + reserved2 [4]byte +} + +type VAR_PPDISP struct { + vt VARTYPE + reserved1 [6]byte + ppdispVal **IDispatch + reserved2 [4]byte +} diff --git a/gui/vendor/github.com/lxn/win/oleaut32_amd64.go b/gui/vendor/github.com/lxn/win/oleaut32_amd64.go new file mode 100644 index 0000000..331a550 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/oleaut32_amd64.go @@ -0,0 +1,75 @@ +// Copyright 2012 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +type VARIANT struct { + Vt VARTYPE + reserved [22]byte +} + +type VAR_I4 struct { + vt VARTYPE + reserved1 [6]byte + lVal int32 + reserved2 [12]byte +} + +type VAR_UI4 struct { + vt VARTYPE + reserved1 [6]byte + ulVal uint32 + reserved2 [12]byte +} + +type VAR_BOOL struct { + vt VARTYPE + reserved1 [6]byte + boolVal VARIANT_BOOL + reserved2 [14]byte +} + +type VAR_BSTR struct { + vt VARTYPE + reserved1 [6]byte + bstrVal *uint16 /*BSTR*/ + reserved2 [8]byte +} + +type VAR_PDISP struct { + vt VARTYPE + reserved1 [6]byte + pdispVal *IDispatch + reserved2 [8]byte +} + +type VAR_PSAFEARRAY struct { + vt VARTYPE + reserved1 [6]byte + parray *SAFEARRAY + reserved2 [8]byte +} + +type VAR_PVAR struct { + vt VARTYPE + reserved1 [6]byte + pvarVal *VARIANT + reserved2 [8]byte +} + +type VAR_PBOOL struct { + vt VARTYPE + reserved1 [6]byte + pboolVal *VARIANT_BOOL + reserved2 [8]byte +} + +type VAR_PPDISP struct { + vt VARTYPE + reserved1 [6]byte + ppdispVal **IDispatch + reserved2 [8]byte +} diff --git a/gui/vendor/github.com/lxn/win/opengl32.go b/gui/vendor/github.com/lxn/win/opengl32.go new file mode 100644 index 0000000..dbacc22 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/opengl32.go @@ -0,0 +1,301 @@ +// Copyright 2011 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +// for second parameter of WglSwapLayerBuffers +const ( + WGL_SWAP_MAIN_PLANE = (1 << 0) + WGL_SWAP_OVERLAY1 = (1 << 1) + WGL_SWAP_OVERLAY2 = (1 << 2) + WGL_SWAP_OVERLAY3 = (1 << 3) + WGL_SWAP_OVERLAY4 = (1 << 4) + WGL_SWAP_OVERLAY5 = (1 << 5) + WGL_SWAP_OVERLAY6 = (1 << 6) + WGL_SWAP_OVERLAY7 = (1 << 7) + WGL_SWAP_OVERLAY8 = (1 << 8) + WGL_SWAP_OVERLAY9 = (1 << 9) + WGL_SWAP_OVERLAY10 = (1 << 10) + WGL_SWAP_OVERLAY11 = (1 << 11) + WGL_SWAP_OVERLAY12 = (1 << 12) + WGL_SWAP_OVERLAY13 = (1 << 13) + WGL_SWAP_OVERLAY14 = (1 << 14) + WGL_SWAP_OVERLAY15 = (1 << 15) + WGL_SWAP_UNDERLAY1 = (1 << 16) + WGL_SWAP_UNDERLAY2 = (1 << 17) + WGL_SWAP_UNDERLAY3 = (1 << 18) + WGL_SWAP_UNDERLAY4 = (1 << 19) + WGL_SWAP_UNDERLAY5 = (1 << 20) + WGL_SWAP_UNDERLAY6 = (1 << 21) + WGL_SWAP_UNDERLAY7 = (1 << 22) + WGL_SWAP_UNDERLAY8 = (1 << 23) + WGL_SWAP_UNDERLAY9 = (1 << 24) + WGL_SWAP_UNDERLAY10 = (1 << 25) + WGL_SWAP_UNDERLAY11 = (1 << 26) + WGL_SWAP_UNDERLAY12 = (1 << 27) + WGL_SWAP_UNDERLAY13 = (1 << 28) + WGL_SWAP_UNDERLAY14 = (1 << 29) + WGL_SWAP_UNDERLAY15 = (1 << 30) +) + +type ( + HGLRC HANDLE +) + +type LAYERPLANEDESCRIPTOR struct { + NSize uint16 + NVersion uint16 + DwFlags uint32 + IPixelType uint8 + CColorBits uint8 + CRedBits uint8 + CRedShift uint8 + CGreenBits uint8 + CGreenShift uint8 + CBlueBits uint8 + CBlueShift uint8 + CAlphaBits uint8 + CAlphaShift uint8 + CAccumBits uint8 + CAccumRedBits uint8 + CAccumGreenBits uint8 + CAccumBlueBits uint8 + CAccumAlphaBits uint8 + CDepthBits uint8 + CStencilBits uint8 + CAuxBuffers uint8 + ILayerType uint8 + BReserved uint8 + CrTransparent COLORREF +} + +type POINTFLOAT struct { + X, Y float32 +} + +type GLYPHMETRICSFLOAT struct { + GmfBlackBoxX float32 + GmfBlackBoxY float32 + GmfptGlyphOrigin POINTFLOAT + GmfCellIncX float32 + GmfCellIncY float32 +} + +var ( + // Library + lib uintptr + + // Functions + wglCopyContext uintptr + wglCreateContext uintptr + wglCreateLayerContext uintptr + wglDeleteContext uintptr + wglDescribeLayerPlane uintptr + wglGetCurrentContext uintptr + wglGetCurrentDC uintptr + wglGetLayerPaletteEntries uintptr + wglGetProcAddress uintptr + wglMakeCurrent uintptr + wglRealizeLayerPalette uintptr + wglSetLayerPaletteEntries uintptr + wglShareLists uintptr + wglSwapLayerBuffers uintptr + wglUseFontBitmaps uintptr + wglUseFontOutlines uintptr +) + +func init() { + // Library + lib = MustLoadLibrary("opengl32.dll") + + // Functions + wglCopyContext = MustGetProcAddress(lib, "wglCopyContext") + wglCreateContext = MustGetProcAddress(lib, "wglCreateContext") + wglCreateLayerContext = MustGetProcAddress(lib, "wglCreateLayerContext") + wglDeleteContext = MustGetProcAddress(lib, "wglDeleteContext") + wglDescribeLayerPlane = MustGetProcAddress(lib, "wglDescribeLayerPlane") + wglGetCurrentContext = MustGetProcAddress(lib, "wglGetCurrentContext") + wglGetCurrentDC = MustGetProcAddress(lib, "wglGetCurrentDC") + wglGetLayerPaletteEntries = MustGetProcAddress(lib, "wglGetLayerPaletteEntries") + wglGetProcAddress = MustGetProcAddress(lib, "wglGetProcAddress") + wglMakeCurrent = MustGetProcAddress(lib, "wglMakeCurrent") + wglRealizeLayerPalette = MustGetProcAddress(lib, "wglRealizeLayerPalette") + wglSetLayerPaletteEntries = MustGetProcAddress(lib, "wglSetLayerPaletteEntries") + wglShareLists = MustGetProcAddress(lib, "wglShareLists") + wglSwapLayerBuffers = MustGetProcAddress(lib, "wglSwapLayerBuffers") + wglUseFontBitmaps = MustGetProcAddress(lib, "wglUseFontBitmapsW") + wglUseFontOutlines = MustGetProcAddress(lib, "wglUseFontOutlinesW") +} + +func WglCopyContext(hglrcSrc, hglrcDst HGLRC, mask uint) bool { + ret, _, _ := syscall.Syscall(wglCopyContext, 3, + uintptr(hglrcSrc), + uintptr(hglrcDst), + uintptr(mask)) + + return ret != 0 +} + +func WglCreateContext(hdc HDC) HGLRC { + ret, _, _ := syscall.Syscall(wglCreateContext, 1, + uintptr(hdc), + 0, + 0) + + return HGLRC(ret) +} + +func WglCreateLayerContext(hdc HDC, iLayerPlane int) HGLRC { + ret, _, _ := syscall.Syscall(wglCreateLayerContext, 2, + uintptr(hdc), + uintptr(iLayerPlane), + 0) + + return HGLRC(ret) +} + +func WglDeleteContext(hglrc HGLRC) bool { + ret, _, _ := syscall.Syscall(wglDeleteContext, 1, + uintptr(hglrc), + 0, + 0) + + return ret != 0 +} + +func WglDescribeLayerPlane(hdc HDC, iPixelFormat, iLayerPlane int, nBytes uint8, plpd *LAYERPLANEDESCRIPTOR) bool { + ret, _, _ := syscall.Syscall6(wglDescribeLayerPlane, 5, + uintptr(hdc), + uintptr(iPixelFormat), + uintptr(iLayerPlane), + uintptr(nBytes), + uintptr(unsafe.Pointer(plpd)), + 0) + + return ret != 0 +} + +func WglGetCurrentContext() HGLRC { + ret, _, _ := syscall.Syscall(wglGetCurrentContext, 0, + 0, + 0, + 0) + + return HGLRC(ret) +} + +func WglGetCurrentDC() HDC { + ret, _, _ := syscall.Syscall(wglGetCurrentDC, 0, + 0, + 0, + 0) + + return HDC(ret) +} + +func WglGetLayerPaletteEntries(hdc HDC, iLayerPlane, iStart, cEntries int, pcr *COLORREF) int { + ret, _, _ := syscall.Syscall6(wglGetLayerPaletteEntries, 5, + uintptr(hdc), + uintptr(iLayerPlane), + uintptr(iStart), + uintptr(cEntries), + uintptr(unsafe.Pointer(pcr)), + 0) + + return int(ret) +} + +func WglGetProcAddress(lpszProc *byte) uintptr { + ret, _, _ := syscall.Syscall(wglGetProcAddress, 1, + uintptr(unsafe.Pointer(lpszProc)), + 0, + 0) + + return uintptr(ret) +} + +func WglMakeCurrent(hdc HDC, hglrc HGLRC) bool { + ret, _, _ := syscall.Syscall(wglMakeCurrent, 2, + uintptr(hdc), + uintptr(hglrc), + 0) + + return ret != 0 +} + +func WglRealizeLayerPalette(hdc HDC, iLayerPlane int, bRealize bool) bool { + ret, _, _ := syscall.Syscall(wglRealizeLayerPalette, 3, + uintptr(hdc), + uintptr(iLayerPlane), + uintptr(BoolToBOOL(bRealize))) + + return ret != 0 +} + +func WglSetLayerPaletteEntries(hdc HDC, iLayerPlane, iStart, cEntries int, pcr *COLORREF) int { + ret, _, _ := syscall.Syscall6(wglSetLayerPaletteEntries, 5, + uintptr(hdc), + uintptr(iLayerPlane), + uintptr(iStart), + uintptr(cEntries), + uintptr(unsafe.Pointer(pcr)), + 0) + + return int(ret) +} + +func WglShareLists(hglrc1, hglrc2 HGLRC) bool { + ret, _, _ := syscall.Syscall(wglShareLists, 2, + uintptr(hglrc1), + uintptr(hglrc2), + 0) + + return ret != 0 +} + +func WglSwapLayerBuffers(hdc HDC, fuPlanes uint) bool { + ret, _, _ := syscall.Syscall(wglSwapLayerBuffers, 2, + uintptr(hdc), + uintptr(fuPlanes), + 0) + + return ret != 0 +} + +func WglUseFontBitmaps(hdc HDC, first, count, listbase uint32) bool { + ret, _, _ := syscall.Syscall6(wglUseFontBitmaps, 4, + uintptr(hdc), + uintptr(first), + uintptr(count), + uintptr(listbase), + 0, + 0) + + return ret != 0 +} + +func WglUseFontOutlines(hdc HDC, first, count, listbase uint32, deviation, extrusion float32, format int, pgmf *GLYPHMETRICSFLOAT) bool { + ret, _, _ := syscall.Syscall12(wglUseFontBitmaps, 8, + uintptr(hdc), + uintptr(first), + uintptr(count), + uintptr(listbase), + uintptr(deviation), + uintptr(extrusion), + uintptr(format), + uintptr(unsafe.Pointer(pgmf)), + 0, + 0, + 0, + 0) + + return ret != 0 +} diff --git a/gui/vendor/github.com/lxn/win/pdh.go b/gui/vendor/github.com/lxn/win/pdh.go new file mode 100644 index 0000000..ca594fe --- /dev/null +++ b/gui/vendor/github.com/lxn/win/pdh.go @@ -0,0 +1,436 @@ +// Copyright 2013 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +// PDH error codes, which can be returned by all Pdh* functions. Taken from mingw-w64 pdhmsg.h +const ( + PDH_CSTATUS_VALID_DATA = 0x00000000 // The returned data is valid. + PDH_CSTATUS_NEW_DATA = 0x00000001 // The return data value is valid and different from the last sample. + PDH_CSTATUS_NO_MACHINE = 0x800007D0 // Unable to connect to the specified computer, or the computer is offline. + PDH_CSTATUS_NO_INSTANCE = 0x800007D1 + PDH_MORE_DATA = 0x800007D2 // The PdhGetFormattedCounterArray* function can return this if there's 'more data to be displayed'. + PDH_CSTATUS_ITEM_NOT_VALIDATED = 0x800007D3 + PDH_RETRY = 0x800007D4 + PDH_NO_DATA = 0x800007D5 // The query does not currently contain any counters (for example, limited access) + PDH_CALC_NEGATIVE_DENOMINATOR = 0x800007D6 + PDH_CALC_NEGATIVE_TIMEBASE = 0x800007D7 + PDH_CALC_NEGATIVE_VALUE = 0x800007D8 + PDH_DIALOG_CANCELLED = 0x800007D9 + PDH_END_OF_LOG_FILE = 0x800007DA + PDH_ASYNC_QUERY_TIMEOUT = 0x800007DB + PDH_CANNOT_SET_DEFAULT_REALTIME_DATASOURCE = 0x800007DC + PDH_CSTATUS_NO_OBJECT = 0xC0000BB8 + PDH_CSTATUS_NO_COUNTER = 0xC0000BB9 // The specified counter could not be found. + PDH_CSTATUS_INVALID_DATA = 0xC0000BBA // The counter was successfully found, but the data returned is not valid. + PDH_MEMORY_ALLOCATION_FAILURE = 0xC0000BBB + PDH_INVALID_HANDLE = 0xC0000BBC + PDH_INVALID_ARGUMENT = 0xC0000BBD // Required argument is missing or incorrect. + PDH_FUNCTION_NOT_FOUND = 0xC0000BBE + PDH_CSTATUS_NO_COUNTERNAME = 0xC0000BBF + PDH_CSTATUS_BAD_COUNTERNAME = 0xC0000BC0 // Unable to parse the counter path. Check the format and syntax of the specified path. + PDH_INVALID_BUFFER = 0xC0000BC1 + PDH_INSUFFICIENT_BUFFER = 0xC0000BC2 + PDH_CANNOT_CONNECT_MACHINE = 0xC0000BC3 + PDH_INVALID_PATH = 0xC0000BC4 + PDH_INVALID_INSTANCE = 0xC0000BC5 + PDH_INVALID_DATA = 0xC0000BC6 // specified counter does not contain valid data or a successful status code. + PDH_NO_DIALOG_DATA = 0xC0000BC7 + PDH_CANNOT_READ_NAME_STRINGS = 0xC0000BC8 + PDH_LOG_FILE_CREATE_ERROR = 0xC0000BC9 + PDH_LOG_FILE_OPEN_ERROR = 0xC0000BCA + PDH_LOG_TYPE_NOT_FOUND = 0xC0000BCB + PDH_NO_MORE_DATA = 0xC0000BCC + PDH_ENTRY_NOT_IN_LOG_FILE = 0xC0000BCD + PDH_DATA_SOURCE_IS_LOG_FILE = 0xC0000BCE + PDH_DATA_SOURCE_IS_REAL_TIME = 0xC0000BCF + PDH_UNABLE_READ_LOG_HEADER = 0xC0000BD0 + PDH_FILE_NOT_FOUND = 0xC0000BD1 + PDH_FILE_ALREADY_EXISTS = 0xC0000BD2 + PDH_NOT_IMPLEMENTED = 0xC0000BD3 + PDH_STRING_NOT_FOUND = 0xC0000BD4 + PDH_UNABLE_MAP_NAME_FILES = 0x80000BD5 + PDH_UNKNOWN_LOG_FORMAT = 0xC0000BD6 + PDH_UNKNOWN_LOGSVC_COMMAND = 0xC0000BD7 + PDH_LOGSVC_QUERY_NOT_FOUND = 0xC0000BD8 + PDH_LOGSVC_NOT_OPENED = 0xC0000BD9 + PDH_WBEM_ERROR = 0xC0000BDA + PDH_ACCESS_DENIED = 0xC0000BDB + PDH_LOG_FILE_TOO_SMALL = 0xC0000BDC + PDH_INVALID_DATASOURCE = 0xC0000BDD + PDH_INVALID_SQLDB = 0xC0000BDE + PDH_NO_COUNTERS = 0xC0000BDF + PDH_SQL_ALLOC_FAILED = 0xC0000BE0 + PDH_SQL_ALLOCCON_FAILED = 0xC0000BE1 + PDH_SQL_EXEC_DIRECT_FAILED = 0xC0000BE2 + PDH_SQL_FETCH_FAILED = 0xC0000BE3 + PDH_SQL_ROWCOUNT_FAILED = 0xC0000BE4 + PDH_SQL_MORE_RESULTS_FAILED = 0xC0000BE5 + PDH_SQL_CONNECT_FAILED = 0xC0000BE6 + PDH_SQL_BIND_FAILED = 0xC0000BE7 + PDH_CANNOT_CONNECT_WMI_SERVER = 0xC0000BE8 + PDH_PLA_COLLECTION_ALREADY_RUNNING = 0xC0000BE9 + PDH_PLA_ERROR_SCHEDULE_OVERLAP = 0xC0000BEA + PDH_PLA_COLLECTION_NOT_FOUND = 0xC0000BEB + PDH_PLA_ERROR_SCHEDULE_ELAPSED = 0xC0000BEC + PDH_PLA_ERROR_NOSTART = 0xC0000BED + PDH_PLA_ERROR_ALREADY_EXISTS = 0xC0000BEE + PDH_PLA_ERROR_TYPE_MISMATCH = 0xC0000BEF + PDH_PLA_ERROR_FILEPATH = 0xC0000BF0 + PDH_PLA_SERVICE_ERROR = 0xC0000BF1 + PDH_PLA_VALIDATION_ERROR = 0xC0000BF2 + PDH_PLA_VALIDATION_WARNING = 0x80000BF3 + PDH_PLA_ERROR_NAME_TOO_LONG = 0xC0000BF4 + PDH_INVALID_SQL_LOG_FORMAT = 0xC0000BF5 + PDH_COUNTER_ALREADY_IN_QUERY = 0xC0000BF6 + PDH_BINARY_LOG_CORRUPT = 0xC0000BF7 + PDH_LOG_SAMPLE_TOO_SMALL = 0xC0000BF8 + PDH_OS_LATER_VERSION = 0xC0000BF9 + PDH_OS_EARLIER_VERSION = 0xC0000BFA + PDH_INCORRECT_APPEND_TIME = 0xC0000BFB + PDH_UNMATCHED_APPEND_COUNTER = 0xC0000BFC + PDH_SQL_ALTER_DETAIL_FAILED = 0xC0000BFD + PDH_QUERY_PERF_DATA_TIMEOUT = 0xC0000BFE +) + +// Formatting options for GetFormattedCounterValue(). +const ( + PDH_FMT_RAW = 0x00000010 + PDH_FMT_ANSI = 0x00000020 + PDH_FMT_UNICODE = 0x00000040 + PDH_FMT_LONG = 0x00000100 // Return data as a long int. + PDH_FMT_DOUBLE = 0x00000200 // Return data as a double precision floating point real. + PDH_FMT_LARGE = 0x00000400 // Return data as a 64 bit integer. + PDH_FMT_NOSCALE = 0x00001000 // can be OR-ed: Do not apply the counter's default scaling factor. + PDH_FMT_1000 = 0x00002000 // can be OR-ed: multiply the actual value by 1,000. + PDH_FMT_NODATA = 0x00004000 // can be OR-ed: unknown what this is for, MSDN says nothing. + PDH_FMT_NOCAP100 = 0x00008000 // can be OR-ed: do not cap values > 100. + PERF_DETAIL_COSTLY = 0x00010000 + PERF_DETAIL_STANDARD = 0x0000FFFF +) + +type ( + PDH_HQUERY HANDLE // query handle + PDH_HCOUNTER HANDLE // counter handle +) + +// Union specialization for double values +type PDH_FMT_COUNTERVALUE_DOUBLE struct { + CStatus uint32 + DoubleValue float64 +} + +// Union specialization for 64 bit integer values +type PDH_FMT_COUNTERVALUE_LARGE struct { + CStatus uint32 + LargeValue int64 +} + +// Union specialization for long values +type PDH_FMT_COUNTERVALUE_LONG struct { + CStatus uint32 + LongValue int32 + padding [4]byte +} + +// Union specialization for double values, used by PdhGetFormattedCounterArrayDouble() +type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE struct { + SzName *uint16 // pointer to a string + FmtValue PDH_FMT_COUNTERVALUE_DOUBLE +} + +// Union specialization for 'large' values, used by PdhGetFormattedCounterArrayLarge() +type PDH_FMT_COUNTERVALUE_ITEM_LARGE struct { + SzName *uint16 // pointer to a string + FmtValue PDH_FMT_COUNTERVALUE_LARGE +} + +// Union specialization for long values, used by PdhGetFormattedCounterArrayLong() +type PDH_FMT_COUNTERVALUE_ITEM_LONG struct { + SzName *uint16 // pointer to a string + FmtValue PDH_FMT_COUNTERVALUE_LONG +} + +var ( + // Library + libpdhDll *syscall.DLL + + // Functions + pdh_AddCounterW *syscall.Proc + pdh_AddEnglishCounterW *syscall.Proc + pdh_CloseQuery *syscall.Proc + pdh_CollectQueryData *syscall.Proc + pdh_GetFormattedCounterValue *syscall.Proc + pdh_GetFormattedCounterArrayW *syscall.Proc + pdh_OpenQuery *syscall.Proc + pdh_ValidatePathW *syscall.Proc +) + +func init() { + // Library + libpdhDll = syscall.MustLoadDLL("pdh.dll") + + // Functions + pdh_AddCounterW = libpdhDll.MustFindProc("PdhAddCounterW") + pdh_AddEnglishCounterW, _ = libpdhDll.FindProc("PdhAddEnglishCounterW") // XXX: only supported on versions > Vista. + pdh_CloseQuery = libpdhDll.MustFindProc("PdhCloseQuery") + pdh_CollectQueryData = libpdhDll.MustFindProc("PdhCollectQueryData") + pdh_GetFormattedCounterValue = libpdhDll.MustFindProc("PdhGetFormattedCounterValue") + pdh_GetFormattedCounterArrayW = libpdhDll.MustFindProc("PdhGetFormattedCounterArrayW") + pdh_OpenQuery = libpdhDll.MustFindProc("PdhOpenQuery") + pdh_ValidatePathW = libpdhDll.MustFindProc("PdhValidatePathW") +} + +// Adds the specified counter to the query. This is the internationalized version. Preferably, use the +// function PdhAddEnglishCounter instead. hQuery is the query handle, which has been fetched by PdhOpenQuery. +// szFullCounterPath is a full, internationalized counter path (this will differ per Windows language version). +// dwUserData is a 'user-defined value', which becomes part of the counter information. To retrieve this value +// later, call PdhGetCounterInfo() and access dwQueryUserData of the PDH_COUNTER_INFO structure. +// +// Examples of szFullCounterPath (in an English version of Windows): +// +// \\Processor(_Total)\\% Idle Time +// \\Processor(_Total)\\% Processor Time +// \\LogicalDisk(C:)\% Free Space +// +// To view all (internationalized...) counters on a system, there are three non-programmatic ways: perfmon utility, +// the typeperf command, and the the registry editor. perfmon.exe is perhaps the easiest way, because it's basically a +// full implemention of the pdh.dll API, except with a GUI and all that. The registry setting also provides an +// interface to the available counters, and can be found at the following key: +// +// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage +// +// This registry key contains several values as follows: +// +// 1 +// 1847 +// 2 +// System +// 4 +// Memory +// 6 +// % Processor Time +// ... many, many more +// +// Somehow, these numeric values can be used as szFullCounterPath too: +// +// \2\6 will correspond to \\System\% Processor Time +// +// The typeperf command may also be pretty easy. To find all performance counters, simply execute: +// +// typeperf -qx +func PdhAddCounter(hQuery PDH_HQUERY, szFullCounterPath string, dwUserData uintptr, phCounter *PDH_HCOUNTER) uint32 { + ptxt, _ := syscall.UTF16PtrFromString(szFullCounterPath) + ret, _, _ := pdh_AddCounterW.Call( + uintptr(hQuery), + uintptr(unsafe.Pointer(ptxt)), + dwUserData, + uintptr(unsafe.Pointer(phCounter))) + + return uint32(ret) +} + +// Adds the specified language-neutral counter to the query. See the PdhAddCounter function. This function only exists on +// Windows versions higher than Vista. +func PdhAddEnglishCounter(hQuery PDH_HQUERY, szFullCounterPath string, dwUserData uintptr, phCounter *PDH_HCOUNTER) uint32 { + if pdh_AddEnglishCounterW == nil { + return ERROR_INVALID_FUNCTION + } + + ptxt, _ := syscall.UTF16PtrFromString(szFullCounterPath) + ret, _, _ := pdh_AddEnglishCounterW.Call( + uintptr(hQuery), + uintptr(unsafe.Pointer(ptxt)), + dwUserData, + uintptr(unsafe.Pointer(phCounter))) + + return uint32(ret) +} + +// Closes all counters contained in the specified query, closes all handles related to the query, +// and frees all memory associated with the query. +func PdhCloseQuery(hQuery PDH_HQUERY) uint32 { + ret, _, _ := pdh_CloseQuery.Call(uintptr(hQuery)) + + return uint32(ret) +} + +// Collects the current raw data value for all counters in the specified query and updates the status +// code of each counter. With some counters, this function needs to be repeatedly called before the value +// of the counter can be extracted with PdhGetFormattedCounterValue(). For example, the following code +// requires at least two calls: +// +// var handle win.PDH_HQUERY +// var counterHandle win.PDH_HCOUNTER +// ret := win.PdhOpenQuery(0, 0, &handle) +// ret = win.PdhAddEnglishCounter(handle, "\\Processor(_Total)\\% Idle Time", 0, &counterHandle) +// var derp win.PDH_FMT_COUNTERVALUE_DOUBLE +// +// ret = win.PdhCollectQueryData(handle) +// fmt.Printf("Collect return code is %x\n", ret) // return code will be PDH_CSTATUS_INVALID_DATA +// ret = win.PdhGetFormattedCounterValueDouble(counterHandle, 0, &derp) +// +// ret = win.PdhCollectQueryData(handle) +// fmt.Printf("Collect return code is %x\n", ret) // return code will be ERROR_SUCCESS +// ret = win.PdhGetFormattedCounterValueDouble(counterHandle, 0, &derp) +// +// The PdhCollectQueryData will return an error in the first call because it needs two values for +// displaying the correct data for the processor idle time. The second call will have a 0 return code. +func PdhCollectQueryData(hQuery PDH_HQUERY) uint32 { + ret, _, _ := pdh_CollectQueryData.Call(uintptr(hQuery)) + + return uint32(ret) +} + +// Formats the given hCounter using a 'double'. The result is set into the specialized union struct pValue. +// This function does not directly translate to a Windows counterpart due to union specialization tricks. +func PdhGetFormattedCounterValueDouble(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_DOUBLE) uint32 { + ret, _, _ := pdh_GetFormattedCounterValue.Call( + uintptr(hCounter), + uintptr(PDH_FMT_DOUBLE), + uintptr(unsafe.Pointer(lpdwType)), + uintptr(unsafe.Pointer(pValue))) + + return uint32(ret) +} + +// Formats the given hCounter using a large int (int64). The result is set into the specialized union struct pValue. +// This function does not directly translate to a Windows counterpart due to union specialization tricks. +func PdhGetFormattedCounterValueLarge(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_LARGE) uint32 { + ret, _, _ := pdh_GetFormattedCounterValue.Call( + uintptr(hCounter), + uintptr(PDH_FMT_LARGE), + uintptr(unsafe.Pointer(lpdwType)), + uintptr(unsafe.Pointer(pValue))) + + return uint32(ret) +} + +// Formats the given hCounter using a 'long'. The result is set into the specialized union struct pValue. +// This function does not directly translate to a Windows counterpart due to union specialization tricks. +// +// BUG(krpors): Testing this function on multiple systems yielded inconsistent results. For instance, +// the pValue.LongValue kept the value '192' on test system A, but on B this was '0', while the padding +// bytes of the struct got the correct value. Until someone can figure out this behaviour, prefer to use +// the Double or Large counterparts instead. These functions provide actually the same data, except in +// a different, working format. +func PdhGetFormattedCounterValueLong(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_LONG) uint32 { + ret, _, _ := pdh_GetFormattedCounterValue.Call( + uintptr(hCounter), + uintptr(PDH_FMT_LONG), + uintptr(unsafe.Pointer(lpdwType)), + uintptr(unsafe.Pointer(pValue))) + + return uint32(ret) +} + +// Returns an array of formatted counter values. Use this function when you want to format the counter values of a +// counter that contains a wildcard character for the instance name. The itemBuffer must a slice of type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE. +// An example of how this function can be used: +// +// okPath := "\\Process(*)\\% Processor Time" // notice the wildcard * character +// +// // ommitted all necessary stuff ... +// +// var bufSize uint32 +// var bufCount uint32 +// var size uint32 = uint32(unsafe.Sizeof(win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE{})) +// var emptyBuf [1]win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE // need at least 1 addressable null ptr. +// +// for { +// // collect +// ret := win.PdhCollectQueryData(queryHandle) +// if ret == win.ERROR_SUCCESS { +// ret = win.PdhGetFormattedCounterArrayDouble(counterHandle, &bufSize, &bufCount, &emptyBuf[0]) // uses null ptr here according to MSDN. +// if ret == win.PDH_MORE_DATA { +// filledBuf := make([]win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE, bufCount*size) +// ret = win.PdhGetFormattedCounterArrayDouble(counterHandle, &bufSize, &bufCount, &filledBuf[0]) +// for i := 0; i < int(bufCount); i++ { +// c := filledBuf[i] +// var s string = win.UTF16PtrToString(c.SzName) +// fmt.Printf("Index %d -> %s, value %v\n", i, s, c.FmtValue.DoubleValue) +// } +// +// filledBuf = nil +// // Need to at least set bufSize to zero, because if not, the function will not +// // return PDH_MORE_DATA and will not set the bufSize. +// bufCount = 0 +// bufSize = 0 +// } +// +// time.Sleep(2000 * time.Millisecond) +// } +// } +func PdhGetFormattedCounterArrayDouble(hCounter PDH_HCOUNTER, lpdwBufferSize *uint32, lpdwBufferCount *uint32, itemBuffer *PDH_FMT_COUNTERVALUE_ITEM_DOUBLE) uint32 { + ret, _, _ := pdh_GetFormattedCounterArrayW.Call( + uintptr(hCounter), + uintptr(PDH_FMT_DOUBLE), + uintptr(unsafe.Pointer(lpdwBufferSize)), + uintptr(unsafe.Pointer(lpdwBufferCount)), + uintptr(unsafe.Pointer(itemBuffer))) + + return uint32(ret) +} + +// Returns an array of formatted counter values. Use this function when you want to format the counter values of a +// counter that contains a wildcard character for the instance name. The itemBuffer must a slice of type PDH_FMT_COUNTERVALUE_ITEM_LARGE. +// For an example usage, see PdhGetFormattedCounterArrayDouble. +func PdhGetFormattedCounterArrayLarge(hCounter PDH_HCOUNTER, lpdwBufferSize *uint32, lpdwBufferCount *uint32, itemBuffer *PDH_FMT_COUNTERVALUE_ITEM_LARGE) uint32 { + ret, _, _ := pdh_GetFormattedCounterArrayW.Call( + uintptr(hCounter), + uintptr(PDH_FMT_LARGE), + uintptr(unsafe.Pointer(lpdwBufferSize)), + uintptr(unsafe.Pointer(lpdwBufferCount)), + uintptr(unsafe.Pointer(itemBuffer))) + + return uint32(ret) +} + +// Returns an array of formatted counter values. Use this function when you want to format the counter values of a +// counter that contains a wildcard character for the instance name. The itemBuffer must a slice of type PDH_FMT_COUNTERVALUE_ITEM_LONG. +// For an example usage, see PdhGetFormattedCounterArrayDouble. +// +// BUG(krpors): See description of PdhGetFormattedCounterValueLong(). +func PdhGetFormattedCounterArrayLong(hCounter PDH_HCOUNTER, lpdwBufferSize *uint32, lpdwBufferCount *uint32, itemBuffer *PDH_FMT_COUNTERVALUE_ITEM_LONG) uint32 { + ret, _, _ := pdh_GetFormattedCounterArrayW.Call( + uintptr(hCounter), + uintptr(PDH_FMT_LONG), + uintptr(unsafe.Pointer(lpdwBufferSize)), + uintptr(unsafe.Pointer(lpdwBufferCount)), + uintptr(unsafe.Pointer(itemBuffer))) + + return uint32(ret) +} + +// Creates a new query that is used to manage the collection of performance data. +// szDataSource is a null terminated string that specifies the name of the log file from which to +// retrieve the performance data. If 0, performance data is collected from a real-time data source. +// dwUserData is a user-defined value to associate with this query. To retrieve the user data later, +// call PdhGetCounterInfo and access dwQueryUserData of the PDH_COUNTER_INFO structure. phQuery is +// the handle to the query, and must be used in subsequent calls. This function returns a PDH_ +// constant error code, or ERROR_SUCCESS if the call succeeded. +func PdhOpenQuery(szDataSource uintptr, dwUserData uintptr, phQuery *PDH_HQUERY) uint32 { + ret, _, _ := pdh_OpenQuery.Call( + szDataSource, + dwUserData, + uintptr(unsafe.Pointer(phQuery))) + + return uint32(ret) +} + +// Validates a path. Will return ERROR_SUCCESS when ok, or PDH_CSTATUS_BAD_COUNTERNAME when the path is +// erroneous. +func PdhValidatePath(path string) uint32 { + ptxt, _ := syscall.UTF16PtrFromString(path) + ret, _, _ := pdh_ValidatePathW.Call(uintptr(unsafe.Pointer(ptxt))) + + return uint32(ret) +} diff --git a/gui/vendor/github.com/lxn/win/shdocvw.go b/gui/vendor/github.com/lxn/win/shdocvw.go new file mode 100644 index 0000000..6d1e81a --- /dev/null +++ b/gui/vendor/github.com/lxn/win/shdocvw.go @@ -0,0 +1,327 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +const ( + DOCHOSTUIDBLCLK_DEFAULT = 0 + DOCHOSTUIDBLCLK_SHOWPROPERTIES = 1 + DOCHOSTUIDBLCLK_SHOWCODE = 2 +) + +const ( + DOCHOSTUIFLAG_DIALOG = 0x1 + DOCHOSTUIFLAG_DISABLE_HELP_MENU = 0x2 + DOCHOSTUIFLAG_NO3DBORDER = 0x4 + DOCHOSTUIFLAG_SCROLL_NO = 0x8 + DOCHOSTUIFLAG_DISABLE_SCRIPT_INACTIVE = 0x10 + DOCHOSTUIFLAG_OPENNEWWIN = 0x20 + DOCHOSTUIFLAG_DISABLE_OFFSCREEN = 0x40 + DOCHOSTUIFLAG_FLAT_SCROLLBAR = 0x80 + DOCHOSTUIFLAG_DIV_BLOCKDEFAULT = 0x100 + DOCHOSTUIFLAG_ACTIVATE_CLIENTHIT_ONLY = 0x200 + DOCHOSTUIFLAG_OVERRIDEBEHAVIORFACTORY = 0x400 + DOCHOSTUIFLAG_CODEPAGELINKEDFONTS = 0x800 + DOCHOSTUIFLAG_URL_ENCODING_DISABLE_UTF8 = 0x1000 + DOCHOSTUIFLAG_URL_ENCODING_ENABLE_UTF8 = 0x2000 + DOCHOSTUIFLAG_ENABLE_FORMS_AUTOCOMPLETE = 0x4000 + DOCHOSTUIFLAG_ENABLE_INPLACE_NAVIGATION = 0x10000 + DOCHOSTUIFLAG_IME_ENABLE_RECONVERSION = 0x20000 + DOCHOSTUIFLAG_THEME = 0x40000 + DOCHOSTUIFLAG_NOTHEME = 0x80000 + DOCHOSTUIFLAG_NOPICS = 0x100000 + DOCHOSTUIFLAG_NO3DOUTERBORDER = 0x200000 + DOCHOSTUIFLAG_DISABLE_EDIT_NS_FIXUP = 0x400000 + DOCHOSTUIFLAG_LOCAL_MACHINE_ACCESS_CHECK = 0x800000 + DOCHOSTUIFLAG_DISABLE_UNTRUSTEDPROTOCOL = 0x1000000 +) + +// BrowserNavConstants +const ( + NavOpenInNewWindow = 0x1 + NavNoHistory = 0x2 + NavNoReadFromCache = 0x4 + NavNoWriteToCache = 0x8 + NavAllowAutosearch = 0x10 + NavBrowserBar = 0x20 + NavHyperlink = 0x40 + NavEnforceRestricted = 0x80 + NavNewWindowsManaged = 0x0100 + NavUntrustedForDownload = 0x0200 + NavTrustedForActiveX = 0x0400 + NavOpenInNewTab = 0x0800 + NavOpenInBackgroundTab = 0x1000 + NavKeepWordWheelText = 0x2000 + NavVirtualTab = 0x4000 + NavBlockRedirectsXDomain = 0x8000 + NavOpenNewForegroundTab = 0x10000 +) + +var ( + CLSID_WebBrowser = CLSID{0x8856F961, 0x340A, 0x11D0, [8]byte{0xA9, 0x6B, 0x00, 0xC0, 0x4F, 0xD7, 0x05, 0xA2}} + DIID_DWebBrowserEvents2 = IID{0x34A715A0, 0x6587, 0x11D0, [8]byte{0x92, 0x4A, 0x00, 0x20, 0xAF, 0xC7, 0xAC, 0x4D}} + IID_IWebBrowser2 = IID{0xD30C1661, 0xCDAF, 0x11D0, [8]byte{0x8A, 0x3E, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E}} + IID_IDocHostUIHandler = IID{0xBD3F23C0, 0xD43E, 0x11CF, [8]byte{0x89, 0x3B, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x1A}} + IID_IOleInPlaceActiveObject = IID{0x00000117, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} +) + +type DWebBrowserEvents2Vtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + GetTypeInfoCount uintptr + GetTypeInfo uintptr + GetIDsOfNames uintptr + Invoke uintptr +} + +type DWebBrowserEvents2 struct { + LpVtbl *DWebBrowserEvents2Vtbl +} + +type IWebBrowser2Vtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + GetTypeInfoCount uintptr + GetTypeInfo uintptr + GetIDsOfNames uintptr + Invoke uintptr + GoBack uintptr + GoForward uintptr + GoHome uintptr + GoSearch uintptr + Navigate uintptr + Refresh uintptr + Refresh2 uintptr + Stop uintptr + Get_Application uintptr + Get_Parent uintptr + Get_Container uintptr + Get_Document uintptr + Get_TopLevelContainer uintptr + Get_Type uintptr + Get_Left uintptr + Put_Left uintptr + Get_Top uintptr + Put_Top uintptr + Get_Width uintptr + Put_Width uintptr + Get_Height uintptr + Put_Height uintptr + Get_LocationName uintptr + Get_LocationURL uintptr + Get_Busy uintptr + Quit uintptr + ClientToWindow uintptr + PutProperty uintptr + GetProperty uintptr + Get_Name uintptr + Get_HWND uintptr + Get_FullName uintptr + Get_Path uintptr + Get_Visible uintptr + Put_Visible uintptr + Get_StatusBar uintptr + Put_StatusBar uintptr + Get_StatusText uintptr + Put_StatusText uintptr + Get_ToolBar uintptr + Put_ToolBar uintptr + Get_MenuBar uintptr + Put_MenuBar uintptr + Get_FullScreen uintptr + Put_FullScreen uintptr + Navigate2 uintptr + QueryStatusWB uintptr + ExecWB uintptr + ShowBrowserBar uintptr + Get_ReadyState uintptr + Get_Offline uintptr + Put_Offline uintptr + Get_Silent uintptr + Put_Silent uintptr + Get_RegisterAsBrowser uintptr + Put_RegisterAsBrowser uintptr + Get_RegisterAsDropTarget uintptr + Put_RegisterAsDropTarget uintptr + Get_TheaterMode uintptr + Put_TheaterMode uintptr + Get_AddressBar uintptr + Put_AddressBar uintptr + Get_Resizable uintptr + Put_Resizable uintptr +} + +type IWebBrowser2 struct { + LpVtbl *IWebBrowser2Vtbl +} + +func (wb2 *IWebBrowser2) QueryInterface(riid REFIID, ppvObject *unsafe.Pointer) HRESULT { + ret, _, _ := syscall.Syscall(wb2.LpVtbl.QueryInterface, 3, + uintptr(unsafe.Pointer(wb2)), + uintptr(unsafe.Pointer(riid)), + uintptr(unsafe.Pointer(ppvObject))) + + return HRESULT(ret) +} + +func (wb2 *IWebBrowser2) Release() HRESULT { + ret, _, _ := syscall.Syscall(wb2.LpVtbl.Release, 1, + uintptr(unsafe.Pointer(wb2)), + 0, + 0) + + return HRESULT(ret) +} + +func (wb2 *IWebBrowser2) Refresh() HRESULT { + ret, _, _ := syscall.Syscall(wb2.LpVtbl.Refresh, 1, + uintptr(unsafe.Pointer(wb2)), + 0, + 0) + + return HRESULT(ret) +} + +func (wb2 *IWebBrowser2) Put_Left(Left int32) HRESULT { + ret, _, _ := syscall.Syscall(wb2.LpVtbl.Put_Left, 2, + uintptr(unsafe.Pointer(wb2)), + uintptr(Left), + 0) + + return HRESULT(ret) +} + +func (wb2 *IWebBrowser2) Put_Top(Top int32) HRESULT { + ret, _, _ := syscall.Syscall(wb2.LpVtbl.Put_Top, 2, + uintptr(unsafe.Pointer(wb2)), + uintptr(Top), + 0) + + return HRESULT(ret) +} + +func (wb2 *IWebBrowser2) Put_Width(Width int32) HRESULT { + ret, _, _ := syscall.Syscall(wb2.LpVtbl.Put_Width, 2, + uintptr(unsafe.Pointer(wb2)), + uintptr(Width), + 0) + + return HRESULT(ret) +} + +func (wb2 *IWebBrowser2) Put_Height(Height int32) HRESULT { + ret, _, _ := syscall.Syscall(wb2.LpVtbl.Put_Height, 2, + uintptr(unsafe.Pointer(wb2)), + uintptr(Height), + 0) + + return HRESULT(ret) +} + +func (wb2 *IWebBrowser2) Get_LocationURL(pbstrLocationURL **uint16 /*BSTR*/) HRESULT { + ret, _, _ := syscall.Syscall(wb2.LpVtbl.Get_LocationURL, 2, + uintptr(unsafe.Pointer(wb2)), + uintptr(unsafe.Pointer(pbstrLocationURL)), + 0) + + return HRESULT(ret) +} + +func (wb2 *IWebBrowser2) Navigate2(URL *VAR_BSTR, Flags *VAR_I4, TargetFrameName *VAR_BSTR, PostData unsafe.Pointer, Headers *VAR_BSTR) HRESULT { + ret, _, _ := syscall.Syscall6(wb2.LpVtbl.Navigate2, 6, + uintptr(unsafe.Pointer(wb2)), + uintptr(unsafe.Pointer(URL)), + uintptr(unsafe.Pointer(Flags)), + uintptr(unsafe.Pointer(TargetFrameName)), + uintptr(PostData), + uintptr(unsafe.Pointer(Headers))) + + return HRESULT(ret) +} + +type IDocHostUIHandlerVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + ShowContextMenu uintptr + GetHostInfo uintptr + ShowUI uintptr + HideUI uintptr + UpdateUI uintptr + EnableModeless uintptr + OnDocWindowActivate uintptr + OnFrameWindowActivate uintptr + ResizeBorder uintptr + TranslateAccelerator uintptr + GetOptionKeyPath uintptr + GetDropTarget uintptr + GetExternal uintptr + TranslateUrl uintptr + FilterDataObject uintptr +} + +type IDocHostUIHandler struct { + LpVtbl *IDocHostUIHandlerVtbl +} + +type DOCHOSTUIINFO struct { + CbSize uint32 + DwFlags uint32 + DwDoubleClick uint32 + PchHostCss *uint16 + PchHostNS *uint16 +} + +type IOleInPlaceActiveObjectVtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + GetWindow uintptr + ContextSensitiveHelp uintptr + TranslateAccelerator uintptr + OnFrameWindowActivate uintptr + OnDocWindowActivate uintptr + ResizeBorder uintptr + EnableModeless uintptr +} + +type IOleInPlaceActiveObject struct { + LpVtbl *IOleInPlaceActiveObjectVtbl +} + +func (activeObj *IOleInPlaceActiveObject) Release() HRESULT { + ret, _, _ := syscall.Syscall(activeObj.LpVtbl.Release, 1, + uintptr(unsafe.Pointer(activeObj)), + 0, + 0) + + return HRESULT(ret) +} + +func (activeObj *IOleInPlaceActiveObject) GetWindow(hWndPtr *HWND) HRESULT { + ret, _, _ := syscall.Syscall(activeObj.LpVtbl.GetWindow, 2, + uintptr(unsafe.Pointer(activeObj)), + uintptr(unsafe.Pointer(hWndPtr)), + 0) + + return HRESULT(ret) +} + +func (activeObj *IOleInPlaceActiveObject) TranslateAccelerator(msg *MSG) HRESULT { + ret, _, _ := syscall.Syscall(activeObj.LpVtbl.TranslateAccelerator, 2, + uintptr(unsafe.Pointer(activeObj)), + uintptr(unsafe.Pointer(msg)), + 0) + + return HRESULT(ret) +} diff --git a/gui/vendor/github.com/lxn/win/shell32.go b/gui/vendor/github.com/lxn/win/shell32.go new file mode 100644 index 0000000..e9aa4bf --- /dev/null +++ b/gui/vendor/github.com/lxn/win/shell32.go @@ -0,0 +1,429 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +type CSIDL uint32 +type HDROP HANDLE + +const ( + CSIDL_DESKTOP = 0x00 + CSIDL_INTERNET = 0x01 + CSIDL_PROGRAMS = 0x02 + CSIDL_CONTROLS = 0x03 + CSIDL_PRINTERS = 0x04 + CSIDL_PERSONAL = 0x05 + CSIDL_FAVORITES = 0x06 + CSIDL_STARTUP = 0x07 + CSIDL_RECENT = 0x08 + CSIDL_SENDTO = 0x09 + CSIDL_BITBUCKET = 0x0A + CSIDL_STARTMENU = 0x0B + CSIDL_MYDOCUMENTS = 0x0C + CSIDL_MYMUSIC = 0x0D + CSIDL_MYVIDEO = 0x0E + CSIDL_DESKTOPDIRECTORY = 0x10 + CSIDL_DRIVES = 0x11 + CSIDL_NETWORK = 0x12 + CSIDL_NETHOOD = 0x13 + CSIDL_FONTS = 0x14 + CSIDL_TEMPLATES = 0x15 + CSIDL_COMMON_STARTMENU = 0x16 + CSIDL_COMMON_PROGRAMS = 0x17 + CSIDL_COMMON_STARTUP = 0x18 + CSIDL_COMMON_DESKTOPDIRECTORY = 0x19 + CSIDL_APPDATA = 0x1A + CSIDL_PRINTHOOD = 0x1B + CSIDL_LOCAL_APPDATA = 0x1C + CSIDL_ALTSTARTUP = 0x1D + CSIDL_COMMON_ALTSTARTUP = 0x1E + CSIDL_COMMON_FAVORITES = 0x1F + CSIDL_INTERNET_CACHE = 0x20 + CSIDL_COOKIES = 0x21 + CSIDL_HISTORY = 0x22 + CSIDL_COMMON_APPDATA = 0x23 + CSIDL_WINDOWS = 0x24 + CSIDL_SYSTEM = 0x25 + CSIDL_PROGRAM_FILES = 0x26 + CSIDL_MYPICTURES = 0x27 + CSIDL_PROFILE = 0x28 + CSIDL_SYSTEMX86 = 0x29 + CSIDL_PROGRAM_FILESX86 = 0x2A + CSIDL_PROGRAM_FILES_COMMON = 0x2B + CSIDL_PROGRAM_FILES_COMMONX86 = 0x2C + CSIDL_COMMON_TEMPLATES = 0x2D + CSIDL_COMMON_DOCUMENTS = 0x2E + CSIDL_COMMON_ADMINTOOLS = 0x2F + CSIDL_ADMINTOOLS = 0x30 + CSIDL_CONNECTIONS = 0x31 + CSIDL_COMMON_MUSIC = 0x35 + CSIDL_COMMON_PICTURES = 0x36 + CSIDL_COMMON_VIDEO = 0x37 + CSIDL_RESOURCES = 0x38 + CSIDL_RESOURCES_LOCALIZED = 0x39 + CSIDL_COMMON_OEM_LINKS = 0x3A + CSIDL_CDBURN_AREA = 0x3B + CSIDL_COMPUTERSNEARME = 0x3D + CSIDL_FLAG_CREATE = 0x8000 + CSIDL_FLAG_DONT_VERIFY = 0x4000 + CSIDL_FLAG_NO_ALIAS = 0x1000 + CSIDL_FLAG_PER_USER_INIT = 0x8000 + CSIDL_FLAG_MASK = 0xFF00 +) + +// NotifyIcon flags +const ( + NIF_MESSAGE = 0x00000001 + NIF_ICON = 0x00000002 + NIF_TIP = 0x00000004 + NIF_STATE = 0x00000008 + NIF_INFO = 0x00000010 +) + +// NotifyIcon messages +const ( + NIM_ADD = 0x00000000 + NIM_MODIFY = 0x00000001 + NIM_DELETE = 0x00000002 + NIM_SETFOCUS = 0x00000003 + NIM_SETVERSION = 0x00000004 +) + +// NotifyIcon states +const ( + NIS_HIDDEN = 0x00000001 + NIS_SHAREDICON = 0x00000002 +) + +// NotifyIcon info flags +const ( + NIIF_NONE = 0x00000000 + NIIF_INFO = 0x00000001 + NIIF_WARNING = 0x00000002 + NIIF_ERROR = 0x00000003 + NIIF_USER = 0x00000004 + NIIF_NOSOUND = 0x00000010 +) + +const NOTIFYICON_VERSION = 3 + +// SHGetFileInfo flags +const ( + SHGFI_LARGEICON = 0x000000000 + SHGFI_SMALLICON = 0x000000001 + SHGFI_OPENICON = 0x000000002 + SHGFI_SHELLICONSIZE = 0x000000004 + SHGFI_PIDL = 0x000000008 + SHGFI_USEFILEATTRIBUTES = 0x000000010 + SHGFI_ADDOVERLAYS = 0x000000020 + SHGFI_OVERLAYINDEX = 0x000000040 + SHGFI_ICON = 0x000000100 + SHGFI_DISPLAYNAME = 0x000000200 + SHGFI_TYPENAME = 0x000000400 + SHGFI_ATTRIBUTES = 0x000000800 + SHGFI_ICONLOCATION = 0x000001000 + SHGFI_EXETYPE = 0x000002000 + SHGFI_SYSICONINDEX = 0x000004000 + SHGFI_LINKOVERLAY = 0x000008000 + SHGFI_SELECTED = 0x000010000 + SHGFI_ATTR_SPECIFIED = 0x000020000 +) + +// SHGetStockIconInfo flags +const ( + SHGSI_ICONLOCATION = 0 + SHGSI_ICON = 0x000000100 + SHGSI_SYSICONINDEX = 0x000004000 + SHGSI_LINKOVERLAY = 0x000008000 + SHGSI_SELECTED = 0x000010000 + SHGSI_LARGEICON = 0x000000000 + SHGSI_SMALLICON = 0x000000001 + SHGSI_SHELLICONSIZE = 0x000000004 +) + +// SHSTOCKICONID values +const ( + SIID_DOCNOASSOC = 0 + SIID_DOCASSOC = 1 + SIID_APPLICATION = 2 + SIID_FOLDER = 3 + SIID_FOLDEROPEN = 4 + SIID_DRIVE525 = 5 + SIID_DRIVE35 = 6 + SIID_DRIVEREMOVE = 7 + SIID_DRIVEFIXED = 8 + SIID_DRIVENET = 9 + SIID_DRIVENETDISABLED = 10 + SIID_DRIVECD = 11 + SIID_DRIVERAM = 12 + SIID_WORLD = 13 + SIID_SERVER = 15 + SIID_PRINTER = 16 + SIID_MYNETWORK = 17 + SIID_FIND = 22 + SIID_HELP = 23 + SIID_SHARE = 28 + SIID_LINK = 29 + SIID_SLOWFILE = 30 + SIID_RECYCLER = 31 + SIID_RECYCLERFULL = 32 + SIID_MEDIACDAUDIO = 40 + SIID_LOCK = 47 + SIID_AUTOLIST = 49 + SIID_PRINTERNET = 50 + SIID_SERVERSHARE = 51 + SIID_PRINTERFAX = 52 + SIID_PRINTERFAXNET = 53 + SIID_PRINTERFILE = 54 + SIID_STACK = 55 + SIID_MEDIASVCD = 56 + SIID_STUFFEDFOLDER = 57 + SIID_DRIVEUNKNOWN = 58 + SIID_DRIVEDVD = 59 + SIID_MEDIADVD = 60 + SIID_MEDIADVDRAM = 61 + SIID_MEDIADVDRW = 62 + SIID_MEDIADVDR = 63 + SIID_MEDIADVDROM = 64 + SIID_MEDIACDAUDIOPLUS = 65 + SIID_MEDIACDRW = 66 + SIID_MEDIACDR = 67 + SIID_MEDIACDBURN = 68 + SIID_MEDIABLANKCD = 69 + SIID_MEDIACDROM = 70 + SIID_AUDIOFILES = 71 + SIID_IMAGEFILES = 72 + SIID_VIDEOFILES = 73 + SIID_MIXEDFILES = 74 + SIID_FOLDERBACK = 75 + SIID_FOLDERFRONT = 76 + SIID_SHIELD = 77 + SIID_WARNING = 78 + SIID_INFO = 79 + SIID_ERROR = 80 + SIID_KEY = 81 + SIID_SOFTWARE = 82 + SIID_RENAME = 83 + SIID_DELETE = 84 + SIID_MEDIAAUDIODVD = 85 + SIID_MEDIAMOVIEDVD = 86 + SIID_MEDIAENHANCEDCD = 87 + SIID_MEDIAENHANCEDDVD = 88 + SIID_MEDIAHDDVD = 89 + SIID_MEDIABLURAY = 90 + SIID_MEDIAVCD = 91 + SIID_MEDIADVDPLUSR = 92 + SIID_MEDIADVDPLUSRW = 93 + SIID_DESKTOPPC = 94 + SIID_MOBILEPC = 95 + SIID_USERS = 96 + SIID_MEDIASMARTMEDIA = 97 + SIID_MEDIACOMPACTFLASH = 98 + SIID_DEVICECELLPHONE = 99 + SIID_DEVICECAMERA = 100 + SIID_DEVICEVIDEOCAMERA = 101 + SIID_DEVICEAUDIOPLAYER = 102 + SIID_NETWORKCONNECT = 103 + SIID_INTERNET = 104 + SIID_ZIPFILE = 105 + SIID_SETTINGS = 106 + SIID_DRIVEHDDVD = 132 + SIID_DRIVEBD = 133 + SIID_MEDIAHDDVDROM = 134 + SIID_MEDIAHDDVDR = 135 + SIID_MEDIAHDDVDRAM = 136 + SIID_MEDIABDROM = 137 + SIID_MEDIABDR = 138 + SIID_MEDIABDRE = 139 + SIID_CLUSTEREDDRIVE = 140 + SIID_MAX_ICONS = 175 +) + +type NOTIFYICONDATA struct { + CbSize uint32 + HWnd HWND + UID uint32 + UFlags uint32 + UCallbackMessage uint32 + HIcon HICON + SzTip [128]uint16 + DwState uint32 + DwStateMask uint32 + SzInfo [256]uint16 + UVersion uint32 + SzInfoTitle [64]uint16 + DwInfoFlags uint32 + GuidItem syscall.GUID +} + +type SHFILEINFO struct { + HIcon HICON + IIcon int32 + DwAttributes uint32 + SzDisplayName [MAX_PATH]uint16 + SzTypeName [80]uint16 +} + +type BROWSEINFO struct { + HwndOwner HWND + PidlRoot uintptr + PszDisplayName *uint16 + LpszTitle *uint16 + UlFlags uint32 + Lpfn uintptr + LParam uintptr + IImage int32 +} + +type SHSTOCKICONINFO struct { + CbSize uint32 + HIcon HICON + ISysImageIndex int32 + IIcon int32 + SzPath [MAX_PATH]uint16 +} + +var ( + // Library + libshell32 uintptr + + // Functions + dragAcceptFiles uintptr + dragFinish uintptr + dragQueryFile uintptr + shBrowseForFolder uintptr + shGetFileInfo uintptr + shGetPathFromIDList uintptr + shGetSpecialFolderPath uintptr + shParseDisplayName uintptr + shGetStockIconInfo uintptr + shell_NotifyIcon uintptr +) + +func init() { + // Library + libshell32 = MustLoadLibrary("shell32.dll") + + // Functions + dragAcceptFiles = MustGetProcAddress(libshell32, "DragAcceptFiles") + dragFinish = MustGetProcAddress(libshell32, "DragFinish") + dragQueryFile = MustGetProcAddress(libshell32, "DragQueryFileW") + shBrowseForFolder = MustGetProcAddress(libshell32, "SHBrowseForFolderW") + shGetFileInfo = MustGetProcAddress(libshell32, "SHGetFileInfoW") + shGetPathFromIDList = MustGetProcAddress(libshell32, "SHGetPathFromIDListW") + shGetSpecialFolderPath = MustGetProcAddress(libshell32, "SHGetSpecialFolderPathW") + shGetStockIconInfo = MaybeGetProcAddress(libshell32, "SHGetStockIconInfo") + shell_NotifyIcon = MustGetProcAddress(libshell32, "Shell_NotifyIconW") + shParseDisplayName = MustGetProcAddress(libshell32, "SHParseDisplayName") +} + +func DragAcceptFiles(hWnd HWND, fAccept bool) bool { + ret, _, _ := syscall.Syscall(dragAcceptFiles, 2, + uintptr(hWnd), + uintptr(BoolToBOOL(fAccept)), + 0) + + return ret != 0 +} + +func DragQueryFile(hDrop HDROP, iFile uint, lpszFile *uint16, cch uint) uint { + ret, _, _ := syscall.Syscall6(dragQueryFile, 4, + uintptr(hDrop), + uintptr(iFile), + uintptr(unsafe.Pointer(lpszFile)), + uintptr(cch), + 0, + 0) + + return uint(ret) +} + +func DragFinish(hDrop HDROP) { + syscall.Syscall(dragAcceptFiles, 1, + uintptr(hDrop), + 0, + 0) +} + +func SHBrowseForFolder(lpbi *BROWSEINFO) uintptr { + ret, _, _ := syscall.Syscall(shBrowseForFolder, 1, + uintptr(unsafe.Pointer(lpbi)), + 0, + 0) + + return ret +} + +func SHGetFileInfo(pszPath *uint16, dwFileAttributes uint32, psfi *SHFILEINFO, cbFileInfo, uFlags uint32) uintptr { + ret, _, _ := syscall.Syscall6(shGetFileInfo, 5, + uintptr(unsafe.Pointer(pszPath)), + uintptr(dwFileAttributes), + uintptr(unsafe.Pointer(psfi)), + uintptr(cbFileInfo), + uintptr(uFlags), + 0) + + return ret +} + +func SHGetPathFromIDList(pidl uintptr, pszPath *uint16) bool { + ret, _, _ := syscall.Syscall(shGetPathFromIDList, 2, + pidl, + uintptr(unsafe.Pointer(pszPath)), + 0) + + return ret != 0 +} + +func SHGetSpecialFolderPath(hwndOwner HWND, lpszPath *uint16, csidl CSIDL, fCreate bool) bool { + ret, _, _ := syscall.Syscall6(shGetSpecialFolderPath, 4, + uintptr(hwndOwner), + uintptr(unsafe.Pointer(lpszPath)), + uintptr(csidl), + uintptr(BoolToBOOL(fCreate)), + 0, + 0) + + return ret != 0 +} + +func SHParseDisplayName(pszName *uint16, pbc uintptr, ppidl *uintptr, sfgaoIn uint32, psfgaoOut *uint32) HRESULT { + ret, _, _ := syscall.Syscall6(shParseDisplayName, 5, + uintptr(unsafe.Pointer(pszName)), + pbc, + uintptr(unsafe.Pointer(ppidl)), + 0, + uintptr(unsafe.Pointer(psfgaoOut)), + 0) + + return HRESULT(ret) +} + +func SHGetStockIconInfo(stockIconId int32, uFlags uint32, stockIcon *SHSTOCKICONINFO) HRESULT { + ret, _, _ := syscall.Syscall6(shGetStockIconInfo, 3, + uintptr(stockIconId), + uintptr(uFlags), + uintptr(unsafe.Pointer(stockIcon)), + 0, + 0, + 0, + ) + return HRESULT(ret) +} + +func Shell_NotifyIcon(dwMessage uint32, lpdata *NOTIFYICONDATA) bool { + ret, _, _ := syscall.Syscall(shell_NotifyIcon, 2, + uintptr(dwMessage), + uintptr(unsafe.Pointer(lpdata)), + 0) + + return ret != 0 +} diff --git a/gui/vendor/github.com/lxn/win/shobj.go b/gui/vendor/github.com/lxn/win/shobj.go new file mode 100644 index 0000000..b3aeefa --- /dev/null +++ b/gui/vendor/github.com/lxn/win/shobj.go @@ -0,0 +1,62 @@ +// Copyright 2012 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +var ( + CLSID_TaskbarList = CLSID{0x56FDF344, 0xFD6D, 0x11d0, [8]byte{0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}} + IID_ITaskbarList3 = IID{0xea1afb91, 0x9e28, 0x4b86, [8]byte{0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf}} +) + +//TBPFLAG +const ( + TBPF_NOPROGRESS = 0 + TBPF_INDETERMINATE = 0x1 + TBPF_NORMAL = 0x2 + TBPF_ERROR = 0x4 + TBPF_PAUSED = 0x8 +) + +type ITaskbarList3Vtbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr + HrInit uintptr + AddTab uintptr + DeleteTab uintptr + ActivateTab uintptr + SetActiveAlt uintptr + MarkFullscreenWindow uintptr + SetProgressValue uintptr + SetProgressState uintptr + RegisterTab uintptr + UnregisterTab uintptr + SetTabOrder uintptr + SetTabActive uintptr + ThumbBarAddButtons uintptr + ThumbBarUpdateButtons uintptr + ThumbBarSetImageList uintptr + SetOverlayIcon uintptr + SetThumbnailTooltip uintptr + SetThumbnailClip uintptr +} + +type ITaskbarList3 struct { + LpVtbl *ITaskbarList3Vtbl +} + +func (obj *ITaskbarList3) SetProgressState(hwnd HWND, state int) HRESULT { + ret, _, _ := syscall.Syscall(obj.LpVtbl.SetProgressState, 3, + uintptr(unsafe.Pointer(obj)), + uintptr(hwnd), + uintptr(state)) + return HRESULT(ret) +} diff --git a/gui/vendor/github.com/lxn/win/shobj_386.go b/gui/vendor/github.com/lxn/win/shobj_386.go new file mode 100644 index 0000000..5e028a3 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/shobj_386.go @@ -0,0 +1,24 @@ +// Copyright 2012 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +func (obj *ITaskbarList3) SetProgressValue(hwnd HWND, current uint32, length uint32) HRESULT { + ret, _, _ := syscall.Syscall6(obj.LpVtbl.SetProgressValue, 6, + uintptr(unsafe.Pointer(obj)), + uintptr(hwnd), + uintptr(current), + 0, + uintptr(length), + 0) + + return HRESULT(ret) +} diff --git a/gui/vendor/github.com/lxn/win/shobj_amd64.go b/gui/vendor/github.com/lxn/win/shobj_amd64.go new file mode 100644 index 0000000..312fa21 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/shobj_amd64.go @@ -0,0 +1,24 @@ +// Copyright 2012 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +func (obj *ITaskbarList3) SetProgressValue(hwnd HWND, current uint32, length uint32) HRESULT { + ret, _, _ := syscall.Syscall6(obj.LpVtbl.SetProgressValue, 4, + uintptr(unsafe.Pointer(obj)), + uintptr(hwnd), + uintptr(current), + uintptr(length), + 0, + 0) + + return HRESULT(ret) +} diff --git a/gui/vendor/github.com/lxn/win/statusbar.go b/gui/vendor/github.com/lxn/win/statusbar.go new file mode 100644 index 0000000..41b7067 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/statusbar.go @@ -0,0 +1,50 @@ +// Copyright 2013 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +// Styles +const ( + SBARS_SIZEGRIP = 0x100 + SBARS_TOOLTIPS = 0x800 +) + +// Messages +const ( + SB_SETPARTS = WM_USER + 4 + SB_GETPARTS = WM_USER + 6 + SB_GETBORDERS = WM_USER + 7 + SB_SETMINHEIGHT = WM_USER + 8 + SB_SIMPLE = WM_USER + 9 + SB_GETRECT = WM_USER + 10 + SB_SETTEXT = WM_USER + 11 + SB_GETTEXTLENGTH = WM_USER + 12 + SB_GETTEXT = WM_USER + 13 + SB_ISSIMPLE = WM_USER + 14 + SB_SETICON = WM_USER + 15 + SB_SETTIPTEXT = WM_USER + 17 + SB_GETTIPTEXT = WM_USER + 19 + SB_GETICON = WM_USER + 20 + SB_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT + SB_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT + SB_SETBKCOLOR = CCM_SETBKCOLOR +) + +// SB_SETTEXT options +const ( + SBT_NOBORDERS = 0x100 + SBT_POPOUT = 0x200 + SBT_RTLREADING = 0x400 + SBT_NOTABPARSING = 0x800 + SBT_OWNERDRAW = 0x1000 +) + +const ( + SBN_FIRST = -880 + SBN_SIMPLEMODECHANGE = SBN_FIRST - 0 +) + +const SB_SIMPLEID = 0xff diff --git a/gui/vendor/github.com/lxn/win/syslink.go b/gui/vendor/github.com/lxn/win/syslink.go new file mode 100644 index 0000000..26455d0 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/syslink.go @@ -0,0 +1,65 @@ +// Copyright 2017 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +const ( + INVALID_LINK_INDEX = -1 + MAX_LINKID_TEXT = 48 + L_MAX_URL_LENGTH = 2048 + 32 + len("://") + WC_LINK = "SysLink" +) + +const ( + LWS_TRANSPARENT = 0x0001 + LWS_IGNORERETURN = 0x0002 + LWS_NOPREFIX = 0x0004 + LWS_USEVISUALSTYLE = 0x0008 + LWS_USECUSTOMTEXT = 0x0010 + LWS_RIGHT = 0x0020 +) + +const ( + LIF_ITEMINDEX = 0x00000001 + LIF_STATE = 0x00000002 + LIF_ITEMID = 0x00000004 + LIF_URL = 0x00000008 +) + +const ( + LIS_FOCUSED = 0x00000001 + LIS_ENABLED = 0x00000002 + LIS_VISITED = 0x00000004 + LIS_HOTTRACK = 0x00000008 + LIS_DEFAULTCOLORS = 0x00000010 +) + +const ( + LM_HITTEST = WM_USER + 0x300 + LM_GETIDEALHEIGHT = WM_USER + 0x301 + LM_SETITEM = WM_USER + 0x302 + LM_GETITEM = WM_USER + 0x303 + LM_GETIDEALSIZE = LM_GETIDEALHEIGHT +) + +type LITEM struct { + Mask uint32 + ILink int32 + State uint32 + StateMask uint32 + SzID [MAX_LINKID_TEXT]uint16 + SzUrl [L_MAX_URL_LENGTH]uint16 +} + +type LHITTESTINFO struct { + Pt POINT + Item LITEM +} + +type NMLINK struct { + Hdr NMHDR + Item LITEM +} diff --git a/gui/vendor/github.com/lxn/win/tab.go b/gui/vendor/github.com/lxn/win/tab.go new file mode 100644 index 0000000..10dbd3d --- /dev/null +++ b/gui/vendor/github.com/lxn/win/tab.go @@ -0,0 +1,128 @@ +// Copyright 2011 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +const TCM_FIRST = 0x1300 +const TCN_FIRST = -550 + +const ( + TCS_SCROLLOPPOSITE = 0x0001 + TCS_BOTTOM = 0x0002 + TCS_RIGHT = 0x0002 + TCS_MULTISELECT = 0x0004 + TCS_FLATBUTTONS = 0x0008 + TCS_FORCEICONLEFT = 0x0010 + TCS_FORCELABELLEFT = 0x0020 + TCS_HOTTRACK = 0x0040 + TCS_VERTICAL = 0x0080 + TCS_TABS = 0x0000 + TCS_BUTTONS = 0x0100 + TCS_SINGLELINE = 0x0000 + TCS_MULTILINE = 0x0200 + TCS_RIGHTJUSTIFY = 0x0000 + TCS_FIXEDWIDTH = 0x0400 + TCS_RAGGEDRIGHT = 0x0800 + TCS_FOCUSONBUTTONDOWN = 0x1000 + TCS_OWNERDRAWFIXED = 0x2000 + TCS_TOOLTIPS = 0x4000 + TCS_FOCUSNEVER = 0x8000 +) + +const ( + TCS_EX_FLATSEPARATORS = 0x00000001 + TCS_EX_REGISTERDROP = 0x00000002 +) + +const ( + TCM_GETIMAGELIST = TCM_FIRST + 2 + TCM_SETIMAGELIST = TCM_FIRST + 3 + TCM_GETITEMCOUNT = TCM_FIRST + 4 + TCM_GETITEM = TCM_FIRST + 60 + TCM_SETITEM = TCM_FIRST + 61 + TCM_INSERTITEM = TCM_FIRST + 62 + TCM_DELETEITEM = TCM_FIRST + 8 + TCM_DELETEALLITEMS = TCM_FIRST + 9 + TCM_GETITEMRECT = TCM_FIRST + 10 + TCM_GETCURSEL = TCM_FIRST + 11 + TCM_SETCURSEL = TCM_FIRST + 12 + TCM_HITTEST = TCM_FIRST + 13 + TCM_SETITEMEXTRA = TCM_FIRST + 14 + TCM_ADJUSTRECT = TCM_FIRST + 40 + TCM_SETITEMSIZE = TCM_FIRST + 41 + TCM_REMOVEIMAGE = TCM_FIRST + 42 + TCM_SETPADDING = TCM_FIRST + 43 + TCM_GETROWCOUNT = TCM_FIRST + 44 + TCM_GETTOOLTIPS = TCM_FIRST + 45 + TCM_SETTOOLTIPS = TCM_FIRST + 46 + TCM_GETCURFOCUS = TCM_FIRST + 47 + TCM_SETCURFOCUS = TCM_FIRST + 48 + TCM_SETMINTABWIDTH = TCM_FIRST + 49 + TCM_DESELECTALL = TCM_FIRST + 50 + TCM_HIGHLIGHTITEM = TCM_FIRST + 51 + TCM_SETEXTENDEDSTYLE = TCM_FIRST + 52 + TCM_GETEXTENDEDSTYLE = TCM_FIRST + 53 + TCM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT + TCM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT +) + +const ( + TCIF_TEXT = 0x0001 + TCIF_IMAGE = 0x0002 + TCIF_RTLREADING = 0x0004 + TCIF_PARAM = 0x0008 + TCIF_STATE = 0x0010 +) + +const ( + TCIS_BUTTONPRESSED = 0x0001 + TCIS_HIGHLIGHTED = 0x0002 +) + +const ( + TCHT_NOWHERE = 0x0001 + TCHT_ONITEMICON = 0x0002 + TCHT_ONITEMLABEL = 0x0004 + TCHT_ONITEM = TCHT_ONITEMICON | TCHT_ONITEMLABEL +) + +const ( + TCN_KEYDOWN = TCN_FIRST - 0 + TCN_SELCHANGE = TCN_FIRST - 1 + TCN_SELCHANGING = TCN_FIRST - 2 + TCN_GETOBJECT = TCN_FIRST - 3 + TCN_FOCUSCHANGE = TCN_FIRST - 4 +) + +type TCITEMHEADER struct { + Mask uint32 + LpReserved1 uint32 + LpReserved2 uint32 + PszText *uint16 + CchTextMax int32 + IImage int32 +} + +type TCITEM struct { + Mask uint32 + DwState uint32 + DwStateMask uint32 + PszText *uint16 + CchTextMax int32 + IImage int32 + LParam uintptr +} + +type TCHITTESTINFO struct { + Pt POINT + flags uint32 +} + +type NMTCKEYDOWN struct { + Hdr NMHDR + WVKey uint16 + Flags uint32 +} diff --git a/gui/vendor/github.com/lxn/win/toolbar.go b/gui/vendor/github.com/lxn/win/toolbar.go new file mode 100644 index 0000000..80f0b0a --- /dev/null +++ b/gui/vendor/github.com/lxn/win/toolbar.go @@ -0,0 +1,219 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +// ToolBar messages +const ( + TB_THUMBPOSITION = 4 + TB_THUMBTRACK = 5 + TB_ENDTRACK = 8 + TB_ENABLEBUTTON = WM_USER + 1 + TB_CHECKBUTTON = WM_USER + 2 + TB_PRESSBUTTON = WM_USER + 3 + TB_HIDEBUTTON = WM_USER + 4 + TB_INDETERMINATE = WM_USER + 5 + TB_MARKBUTTON = WM_USER + 6 + TB_ISBUTTONENABLED = WM_USER + 9 + TB_ISBUTTONCHECKED = WM_USER + 10 + TB_ISBUTTONPRESSED = WM_USER + 11 + TB_ISBUTTONHIDDEN = WM_USER + 12 + TB_ISBUTTONINDETERMINATE = WM_USER + 13 + TB_ISBUTTONHIGHLIGHTED = WM_USER + 14 + TB_SETSTATE = WM_USER + 17 + TB_GETSTATE = WM_USER + 18 + TB_ADDBITMAP = WM_USER + 19 + TB_DELETEBUTTON = WM_USER + 22 + TB_GETBUTTON = WM_USER + 23 + TB_BUTTONCOUNT = WM_USER + 24 + TB_COMMANDTOINDEX = WM_USER + 25 + TB_SAVERESTORE = WM_USER + 76 + TB_CUSTOMIZE = WM_USER + 27 + TB_ADDSTRING = WM_USER + 77 + TB_GETITEMRECT = WM_USER + 29 + TB_BUTTONSTRUCTSIZE = WM_USER + 30 + TB_SETBUTTONSIZE = WM_USER + 31 + TB_SETBITMAPSIZE = WM_USER + 32 + TB_AUTOSIZE = WM_USER + 33 + TB_GETTOOLTIPS = WM_USER + 35 + TB_SETTOOLTIPS = WM_USER + 36 + TB_SETPARENT = WM_USER + 37 + TB_SETROWS = WM_USER + 39 + TB_GETROWS = WM_USER + 40 + TB_GETBITMAPFLAGS = WM_USER + 41 + TB_SETCMDID = WM_USER + 42 + TB_CHANGEBITMAP = WM_USER + 43 + TB_GETBITMAP = WM_USER + 44 + TB_GETBUTTONTEXT = WM_USER + 75 + TB_REPLACEBITMAP = WM_USER + 46 + TB_GETBUTTONSIZE = WM_USER + 58 + TB_SETBUTTONWIDTH = WM_USER + 59 + TB_SETINDENT = WM_USER + 47 + TB_SETIMAGELIST = WM_USER + 48 + TB_GETIMAGELIST = WM_USER + 49 + TB_LOADIMAGES = WM_USER + 50 + TB_GETRECT = WM_USER + 51 + TB_SETHOTIMAGELIST = WM_USER + 52 + TB_GETHOTIMAGELIST = WM_USER + 53 + TB_SETDISABLEDIMAGELIST = WM_USER + 54 + TB_GETDISABLEDIMAGELIST = WM_USER + 55 + TB_SETSTYLE = WM_USER + 56 + TB_GETSTYLE = WM_USER + 57 + TB_SETMAXTEXTROWS = WM_USER + 60 + TB_GETTEXTROWS = WM_USER + 61 + TB_GETOBJECT = WM_USER + 62 + TB_GETBUTTONINFO = WM_USER + 63 + TB_SETBUTTONINFO = WM_USER + 64 + TB_INSERTBUTTON = WM_USER + 67 + TB_ADDBUTTONS = WM_USER + 68 + TB_HITTEST = WM_USER + 69 + TB_SETDRAWTEXTFLAGS = WM_USER + 70 + TB_GETHOTITEM = WM_USER + 71 + TB_SETHOTITEM = WM_USER + 72 + TB_SETANCHORHIGHLIGHT = WM_USER + 73 + TB_GETANCHORHIGHLIGHT = WM_USER + 74 + TB_GETINSERTMARK = WM_USER + 79 + TB_SETINSERTMARK = WM_USER + 80 + TB_INSERTMARKHITTEST = WM_USER + 81 + TB_MOVEBUTTON = WM_USER + 82 + TB_GETMAXSIZE = WM_USER + 83 + TB_SETEXTENDEDSTYLE = WM_USER + 84 + TB_GETEXTENDEDSTYLE = WM_USER + 85 + TB_GETPADDING = WM_USER + 86 + TB_SETPADDING = WM_USER + 87 + TB_SETINSERTMARKCOLOR = WM_USER + 88 + TB_GETINSERTMARKCOLOR = WM_USER + 89 + TB_MAPACCELERATOR = WM_USER + 90 + TB_GETSTRING = WM_USER + 91 + TB_GETIDEALSIZE = WM_USER + 99 + TB_SETCOLORSCHEME = CCM_SETCOLORSCHEME + TB_GETCOLORSCHEME = CCM_GETCOLORSCHEME + TB_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT + TB_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT +) + +// ToolBar notifications +const ( + TBN_FIRST = -700 + TBN_DROPDOWN = TBN_FIRST - 10 +) + +// TBN_DROPDOWN return codes +const ( + TBDDRET_DEFAULT = 0 + TBDDRET_NODEFAULT = 1 + TBDDRET_TREATPRESSED = 2 +) + +// ToolBar state constants +const ( + TBSTATE_CHECKED = 1 + TBSTATE_PRESSED = 2 + TBSTATE_ENABLED = 4 + TBSTATE_HIDDEN = 8 + TBSTATE_INDETERMINATE = 16 + TBSTATE_WRAP = 32 + TBSTATE_ELLIPSES = 0x40 + TBSTATE_MARKED = 0x0080 +) + +// ToolBar style constants +const ( + TBSTYLE_BUTTON = 0 + TBSTYLE_SEP = 1 + TBSTYLE_CHECK = 2 + TBSTYLE_GROUP = 4 + TBSTYLE_CHECKGROUP = TBSTYLE_GROUP | TBSTYLE_CHECK + TBSTYLE_DROPDOWN = 8 + TBSTYLE_AUTOSIZE = 16 + TBSTYLE_NOPREFIX = 32 + TBSTYLE_TOOLTIPS = 256 + TBSTYLE_WRAPABLE = 512 + TBSTYLE_ALTDRAG = 1024 + TBSTYLE_FLAT = 2048 + TBSTYLE_LIST = 4096 + TBSTYLE_CUSTOMERASE = 8192 + TBSTYLE_REGISTERDROP = 0x4000 + TBSTYLE_TRANSPARENT = 0x8000 +) + +// ToolBar extended style constants +const ( + TBSTYLE_EX_DRAWDDARROWS = 0x00000001 + TBSTYLE_EX_MIXEDBUTTONS = 8 + TBSTYLE_EX_HIDECLIPPEDBUTTONS = 16 + TBSTYLE_EX_DOUBLEBUFFER = 0x80 +) + +// ToolBar button style constants +const ( + BTNS_BUTTON = TBSTYLE_BUTTON + BTNS_SEP = TBSTYLE_SEP + BTNS_CHECK = TBSTYLE_CHECK + BTNS_GROUP = TBSTYLE_GROUP + BTNS_CHECKGROUP = TBSTYLE_CHECKGROUP + BTNS_DROPDOWN = TBSTYLE_DROPDOWN + BTNS_AUTOSIZE = TBSTYLE_AUTOSIZE + BTNS_NOPREFIX = TBSTYLE_NOPREFIX + BTNS_WHOLEDROPDOWN = 0x0080 + BTNS_SHOWTEXT = 0x0040 +) + +// TBBUTTONINFO mask flags +const ( + TBIF_IMAGE = 0x00000001 + TBIF_TEXT = 0x00000002 + TBIF_STATE = 0x00000004 + TBIF_STYLE = 0x00000008 + TBIF_LPARAM = 0x00000010 + TBIF_COMMAND = 0x00000020 + TBIF_SIZE = 0x00000040 + TBIF_BYINDEX = 0x80000000 +) + +type NMMOUSE struct { + Hdr NMHDR + DwItemSpec uintptr + DwItemData uintptr + Pt POINT + DwHitInfo uintptr +} + +type NMTOOLBAR struct { + Hdr NMHDR + IItem int32 + TbButton TBBUTTON + CchText int32 + PszText *uint16 + RcButton RECT +} + +type TBBUTTON struct { + IBitmap int32 + IdCommand int32 + FsState byte + FsStyle byte + //#ifdef _WIN64 + // BYTE bReserved[6] // padding for alignment + //#elif defined(_WIN32) + BReserved [2]byte // padding for alignment + //#endif + DwData uintptr + IString uintptr +} + +type TBBUTTONINFO struct { + CbSize uint32 + DwMask uint32 + IdCommand int32 + IImage int32 + FsState byte + FsStyle byte + Cx uint16 + LParam uintptr + PszText uintptr + CchText int32 +} diff --git a/gui/vendor/github.com/lxn/win/tooltip.go b/gui/vendor/github.com/lxn/win/tooltip.go new file mode 100644 index 0000000..8e2aec7 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/tooltip.go @@ -0,0 +1,97 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "unsafe" +) + +// ToolTip styles +const ( + TTS_ALWAYSTIP = 0x01 + TTS_NOPREFIX = 0x02 + TTS_NOANIMATE = 0x10 + TTS_NOFADE = 0x20 + TTS_BALLOON = 0x40 + TTS_CLOSE = 0x80 +) + +// ToolTip messages +const ( + TTM_ACTIVATE = WM_USER + 1 + TTM_SETDELAYTIME = WM_USER + 3 + TTM_ADDTOOL = WM_USER + 50 + TTM_DELTOOL = WM_USER + 51 + TTM_NEWTOOLRECT = WM_USER + 52 + TTM_RELAYEVENT = WM_USER + 7 + TTM_GETTOOLINFO = WM_USER + 53 + TTM_SETTOOLINFO = WM_USER + 54 + TTM_HITTEST = WM_USER + 55 + TTM_GETTEXT = WM_USER + 56 + TTM_UPDATETIPTEXT = WM_USER + 57 + TTM_GETTOOLCOUNT = WM_USER + 13 + TTM_ENUMTOOLS = WM_USER + 58 + TTM_GETCURRENTTOOL = WM_USER + 59 + TTM_WINDOWFROMPOINT = WM_USER + 16 + TTM_TRACKACTIVATE = WM_USER + 17 + TTM_TRACKPOSITION = WM_USER + 18 + TTM_SETTIPBKCOLOR = WM_USER + 19 + TTM_SETTIPTEXTCOLOR = WM_USER + 20 + TTM_GETDELAYTIME = WM_USER + 21 + TTM_GETTIPBKCOLOR = WM_USER + 22 + TTM_GETTIPTEXTCOLOR = WM_USER + 23 + TTM_SETMAXTIPWIDTH = WM_USER + 24 + TTM_GETMAXTIPWIDTH = WM_USER + 25 + TTM_SETMARGIN = WM_USER + 26 + TTM_GETMARGIN = WM_USER + 27 + TTM_POP = WM_USER + 28 + TTM_UPDATE = WM_USER + 29 + TTM_GETBUBBLESIZE = WM_USER + 30 + TTM_ADJUSTRECT = WM_USER + 31 + TTM_SETTITLE = WM_USER + 33 + TTM_POPUP = WM_USER + 34 + TTM_GETTITLE = WM_USER + 35 +) + +// ToolTip flags +const ( + TTF_IDISHWND = 0x0001 + TTF_CENTERTIP = 0x0002 + TTF_RTLREADING = 0x0004 + TTF_SUBCLASS = 0x0010 + TTF_TRACK = 0x0020 + TTF_ABSOLUTE = 0x0080 + TTF_TRANSPARENT = 0x0100 + TTF_DI_SETITEM = 0x8000 +) + +// ToolTip icons +const ( + TTI_NONE = 0 + TTI_INFO = 1 + TTI_WARNING = 2 + TTI_ERROR = 3 +) + +type TOOLINFO struct { + CbSize uint32 + UFlags uint32 + Hwnd HWND + UId uintptr + Rect RECT + Hinst HINSTANCE + LpszText *uint16 + LParam uintptr + LpReserved unsafe.Pointer +} + +type TTGETTITLE struct { + DwSize uint32 + UTitleBitmap uint32 + Cch uint32 + PszTitle *uint16 +} diff --git a/gui/vendor/github.com/lxn/win/treeview.go b/gui/vendor/github.com/lxn/win/treeview.go new file mode 100644 index 0000000..b21e42f --- /dev/null +++ b/gui/vendor/github.com/lxn/win/treeview.go @@ -0,0 +1,247 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +// TreeView styles +const ( + TVS_HASBUTTONS = 0x0001 + TVS_HASLINES = 0x0002 + TVS_LINESATROOT = 0x0004 + TVS_EDITLABELS = 0x0008 + TVS_DISABLEDRAGDROP = 0x0010 + TVS_SHOWSELALWAYS = 0x0020 + TVS_RTLREADING = 0x0040 + TVS_NOTOOLTIPS = 0x0080 + TVS_CHECKBOXES = 0x0100 + TVS_TRACKSELECT = 0x0200 + TVS_SINGLEEXPAND = 0x0400 + TVS_INFOTIP = 0x0800 + TVS_FULLROWSELECT = 0x1000 + TVS_NOSCROLL = 0x2000 + TVS_NONEVENHEIGHT = 0x4000 + TVS_NOHSCROLL = 0x8000 +) + +const ( + TVS_EX_NOSINGLECOLLAPSE = 0x0001 + TVS_EX_MULTISELECT = 0x0002 + TVS_EX_DOUBLEBUFFER = 0x0004 + TVS_EX_NOINDENTSTATE = 0x0008 + TVS_EX_RICHTOOLTIP = 0x0010 + TVS_EX_AUTOHSCROLL = 0x0020 + TVS_EX_FADEINOUTEXPANDOS = 0x0040 + TVS_EX_PARTIALCHECKBOXES = 0x0080 + TVS_EX_EXCLUSIONCHECKBOXES = 0x0100 + TVS_EX_DIMMEDCHECKBOXES = 0x0200 + TVS_EX_DRAWIMAGEASYNC = 0x0400 +) + +const ( + TVIF_TEXT = 0x0001 + TVIF_IMAGE = 0x0002 + TVIF_PARAM = 0x0004 + TVIF_STATE = 0x0008 + TVIF_HANDLE = 0x0010 + TVIF_SELECTEDIMAGE = 0x0020 + TVIF_CHILDREN = 0x0040 + TVIF_INTEGRAL = 0x0080 + TVIF_STATEEX = 0x0100 + TVIF_EXPANDEDIMAGE = 0x0200 +) + +const ( + TVIS_SELECTED = 0x0002 + TVIS_CUT = 0x0004 + TVIS_DROPHILITED = 0x0008 + TVIS_BOLD = 0x0010 + TVIS_EXPANDED = 0x0020 + TVIS_EXPANDEDONCE = 0x0040 + TVIS_EXPANDPARTIAL = 0x0080 + TVIS_OVERLAYMASK = 0x0F00 + TVIS_STATEIMAGEMASK = 0xF000 + TVIS_USERMASK = 0xF000 +) + +const ( + TVIS_EX_FLAT = 0x0001 + TVIS_EX_DISABLED = 0x0002 + TVIS_EX_ALL = 0x0002 +) + +const ( + TVI_ROOT = ^HTREEITEM(0xffff) + TVI_FIRST = ^HTREEITEM(0xfffe) + TVI_LAST = ^HTREEITEM(0xfffd) + TVI_SORT = ^HTREEITEM(0xfffc) +) + +// TVM_EXPAND action flags +const ( + TVE_COLLAPSE = 0x0001 + TVE_EXPAND = 0x0002 + TVE_TOGGLE = 0x0003 + TVE_EXPANDPARTIAL = 0x4000 + TVE_COLLAPSERESET = 0x8000 +) + +const ( + TVGN_CARET = 9 +) + +// TreeView messages +const ( + TV_FIRST = 0x1100 + + TVM_INSERTITEM = TV_FIRST + 50 + TVM_DELETEITEM = TV_FIRST + 1 + TVM_EXPAND = TV_FIRST + 2 + TVM_GETITEMRECT = TV_FIRST + 4 + TVM_GETCOUNT = TV_FIRST + 5 + TVM_GETINDENT = TV_FIRST + 6 + TVM_SETINDENT = TV_FIRST + 7 + TVM_GETIMAGELIST = TV_FIRST + 8 + TVM_SETIMAGELIST = TV_FIRST + 9 + TVM_GETNEXTITEM = TV_FIRST + 10 + TVM_SELECTITEM = TV_FIRST + 11 + TVM_GETITEM = TV_FIRST + 62 + TVM_SETITEM = TV_FIRST + 63 + TVM_EDITLABEL = TV_FIRST + 65 + TVM_GETEDITCONTROL = TV_FIRST + 15 + TVM_GETVISIBLECOUNT = TV_FIRST + 16 + TVM_HITTEST = TV_FIRST + 17 + TVM_CREATEDRAGIMAGE = TV_FIRST + 18 + TVM_SORTCHILDREN = TV_FIRST + 19 + TVM_ENSUREVISIBLE = TV_FIRST + 20 + TVM_SORTCHILDRENCB = TV_FIRST + 21 + TVM_ENDEDITLABELNOW = TV_FIRST + 22 + TVM_GETISEARCHSTRING = TV_FIRST + 64 + TVM_SETTOOLTIPS = TV_FIRST + 24 + TVM_GETTOOLTIPS = TV_FIRST + 25 + TVM_SETINSERTMARK = TV_FIRST + 26 + TVM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT + TVM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT + TVM_SETITEMHEIGHT = TV_FIRST + 27 + TVM_GETITEMHEIGHT = TV_FIRST + 28 + TVM_SETBKCOLOR = TV_FIRST + 29 + TVM_SETTEXTCOLOR = TV_FIRST + 30 + TVM_GETBKCOLOR = TV_FIRST + 31 + TVM_GETTEXTCOLOR = TV_FIRST + 32 + TVM_SETSCROLLTIME = TV_FIRST + 33 + TVM_GETSCROLLTIME = TV_FIRST + 34 + TVM_SETINSERTMARKCOLOR = TV_FIRST + 37 + TVM_GETINSERTMARKCOLOR = TV_FIRST + 38 + TVM_GETITEMSTATE = TV_FIRST + 39 + TVM_SETLINECOLOR = TV_FIRST + 40 + TVM_GETLINECOLOR = TV_FIRST + 41 + TVM_MAPACCIDTOHTREEITEM = TV_FIRST + 42 + TVM_MAPHTREEITEMTOACCID = TV_FIRST + 43 + TVM_SETEXTENDEDSTYLE = TV_FIRST + 44 + TVM_GETEXTENDEDSTYLE = TV_FIRST + 45 + TVM_SETAUTOSCROLLINFO = TV_FIRST + 59 +) + +// TreeView notifications +const ( + TVN_FIRST = ^uint32(399) + + TVN_SELCHANGING = TVN_FIRST - 50 + TVN_SELCHANGED = TVN_FIRST - 51 + TVN_GETDISPINFO = TVN_FIRST - 52 + TVN_ITEMEXPANDING = TVN_FIRST - 54 + TVN_ITEMEXPANDED = TVN_FIRST - 55 + TVN_BEGINDRAG = TVN_FIRST - 56 + TVN_BEGINRDRAG = TVN_FIRST - 57 + TVN_DELETEITEM = TVN_FIRST - 58 + TVN_BEGINLABELEDIT = TVN_FIRST - 59 + TVN_ENDLABELEDIT = TVN_FIRST - 60 + TVN_KEYDOWN = TVN_FIRST - 12 + TVN_GETINFOTIP = TVN_FIRST - 14 + TVN_SINGLEEXPAND = TVN_FIRST - 15 + TVN_ITEMCHANGING = TVN_FIRST - 17 + TVN_ITEMCHANGED = TVN_FIRST - 19 + TVN_ASYNCDRAW = TVN_FIRST - 20 +) + +// TreeView hit test constants +const ( + TVHT_NOWHERE = 1 + TVHT_ONITEMICON = 2 + TVHT_ONITEMLABEL = 4 + TVHT_ONITEM = TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON + TVHT_ONITEMINDENT = 8 + TVHT_ONITEMBUTTON = 16 + TVHT_ONITEMRIGHT = 32 + TVHT_ONITEMSTATEICON = 64 + TVHT_ABOVE = 256 + TVHT_BELOW = 512 + TVHT_TORIGHT = 1024 + TVHT_TOLEFT = 2048 +) + +type HTREEITEM HANDLE + +type TVITEM struct { + Mask uint32 + HItem HTREEITEM + State uint32 + StateMask uint32 + PszText uintptr + CchTextMax int32 + IImage int32 + ISelectedImage int32 + CChildren int32 + LParam uintptr +} + +/*type TVITEMEX struct { + mask UINT + hItem HTREEITEM + state UINT + stateMask UINT + pszText LPWSTR + cchTextMax int + iImage int + iSelectedImage int + cChildren int + lParam LPARAM + iIntegral int + uStateEx UINT + hwnd HWND + iExpandedImage int +}*/ + +type TVINSERTSTRUCT struct { + HParent HTREEITEM + HInsertAfter HTREEITEM + Item TVITEM + // itemex TVITEMEX +} + +type NMTREEVIEW struct { + Hdr NMHDR + Action uint32 + ItemOld TVITEM + ItemNew TVITEM + PtDrag POINT +} + +type NMTVDISPINFO struct { + Hdr NMHDR + Item TVITEM +} + +type NMTVKEYDOWN struct { + Hdr NMHDR + WVKey uint16 + Flags uint32 +} + +type TVHITTESTINFO struct { + Pt POINT + Flags uint32 + HItem HTREEITEM +} diff --git a/gui/vendor/github.com/lxn/win/updown.go b/gui/vendor/github.com/lxn/win/updown.go new file mode 100644 index 0000000..f315c3f --- /dev/null +++ b/gui/vendor/github.com/lxn/win/updown.go @@ -0,0 +1,58 @@ +// Copyright 2011 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +const UDN_FIRST = ^uint32(720) + +const ( + UD_MAXVAL = 0x7fff + UD_MINVAL = ^uintptr(UD_MAXVAL - 1) +) + +const ( + UDS_WRAP = 0x0001 + UDS_SETBUDDYINT = 0x0002 + UDS_ALIGNRIGHT = 0x0004 + UDS_ALIGNLEFT = 0x0008 + UDS_AUTOBUDDY = 0x0010 + UDS_ARROWKEYS = 0x0020 + UDS_HORZ = 0x0040 + UDS_NOTHOUSANDS = 0x0080 + UDS_HOTTRACK = 0x0100 +) + +const ( + UDM_SETRANGE = WM_USER + 101 + UDM_GETRANGE = WM_USER + 102 + UDM_SETPOS = WM_USER + 103 + UDM_GETPOS = WM_USER + 104 + UDM_SETBUDDY = WM_USER + 105 + UDM_GETBUDDY = WM_USER + 106 + UDM_SETACCEL = WM_USER + 107 + UDM_GETACCEL = WM_USER + 108 + UDM_SETBASE = WM_USER + 109 + UDM_GETBASE = WM_USER + 110 + UDM_SETRANGE32 = WM_USER + 111 + UDM_GETRANGE32 = WM_USER + 112 + UDM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT + UDM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT + UDM_SETPOS32 = WM_USER + 113 + UDM_GETPOS32 = WM_USER + 114 +) + +const UDN_DELTAPOS = UDN_FIRST - 1 + +type UDACCEL struct { + NSec uint32 + NInc uint32 +} + +type NMUPDOWN struct { + Hdr NMHDR + IPos int32 + IDelta int32 +} diff --git a/gui/vendor/github.com/lxn/win/user32.go b/gui/vendor/github.com/lxn/win/user32.go new file mode 100644 index 0000000..5d21dae --- /dev/null +++ b/gui/vendor/github.com/lxn/win/user32.go @@ -0,0 +1,2922 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +const CW_USEDEFAULT = ^0x7fffffff + +// MessageBox constants +const ( + MB_OK = 0x00000000 + MB_OKCANCEL = 0x00000001 + MB_ABORTRETRYIGNORE = 0x00000002 + MB_YESNOCANCEL = 0x00000003 + MB_YESNO = 0x00000004 + MB_RETRYCANCEL = 0x00000005 + MB_CANCELTRYCONTINUE = 0x00000006 + MB_ICONHAND = 0x00000010 + MB_ICONQUESTION = 0x00000020 + MB_ICONEXCLAMATION = 0x00000030 + MB_ICONASTERISK = 0x00000040 + MB_USERICON = 0x00000080 + MB_ICONWARNING = MB_ICONEXCLAMATION + MB_ICONERROR = MB_ICONHAND + MB_ICONINFORMATION = MB_ICONASTERISK + MB_ICONSTOP = MB_ICONHAND + MB_DEFBUTTON1 = 0x00000000 + MB_DEFBUTTON2 = 0x00000100 + MB_DEFBUTTON3 = 0x00000200 + MB_DEFBUTTON4 = 0x00000300 +) + +// Dialog box command ids +const ( + IDOK = 1 + IDCANCEL = 2 + IDABORT = 3 + IDRETRY = 4 + IDIGNORE = 5 + IDYES = 6 + IDNO = 7 + IDCLOSE = 8 + IDHELP = 9 + IDTRYAGAIN = 10 + IDCONTINUE = 11 + IDTIMEOUT = 32000 +) + +// System commands +const ( + SC_SIZE = 0xF000 + SC_MOVE = 0xF010 + SC_MINIMIZE = 0xF020 + SC_MAXIMIZE = 0xF030 + SC_NEXTWINDOW = 0xF040 + SC_PREVWINDOW = 0xF050 + SC_CLOSE = 0xF060 + SC_VSCROLL = 0xF070 + SC_HSCROLL = 0xF080 + SC_MOUSEMENU = 0xF090 + SC_KEYMENU = 0xF100 + SC_ARRANGE = 0xF110 + SC_RESTORE = 0xF120 + SC_TASKLIST = 0xF130 + SC_SCREENSAVE = 0xF140 + SC_HOTKEY = 0xF150 + SC_DEFAULT = 0xF160 + SC_MONITORPOWER = 0xF170 + SC_CONTEXTHELP = 0xF180 + SC_SEPARATOR = 0xF00F +) + +// Static control styles +const ( + SS_BITMAP = 14 + SS_BLACKFRAME = 7 + SS_BLACKRECT = 4 + SS_CENTER = 1 + SS_CENTERIMAGE = 512 + SS_EDITCONTROL = 0x2000 + SS_ENHMETAFILE = 15 + SS_ETCHEDFRAME = 18 + SS_ETCHEDHORZ = 16 + SS_ETCHEDVERT = 17 + SS_GRAYFRAME = 8 + SS_GRAYRECT = 5 + SS_ICON = 3 + SS_LEFT = 0 + SS_LEFTNOWORDWRAP = 0xc + SS_NOPREFIX = 128 + SS_NOTIFY = 256 + SS_OWNERDRAW = 0xd + SS_REALSIZECONTROL = 0x040 + SS_REALSIZEIMAGE = 0x800 + SS_RIGHT = 2 + SS_RIGHTJUST = 0x400 + SS_SIMPLE = 11 + SS_SUNKEN = 4096 + SS_WHITEFRAME = 9 + SS_WHITERECT = 6 + SS_USERITEM = 10 + SS_TYPEMASK = 0x0000001F + SS_ENDELLIPSIS = 0x00004000 + SS_PATHELLIPSIS = 0x00008000 + SS_WORDELLIPSIS = 0x0000C000 + SS_ELLIPSISMASK = 0x0000C000 +) + +// Button message constants +const ( + BM_CLICK = 245 + BM_GETCHECK = 240 + BM_GETIMAGE = 246 + BM_GETSTATE = 242 + BM_SETCHECK = 241 + BM_SETIMAGE = 247 + BM_SETSTATE = 243 + BM_SETSTYLE = 244 +) + +// Button notifications +const ( + BCN_DROPDOWN = 0xfffffb20 + BN_CLICKED = 0 + BN_PAINT = 1 + BN_HILITE = 2 + BN_PUSHED = BN_HILITE + BN_UNHILITE = 3 + BN_UNPUSHED = BN_UNHILITE + BN_DISABLE = 4 + BN_DOUBLECLICKED = 5 + BN_DBLCLK = BN_DOUBLECLICKED + BN_SETFOCUS = 6 + BN_KILLFOCUS = 7 +) + +const ( + IMAGE_BITMAP = 0 + IMAGE_ICON = 1 + IMAGE_CURSOR = 2 + IMAGE_ENHMETAFILE = 3 +) + +const ( + LR_DEFAULTCOLOR = 0 + LR_MONOCHROME = 1 + LR_COLOR = 2 + LR_COPYRETURNORG = 4 + LR_COPYDELETEORG = 8 + LR_LOADFROMFILE = 16 + LR_LOADTRANSPARENT = 32 + LR_LOADREALSIZE = 128 + LR_DEFAULTSIZE = 0x0040 + LR_VGACOLOR = 0x0080 + LR_LOADMAP3DCOLORS = 4096 + LR_CREATEDIBSECTION = 8192 + LR_COPYFROMRESOURCE = 0x4000 + LR_SHARED = 32768 +) + +// Button style constants +const ( + BS_3STATE = 5 + BS_AUTO3STATE = 6 + BS_AUTOCHECKBOX = 3 + BS_AUTORADIOBUTTON = 9 + BS_BITMAP = 128 + BS_BOTTOM = 0X800 + BS_CENTER = 0X300 + BS_CHECKBOX = 2 + BS_DEFPUSHBUTTON = 1 + BS_GROUPBOX = 7 + BS_ICON = 64 + BS_LEFT = 256 + BS_LEFTTEXT = 32 + BS_MULTILINE = 0X2000 + BS_NOTIFY = 0X4000 + BS_OWNERDRAW = 0XB + BS_PUSHBUTTON = 0 + BS_PUSHLIKE = 4096 + BS_RADIOBUTTON = 4 + BS_RIGHT = 512 + BS_RIGHTBUTTON = 32 + BS_SPLITBUTTON = 0x0000000c + BS_TEXT = 0 + BS_TOP = 0X400 + BS_USERBUTTON = 8 + BS_VCENTER = 0XC00 + BS_FLAT = 0X8000 +) + +const ( + PM_NOREMOVE = 0x0000 + PM_REMOVE = 0x0001 + PM_NOYIELD = 0x0002 +) + +// Button state constants +const ( + BST_CHECKED = 1 + BST_INDETERMINATE = 2 + BST_UNCHECKED = 0 + BST_FOCUS = 8 + BST_PUSHED = 4 +) + +// Predefined brushes constants +const ( + COLOR_3DDKSHADOW = 21 + COLOR_3DFACE = 15 + COLOR_3DHILIGHT = 20 + COLOR_3DHIGHLIGHT = 20 + COLOR_3DLIGHT = 22 + COLOR_BTNHILIGHT = 20 + COLOR_3DSHADOW = 16 + COLOR_ACTIVEBORDER = 10 + COLOR_ACTIVECAPTION = 2 + COLOR_APPWORKSPACE = 12 + COLOR_BACKGROUND = 1 + COLOR_DESKTOP = 1 + COLOR_BTNFACE = 15 + COLOR_BTNHIGHLIGHT = 20 + COLOR_BTNSHADOW = 16 + COLOR_BTNTEXT = 18 + COLOR_CAPTIONTEXT = 9 + COLOR_GRAYTEXT = 17 + COLOR_HIGHLIGHT = 13 + COLOR_HIGHLIGHTTEXT = 14 + COLOR_INACTIVEBORDER = 11 + COLOR_INACTIVECAPTION = 3 + COLOR_INACTIVECAPTIONTEXT = 19 + COLOR_INFOBK = 24 + COLOR_INFOTEXT = 23 + COLOR_MENU = 4 + COLOR_MENUTEXT = 7 + COLOR_SCROLLBAR = 0 + COLOR_WINDOW = 5 + COLOR_WINDOWFRAME = 6 + COLOR_WINDOWTEXT = 8 + COLOR_HOTLIGHT = 26 + COLOR_GRADIENTACTIVECAPTION = 27 + COLOR_GRADIENTINACTIVECAPTION = 28 +) + +// GetAncestor flags +const ( + GA_PARENT = 1 + GA_ROOT = 2 + GA_ROOTOWNER = 3 +) + +// GetWindowLong and GetWindowLongPtr constants +const ( + GWL_EXSTYLE = -20 + GWL_STYLE = -16 + GWL_WNDPROC = -4 + GWLP_WNDPROC = -4 + GWL_HINSTANCE = -6 + GWLP_HINSTANCE = -6 + GWL_HWNDPARENT = -8 + GWLP_HWNDPARENT = -8 + GWL_ID = -12 + GWLP_ID = -12 + GWL_USERDATA = -21 + GWLP_USERDATA = -21 +) + +// Predefined window handles +const ( + HWND_BROADCAST = HWND(0xFFFF) + HWND_BOTTOM = HWND(1) + HWND_NOTOPMOST = ^HWND(1) // -2 + HWND_TOP = HWND(0) + HWND_TOPMOST = ^HWND(0) // -1 + HWND_DESKTOP = HWND(0) + HWND_MESSAGE = ^HWND(2) // -3 +) + +// Predefined icon constants +const ( + IDI_APPLICATION = 32512 + IDI_HAND = 32513 + IDI_QUESTION = 32514 + IDI_EXCLAMATION = 32515 + IDI_ASTERISK = 32516 + IDI_WINLOGO = 32517 + IDI_SHIELD = 32518 + IDI_WARNING = IDI_EXCLAMATION + IDI_ERROR = IDI_HAND + IDI_INFORMATION = IDI_ASTERISK +) + +// Predefined cursor constants +const ( + IDC_ARROW = 32512 + IDC_IBEAM = 32513 + IDC_WAIT = 32514 + IDC_CROSS = 32515 + IDC_UPARROW = 32516 + IDC_SIZENWSE = 32642 + IDC_SIZENESW = 32643 + IDC_SIZEWE = 32644 + IDC_SIZENS = 32645 + IDC_SIZEALL = 32646 + IDC_NO = 32648 + IDC_HAND = 32649 + IDC_APPSTARTING = 32650 + IDC_HELP = 32651 + IDC_ICON = 32641 + IDC_SIZE = 32640 +) + +// GetSystemMetrics constants +const ( + SM_CXSCREEN = 0 + SM_CYSCREEN = 1 + SM_CXVSCROLL = 2 + SM_CYHSCROLL = 3 + SM_CYCAPTION = 4 + SM_CXBORDER = 5 + SM_CYBORDER = 6 + SM_CXDLGFRAME = 7 + SM_CYDLGFRAME = 8 + SM_CYVTHUMB = 9 + SM_CXHTHUMB = 10 + SM_CXICON = 11 + SM_CYICON = 12 + SM_CXCURSOR = 13 + SM_CYCURSOR = 14 + SM_CYMENU = 15 + SM_CXFULLSCREEN = 16 + SM_CYFULLSCREEN = 17 + SM_CYKANJIWINDOW = 18 + SM_MOUSEPRESENT = 19 + SM_CYVSCROLL = 20 + SM_CXHSCROLL = 21 + SM_DEBUG = 22 + SM_SWAPBUTTON = 23 + SM_RESERVED1 = 24 + SM_RESERVED2 = 25 + SM_RESERVED3 = 26 + SM_RESERVED4 = 27 + SM_CXMIN = 28 + SM_CYMIN = 29 + SM_CXSIZE = 30 + SM_CYSIZE = 31 + SM_CXFRAME = 32 + SM_CYFRAME = 33 + SM_CXMINTRACK = 34 + SM_CYMINTRACK = 35 + SM_CXDOUBLECLK = 36 + SM_CYDOUBLECLK = 37 + SM_CXICONSPACING = 38 + SM_CYICONSPACING = 39 + SM_MENUDROPALIGNMENT = 40 + SM_PENWINDOWS = 41 + SM_DBCSENABLED = 42 + SM_CMOUSEBUTTONS = 43 + SM_CXFIXEDFRAME = SM_CXDLGFRAME + SM_CYFIXEDFRAME = SM_CYDLGFRAME + SM_CXSIZEFRAME = SM_CXFRAME + SM_CYSIZEFRAME = SM_CYFRAME + SM_SECURE = 44 + SM_CXEDGE = 45 + SM_CYEDGE = 46 + SM_CXMINSPACING = 47 + SM_CYMINSPACING = 48 + SM_CXSMICON = 49 + SM_CYSMICON = 50 + SM_CYSMCAPTION = 51 + SM_CXSMSIZE = 52 + SM_CYSMSIZE = 53 + SM_CXMENUSIZE = 54 + SM_CYMENUSIZE = 55 + SM_ARRANGE = 56 + SM_CXMINIMIZED = 57 + SM_CYMINIMIZED = 58 + SM_CXMAXTRACK = 59 + SM_CYMAXTRACK = 60 + SM_CXMAXIMIZED = 61 + SM_CYMAXIMIZED = 62 + SM_NETWORK = 63 + SM_CLEANBOOT = 67 + SM_CXDRAG = 68 + SM_CYDRAG = 69 + SM_SHOWSOUNDS = 70 + SM_CXMENUCHECK = 71 + SM_CYMENUCHECK = 72 + SM_SLOWMACHINE = 73 + SM_MIDEASTENABLED = 74 + SM_MOUSEWHEELPRESENT = 75 + SM_XVIRTUALSCREEN = 76 + SM_YVIRTUALSCREEN = 77 + SM_CXVIRTUALSCREEN = 78 + SM_CYVIRTUALSCREEN = 79 + SM_CMONITORS = 80 + SM_SAMEDISPLAYFORMAT = 81 + SM_IMMENABLED = 82 + SM_CXFOCUSBORDER = 83 + SM_CYFOCUSBORDER = 84 + SM_TABLETPC = 86 + SM_MEDIACENTER = 87 + SM_STARTER = 88 + SM_SERVERR2 = 89 + SM_CMETRICS = 91 + SM_REMOTESESSION = 0x1000 + SM_SHUTTINGDOWN = 0x2000 + SM_REMOTECONTROL = 0x2001 + SM_CARETBLINKINGENABLED = 0x2002 +) + +// ShowWindow constants +const ( + SW_HIDE = 0 + SW_NORMAL = 1 + SW_SHOWNORMAL = 1 + SW_SHOWMINIMIZED = 2 + SW_MAXIMIZE = 3 + SW_SHOWMAXIMIZED = 3 + SW_SHOWNOACTIVATE = 4 + SW_SHOW = 5 + SW_MINIMIZE = 6 + SW_SHOWMINNOACTIVE = 7 + SW_SHOWNA = 8 + SW_RESTORE = 9 + SW_SHOWDEFAULT = 10 + SW_FORCEMINIMIZE = 11 +) + +// SetWindowPos flags +const ( + SWP_DRAWFRAME = 0x0020 + SWP_FRAMECHANGED = 0x0020 + SWP_HIDEWINDOW = 0x0080 + SWP_NOACTIVATE = 0x0010 + SWP_NOCOPYBITS = 0x0100 + SWP_NOMOVE = 0x0002 + SWP_NOSIZE = 0x0001 + SWP_NOREDRAW = 0x0008 + SWP_NOZORDER = 0x0004 + SWP_SHOWWINDOW = 0x0040 + SWP_NOOWNERZORDER = 0x0200 + SWP_NOREPOSITION = SWP_NOOWNERZORDER + SWP_NOSENDCHANGING = 0x0400 + SWP_DEFERERASE = 0x2000 + SWP_ASYNCWINDOWPOS = 0x4000 +) + +// UI state constants +const ( + UIS_SET = 1 + UIS_CLEAR = 2 + UIS_INITIALIZE = 3 +) + +// UI state constants +const ( + UISF_HIDEFOCUS = 0x1 + UISF_HIDEACCEL = 0x2 + UISF_ACTIVE = 0x4 +) + +// Virtual key codes +const ( + VK_LBUTTON = 1 + VK_RBUTTON = 2 + VK_CANCEL = 3 + VK_MBUTTON = 4 + VK_XBUTTON1 = 5 + VK_XBUTTON2 = 6 + VK_BACK = 8 + VK_TAB = 9 + VK_CLEAR = 12 + VK_RETURN = 13 + VK_SHIFT = 16 + VK_CONTROL = 17 + VK_MENU = 18 + VK_PAUSE = 19 + VK_CAPITAL = 20 + VK_KANA = 0x15 + VK_HANGEUL = 0x15 + VK_HANGUL = 0x15 + VK_JUNJA = 0x17 + VK_FINAL = 0x18 + VK_HANJA = 0x19 + VK_KANJI = 0x19 + VK_ESCAPE = 0x1B + VK_CONVERT = 0x1C + VK_NONCONVERT = 0x1D + VK_ACCEPT = 0x1E + VK_MODECHANGE = 0x1F + VK_SPACE = 32 + VK_PRIOR = 33 + VK_NEXT = 34 + VK_END = 35 + VK_HOME = 36 + VK_LEFT = 37 + VK_UP = 38 + VK_RIGHT = 39 + VK_DOWN = 40 + VK_SELECT = 41 + VK_PRINT = 42 + VK_EXECUTE = 43 + VK_SNAPSHOT = 44 + VK_INSERT = 45 + VK_DELETE = 46 + VK_HELP = 47 + VK_LWIN = 0x5B + VK_RWIN = 0x5C + VK_APPS = 0x5D + VK_SLEEP = 0x5F + VK_NUMPAD0 = 0x60 + VK_NUMPAD1 = 0x61 + VK_NUMPAD2 = 0x62 + VK_NUMPAD3 = 0x63 + VK_NUMPAD4 = 0x64 + VK_NUMPAD5 = 0x65 + VK_NUMPAD6 = 0x66 + VK_NUMPAD7 = 0x67 + VK_NUMPAD8 = 0x68 + VK_NUMPAD9 = 0x69 + VK_MULTIPLY = 0x6A + VK_ADD = 0x6B + VK_SEPARATOR = 0x6C + VK_SUBTRACT = 0x6D + VK_DECIMAL = 0x6E + VK_DIVIDE = 0x6F + VK_F1 = 0x70 + VK_F2 = 0x71 + VK_F3 = 0x72 + VK_F4 = 0x73 + VK_F5 = 0x74 + VK_F6 = 0x75 + VK_F7 = 0x76 + VK_F8 = 0x77 + VK_F9 = 0x78 + VK_F10 = 0x79 + VK_F11 = 0x7A + VK_F12 = 0x7B + VK_F13 = 0x7C + VK_F14 = 0x7D + VK_F15 = 0x7E + VK_F16 = 0x7F + VK_F17 = 0x80 + VK_F18 = 0x81 + VK_F19 = 0x82 + VK_F20 = 0x83 + VK_F21 = 0x84 + VK_F22 = 0x85 + VK_F23 = 0x86 + VK_F24 = 0x87 + VK_NUMLOCK = 0x90 + VK_SCROLL = 0x91 + VK_LSHIFT = 0xA0 + VK_RSHIFT = 0xA1 + VK_LCONTROL = 0xA2 + VK_RCONTROL = 0xA3 + VK_LMENU = 0xA4 + VK_RMENU = 0xA5 + VK_BROWSER_BACK = 0xA6 + VK_BROWSER_FORWARD = 0xA7 + VK_BROWSER_REFRESH = 0xA8 + VK_BROWSER_STOP = 0xA9 + VK_BROWSER_SEARCH = 0xAA + VK_BROWSER_FAVORITES = 0xAB + VK_BROWSER_HOME = 0xAC + VK_VOLUME_MUTE = 0xAD + VK_VOLUME_DOWN = 0xAE + VK_VOLUME_UP = 0xAF + VK_MEDIA_NEXT_TRACK = 0xB0 + VK_MEDIA_PREV_TRACK = 0xB1 + VK_MEDIA_STOP = 0xB2 + VK_MEDIA_PLAY_PAUSE = 0xB3 + VK_LAUNCH_MAIL = 0xB4 + VK_LAUNCH_MEDIA_SELECT = 0xB5 + VK_LAUNCH_APP1 = 0xB6 + VK_LAUNCH_APP2 = 0xB7 + VK_OEM_1 = 0xBA + VK_OEM_PLUS = 0xBB + VK_OEM_COMMA = 0xBC + VK_OEM_MINUS = 0xBD + VK_OEM_PERIOD = 0xBE + VK_OEM_2 = 0xBF + VK_OEM_3 = 0xC0 + VK_OEM_4 = 0xDB + VK_OEM_5 = 0xDC + VK_OEM_6 = 0xDD + VK_OEM_7 = 0xDE + VK_OEM_8 = 0xDF + VK_OEM_102 = 0xE2 + VK_PROCESSKEY = 0xE5 + VK_PACKET = 0xE7 + VK_ATTN = 0xF6 + VK_CRSEL = 0xF7 + VK_EXSEL = 0xF8 + VK_EREOF = 0xF9 + VK_PLAY = 0xFA + VK_ZOOM = 0xFB + VK_NONAME = 0xFC + VK_PA1 = 0xFD + VK_OEM_CLEAR = 0xFE +) + +// Window style constants +const ( + WS_OVERLAPPED = 0X00000000 + WS_POPUP = 0X80000000 + WS_CHILD = 0X40000000 + WS_MINIMIZE = 0X20000000 + WS_VISIBLE = 0X10000000 + WS_DISABLED = 0X08000000 + WS_CLIPSIBLINGS = 0X04000000 + WS_CLIPCHILDREN = 0X02000000 + WS_MAXIMIZE = 0X01000000 + WS_CAPTION = 0X00C00000 + WS_BORDER = 0X00800000 + WS_DLGFRAME = 0X00400000 + WS_VSCROLL = 0X00200000 + WS_HSCROLL = 0X00100000 + WS_SYSMENU = 0X00080000 + WS_THICKFRAME = 0X00040000 + WS_GROUP = 0X00020000 + WS_TABSTOP = 0X00010000 + WS_MINIMIZEBOX = 0X00020000 + WS_MAXIMIZEBOX = 0X00010000 + WS_TILED = 0X00000000 + WS_ICONIC = 0X20000000 + WS_SIZEBOX = 0X00040000 + WS_OVERLAPPEDWINDOW = 0X00000000 | 0X00C00000 | 0X00080000 | 0X00040000 | 0X00020000 | 0X00010000 + WS_POPUPWINDOW = 0X80000000 | 0X00800000 | 0X00080000 + WS_CHILDWINDOW = 0X40000000 +) + +// Extended window style constants +const ( + WS_EX_DLGMODALFRAME = 0X00000001 + WS_EX_NOPARENTNOTIFY = 0X00000004 + WS_EX_TOPMOST = 0X00000008 + WS_EX_ACCEPTFILES = 0X00000010 + WS_EX_TRANSPARENT = 0X00000020 + WS_EX_MDICHILD = 0X00000040 + WS_EX_TOOLWINDOW = 0X00000080 + WS_EX_WINDOWEDGE = 0X00000100 + WS_EX_CLIENTEDGE = 0X00000200 + WS_EX_CONTEXTHELP = 0X00000400 + WS_EX_RIGHT = 0X00001000 + WS_EX_LEFT = 0X00000000 + WS_EX_RTLREADING = 0X00002000 + WS_EX_LTRREADING = 0X00000000 + WS_EX_LEFTSCROLLBAR = 0X00004000 + WS_EX_RIGHTSCROLLBAR = 0X00000000 + WS_EX_CONTROLPARENT = 0X00010000 + WS_EX_STATICEDGE = 0X00020000 + WS_EX_APPWINDOW = 0X00040000 + WS_EX_OVERLAPPEDWINDOW = 0X00000100 | 0X00000200 + WS_EX_PALETTEWINDOW = 0X00000100 | 0X00000080 | 0X00000008 + WS_EX_LAYERED = 0X00080000 + WS_EX_NOINHERITLAYOUT = 0X00100000 + WS_EX_LAYOUTRTL = 0X00400000 + WS_EX_NOACTIVATE = 0X08000000 +) + +// Window message constants +const ( + WM_APP = 32768 + WM_ACTIVATE = 6 + WM_ACTIVATEAPP = 28 + WM_AFXFIRST = 864 + WM_AFXLAST = 895 + WM_ASKCBFORMATNAME = 780 + WM_CANCELJOURNAL = 75 + WM_CANCELMODE = 31 + WM_CAPTURECHANGED = 533 + WM_CHANGECBCHAIN = 781 + WM_CHAR = 258 + WM_CHARTOITEM = 47 + WM_CHILDACTIVATE = 34 + WM_CLEAR = 771 + WM_CLOSE = 16 + WM_COMMAND = 273 + WM_COMMNOTIFY = 68 /* OBSOLETE */ + WM_COMPACTING = 65 + WM_COMPAREITEM = 57 + WM_CONTEXTMENU = 123 + WM_COPY = 769 + WM_COPYDATA = 74 + WM_CREATE = 1 + WM_CTLCOLORBTN = 309 + WM_CTLCOLORDLG = 310 + WM_CTLCOLOREDIT = 307 + WM_CTLCOLORLISTBOX = 308 + WM_CTLCOLORMSGBOX = 306 + WM_CTLCOLORSCROLLBAR = 311 + WM_CTLCOLORSTATIC = 312 + WM_CUT = 768 + WM_DEADCHAR = 259 + WM_DELETEITEM = 45 + WM_DESTROY = 2 + WM_DESTROYCLIPBOARD = 775 + WM_DEVICECHANGE = 537 + WM_DEVMODECHANGE = 27 + WM_DISPLAYCHANGE = 126 + WM_DRAWCLIPBOARD = 776 + WM_DRAWITEM = 43 + WM_DROPFILES = 563 + WM_ENABLE = 10 + WM_ENDSESSION = 22 + WM_ENTERIDLE = 289 + WM_ENTERMENULOOP = 529 + WM_ENTERSIZEMOVE = 561 + WM_ERASEBKGND = 20 + WM_EXITMENULOOP = 530 + WM_EXITSIZEMOVE = 562 + WM_FONTCHANGE = 29 + WM_GETDLGCODE = 135 + WM_GETFONT = 49 + WM_GETHOTKEY = 51 + WM_GETICON = 127 + WM_GETMINMAXINFO = 36 + WM_GETTEXT = 13 + WM_GETTEXTLENGTH = 14 + WM_HANDHELDFIRST = 856 + WM_HANDHELDLAST = 863 + WM_HELP = 83 + WM_HOTKEY = 786 + WM_HSCROLL = 276 + WM_HSCROLLCLIPBOARD = 782 + WM_ICONERASEBKGND = 39 + WM_INITDIALOG = 272 + WM_INITMENU = 278 + WM_INITMENUPOPUP = 279 + WM_INPUT = 0X00FF + WM_INPUTLANGCHANGE = 81 + WM_INPUTLANGCHANGEREQUEST = 80 + WM_KEYDOWN = 256 + WM_KEYUP = 257 + WM_KILLFOCUS = 8 + WM_MDIACTIVATE = 546 + WM_MDICASCADE = 551 + WM_MDICREATE = 544 + WM_MDIDESTROY = 545 + WM_MDIGETACTIVE = 553 + WM_MDIICONARRANGE = 552 + WM_MDIMAXIMIZE = 549 + WM_MDINEXT = 548 + WM_MDIREFRESHMENU = 564 + WM_MDIRESTORE = 547 + WM_MDISETMENU = 560 + WM_MDITILE = 550 + WM_MEASUREITEM = 44 + WM_GETOBJECT = 0X003D + WM_CHANGEUISTATE = 0X0127 + WM_UPDATEUISTATE = 0X0128 + WM_QUERYUISTATE = 0X0129 + WM_UNINITMENUPOPUP = 0X0125 + WM_MENURBUTTONUP = 290 + WM_MENUCOMMAND = 0X0126 + WM_MENUGETOBJECT = 0X0124 + WM_MENUDRAG = 0X0123 + WM_APPCOMMAND = 0X0319 + WM_MENUCHAR = 288 + WM_MENUSELECT = 287 + WM_MOVE = 3 + WM_MOVING = 534 + WM_NCACTIVATE = 134 + WM_NCCALCSIZE = 131 + WM_NCCREATE = 129 + WM_NCDESTROY = 130 + WM_NCHITTEST = 132 + WM_NCLBUTTONDBLCLK = 163 + WM_NCLBUTTONDOWN = 161 + WM_NCLBUTTONUP = 162 + WM_NCMBUTTONDBLCLK = 169 + WM_NCMBUTTONDOWN = 167 + WM_NCMBUTTONUP = 168 + WM_NCXBUTTONDOWN = 171 + WM_NCXBUTTONUP = 172 + WM_NCXBUTTONDBLCLK = 173 + WM_NCMOUSEHOVER = 0X02A0 + WM_NCMOUSELEAVE = 0X02A2 + WM_NCMOUSEMOVE = 160 + WM_NCPAINT = 133 + WM_NCRBUTTONDBLCLK = 166 + WM_NCRBUTTONDOWN = 164 + WM_NCRBUTTONUP = 165 + WM_NEXTDLGCTL = 40 + WM_NEXTMENU = 531 + WM_NOTIFY = 78 + WM_NOTIFYFORMAT = 85 + WM_NULL = 0 + WM_PAINT = 15 + WM_PAINTCLIPBOARD = 777 + WM_PAINTICON = 38 + WM_PALETTECHANGED = 785 + WM_PALETTEISCHANGING = 784 + WM_PARENTNOTIFY = 528 + WM_PASTE = 770 + WM_PENWINFIRST = 896 + WM_PENWINLAST = 911 + WM_POWER = 72 + WM_POWERBROADCAST = 536 + WM_PRINT = 791 + WM_PRINTCLIENT = 792 + WM_QUERYDRAGICON = 55 + WM_QUERYENDSESSION = 17 + WM_QUERYNEWPALETTE = 783 + WM_QUERYOPEN = 19 + WM_QUEUESYNC = 35 + WM_QUIT = 18 + WM_RENDERALLFORMATS = 774 + WM_RENDERFORMAT = 773 + WM_SETCURSOR = 32 + WM_SETFOCUS = 7 + WM_SETFONT = 48 + WM_SETHOTKEY = 50 + WM_SETICON = 128 + WM_SETREDRAW = 11 + WM_SETTEXT = 12 + WM_SETTINGCHANGE = 26 + WM_SHOWWINDOW = 24 + WM_SIZE = 5 + WM_SIZECLIPBOARD = 779 + WM_SIZING = 532 + WM_SPOOLERSTATUS = 42 + WM_STYLECHANGED = 125 + WM_STYLECHANGING = 124 + WM_SYSCHAR = 262 + WM_SYSCOLORCHANGE = 21 + WM_SYSCOMMAND = 274 + WM_SYSDEADCHAR = 263 + WM_SYSKEYDOWN = 260 + WM_SYSKEYUP = 261 + WM_TCARD = 82 + WM_THEMECHANGED = 794 + WM_TIMECHANGE = 30 + WM_TIMER = 275 + WM_UNDO = 772 + WM_USER = 1024 + WM_USERCHANGED = 84 + WM_VKEYTOITEM = 46 + WM_VSCROLL = 277 + WM_VSCROLLCLIPBOARD = 778 + WM_WINDOWPOSCHANGED = 71 + WM_WINDOWPOSCHANGING = 70 + WM_WININICHANGE = 26 + WM_KEYFIRST = 256 + WM_KEYLAST = 264 + WM_SYNCPAINT = 136 + WM_MOUSEACTIVATE = 33 + WM_MOUSEMOVE = 512 + WM_LBUTTONDOWN = 513 + WM_LBUTTONUP = 514 + WM_LBUTTONDBLCLK = 515 + WM_RBUTTONDOWN = 516 + WM_RBUTTONUP = 517 + WM_RBUTTONDBLCLK = 518 + WM_MBUTTONDOWN = 519 + WM_MBUTTONUP = 520 + WM_MBUTTONDBLCLK = 521 + WM_MOUSEWHEEL = 522 + WM_MOUSEFIRST = 512 + WM_XBUTTONDOWN = 523 + WM_XBUTTONUP = 524 + WM_XBUTTONDBLCLK = 525 + WM_MOUSELAST = 525 + WM_MOUSEHOVER = 0X2A1 + WM_MOUSELEAVE = 0X2A3 + WM_CLIPBOARDUPDATE = 0x031D +) + +// mouse button constants +const ( + MK_CONTROL = 0x0008 + MK_LBUTTON = 0x0001 + MK_MBUTTON = 0x0010 + MK_RBUTTON = 0x0002 + MK_SHIFT = 0x0004 + MK_XBUTTON1 = 0x0020 + MK_XBUTTON2 = 0x0040 +) + +// TrackPopupMenu[Ex] flags +const ( + TPM_CENTERALIGN = 0x0004 + TPM_LEFTALIGN = 0x0000 + TPM_RIGHTALIGN = 0x0008 + TPM_BOTTOMALIGN = 0x0020 + TPM_TOPALIGN = 0x0000 + TPM_VCENTERALIGN = 0x0010 + TPM_NONOTIFY = 0x0080 + TPM_RETURNCMD = 0x0100 + TPM_LEFTBUTTON = 0x0000 + TPM_RIGHTBUTTON = 0x0002 + TPM_HORNEGANIMATION = 0x0800 + TPM_HORPOSANIMATION = 0x0400 + TPM_NOANIMATION = 0x4000 + TPM_VERNEGANIMATION = 0x2000 + TPM_VERPOSANIMATION = 0x1000 + TPM_HORIZONTAL = 0x0000 + TPM_VERTICAL = 0x0040 +) + +// WINDOWPLACEMENT flags +const ( + WPF_ASYNCWINDOWPLACEMENT = 0x0004 + WPF_RESTORETOMAXIMIZED = 0x0002 + WPF_SETMINPOSITION = 0x0001 +) + +// DrawText[Ex] format flags +const ( + DT_TOP = 0x00000000 + DT_LEFT = 0x00000000 + DT_CENTER = 0x00000001 + DT_RIGHT = 0x00000002 + DT_VCENTER = 0x00000004 + DT_BOTTOM = 0x00000008 + DT_WORDBREAK = 0x00000010 + DT_SINGLELINE = 0x00000020 + DT_EXPANDTABS = 0x00000040 + DT_TABSTOP = 0x00000080 + DT_NOCLIP = 0x00000100 + DT_EXTERNALLEADING = 0x00000200 + DT_CALCRECT = 0x00000400 + DT_NOPREFIX = 0x00000800 + DT_INTERNAL = 0x00001000 + DT_EDITCONTROL = 0x00002000 + DT_PATH_ELLIPSIS = 0x00004000 + DT_END_ELLIPSIS = 0x00008000 + DT_MODIFYSTRING = 0x00010000 + DT_RTLREADING = 0x00020000 + DT_WORD_ELLIPSIS = 0x00040000 + DT_NOFULLWIDTHCHARBREAK = 0x00080000 + DT_HIDEPREFIX = 0x00100000 + DT_PREFIXONLY = 0x00200000 +) + +// Window class styles +const ( + CS_VREDRAW = 0x00000001 + CS_HREDRAW = 0x00000002 + CS_KEYCVTWINDOW = 0x00000004 + CS_DBLCLKS = 0x00000008 + CS_OWNDC = 0x00000020 + CS_CLASSDC = 0x00000040 + CS_PARENTDC = 0x00000080 + CS_NOKEYCVT = 0x00000100 + CS_NOCLOSE = 0x00000200 + CS_SAVEBITS = 0x00000800 + CS_BYTEALIGNCLIENT = 0x00001000 + CS_BYTEALIGNWINDOW = 0x00002000 + CS_GLOBALCLASS = 0x00004000 + CS_IME = 0x00010000 + CS_DROPSHADOW = 0x00020000 +) + +// SystemParametersInfo actions +const ( + SPI_GETNONCLIENTMETRICS = 0x0029 +) + +// Dialog styles +const ( + DS_ABSALIGN = 0x0001 + DS_SYSMODAL = 0x0002 + DS_3DLOOK = 0x0004 + DS_FIXEDSYS = 0x0008 + DS_NOFAILCREATE = 0x0010 + DS_LOCALEDIT = 0x0020 + DS_SETFONT = 0x0040 + DS_MODALFRAME = 0x0080 + DS_NOIDLEMSG = 0x0100 + DS_SETFOREGROUND = 0x0200 + DS_CONTROL = 0x0400 + DS_CENTER = 0x0800 + DS_CENTERMOUSE = 0x1000 + DS_CONTEXTHELP = 0x2000 + DS_USEPIXELS = 0x8000 + DS_SHELLFONT = (DS_SETFONT | DS_FIXEDSYS) +) + +// WM_GETDLGCODE return values +const ( + DLGC_BUTTON = 0x2000 + DLGC_DEFPUSHBUTTON = 0x0010 + DLGC_HASSETSEL = 0x0008 + DLGC_RADIOBUTTON = 0x0040 + DLGC_STATIC = 0x0100 + DLGC_UNDEFPUSHBUTTON = 0x0020 + DLGC_WANTALLKEYS = 0x0004 + DLGC_WANTARROWS = 0x0001 + DLGC_WANTCHARS = 0x0080 + DLGC_WANTMESSAGE = 0x0004 + DLGC_WANTTAB = 0x0002 +) + +// WM_ACTIVATE codes +const ( + WA_ACTIVE = 1 + WA_CLICKACTIVE = 2 + WA_INACTIVE = 0 +) + +// Owner drawing states +const ( + ODS_CHECKED = 0x0001 + ODS_COMBOBOXEDIT = 0x0002 + ODS_DEFAULT = 0x0004 + ODS_DISABLED = 0x0008 + ODS_FOCUS = 0x0010 + ODS_GRAYED = 0x0020 + ODS_SELECTED = 0x0040 +) + +// Raw input device flags +const ( + RIDEV_APPKEYS = 0x00000400 + RIDEV_CAPTUREMOUSE = 0x00000200 + RIDEV_DEVNOTIFY = 0x00002000 + RIDEV_EXCLUDE = 0x00000010 + RIDEV_EXINPUTSINK = 0x00001000 + RIDEV_INPUTSINK = 0x00000100 + RIDEV_NOHOTKEYS = 0x00000200 + RIDEV_NOLEGACY = 0x00000030 + RIDEV_PAGEONLY = 0x00000020 + RIDEV_REMOVE = 0x00000001 +) + +// Raw input device command flags +const ( + RID_HEADER = 0x10000005 + RID_INPUT = 0x10000003 +) + +// Raw input type +const ( + RIM_TYPEHID = 2 + RIM_TYPEKEYBOARD = 1 + RIM_TYPEMOUSE = 0 +) + +// Raw input scan code information +const ( + RI_KEY_MAKE = 0 + RI_KEY_BREAK = 1 + RI_KEY_E0 = 2 + RI_KEY_E1 = 4 +) + +// Raw input mouse state +const ( + MOUSE_MOVE_RELATIVE = 0x00 + MOUSE_MOVE_ABSOLUTE = 0x01 + MOUSE_VIRTUAL_DESKTOP = 0x02 + MOUSE_ATTRIBUTES_CHANGED = 0x04 +) + +// Raw input transistion state of mouse buttons +const ( + RI_MOUSE_LEFT_BUTTON_DOWN = 0x0001 + RI_MOUSE_LEFT_BUTTON_UP = 0x0002 + RI_MOUSE_MIDDLE_BUTTON_DOWN = 0x0010 + RI_MOUSE_MIDDLE_BUTTON_UP = 0x0020 + RI_MOUSE_RIGHT_BUTTON_DOWN = 0x0004 + RI_MOUSE_RIGHT_BUTTON_UP = 0x0008 + RI_MOUSE_BUTTON_1_DOWN = 0x0001 + RI_MOUSE_BUTTON_1_UP = 0x0002 + RI_MOUSE_BUTTON_2_DOWN = 0x0004 + RI_MOUSE_BUTTON_2_UP = 0x0008 + RI_MOUSE_BUTTON_3_DOWN = 0x0010 + RI_MOUSE_BUTTON_3_UP = 0x0020 + RI_MOUSE_BUTTON_4_DOWN = 0x0040 + RI_MOUSE_BUTTON_4_UP = 0x0080 + RI_MOUSE_BUTTON_5_DOWN = 0x0100 + RI_MOUSE_BUTTON_5_UP = 0x0200 + RI_MOUSE_WHEEL = 0x0400 +) + +// Multi monitor constants +const ( + MONITOR_DEFAULTTONULL = 0x0 + MONITOR_DEFAULTTOPRIMARY = 0x1 + MONITOR_DEFAULTTONEAREST = 0x2 +) + +// MONITORINFO flags +const ( + MONITORINFOF_PRIMARY = 0x1 +) + +// INPUT Type +const ( + INPUT_MOUSE = 0 + INPUT_KEYBOARD = 1 + INPUT_HARDWARE = 2 +) + +// MOUSEINPUT MouseData +const ( + XBUTTON1 = 0x0001 + XBUTTON2 = 0x0002 +) + +// MOUSEINPUT DwFlags +const ( + MOUSEEVENTF_ABSOLUTE = 0x8000 + MOUSEEVENTF_HWHEEL = 0x1000 + MOUSEEVENTF_MOVE = 0x0001 + MOUSEEVENTF_MOVE_NOCOALESCE = 0x2000 + MOUSEEVENTF_LEFTDOWN = 0x0002 + MOUSEEVENTF_LEFTUP = 0x0004 + MOUSEEVENTF_RIGHTDOWN = 0x0008 + MOUSEEVENTF_RIGHTUP = 0x0010 + MOUSEEVENTF_MIDDLEDOWN = 0x0020 + MOUSEEVENTF_MIDDLEUP = 0x0040 + MOUSEEVENTF_VIRTUALDESK = 0x4000 + MOUSEEVENTF_WHEEL = 0x0800 + MOUSEEVENTF_XDOWN = 0x0080 + MOUSEEVENTF_XUP = 0x0100 +) + +// KEYBDINPUT DwFlags +const ( + KEYEVENTF_EXTENDEDKEY = 0x0001 + KEYEVENTF_KEYUP = 0x0002 + KEYEVENTF_SCANCODE = 0x0008 + KEYEVENTF_UNICODE = 0x0004 +) + +// GetWindow uCmd constants +const ( + GW_CHILD = 5 + GW_ENABLEDPOPUP = 6 + GW_HWNDFIRST = 0 + GW_HWNDLAST = 1 + GW_HWNDNEXT = 2 + GW_HWNDPREV = 3 + GW_OWNER = 4 +) + +// Standard clipboard formats +const ( + CF_BITMAP = 2 + CF_DIB = 8 + CF_DIBV5 = 17 + CF_DIF = 5 + CF_DSPBITMAP = 0x0082 + CF_DSPENHMETAFILE = 0x008E + CF_DSPMETAFILEPICT = 0x0083 + CF_DSPTEXT = 0x0081 + CF_ENHMETAFILE = 14 + CF_GDIOBJFIRST = 0x0300 + CF_GDIOBJLAST = 0x03FF + CF_HDROP = 15 + CF_LOCALE = 16 + CF_METAFILEPICT = 3 + CF_OEMTEXT = 7 + CF_OWNERDISPLAY = 0x0080 + CF_PALETTE = 9 + CF_PENDATA = 10 + CF_PRIVATEFIRST = 0x0200 + CF_PRIVATELAST = 0x02FF + CF_RIFF = 11 + CF_SYLK = 4 + CF_TEXT = 1 + CF_TIFF = 6 + CF_UNICODETEXT = 13 + CF_WAVE = 12 +) + +// ScrollBar constants +const ( + SB_HORZ = 0 + SB_VERT = 1 + SB_CTL = 2 + SB_BOTH = 3 +) + +// ScrollBar commands +const ( + SB_LINEUP = 0 + SB_LINELEFT = 0 + SB_LINEDOWN = 1 + SB_LINERIGHT = 1 + SB_PAGEUP = 2 + SB_PAGELEFT = 2 + SB_PAGEDOWN = 3 + SB_PAGERIGHT = 3 + SB_THUMBPOSITION = 4 + SB_THUMBTRACK = 5 + SB_TOP = 6 + SB_LEFT = 6 + SB_BOTTOM = 7 + SB_RIGHT = 7 + SB_ENDSCROLL = 8 +) + +// [Get|Set]ScrollInfo mask constants +const ( + SIF_RANGE = 1 + SIF_PAGE = 2 + SIF_POS = 4 + SIF_DISABLENOSCROLL = 8 + SIF_TRACKPOS = 16 + SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS +) + +// DrawIconEx flags +const ( + DI_COMPAT = 0x0004 + DI_DEFAULTSIZE = 0x0008 + DI_IMAGE = 0x0002 + DI_MASK = 0x0001 + DI_NOMIRROR = 0x0010 + DI_NORMAL = DI_IMAGE | DI_MASK +) + +// WM_NCHITTEST constants +const ( + HTBORDER = 18 + HTBOTTOM = 15 + HTBOTTOMLEFT = 16 + HTBOTTOMRIGHT = 17 + HTCAPTION = 2 + HTCLIENT = 1 + HTCLOSE = 20 + HTERROR = -2 + HTGROWBOX = 4 + HTHELP = 21 + HTHSCROLL = 6 + HTLEFT = 10 + HTMENU = 5 + HTMAXBUTTON = 9 + HTMINBUTTON = 8 + HTNOWHERE = 0 + HTREDUCE = 8 + HTRIGHT = 11 + HTSIZE = 4 + HTSYSMENU = 3 + HTTOP = 12 + HTTOPLEFT = 13 + HTTOPRIGHT = 14 + HTTRANSPARENT = -1 + HTVSCROLL = 7 + HTZOOM = 9 +) + +// AnimateWindow flags +const ( + AW_ACTIVATE = 0x00020000 + AW_BLEND = 0x00080000 + AW_CENTER = 0x00000010 + AW_HIDE = 0x00010000 + AW_HOR_POSITIVE = 0x00000001 + AW_HOR_NEGATIVE = 0x00000002 + AW_SLIDE = 0x00040000 + AW_VER_POSITIVE = 0x00000004 + AW_VER_NEGATIVE = 0x00000008 +) + +type NMBCDROPDOWN struct { + Hdr NMHDR + RcButton RECT +} + +type MONITORINFO struct { + CbSize uint32 + RcMonitor RECT + RcWork RECT + DwFlags uint32 +} + +type ( + HACCEL HANDLE + HCURSOR HANDLE + HDWP HANDLE + HICON HANDLE + HMENU HANDLE + HMONITOR HANDLE + HRAWINPUT HANDLE + HWND HANDLE +) + +type MSG struct { + HWnd HWND + Message uint32 + WParam uintptr + LParam uintptr + Time uint32 + Pt POINT +} + +type RAWINPUTDEVICE struct { + UsUsagePage uint16 + UsUsage uint16 + DwFlags uint32 + HwndTarget HWND +} + +type RAWINPUTHEADER struct { + DwType uint32 + DwSize uint32 + HDevice HANDLE + WParam uintptr +} + +type RAWINPUTMOUSE struct { + Header RAWINPUTHEADER + Data RAWMOUSE +} + +type RAWINPUTKEYBOARD struct { + Header RAWINPUTHEADER + Data RAWKEYBOARD +} + +type RAWINPUTHID struct { + Header RAWINPUTHEADER + Data RAWHID +} + +type RAWMOUSE struct { + UsFlags uint16 + UsButtonFlags uint16 + UsButtonData uint16 + Pad_cgo_0 [2]byte + UlRawButtons uint32 + LLastX int32 + LLastY int32 + UlExtraInformation uint32 +} + +type RAWKEYBOARD struct { + MakeCode uint16 + Flags uint16 + Reserved int16 + VKey uint16 + Message uint32 + ExtraInformation uint32 +} + +type RAWHID struct { + DwSizeHid uint32 + DwCount uint32 + BRawData [1]byte +} + +type NMHDR struct { + HwndFrom HWND + IdFrom uintptr + Code uint32 +} + +type CREATESTRUCT struct { + CreateParams uintptr + Instance HINSTANCE + Menu HMENU + Parent HWND + Cy int32 + Cx int32 + Y int32 + X int32 + Style int32 + Name, ClassName uintptr + ExStyle uint32 +} + +type WNDCLASSEX struct { + CbSize uint32 + Style uint32 + LpfnWndProc uintptr + CbClsExtra int32 + CbWndExtra int32 + HInstance HINSTANCE + HIcon HICON + HCursor HCURSOR + HbrBackground HBRUSH + LpszMenuName *uint16 + LpszClassName *uint16 + HIconSm HICON +} + +type TPMPARAMS struct { + CbSize uint32 + RcExclude RECT +} + +type WINDOWPLACEMENT struct { + Length uint32 + Flags uint32 + ShowCmd uint32 + PtMinPosition POINT + PtMaxPosition POINT + RcNormalPosition RECT +} + +type DRAWTEXTPARAMS struct { + CbSize uint32 + ITabLength int32 + ILeftMargin int32 + IRightMargin int32 + UiLengthDrawn uint32 +} + +type PAINTSTRUCT struct { + Hdc HDC + FErase BOOL + RcPaint RECT + FRestore BOOL + FIncUpdate BOOL + RgbReserved [32]byte +} + +type MINMAXINFO struct { + PtReserved POINT + PtMaxSize POINT + PtMaxPosition POINT + PtMinTrackSize POINT + PtMaxTrackSize POINT +} + +type NONCLIENTMETRICS struct { + CbSize uint32 + IBorderWidth int32 + IScrollWidth int32 + IScrollHeight int32 + ICaptionWidth int32 + ICaptionHeight int32 + LfCaptionFont LOGFONT + ISmCaptionWidth int32 + ISmCaptionHeight int32 + LfSmCaptionFont LOGFONT + IMenuWidth int32 + IMenuHeight int32 + LfMenuFont LOGFONT + LfStatusFont LOGFONT + LfMessageFont LOGFONT +} + +type MEASUREITEMSTRUCT struct { + CtlType uint32 + CtlID uint32 + ItemID int32 + ItemWidth uint32 + ItemHeight uint32 + ItemData uintptr +} + +type DRAWITEMSTRUCT struct { + CtlType uint32 + CtlID uint32 + ItemID int32 + ItemAction uint32 + ItemState uint32 + HwndItem HWND + HDC HDC + RcItem RECT + ItemData uintptr +} + +type ICONINFO struct { + FIcon BOOL + XHotspot uint32 + YHotspot uint32 + HbmMask HBITMAP + HbmColor HBITMAP +} + +type MOUSE_INPUT struct { + Type uint32 + Mi MOUSEINPUT +} + +type MOUSEINPUT struct { + Dx int32 + Dy int32 + MouseData uint32 + DwFlags uint32 + Time uint32 + DwExtraInfo uintptr +} + +type KEYBD_INPUT struct { + Type uint32 + Ki KEYBDINPUT +} + +type KEYBDINPUT struct { + WVk uint16 + WScan uint16 + DwFlags uint32 + Time uint32 + DwExtraInfo uintptr + Unused [8]byte +} + +type HARDWARE_INPUT struct { + Type uint32 + Hi HARDWAREINPUT +} + +type HARDWAREINPUT struct { + UMsg uint32 + WParamL uint16 + WParamH uint16 + Unused [16]byte +} + +type SCROLLINFO struct { + CbSize uint32 + FMask uint32 + NMin int32 + NMax int32 + NPage uint32 + NPos int32 + NTrackPos int32 +} + +type WINDOWPOS struct { + Hwnd HWND + HwndInsertAfter HWND + X int32 + Y int32 + Cx int32 + Cy int32 + Flags uint32 +} + +func GET_X_LPARAM(lp uintptr) int32 { + return int32(int16(LOWORD(uint32(lp)))) +} + +func GET_Y_LPARAM(lp uintptr) int32 { + return int32(int16(HIWORD(uint32(lp)))) +} + +var ( + // Library + libuser32 uintptr + + // Functions + addClipboardFormatListener uintptr + adjustWindowRect uintptr + animateWindow uintptr + beginDeferWindowPos uintptr + beginPaint uintptr + callWindowProc uintptr + clientToScreen uintptr + closeClipboard uintptr + createDialogParam uintptr + createIconIndirect uintptr + createMenu uintptr + createPopupMenu uintptr + createWindowEx uintptr + deferWindowPos uintptr + defWindowProc uintptr + destroyIcon uintptr + destroyMenu uintptr + destroyWindow uintptr + dialogBoxParam uintptr + dispatchMessage uintptr + drawIconEx uintptr + drawMenuBar uintptr + drawFocusRect uintptr + drawTextEx uintptr + emptyClipboard uintptr + enableWindow uintptr + endDeferWindowPos uintptr + endDialog uintptr + endPaint uintptr + enumChildWindows uintptr + findWindow uintptr + getActiveWindow uintptr + getAncestor uintptr + getCaretPos uintptr + getClientRect uintptr + getClipboardData uintptr + getCursorPos uintptr + getDC uintptr + getDesktopWindow uintptr + getFocus uintptr + getForegroundWindow uintptr + getKeyState uintptr + getMenuInfo uintptr + getMessage uintptr + getMonitorInfo uintptr + getParent uintptr + getRawInputData uintptr + getScrollInfo uintptr + getSysColor uintptr + getSysColorBrush uintptr + getSystemMetrics uintptr + getWindow uintptr + getWindowLong uintptr + getWindowLongPtr uintptr + getWindowPlacement uintptr + getWindowRect uintptr + insertMenuItem uintptr + invalidateRect uintptr + isChild uintptr + isClipboardFormatAvailable uintptr + isDialogMessage uintptr + isWindowEnabled uintptr + isWindowVisible uintptr + killTimer uintptr + loadCursor uintptr + loadIcon uintptr + loadImage uintptr + loadMenu uintptr + loadString uintptr + messageBeep uintptr + messageBox uintptr + monitorFromWindow uintptr + moveWindow uintptr + unregisterClass uintptr + openClipboard uintptr + peekMessage uintptr + postMessage uintptr + postQuitMessage uintptr + registerClassEx uintptr + registerRawInputDevices uintptr + registerWindowMessage uintptr + releaseCapture uintptr + releaseDC uintptr + removeMenu uintptr + screenToClient uintptr + sendDlgItemMessage uintptr + sendInput uintptr + sendMessage uintptr + setActiveWindow uintptr + setCapture uintptr + setClipboardData uintptr + setCursor uintptr + setCursorPos uintptr + setFocus uintptr + setForegroundWindow uintptr + setMenu uintptr + setMenuInfo uintptr + setMenuItemInfo uintptr + setParent uintptr + setRect uintptr + setScrollInfo uintptr + setTimer uintptr + setWindowLong uintptr + setWindowLongPtr uintptr + setWindowPlacement uintptr + setWindowPos uintptr + showWindow uintptr + systemParametersInfo uintptr + trackPopupMenuEx uintptr + translateMessage uintptr + updateWindow uintptr + windowFromDC uintptr + windowFromPoint uintptr +) + +func init() { + is64bit := unsafe.Sizeof(uintptr(0)) == 8 + + // Library + libuser32 = MustLoadLibrary("user32.dll") + + // Functions + addClipboardFormatListener, _ = syscall.GetProcAddress(syscall.Handle(libuser32), "AddClipboardFormatListener") + adjustWindowRect = MustGetProcAddress(libuser32, "AdjustWindowRect") + animateWindow = MustGetProcAddress(libuser32, "AnimateWindow") + beginDeferWindowPos = MustGetProcAddress(libuser32, "BeginDeferWindowPos") + beginPaint = MustGetProcAddress(libuser32, "BeginPaint") + callWindowProc = MustGetProcAddress(libuser32, "CallWindowProcW") + clientToScreen = MustGetProcAddress(libuser32, "ClientToScreen") + closeClipboard = MustGetProcAddress(libuser32, "CloseClipboard") + createDialogParam = MustGetProcAddress(libuser32, "CreateDialogParamW") + createIconIndirect = MustGetProcAddress(libuser32, "CreateIconIndirect") + createMenu = MustGetProcAddress(libuser32, "CreateMenu") + createPopupMenu = MustGetProcAddress(libuser32, "CreatePopupMenu") + createWindowEx = MustGetProcAddress(libuser32, "CreateWindowExW") + deferWindowPos = MustGetProcAddress(libuser32, "DeferWindowPos") + defWindowProc = MustGetProcAddress(libuser32, "DefWindowProcW") + destroyIcon = MustGetProcAddress(libuser32, "DestroyIcon") + destroyMenu = MustGetProcAddress(libuser32, "DestroyMenu") + destroyWindow = MustGetProcAddress(libuser32, "DestroyWindow") + dialogBoxParam = MustGetProcAddress(libuser32, "DialogBoxParamW") + dispatchMessage = MustGetProcAddress(libuser32, "DispatchMessageW") + drawIconEx = MustGetProcAddress(libuser32, "DrawIconEx") + drawFocusRect = MustGetProcAddress(libuser32, "DrawFocusRect") + drawMenuBar = MustGetProcAddress(libuser32, "DrawMenuBar") + drawTextEx = MustGetProcAddress(libuser32, "DrawTextExW") + emptyClipboard = MustGetProcAddress(libuser32, "EmptyClipboard") + enableWindow = MustGetProcAddress(libuser32, "EnableWindow") + endDeferWindowPos = MustGetProcAddress(libuser32, "EndDeferWindowPos") + endDialog = MustGetProcAddress(libuser32, "EndDialog") + endPaint = MustGetProcAddress(libuser32, "EndPaint") + enumChildWindows = MustGetProcAddress(libuser32, "EnumChildWindows") + findWindow = MustGetProcAddress(libuser32, "FindWindowW") + getActiveWindow = MustGetProcAddress(libuser32, "GetActiveWindow") + getAncestor = MustGetProcAddress(libuser32, "GetAncestor") + getCaretPos = MustGetProcAddress(libuser32, "GetCaretPos") + getClientRect = MustGetProcAddress(libuser32, "GetClientRect") + getClipboardData = MustGetProcAddress(libuser32, "GetClipboardData") + getCursorPos = MustGetProcAddress(libuser32, "GetCursorPos") + getDC = MustGetProcAddress(libuser32, "GetDC") + getDesktopWindow = MustGetProcAddress(libuser32, "GetDesktopWindow") + getFocus = MustGetProcAddress(libuser32, "GetFocus") + getForegroundWindow = MustGetProcAddress(libuser32, "GetForegroundWindow") + getKeyState = MustGetProcAddress(libuser32, "GetKeyState") + getMenuInfo = MustGetProcAddress(libuser32, "GetMenuInfo") + getMessage = MustGetProcAddress(libuser32, "GetMessageW") + getMonitorInfo = MustGetProcAddress(libuser32, "GetMonitorInfoW") + getParent = MustGetProcAddress(libuser32, "GetParent") + getRawInputData = MustGetProcAddress(libuser32, "GetRawInputData") + getScrollInfo = MustGetProcAddress(libuser32, "GetScrollInfo") + getSysColor = MustGetProcAddress(libuser32, "GetSysColor") + getSysColorBrush = MustGetProcAddress(libuser32, "GetSysColorBrush") + getSystemMetrics = MustGetProcAddress(libuser32, "GetSystemMetrics") + getWindow = MustGetProcAddress(libuser32, "GetWindow") + getWindowLong = MustGetProcAddress(libuser32, "GetWindowLongW") + // On 32 bit GetWindowLongPtrW is not available + if is64bit { + getWindowLongPtr = MustGetProcAddress(libuser32, "GetWindowLongPtrW") + } else { + getWindowLongPtr = MustGetProcAddress(libuser32, "GetWindowLongW") + } + getWindowPlacement = MustGetProcAddress(libuser32, "GetWindowPlacement") + getWindowRect = MustGetProcAddress(libuser32, "GetWindowRect") + insertMenuItem = MustGetProcAddress(libuser32, "InsertMenuItemW") + invalidateRect = MustGetProcAddress(libuser32, "InvalidateRect") + isChild = MustGetProcAddress(libuser32, "IsChild") + isClipboardFormatAvailable = MustGetProcAddress(libuser32, "IsClipboardFormatAvailable") + isDialogMessage = MustGetProcAddress(libuser32, "IsDialogMessageW") + isWindowEnabled = MustGetProcAddress(libuser32, "IsWindowEnabled") + isWindowVisible = MustGetProcAddress(libuser32, "IsWindowVisible") + killTimer = MustGetProcAddress(libuser32, "KillTimer") + loadCursor = MustGetProcAddress(libuser32, "LoadCursorW") + loadIcon = MustGetProcAddress(libuser32, "LoadIconW") + loadImage = MustGetProcAddress(libuser32, "LoadImageW") + loadMenu = MustGetProcAddress(libuser32, "LoadMenuW") + loadString = MustGetProcAddress(libuser32, "LoadStringW") + messageBeep = MustGetProcAddress(libuser32, "MessageBeep") + messageBox = MustGetProcAddress(libuser32, "MessageBoxW") + monitorFromWindow = MustGetProcAddress(libuser32, "MonitorFromWindow") + moveWindow = MustGetProcAddress(libuser32, "MoveWindow") + unregisterClass = MustGetProcAddress(libuser32, "UnregisterClassW") + openClipboard = MustGetProcAddress(libuser32, "OpenClipboard") + peekMessage = MustGetProcAddress(libuser32, "PeekMessageW") + postMessage = MustGetProcAddress(libuser32, "PostMessageW") + postQuitMessage = MustGetProcAddress(libuser32, "PostQuitMessage") + registerClassEx = MustGetProcAddress(libuser32, "RegisterClassExW") + registerRawInputDevices = MustGetProcAddress(libuser32, "RegisterRawInputDevices") + registerWindowMessage = MustGetProcAddress(libuser32, "RegisterWindowMessageW") + releaseCapture = MustGetProcAddress(libuser32, "ReleaseCapture") + releaseDC = MustGetProcAddress(libuser32, "ReleaseDC") + removeMenu = MustGetProcAddress(libuser32, "RemoveMenu") + screenToClient = MustGetProcAddress(libuser32, "ScreenToClient") + sendDlgItemMessage = MustGetProcAddress(libuser32, "SendDlgItemMessageW") + sendInput = MustGetProcAddress(libuser32, "SendInput") + sendMessage = MustGetProcAddress(libuser32, "SendMessageW") + setActiveWindow = MustGetProcAddress(libuser32, "SetActiveWindow") + setCapture = MustGetProcAddress(libuser32, "SetCapture") + setClipboardData = MustGetProcAddress(libuser32, "SetClipboardData") + setCursor = MustGetProcAddress(libuser32, "SetCursor") + setCursorPos = MustGetProcAddress(libuser32, "SetCursorPos") + setFocus = MustGetProcAddress(libuser32, "SetFocus") + setForegroundWindow = MustGetProcAddress(libuser32, "SetForegroundWindow") + setMenu = MustGetProcAddress(libuser32, "SetMenu") + setMenuInfo = MustGetProcAddress(libuser32, "SetMenuInfo") + setMenuItemInfo = MustGetProcAddress(libuser32, "SetMenuItemInfoW") + setRect = MustGetProcAddress(libuser32, "SetRect") + setParent = MustGetProcAddress(libuser32, "SetParent") + setScrollInfo = MustGetProcAddress(libuser32, "SetScrollInfo") + setTimer = MustGetProcAddress(libuser32, "SetTimer") + setWindowLong = MustGetProcAddress(libuser32, "SetWindowLongW") + // On 32 bit SetWindowLongPtrW is not available + if is64bit { + setWindowLongPtr = MustGetProcAddress(libuser32, "SetWindowLongPtrW") + } else { + setWindowLongPtr = MustGetProcAddress(libuser32, "SetWindowLongW") + } + setWindowPlacement = MustGetProcAddress(libuser32, "SetWindowPlacement") + setWindowPos = MustGetProcAddress(libuser32, "SetWindowPos") + showWindow = MustGetProcAddress(libuser32, "ShowWindow") + systemParametersInfo = MustGetProcAddress(libuser32, "SystemParametersInfoW") + trackPopupMenuEx = MustGetProcAddress(libuser32, "TrackPopupMenuEx") + translateMessage = MustGetProcAddress(libuser32, "TranslateMessage") + updateWindow = MustGetProcAddress(libuser32, "UpdateWindow") + windowFromDC = MustGetProcAddress(libuser32, "WindowFromDC") + windowFromPoint = MustGetProcAddress(libuser32, "WindowFromPoint") +} + +func AddClipboardFormatListener(hwnd HWND) bool { + if addClipboardFormatListener == 0 { + return false + } + + ret, _, _ := syscall.Syscall(addClipboardFormatListener, 1, + uintptr(hwnd), + 0, + 0) + + return ret != 0 +} + +func AdjustWindowRect(lpRect *RECT, dwStyle uint32, bMenu bool) bool { + ret, _, _ := syscall.Syscall(adjustWindowRect, 3, + uintptr(unsafe.Pointer(lpRect)), + uintptr(dwStyle), + uintptr(BoolToBOOL(bMenu))) + + return ret != 0 +} + +func AnimateWindow(hwnd HWND, dwTime, dwFlags uint32) bool { + ret, _, _ := syscall.Syscall(animateWindow, 3, + uintptr(hwnd), + uintptr(dwTime), + uintptr(dwFlags)) + + return ret != 0 +} + +func BeginDeferWindowPos(nNumWindows int32) HDWP { + ret, _, _ := syscall.Syscall(beginDeferWindowPos, 1, + uintptr(nNumWindows), + 0, + 0) + + return HDWP(ret) +} + +func BeginPaint(hwnd HWND, lpPaint *PAINTSTRUCT) HDC { + ret, _, _ := syscall.Syscall(beginPaint, 2, + uintptr(hwnd), + uintptr(unsafe.Pointer(lpPaint)), + 0) + + return HDC(ret) +} + +func CallWindowProc(lpPrevWndFunc uintptr, hWnd HWND, Msg uint32, wParam, lParam uintptr) uintptr { + ret, _, _ := syscall.Syscall6(callWindowProc, 5, + lpPrevWndFunc, + uintptr(hWnd), + uintptr(Msg), + wParam, + lParam, + 0) + + return ret +} + +func ClientToScreen(hwnd HWND, lpPoint *POINT) bool { + ret, _, _ := syscall.Syscall(clientToScreen, 2, + uintptr(hwnd), + uintptr(unsafe.Pointer(lpPoint)), + 0) + + return ret != 0 +} + +func CloseClipboard() bool { + ret, _, _ := syscall.Syscall(closeClipboard, 0, + 0, + 0, + 0) + + return ret != 0 +} + +func CreateDialogParam(instRes HINSTANCE, name *uint16, parent HWND, + proc, param uintptr) HWND { + ret, _, _ := syscall.Syscall6(createDialogParam, 5, + uintptr(instRes), + uintptr(unsafe.Pointer(name)), + uintptr(parent), + proc, + param, + 0) + + return HWND(ret) +} + +func CreateIconIndirect(lpiconinfo *ICONINFO) HICON { + ret, _, _ := syscall.Syscall(createIconIndirect, 1, + uintptr(unsafe.Pointer(lpiconinfo)), + 0, + 0) + + return HICON(ret) +} + +func CreateMenu() HMENU { + ret, _, _ := syscall.Syscall(createMenu, 0, + 0, + 0, + 0) + + return HMENU(ret) +} + +func CreatePopupMenu() HMENU { + ret, _, _ := syscall.Syscall(createPopupMenu, 0, + 0, + 0, + 0) + + return HMENU(ret) +} + +func CreateWindowEx(dwExStyle uint32, lpClassName, lpWindowName *uint16, dwStyle uint32, x, y, nWidth, nHeight int32, hWndParent HWND, hMenu HMENU, hInstance HINSTANCE, lpParam unsafe.Pointer) HWND { + ret, _, _ := syscall.Syscall12(createWindowEx, 12, + uintptr(dwExStyle), + uintptr(unsafe.Pointer(lpClassName)), + uintptr(unsafe.Pointer(lpWindowName)), + uintptr(dwStyle), + uintptr(x), + uintptr(y), + uintptr(nWidth), + uintptr(nHeight), + uintptr(hWndParent), + uintptr(hMenu), + uintptr(hInstance), + uintptr(lpParam)) + + return HWND(ret) +} + +func DeferWindowPos(hWinPosInfo HDWP, hWnd, hWndInsertAfter HWND, x, y, cx, cy int32, uFlags uint32) HDWP { + ret, _, _ := syscall.Syscall9(deferWindowPos, 8, + uintptr(hWinPosInfo), + uintptr(hWnd), + uintptr(hWndInsertAfter), + uintptr(x), + uintptr(y), + uintptr(cx), + uintptr(cy), + uintptr(uFlags), + 0) + + return HDWP(ret) +} + +func DefWindowProc(hWnd HWND, Msg uint32, wParam, lParam uintptr) uintptr { + ret, _, _ := syscall.Syscall6(defWindowProc, 4, + uintptr(hWnd), + uintptr(Msg), + wParam, + lParam, + 0, + 0) + + return ret +} + +func DestroyIcon(hIcon HICON) bool { + ret, _, _ := syscall.Syscall(destroyIcon, 1, + uintptr(hIcon), + 0, + 0) + + return ret != 0 +} + +func DestroyMenu(hMenu HMENU) bool { + ret, _, _ := syscall.Syscall(destroyMenu, 1, + uintptr(hMenu), + 0, + 0) + + return ret != 0 +} + +func DestroyWindow(hWnd HWND) bool { + ret, _, _ := syscall.Syscall(destroyWindow, 1, + uintptr(hWnd), + 0, + 0) + + return ret != 0 +} + +func DialogBoxParam(instRes HINSTANCE, name *uint16, parent HWND, proc, param uintptr) int { + ret, _, _ := syscall.Syscall6(dialogBoxParam, 5, + uintptr(instRes), + uintptr(unsafe.Pointer(name)), + uintptr(parent), + proc, + param, + 0) + + return int(ret) +} + +func DispatchMessage(msg *MSG) uintptr { + ret, _, _ := syscall.Syscall(dispatchMessage, 1, + uintptr(unsafe.Pointer(msg)), + 0, + 0) + + return ret +} + +func DrawFocusRect(hDC HDC, lprc *RECT) bool { + ret, _, _ := syscall.Syscall(drawFocusRect, 2, + uintptr(hDC), + uintptr(unsafe.Pointer(lprc)), + 0) + + return ret != 0 +} + +func DrawIconEx(hdc HDC, xLeft, yTop int32, hIcon HICON, cxWidth, cyWidth int32, istepIfAniCur uint32, hbrFlickerFreeDraw HBRUSH, diFlags uint32) bool { + ret, _, _ := syscall.Syscall9(drawIconEx, 9, + uintptr(hdc), + uintptr(xLeft), + uintptr(yTop), + uintptr(hIcon), + uintptr(cxWidth), + uintptr(cyWidth), + uintptr(istepIfAniCur), + uintptr(hbrFlickerFreeDraw), + uintptr(diFlags)) + + return ret != 0 +} + +func DrawMenuBar(hWnd HWND) bool { + ret, _, _ := syscall.Syscall(drawMenuBar, 1, + uintptr(hWnd), + 0, + 0) + + return ret != 0 +} + +func DrawTextEx(hdc HDC, lpchText *uint16, cchText int32, lprc *RECT, dwDTFormat uint32, lpDTParams *DRAWTEXTPARAMS) int32 { + ret, _, _ := syscall.Syscall6(drawTextEx, 6, + uintptr(hdc), + uintptr(unsafe.Pointer(lpchText)), + uintptr(cchText), + uintptr(unsafe.Pointer(lprc)), + uintptr(dwDTFormat), + uintptr(unsafe.Pointer(lpDTParams))) + + return int32(ret) +} + +func EmptyClipboard() bool { + ret, _, _ := syscall.Syscall(emptyClipboard, 0, + 0, + 0, + 0) + + return ret != 0 +} + +func EnableWindow(hWnd HWND, bEnable bool) bool { + ret, _, _ := syscall.Syscall(enableWindow, 2, + uintptr(hWnd), + uintptr(BoolToBOOL(bEnable)), + 0) + + return ret != 0 +} + +func EndDeferWindowPos(hWinPosInfo HDWP) bool { + ret, _, _ := syscall.Syscall(endDeferWindowPos, 1, + uintptr(hWinPosInfo), + 0, + 0) + + return ret != 0 +} + +func EndDialog(hwnd HWND, result int) bool { + ret, _, _ := syscall.Syscall(endDialog, 2, + uintptr(hwnd), + uintptr(result), + 0) + + return ret != 0 +} + +func EndPaint(hwnd HWND, lpPaint *PAINTSTRUCT) bool { + ret, _, _ := syscall.Syscall(endPaint, 2, + uintptr(hwnd), + uintptr(unsafe.Pointer(lpPaint)), + 0) + + return ret != 0 +} + +func EnumChildWindows(hWndParent HWND, lpEnumFunc, lParam uintptr) bool { + ret, _, _ := syscall.Syscall(enumChildWindows, 3, + uintptr(hWndParent), + lpEnumFunc, + lParam) + + return ret != 0 +} + +func FindWindow(lpClassName, lpWindowName *uint16) HWND { + ret, _, _ := syscall.Syscall(findWindow, 2, + uintptr(unsafe.Pointer(lpClassName)), + uintptr(unsafe.Pointer(lpWindowName)), + 0) + + return HWND(ret) +} + +func GetActiveWindow() HWND { + ret, _, _ := syscall.Syscall(getActiveWindow, 0, + 0, + 0, + 0) + + return HWND(ret) +} + +func GetAncestor(hWnd HWND, gaFlags uint32) HWND { + ret, _, _ := syscall.Syscall(getAncestor, 2, + uintptr(hWnd), + uintptr(gaFlags), + 0) + + return HWND(ret) +} + +func GetCaretPos(lpPoint *POINT) bool { + ret, _, _ := syscall.Syscall(getCaretPos, 1, + uintptr(unsafe.Pointer(lpPoint)), + 0, + 0) + + return ret != 0 +} + +func GetClientRect(hWnd HWND, rect *RECT) bool { + ret, _, _ := syscall.Syscall(getClientRect, 2, + uintptr(hWnd), + uintptr(unsafe.Pointer(rect)), + 0) + + return ret != 0 +} + +func GetClipboardData(uFormat uint32) HANDLE { + ret, _, _ := syscall.Syscall(getClipboardData, 1, + uintptr(uFormat), + 0, + 0) + + return HANDLE(ret) +} + +func GetCursorPos(lpPoint *POINT) bool { + ret, _, _ := syscall.Syscall(getCursorPos, 1, + uintptr(unsafe.Pointer(lpPoint)), + 0, + 0) + + return ret != 0 +} + +func GetDesktopWindow() HWND { + ret, _, _ := syscall.Syscall(getDesktopWindow, 0, + 0, + 0, + 0) + + return HWND(ret) +} + +func GetDC(hWnd HWND) HDC { + ret, _, _ := syscall.Syscall(getDC, 1, + uintptr(hWnd), + 0, + 0) + + return HDC(ret) +} + +func GetFocus() HWND { + ret, _, _ := syscall.Syscall(getFocus, 0, + 0, + 0, + 0) + + return HWND(ret) +} + +func GetForegroundWindow() HWND { + ret, _, _ := syscall.Syscall(getForegroundWindow, 0, + 0, + 0, + 0) + + return HWND(ret) +} + +func GetKeyState(nVirtKey int32) int16 { + ret, _, _ := syscall.Syscall(getKeyState, 1, + uintptr(nVirtKey), + 0, + 0) + + return int16(ret) +} + +func GetMenuInfo(hmenu HMENU, lpcmi *MENUINFO) bool { + ret, _, _ := syscall.Syscall(getMenuInfo, 2, + uintptr(hmenu), + uintptr(unsafe.Pointer(lpcmi)), + 0) + + return ret != 0 +} + +func GetMessage(msg *MSG, hWnd HWND, msgFilterMin, msgFilterMax uint32) BOOL { + ret, _, _ := syscall.Syscall6(getMessage, 4, + uintptr(unsafe.Pointer(msg)), + uintptr(hWnd), + uintptr(msgFilterMin), + uintptr(msgFilterMax), + 0, + 0) + + return BOOL(ret) +} + +func GetMonitorInfo(hMonitor HMONITOR, lpmi *MONITORINFO) bool { + ret, _, _ := syscall.Syscall(getMonitorInfo, 2, + uintptr(hMonitor), + uintptr(unsafe.Pointer(lpmi)), + 0) + + return ret != 0 +} + +func GetParent(hWnd HWND) HWND { + ret, _, _ := syscall.Syscall(getParent, 1, + uintptr(hWnd), + 0, + 0) + + return HWND(ret) +} + +func GetRawInputData(hRawInput HRAWINPUT, uiCommand uint32, pData unsafe.Pointer, pcbSize *uint32, cBSizeHeader uint32) uint32 { + ret, _, _ := syscall.Syscall6(getRawInputData, 5, + uintptr(hRawInput), + uintptr(uiCommand), + uintptr(pData), + uintptr(unsafe.Pointer(pcbSize)), + uintptr(cBSizeHeader), + 0) + + return uint32(ret) +} + +func GetScrollInfo(hwnd HWND, fnBar int32, lpsi *SCROLLINFO) bool { + ret, _, _ := syscall.Syscall(getScrollInfo, 3, + uintptr(hwnd), + uintptr(fnBar), + uintptr(unsafe.Pointer(lpsi))) + + return ret != 0 +} + +func GetSysColor(nIndex int) uint32 { + ret, _, _ := syscall.Syscall(getSysColor, 1, + uintptr(nIndex), + 0, + 0) + + return uint32(ret) +} + +func GetSysColorBrush(nIndex int) HBRUSH { + ret, _, _ := syscall.Syscall(getSysColorBrush, 1, + uintptr(nIndex), + 0, + 0) + + return HBRUSH(ret) +} + +func GetSystemMetrics(nIndex int32) int32 { + ret, _, _ := syscall.Syscall(getSystemMetrics, 1, + uintptr(nIndex), + 0, + 0) + + return int32(ret) +} + +func GetWindow(hWnd HWND, uCmd uint32) HWND { + ret, _, _ := syscall.Syscall(getWindow, 2, + uintptr(hWnd), + uintptr(uCmd), + 0) + + return HWND(ret) +} + +func GetWindowLong(hWnd HWND, index int32) int32 { + ret, _, _ := syscall.Syscall(getWindowLong, 2, + uintptr(hWnd), + uintptr(index), + 0) + + return int32(ret) +} + +func GetWindowLongPtr(hWnd HWND, index int32) uintptr { + ret, _, _ := syscall.Syscall(getWindowLongPtr, 2, + uintptr(hWnd), + uintptr(index), + 0) + + return ret +} + +func GetWindowPlacement(hWnd HWND, lpwndpl *WINDOWPLACEMENT) bool { + ret, _, _ := syscall.Syscall(getWindowPlacement, 2, + uintptr(hWnd), + uintptr(unsafe.Pointer(lpwndpl)), + 0) + + return ret != 0 +} + +func GetWindowRect(hWnd HWND, rect *RECT) bool { + ret, _, _ := syscall.Syscall(getWindowRect, 2, + uintptr(hWnd), + uintptr(unsafe.Pointer(rect)), + 0) + + return ret != 0 +} + +func InsertMenuItem(hMenu HMENU, uItem uint32, fByPosition bool, lpmii *MENUITEMINFO) bool { + ret, _, _ := syscall.Syscall6(insertMenuItem, 4, + uintptr(hMenu), + uintptr(uItem), + uintptr(BoolToBOOL(fByPosition)), + uintptr(unsafe.Pointer(lpmii)), + 0, + 0) + + return ret != 0 +} + +func InvalidateRect(hWnd HWND, lpRect *RECT, bErase bool) bool { + ret, _, _ := syscall.Syscall(invalidateRect, 3, + uintptr(hWnd), + uintptr(unsafe.Pointer(lpRect)), + uintptr(BoolToBOOL(bErase))) + + return ret != 0 +} + +func IsChild(hWndParent, hWnd HWND) bool { + ret, _, _ := syscall.Syscall(isChild, 2, + uintptr(hWndParent), + uintptr(hWnd), + 0) + + return ret != 0 +} + +func IsClipboardFormatAvailable(format uint32) bool { + ret, _, _ := syscall.Syscall(isClipboardFormatAvailable, 1, + uintptr(format), + 0, + 0) + + return ret != 0 +} + +func IsDialogMessage(hWnd HWND, msg *MSG) bool { + ret, _, _ := syscall.Syscall(isDialogMessage, 2, + uintptr(hWnd), + uintptr(unsafe.Pointer(msg)), + 0) + + return ret != 0 +} + +func IsWindowEnabled(hWnd HWND) bool { + ret, _, _ := syscall.Syscall(isWindowEnabled, 1, + uintptr(hWnd), + 0, + 0) + + return ret != 0 +} + +func IsWindowVisible(hWnd HWND) bool { + ret, _, _ := syscall.Syscall(isWindowVisible, 1, + uintptr(hWnd), + 0, + 0) + + return ret != 0 +} + +func KillTimer(hWnd HWND, uIDEvent uintptr) bool { + ret, _, _ := syscall.Syscall(killTimer, 2, + uintptr(hWnd), + uIDEvent, + 0) + + return ret != 0 +} + +func LoadCursor(hInstance HINSTANCE, lpCursorName *uint16) HCURSOR { + ret, _, _ := syscall.Syscall(loadCursor, 2, + uintptr(hInstance), + uintptr(unsafe.Pointer(lpCursorName)), + 0) + + return HCURSOR(ret) +} + +func LoadIcon(hInstance HINSTANCE, lpIconName *uint16) HICON { + ret, _, _ := syscall.Syscall(loadIcon, 2, + uintptr(hInstance), + uintptr(unsafe.Pointer(lpIconName)), + 0) + + return HICON(ret) +} + +func LoadImage(hinst HINSTANCE, lpszName *uint16, uType uint32, cxDesired, cyDesired int32, fuLoad uint32) HANDLE { + ret, _, _ := syscall.Syscall6(loadImage, 6, + uintptr(hinst), + uintptr(unsafe.Pointer(lpszName)), + uintptr(uType), + uintptr(cxDesired), + uintptr(cyDesired), + uintptr(fuLoad)) + + return HANDLE(ret) +} + +func LoadMenu(hinst HINSTANCE, name *uint16) HMENU { + ret, _, _ := syscall.Syscall(loadMenu, 2, + uintptr(hinst), + uintptr(unsafe.Pointer(name)), + 0) + + return HMENU(ret) +} + +func LoadString(instRes HINSTANCE, id uint32, buf *uint16, length int32) int32 { + ret, _, _ := syscall.Syscall6(loadString, 4, + uintptr(instRes), + uintptr(id), + uintptr(unsafe.Pointer(buf)), + uintptr(length), + 0, + 0) + + return int32(ret) +} + +// Plays a waveform sound. uType is the sound to be played. The sounds are set by the user through the Sound control panel application. +// The following values can be used as a sound: +// +// MB_ICONASTERISK (see MB_ICONINFORMATION) +// MB_ICONEXCLAMATION (see MB_ICONWARNING) +// MB_ICONERROR (The sound specified as the Windows Critical Stop sound) +// MB_ICONHAND (See MB_ICONERROR) +// MB_ICONINFORMATION (The sounds specified as the Windows Asterisk sound) +// MB_ICONQUESTION (The sound specified as the Windows Question sound) +// MB_ICONSTOP (See MB_ICONERROR) +// MB_ICONWARNING (The sounds specified as the Windows Exclamation sound) +// MB_OK (The sound specified as the Windows Default Beep sound) +// +// The function will return true if the function succeeds, false if otherwise. +func MessageBeep(uType uint32) bool { + ret, _, _ := syscall.Syscall(messageBeep, 2, + uintptr(uType), + 0, + 0) + + return ret != 0 +} + +func MessageBox(hWnd HWND, lpText, lpCaption *uint16, uType uint32) int32 { + ret, _, _ := syscall.Syscall6(messageBox, 4, + uintptr(hWnd), + uintptr(unsafe.Pointer(lpText)), + uintptr(unsafe.Pointer(lpCaption)), + uintptr(uType), + 0, + 0) + + return int32(ret) +} + +func MonitorFromWindow(hwnd HWND, dwFlags uint32) HMONITOR { + ret, _, _ := syscall.Syscall(monitorFromWindow, 2, + uintptr(hwnd), + uintptr(dwFlags), + 0) + + return HMONITOR(ret) +} + +func MoveWindow(hWnd HWND, x, y, width, height int32, repaint bool) bool { + ret, _, _ := syscall.Syscall6(moveWindow, 6, + uintptr(hWnd), + uintptr(x), + uintptr(y), + uintptr(width), + uintptr(height), + uintptr(BoolToBOOL(repaint))) + + return ret != 0 +} + +func UnregisterClass(name *uint16) bool { + ret, _, _ := syscall.Syscall(unregisterClass, 1, + uintptr(unsafe.Pointer(name)), + 0, + 0) + + return ret != 0 +} + +func OpenClipboard(hWndNewOwner HWND) bool { + ret, _, _ := syscall.Syscall(openClipboard, 1, + uintptr(hWndNewOwner), + 0, + 0) + + return ret != 0 +} + +func PeekMessage(lpMsg *MSG, hWnd HWND, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool { + ret, _, _ := syscall.Syscall6(peekMessage, 5, + uintptr(unsafe.Pointer(lpMsg)), + uintptr(hWnd), + uintptr(wMsgFilterMin), + uintptr(wMsgFilterMax), + uintptr(wRemoveMsg), + 0) + + return ret != 0 +} + +func PostMessage(hWnd HWND, msg uint32, wParam, lParam uintptr) uintptr { + ret, _, _ := syscall.Syscall6(postMessage, 4, + uintptr(hWnd), + uintptr(msg), + wParam, + lParam, + 0, + 0) + + return ret +} + +func PostQuitMessage(exitCode int32) { + syscall.Syscall(postQuitMessage, 1, + uintptr(exitCode), + 0, + 0) +} + +func RegisterClassEx(windowClass *WNDCLASSEX) ATOM { + ret, _, _ := syscall.Syscall(registerClassEx, 1, + uintptr(unsafe.Pointer(windowClass)), + 0, + 0) + + return ATOM(ret) +} + +func RegisterRawInputDevices(pRawInputDevices *RAWINPUTDEVICE, uiNumDevices uint32, cbSize uint32) bool { + ret, _, _ := syscall.Syscall(registerRawInputDevices, 3, + uintptr(unsafe.Pointer(pRawInputDevices)), + uintptr(uiNumDevices), + uintptr(cbSize)) + + return ret != 0 +} + +func RegisterWindowMessage(lpString *uint16) uint32 { + ret, _, _ := syscall.Syscall(registerWindowMessage, 1, + uintptr(unsafe.Pointer(lpString)), + 0, + 0) + + return uint32(ret) +} + +func ReleaseCapture() bool { + ret, _, _ := syscall.Syscall(releaseCapture, 0, + 0, + 0, + 0) + + return ret != 0 +} + +func ReleaseDC(hWnd HWND, hDC HDC) bool { + ret, _, _ := syscall.Syscall(releaseDC, 2, + uintptr(hWnd), + uintptr(hDC), + 0) + + return ret != 0 +} + +func RemoveMenu(hMenu HMENU, uPosition, uFlags uint32) bool { + ret, _, _ := syscall.Syscall(removeMenu, 3, + uintptr(hMenu), + uintptr(uPosition), + uintptr(uFlags)) + + return ret != 0 +} + +func ScreenToClient(hWnd HWND, point *POINT) bool { + ret, _, _ := syscall.Syscall(screenToClient, 2, + uintptr(hWnd), + uintptr(unsafe.Pointer(point)), + 0) + + return ret != 0 +} + +func SendDlgItemMessage(hWnd HWND, id int32, msg uint32, wParam, lParam uintptr) uintptr { + ret, _, _ := syscall.Syscall6(sendDlgItemMessage, 5, + uintptr(hWnd), + uintptr(id), + uintptr(msg), + wParam, + lParam, + 0) + + return ret +} + +// pInputs expects a unsafe.Pointer to a slice of MOUSE_INPUT or KEYBD_INPUT or HARDWARE_INPUT structs. +func SendInput(nInputs uint32, pInputs unsafe.Pointer, cbSize int32) uint32 { + ret, _, _ := syscall.Syscall(sendInput, 3, + uintptr(nInputs), + uintptr(pInputs), + uintptr(cbSize)) + + return uint32(ret) +} + +func SendMessage(hWnd HWND, msg uint32, wParam, lParam uintptr) uintptr { + ret, _, _ := syscall.Syscall6(sendMessage, 4, + uintptr(hWnd), + uintptr(msg), + wParam, + lParam, + 0, + 0) + + return ret +} + +func SetActiveWindow(hWnd HWND) HWND { + ret, _, _ := syscall.Syscall(setActiveWindow, 1, + uintptr(hWnd), + 0, + 0) + + return HWND(ret) +} + +func SetCapture(hWnd HWND) HWND { + ret, _, _ := syscall.Syscall(setCapture, 1, + uintptr(hWnd), + 0, + 0) + + return HWND(ret) +} + +func SetClipboardData(uFormat uint32, hMem HANDLE) HANDLE { + ret, _, _ := syscall.Syscall(setClipboardData, 2, + uintptr(uFormat), + uintptr(hMem), + 0) + + return HANDLE(ret) +} + +func SetCursor(hCursor HCURSOR) HCURSOR { + ret, _, _ := syscall.Syscall(setCursor, 1, + uintptr(hCursor), + 0, + 0) + + return HCURSOR(ret) +} + +func SetCursorPos(X, Y int32) bool { + ret, _, _ := syscall.Syscall(setCursorPos, 2, + uintptr(X), + uintptr(Y), + 0) + + return ret != 0 +} + +func SetFocus(hWnd HWND) HWND { + ret, _, _ := syscall.Syscall(setFocus, 1, + uintptr(hWnd), + 0, + 0) + + return HWND(ret) +} + +func SetForegroundWindow(hWnd HWND) bool { + ret, _, _ := syscall.Syscall(setForegroundWindow, 1, + uintptr(hWnd), + 0, + 0) + + return ret != 0 +} + +func SetMenu(hWnd HWND, hMenu HMENU) bool { + ret, _, _ := syscall.Syscall(setMenu, 2, + uintptr(hWnd), + uintptr(hMenu), + 0) + + return ret != 0 +} + +func SetMenuInfo(hmenu HMENU, lpcmi *MENUINFO) bool { + ret, _, _ := syscall.Syscall(setMenuInfo, 2, + uintptr(hmenu), + uintptr(unsafe.Pointer(lpcmi)), + 0) + + return ret != 0 +} + +func SetMenuItemInfo(hMenu HMENU, uItem uint32, fByPosition bool, lpmii *MENUITEMINFO) bool { + ret, _, _ := syscall.Syscall6(setMenuItemInfo, 4, + uintptr(hMenu), + uintptr(uItem), + uintptr(BoolToBOOL(fByPosition)), + uintptr(unsafe.Pointer(lpmii)), + 0, + 0) + + return ret != 0 +} + +func SetParent(hWnd HWND, parentHWnd HWND) HWND { + ret, _, _ := syscall.Syscall(setParent, 2, + uintptr(hWnd), + uintptr(parentHWnd), + 0) + + return HWND(ret) +} + +func SetRect(lprc *RECT, xLeft, yTop, xRight, yBottom uint32) BOOL { + ret, _, _ := syscall.Syscall6(setRect, 5, + uintptr(unsafe.Pointer(lprc)), + uintptr(xLeft), + uintptr(yTop), + uintptr(xRight), + uintptr(yBottom), + 0) + + return BOOL(ret) +} + +func SetScrollInfo(hwnd HWND, fnBar int32, lpsi *SCROLLINFO, fRedraw bool) int32 { + ret, _, _ := syscall.Syscall6(setScrollInfo, 4, + uintptr(hwnd), + uintptr(fnBar), + uintptr(unsafe.Pointer(lpsi)), + uintptr(BoolToBOOL(fRedraw)), + 0, + 0) + + return int32(ret) +} + +func SetTimer(hWnd HWND, nIDEvent uintptr, uElapse uint32, lpTimerFunc uintptr) uintptr { + ret, _, _ := syscall.Syscall6(setTimer, 4, + uintptr(hWnd), + nIDEvent, + uintptr(uElapse), + lpTimerFunc, + 0, + 0) + + return ret +} + +func SetWindowLong(hWnd HWND, index, value int32) int32 { + ret, _, _ := syscall.Syscall(setWindowLong, 3, + uintptr(hWnd), + uintptr(index), + uintptr(value)) + + return int32(ret) +} + +func SetWindowLongPtr(hWnd HWND, index int, value uintptr) uintptr { + ret, _, _ := syscall.Syscall(setWindowLongPtr, 3, + uintptr(hWnd), + uintptr(index), + value) + + return ret +} + +func SetWindowPlacement(hWnd HWND, lpwndpl *WINDOWPLACEMENT) bool { + ret, _, _ := syscall.Syscall(setWindowPlacement, 2, + uintptr(hWnd), + uintptr(unsafe.Pointer(lpwndpl)), + 0) + + return ret != 0 +} + +func SetWindowPos(hWnd, hWndInsertAfter HWND, x, y, width, height int32, flags uint32) bool { + ret, _, _ := syscall.Syscall9(setWindowPos, 7, + uintptr(hWnd), + uintptr(hWndInsertAfter), + uintptr(x), + uintptr(y), + uintptr(width), + uintptr(height), + uintptr(flags), + 0, + 0) + + return ret != 0 +} + +func ShowWindow(hWnd HWND, nCmdShow int32) bool { + ret, _, _ := syscall.Syscall(showWindow, 2, + uintptr(hWnd), + uintptr(nCmdShow), + 0) + + return ret != 0 +} + +func SystemParametersInfo(uiAction, uiParam uint32, pvParam unsafe.Pointer, fWinIni uint32) bool { + ret, _, _ := syscall.Syscall6(systemParametersInfo, 4, + uintptr(uiAction), + uintptr(uiParam), + uintptr(pvParam), + uintptr(fWinIni), + 0, + 0) + + return ret != 0 +} + +func TrackPopupMenuEx(hMenu HMENU, fuFlags uint32, x, y int32, hWnd HWND, lptpm *TPMPARAMS) BOOL { + ret, _, _ := syscall.Syscall6(trackPopupMenuEx, 6, + uintptr(hMenu), + uintptr(fuFlags), + uintptr(x), + uintptr(y), + uintptr(hWnd), + uintptr(unsafe.Pointer(lptpm))) + + return BOOL(ret) +} + +func TranslateMessage(msg *MSG) bool { + ret, _, _ := syscall.Syscall(translateMessage, 1, + uintptr(unsafe.Pointer(msg)), + 0, + 0) + + return ret != 0 +} + +func UpdateWindow(hwnd HWND) bool { + ret, _, _ := syscall.Syscall(updateWindow, 1, + uintptr(hwnd), + 0, + 0) + + return ret != 0 +} + +func WindowFromDC(hDC HDC) HWND { + ret, _, _ := syscall.Syscall(windowFromDC, 1, + uintptr(hDC), + 0, + 0) + + return HWND(ret) +} + +func WindowFromPoint(Point POINT) HWND { + ret, _, _ := syscall.Syscall(windowFromPoint, 2, + uintptr(Point.X), + uintptr(Point.Y), + 0) + + return HWND(ret) +} diff --git a/gui/vendor/github.com/lxn/win/uxtheme.go b/gui/vendor/github.com/lxn/win/uxtheme.go new file mode 100644 index 0000000..2714ed1 --- /dev/null +++ b/gui/vendor/github.com/lxn/win/uxtheme.go @@ -0,0 +1,260 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +// CheckBox parts +const ( + BP_CHECKBOX = 3 +) + +// CheckBox states +const ( + CBS_UNCHECKEDNORMAL = 1 +) + +// LISTVIEW parts +const ( + LVP_LISTITEM = 1 + LVP_LISTGROUP = 2 + LVP_LISTDETAIL = 3 + LVP_LISTSORTEDDETAIL = 4 + LVP_EMPTYTEXT = 5 + LVP_GROUPHEADER = 6 + LVP_GROUPHEADERLINE = 7 + LVP_EXPANDBUTTON = 8 + LVP_COLLAPSEBUTTON = 9 + LVP_COLUMNDETAIL = 10 +) + +// LVP_LISTITEM states +const ( + LISS_NORMAL = 1 + LISS_HOT = 2 + LISS_SELECTED = 3 + LISS_DISABLED = 4 + LISS_SELECTEDNOTFOCUS = 5 + LISS_HOTSELECTED = 6 +) + +// TAB parts +const ( + TABP_TABITEM = 1 +) + +// TABP_TABITEM states +const ( + TIS_NORMAL = 1 + TIS_HOT = 2 + TIS_SELECTED = 3 + TIS_DISABLED = 4 + TIS_FOCUSED = 5 +) + +// TREEVIEW parts +const ( + TVP_TREEITEM = 1 + TVP_GLYPH = 2 + TVP_BRANCH = 3 + TVP_HOTGLYPH = 4 +) + +// TVP_TREEITEM states +const ( + TREIS_NORMAL = 1 + TREIS_HOT = 2 + TREIS_SELECTED = 3 + TREIS_DISABLED = 4 + TREIS_SELECTEDNOTFOCUS = 5 + TREIS_HOTSELECTED = 6 +) + +// DTTOPTS flags +const ( + DTT_TEXTCOLOR = 1 << 0 + DTT_BORDERCOLOR = 1 << 1 + DTT_SHADOWCOLOR = 1 << 2 + DTT_SHADOWTYPE = 1 << 3 + DTT_SHADOWOFFSET = 1 << 4 + DTT_BORDERSIZE = 1 << 5 + DTT_FONTPROP = 1 << 6 + DTT_COLORPROP = 1 << 7 + DTT_STATEID = 1 << 8 + DTT_CALCRECT = 1 << 9 + DTT_APPLYOVERLAY = 1 << 10 + DTT_GLOWSIZE = 1 << 11 + DTT_CALLBACK = 1 << 12 + DTT_COMPOSITED = 1 << 13 + DTT_VALIDBITS = DTT_TEXTCOLOR | + DTT_BORDERCOLOR | + DTT_SHADOWCOLOR | + DTT_SHADOWTYPE | + DTT_SHADOWOFFSET | + DTT_BORDERSIZE | + DTT_FONTPROP | + DTT_COLORPROP | + DTT_STATEID | + DTT_CALCRECT | + DTT_APPLYOVERLAY | + DTT_GLOWSIZE | + DTT_COMPOSITED +) + +type HTHEME HANDLE + +type THEMESIZE int + +const ( + TS_MIN THEMESIZE = iota + TS_TRUE + TS_DRAW +) + +type DTTOPTS struct { + DwSize uint32 + DwFlags uint32 + CrText COLORREF + CrBorder COLORREF + CrShadow COLORREF + ITextShadowType int32 + PtShadowOffset POINT + IBorderSize int32 + IFontPropId int32 + IColorPropId int32 + IStateId int32 + FApplyOverlay BOOL + IGlowSize int32 + PfnDrawTextCallback uintptr + LParam uintptr +} + +var ( + // Library + libuxtheme uintptr + + // Functions + closeThemeData uintptr + drawThemeBackground uintptr + drawThemeTextEx uintptr + getThemePartSize uintptr + getThemeTextExtent uintptr + isAppThemed uintptr + openThemeData uintptr + setWindowTheme uintptr +) + +func init() { + // Library + libuxtheme = MustLoadLibrary("uxtheme.dll") + + // Functions + closeThemeData = MustGetProcAddress(libuxtheme, "CloseThemeData") + drawThemeBackground = MustGetProcAddress(libuxtheme, "DrawThemeBackground") + drawThemeTextEx, _ = syscall.GetProcAddress(syscall.Handle(libuxtheme), "DrawThemeTextEx") + getThemePartSize = MustGetProcAddress(libuxtheme, "GetThemePartSize") + getThemeTextExtent = MustGetProcAddress(libuxtheme, "GetThemeTextExtent") + isAppThemed = MustGetProcAddress(libuxtheme, "IsAppThemed") + openThemeData = MustGetProcAddress(libuxtheme, "OpenThemeData") + setWindowTheme = MustGetProcAddress(libuxtheme, "SetWindowTheme") +} + +func CloseThemeData(hTheme HTHEME) HRESULT { + ret, _, _ := syscall.Syscall(closeThemeData, 1, + uintptr(hTheme), + 0, + 0) + + return HRESULT(ret) +} + +func DrawThemeBackground(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pRect, pClipRect *RECT) HRESULT { + ret, _, _ := syscall.Syscall6(drawThemeBackground, 6, + uintptr(hTheme), + uintptr(hdc), + uintptr(iPartId), + uintptr(iStateId), + uintptr(unsafe.Pointer(pRect)), + uintptr(unsafe.Pointer(pClipRect))) + + return HRESULT(ret) +} + +func DrawThemeTextEx(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pszText *uint16, iCharCount int32, dwFlags uint32, pRect *RECT, pOptions *DTTOPTS) HRESULT { + ret, _, _ := syscall.Syscall9(drawThemeTextEx, 9, + uintptr(hTheme), + uintptr(hdc), + uintptr(iPartId), + uintptr(iStateId), + uintptr(unsafe.Pointer(pszText)), + uintptr(iCharCount), + uintptr(dwFlags), + uintptr(unsafe.Pointer(pRect)), + uintptr(unsafe.Pointer(pOptions))) + + return HRESULT(ret) +} + +func GetThemePartSize(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, prc *RECT, eSize THEMESIZE, psz *SIZE) HRESULT { + ret, _, _ := syscall.Syscall9(getThemePartSize, 7, + uintptr(hTheme), + uintptr(hdc), + uintptr(iPartId), + uintptr(iStateId), + uintptr(unsafe.Pointer(prc)), + uintptr(eSize), + uintptr(unsafe.Pointer(psz)), + 0, + 0) + + return HRESULT(ret) +} + +func GetThemeTextExtent(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pszText *uint16, iCharCount int32, dwTextFlags uint32, pBoundingRect, pExtentRect *RECT) HRESULT { + ret, _, _ := syscall.Syscall9(getThemeTextExtent, 9, + uintptr(hTheme), + uintptr(hdc), + uintptr(iPartId), + uintptr(iStateId), + uintptr(unsafe.Pointer(pszText)), + uintptr(iCharCount), + uintptr(dwTextFlags), + uintptr(unsafe.Pointer(pBoundingRect)), + uintptr(unsafe.Pointer(pExtentRect))) + + return HRESULT(ret) +} + +func IsAppThemed() bool { + ret, _, _ := syscall.Syscall(isAppThemed, 0, + 0, + 0, + 0) + + return ret != 0 +} + +func OpenThemeData(hwnd HWND, pszClassList *uint16) HTHEME { + ret, _, _ := syscall.Syscall(openThemeData, 2, + uintptr(hwnd), + uintptr(unsafe.Pointer(pszClassList)), + 0) + + return HTHEME(ret) +} + +func SetWindowTheme(hwnd HWND, pszSubAppName, pszSubIdList *uint16) HRESULT { + ret, _, _ := syscall.Syscall(setWindowTheme, 3, + uintptr(hwnd), + uintptr(unsafe.Pointer(pszSubAppName)), + uintptr(unsafe.Pointer(pszSubIdList))) + + return HRESULT(ret) +} diff --git a/gui/vendor/github.com/lxn/win/win.go b/gui/vendor/github.com/lxn/win/win.go new file mode 100644 index 0000000..3e9f84b --- /dev/null +++ b/gui/vendor/github.com/lxn/win/win.go @@ -0,0 +1,118 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "runtime" + "syscall" + "unsafe" +) + +func init() { + runtime.LockOSThread() +} + +const ( + S_OK = 0x00000000 + S_FALSE = 0x00000001 + E_UNEXPECTED = 0x8000FFFF + E_NOTIMPL = 0x80004001 + E_OUTOFMEMORY = 0x8007000E + E_INVALIDARG = 0x80070057 + E_NOINTERFACE = 0x80004002 + E_POINTER = 0x80004003 + E_HANDLE = 0x80070006 + E_ABORT = 0x80004004 + E_FAIL = 0x80004005 + E_ACCESSDENIED = 0x80070005 + E_PENDING = 0x8000000A +) + +const ( + FALSE = 0 + TRUE = 1 +) + +type ( + BOOL int32 + HRESULT int32 +) + +func MustLoadLibrary(name string) uintptr { + lib, err := syscall.LoadLibrary(name) + if err != nil { + panic(err) + } + + return uintptr(lib) +} + +func MustGetProcAddress(lib uintptr, name string) uintptr { + addr, err := syscall.GetProcAddress(syscall.Handle(lib), name) + if err != nil { + panic(err) + } + + return uintptr(addr) +} + +func MaybeGetProcAddress(lib uintptr, name string) uintptr { + addr, _ := syscall.GetProcAddress(syscall.Handle(lib), name) + + return uintptr(addr) +} + +func SUCCEEDED(hr HRESULT) bool { + return hr >= 0 +} + +func FAILED(hr HRESULT) bool { + return hr < 0 +} + +func MAKEWORD(lo, hi byte) uint16 { + return uint16(uint16(lo) | ((uint16(hi)) << 8)) +} + +func LOBYTE(w uint16) byte { + return byte(w) +} + +func HIBYTE(w uint16) byte { + return byte(w >> 8 & 0xff) +} + +func MAKELONG(lo, hi uint16) uint32 { + return uint32(uint32(lo) | ((uint32(hi)) << 16)) +} + +func LOWORD(dw uint32) uint16 { + return uint16(dw) +} + +func HIWORD(dw uint32) uint16 { + return uint16(dw >> 16 & 0xffff) +} + +func UTF16PtrToString(s *uint16) string { + if s == nil { + return "" + } + return syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(s))[0:]) +} + +func MAKEINTRESOURCE(id uintptr) *uint16 { + return (*uint16)(unsafe.Pointer(id)) +} + +func BoolToBOOL(value bool) BOOL { + if value { + return 1 + } + + return 0 +} diff --git a/gui/vendor/github.com/lxn/win/winspool.go b/gui/vendor/github.com/lxn/win/winspool.go new file mode 100644 index 0000000..c69214d --- /dev/null +++ b/gui/vendor/github.com/lxn/win/winspool.go @@ -0,0 +1,100 @@ +// Copyright 2010 The win Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package win + +import ( + "syscall" + "unsafe" +) + +// EnumPrinters flags +const ( + PRINTER_ENUM_DEFAULT = 0x00000001 + PRINTER_ENUM_LOCAL = 0x00000002 + PRINTER_ENUM_CONNECTIONS = 0x00000004 + PRINTER_ENUM_FAVORITE = 0x00000004 + PRINTER_ENUM_NAME = 0x00000008 + PRINTER_ENUM_REMOTE = 0x00000010 + PRINTER_ENUM_SHARED = 0x00000020 + PRINTER_ENUM_NETWORK = 0x00000040 +) + +type PRINTER_INFO_4 struct { + PPrinterName *uint16 + PServerName *uint16 + Attributes uint32 +} + +var ( + // Library + libwinspool uintptr + + // Functions + deviceCapabilities uintptr + documentProperties uintptr + enumPrinters uintptr + getDefaultPrinter uintptr +) + +func init() { + // Library + libwinspool = MustLoadLibrary("winspool.drv") + + // Functions + deviceCapabilities = MustGetProcAddress(libwinspool, "DeviceCapabilitiesW") + documentProperties = MustGetProcAddress(libwinspool, "DocumentPropertiesW") + enumPrinters = MustGetProcAddress(libwinspool, "EnumPrintersW") + getDefaultPrinter = MustGetProcAddress(libwinspool, "GetDefaultPrinterW") +} + +func DeviceCapabilities(pDevice, pPort *uint16, fwCapability uint16, pOutput *uint16, pDevMode *DEVMODE) uint32 { + ret, _, _ := syscall.Syscall6(deviceCapabilities, 5, + uintptr(unsafe.Pointer(pDevice)), + uintptr(unsafe.Pointer(pPort)), + uintptr(fwCapability), + uintptr(unsafe.Pointer(pOutput)), + uintptr(unsafe.Pointer(pDevMode)), + 0) + + return uint32(ret) +} + +func DocumentProperties(hWnd HWND, hPrinter HANDLE, pDeviceName *uint16, pDevModeOutput, pDevModeInput *DEVMODE, fMode uint32) int32 { + ret, _, _ := syscall.Syscall6(documentProperties, 6, + uintptr(hWnd), + uintptr(hPrinter), + uintptr(unsafe.Pointer(pDeviceName)), + uintptr(unsafe.Pointer(pDevModeOutput)), + uintptr(unsafe.Pointer(pDevModeInput)), + uintptr(fMode)) + + return int32(ret) +} + +func EnumPrinters(Flags uint32, Name *uint16, Level uint32, pPrinterEnum *byte, cbBuf uint32, pcbNeeded, pcReturned *uint32) bool { + ret, _, _ := syscall.Syscall9(enumPrinters, 7, + uintptr(Flags), + uintptr(unsafe.Pointer(Name)), + uintptr(Level), + uintptr(unsafe.Pointer(pPrinterEnum)), + uintptr(cbBuf), + uintptr(unsafe.Pointer(pcbNeeded)), + uintptr(unsafe.Pointer(pcReturned)), + 0, + 0) + + return ret != 0 +} + +func GetDefaultPrinter(pszBuffer *uint16, pcchBuffer *uint32) bool { + ret, _, _ := syscall.Syscall(getDefaultPrinter, 2, + uintptr(unsafe.Pointer(pszBuffer)), + uintptr(unsafe.Pointer(pcchBuffer)), + 0) + + return ret != 0 +} diff --git a/main.go b/main.go index 0f73a10..4e96160 100644 --- a/main.go +++ b/main.go @@ -2,17 +2,21 @@ package main import ( "fmt" - "os" - "runtime" - "github.com/liamg/aminal/gui" "github.com/liamg/aminal/platform" "github.com/liamg/aminal/terminal" "github.com/riywo/loginshell" + "os" + "runtime" ) -func main() { +type callback func(terminal *terminal.Terminal, g *gui.GUI) +func main() { + initialize(nil) +} + +func initialize(fn callback) { runtime.LockOSThread() conf := getConfig() @@ -56,6 +60,10 @@ func main() { logger.Fatalf("Cannot start: %s", err) } + if fn != nil { + go fn(terminal, g) + } + go func() { if err := guestProcess.Wait(); err != nil { logger.Fatalf("Failed to wait for guest process: %s", err) diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..1eef9ea --- /dev/null +++ b/main_test.go @@ -0,0 +1,77 @@ +// +build linux + +package main + +import ( + "fmt" + "os" + "testing" + "time" + + "github.com/liamg/aminal/gui" + "github.com/liamg/aminal/terminal" + + "github.com/carlogit/phash" +) + +func terminate(msg string) int { + defer fmt.Print(msg) + return 1 +} + +func sleep() { + time.Sleep(time.Second) +} + +func hash(path string) string { + image, err := os.Open(path) + if err != nil { + panic(err) + } + defer image.Close() + imageHash, err := phash.GetHash(image) + if err != nil { + panic(err) + } + return imageHash +} + +func compareImages(img1 string, img2 string) { + template := hash(img1) + screen := hash(img2) + distance := phash.GetDistance(template, screen) + if distance != 0 { + os.Exit(terminate(fmt.Sprintf("Screenshot doesn't match expected image. Distance of hashes difference: %d\n", distance))) + } +} + +func send(terminal *terminal.Terminal, cmd string) { + terminal.Write([]byte(cmd)) +} + +func enter(terminal *terminal.Terminal) { + terminal.Write([]byte("\n")) +} + +func TestCursorMovement(t *testing.T) { + + testFunc := func(term *terminal.Terminal, g *gui.GUI) { + sleep() + send(term, "vttest\n") + sleep() + send(term, "1\n") + sleep() + + if term.ActiveBuffer().Compare("vttest/test-cursor-movement-1") == false { + t.Error(fmt.Sprint("ActiveBuffer doesn't match vttest template")) + } + + enter(term) + sleep() + g.Screenshot ("test-cursor-movement-2.png") + compareImages("vttest/test-cursor-movement-2.png", "test-cursor-movement-2.png") + os.Exit(0) + } + + initialize(testFunc) +} diff --git a/terminal/terminal.go b/terminal/terminal.go index b5c2a01..6b9e31a 100644 --- a/terminal/terminal.go +++ b/terminal/terminal.go @@ -3,13 +3,12 @@ package terminal import ( "bufio" "fmt" - "io" - "sync" - "github.com/liamg/aminal/buffer" "github.com/liamg/aminal/config" "github.com/liamg/aminal/platform" "go.uber.org/zap" + "io" + "sync" ) const ( diff --git a/vendor/github.com/carlogit/phash/.gitignore b/vendor/github.com/carlogit/phash/.gitignore new file mode 100644 index 0000000..daf913b --- /dev/null +++ b/vendor/github.com/carlogit/phash/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/carlogit/phash/LICENSE b/vendor/github.com/carlogit/phash/LICENSE new file mode 100644 index 0000000..c10f05e --- /dev/null +++ b/vendor/github.com/carlogit/phash/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 carlogit + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/github.com/carlogit/phash/README.md b/vendor/github.com/carlogit/phash/README.md new file mode 100644 index 0000000..4deb6de --- /dev/null +++ b/vendor/github.com/carlogit/phash/README.md @@ -0,0 +1,2 @@ +# phash +A simple Go Library to calculate a phash string for a JPEG image. diff --git a/vendor/github.com/carlogit/phash/dct.go b/vendor/github.com/carlogit/phash/dct.go new file mode 100644 index 0000000..c516932 --- /dev/null +++ b/vendor/github.com/carlogit/phash/dct.go @@ -0,0 +1,60 @@ +package phash + +import ( + "math" +) + +type dctPoint struct { + xMax, yMax int + xScales, yScales [2]float64 +} + +func (point *dctPoint) initializeScaleFactors() { + point.xScales = [2]float64{ 1.0 / math.Sqrt(float64(point.xMax)), math.Sqrt(2.0 / float64(point.xMax))} + point.yScales = [2]float64 { 1.0 / math.Sqrt(float64(point.yMax)), math.Sqrt(2.0 / float64(point.yMax))} +} + +func (point *dctPoint) calculateValue(imageData [][]float64, x, y int) float64 { + sum := float64(0.0) + for i := 0; i < point.xMax; i++ { + for j := 0; j < point.yMax; j++ { + imageValue := float64(imageData[i][j]) + firstCosine := math.Cos(float64((1 + (2 * i)) * x) * math.Pi / float64(2 * point.xMax)) + secondCosine := math.Cos(float64((1 + (2 * j)) * y) * math.Pi / float64(2 * point.yMax)) + sum += (imageValue * firstCosine * secondCosine) + } + } + return sum * point.getScaleFactor(x, y) +} + +func (point *dctPoint) getScaleFactor(x, y int) float64 { + xScaleFactor := point.xScales[1] + if x == 0 { + xScaleFactor = point.xScales[0] + } + yScaleFactor := point.yScales[1] + if y == 0 { + yScaleFactor = point.yScales[0] + } + + return xScaleFactor * yScaleFactor +} + +// getDCTMatrix Generates a DCT matrix from a given matrix. +// This is done using the Discrete Cosine Transformation (DCT) type-II algorithm. +func getDCTMatrix(matrix [][]float64) [][]float64 { + xMax := len(matrix) + yMax := len(matrix[0]) + + dctPoint := &dctPoint{xMax:xMax, yMax:yMax} + dctPoint.initializeScaleFactors() + dctMatrix := make([][]float64, xMax) + for x := 0; x < xMax; x++ { + dctMatrix[x] = make([]float64, yMax) + for y := 0; y < yMax; y++ { + dctMatrix[x][y] = dctPoint.calculateValue(matrix, x, y) + } + } + + return dctMatrix +} diff --git a/vendor/github.com/carlogit/phash/imageprocess.go b/vendor/github.com/carlogit/phash/imageprocess.go new file mode 100644 index 0000000..6a968b1 --- /dev/null +++ b/vendor/github.com/carlogit/phash/imageprocess.go @@ -0,0 +1,26 @@ +package phash + +import ( + "image" +) + +func getImageMatrix(img image.Image) [][]float64 { + xSize := img.Bounds().Max.X + ySize := img.Bounds().Max.Y + + vals := make([][]float64, xSize) + + for x := 0; x < xSize; x++ { + vals[x] = make([]float64, ySize) + for y := 0; y < ySize; y++ { + vals[x][y] = getXYValue(img, x, y) + } + } + + return vals +} + +func getXYValue(img image.Image, x int, y int) float64 { + _, _, b, _ := img.At(x, y).RGBA() + return float64(b) +} diff --git a/vendor/github.com/carlogit/phash/matrixutil.go b/vendor/github.com/carlogit/phash/matrixutil.go new file mode 100644 index 0000000..8ce85b5 --- /dev/null +++ b/vendor/github.com/carlogit/phash/matrixutil.go @@ -0,0 +1,32 @@ +package phash + +func reduceMatrix(dctMatrix [][]float64, size int) [][]float64 { + newMatrix := make([][]float64, size) + for x := 0; x < size; x++ { + newMatrix[x] = make([]float64, size) + for y := 0; y < size; y++ { + newMatrix[x][y] = dctMatrix[x][y] + } + } + + return newMatrix +} + + +func calculateMeanValue(dctMatrix [][]float64) float64 { + var total float64 + var xSize = len(dctMatrix) + var ySize = len(dctMatrix[0]) + + for x := 0; x < xSize; x++ { + for y := 0; y < ySize; y++ { + total += dctMatrix[x][y] + } + } + + total -= dctMatrix[0][0] + + avg := total / float64((xSize * ySize) - 1) + + return avg +} diff --git a/vendor/github.com/carlogit/phash/matrixutil_test.go b/vendor/github.com/carlogit/phash/matrixutil_test.go new file mode 100644 index 0000000..05531fe --- /dev/null +++ b/vendor/github.com/carlogit/phash/matrixutil_test.go @@ -0,0 +1,70 @@ +package phash + +import ( + "testing" +) + +func TestReduceMatrix(t *testing.T) { + matrix := make([][]float64, 9) + for i:=0; i < 9; i++ { + matrix[i] = make([]float64, 9) + for j:=0; j < 9; j++ { + matrix[i][j] = float64(i * 10 + j) + } + } + + + newMatrix := reduceMatrix(matrix, 2) + + if len(newMatrix) != 2 { + t.Errorf("number of rows => %d, want %d", len(newMatrix), 2) + } + + if len(newMatrix[0]) != 2 { + t.Errorf("number of columns for row 1 => %d, want %d", len(newMatrix[0]), 2) + } + + if len(newMatrix[1]) != 2 { + t.Errorf("number of columns for row 2 => %d, want %d", len(newMatrix[1]), 2) + } + + if newMatrix[0][0] != 0 { + t.Errorf("value for [%d, %d] => %d, want %d", newMatrix[0][0], 0) + } + + if newMatrix[0][1] != 1 { + t.Errorf("value for [%d, %d] => %d, want %d", newMatrix[0][1], 1) + } + if newMatrix[1][0] != 10 { + t.Errorf("value for [%d, %d] => %d, want %d", newMatrix[1][0], 10) + } + if newMatrix[1][1] != 11 { + t.Errorf("value for [%d, %d] => %d, want %d", newMatrix[1][1], 11) + } +} + +func TestCalculateMeanValue(t *testing.T) { + matrix := make([][]float64, 3) + matrix[0] = make([]float64, 3) + matrix[1] = make([]float64, 3) + matrix[2] = make([]float64, 3) + + matrix[0][0] = 10 + matrix[0][1] = 20 + matrix[0][2] = 30 + + matrix[1][0] = 5 + matrix[1][1] = 25 + matrix[1][2] = 45 + + matrix[2][0] = 23 + matrix[2][1] = 34 + matrix[2][2] = 66 + + meanValue := calculateMeanValue(matrix) + + if meanValue != 31 { + t.Errorf("mean value for matrix => %d, want %d", meanValue, 31) + } +} + diff --git a/vendor/github.com/carlogit/phash/phash.go b/vendor/github.com/carlogit/phash/phash.go new file mode 100644 index 0000000..6ceb44b --- /dev/null +++ b/vendor/github.com/carlogit/phash/phash.go @@ -0,0 +1,58 @@ +// Package phash computes a phash string for a JPEG image and retrieves +// the hamming distance between two phash strings. +package phash + +import ( + "io" + + "github.com/disintegration/imaging" +) + +// GetHash returns a phash string for a JPEG image +func GetHash(reader io.Reader) (string, error) { + image, err := imaging.Decode(reader) + + if err != nil { + return "", err + } + + image = imaging.Resize(image, 32, 32, imaging.Lanczos) + image = imaging.Grayscale(image) + + imageMatrixData := getImageMatrix(image) + dctMatrix := getDCTMatrix(imageMatrixData) + + smallDctMatrix := reduceMatrix(dctMatrix, 8) + dctMeanValue := calculateMeanValue(smallDctMatrix) + return buildHash(smallDctMatrix, dctMeanValue), nil +} + +// GetDistance returns the hamming distance between two phashes +func GetDistance(hash1, hash2 string) int { + distance := 0 + for i := 0; i < len(hash1); i++ { + if hash1[i] != hash2[i] { + distance++ + } + } + + return distance +} + +func buildHash(dctMatrix [][]float64, dctMeanValue float64) string { + var hash string + var xSize = len(dctMatrix) + var ySize = len(dctMatrix[0]) + + for x := 0; x < xSize; x++ { + for y := 0; y < ySize; y++ { + if dctMatrix[x][y] > dctMeanValue { + hash += "1" + } else { + hash += "0" + } + } + } + + return hash +} diff --git a/vendor/github.com/carlogit/phash/phash_test.go b/vendor/github.com/carlogit/phash/phash_test.go new file mode 100644 index 0000000..afe2baf --- /dev/null +++ b/vendor/github.com/carlogit/phash/phash_test.go @@ -0,0 +1,96 @@ +package phash + +import ( + "os" + "testing" +) + +func TestGetHash(t *testing.T) { + file1 := openFile("testdata/soccerball.jpg") + defer file1.Close() + + file2 := openFile("testdata/soccerball (copy).jpg") + defer file2.Close() + + phash1, _ := GetHash(file1) + phash2, _ := GetHash(file2) + + expectedHash := "1101100110001110001101010011100000011010000000010111110111101000" + if phash1 != expectedHash { + t.Errorf("phash => %s, want %s", phash1, expectedHash) + } + + if phash1 != phash2 { + t.Errorf("phashes for files %s and %s must be the same, but they are different", file1.Name(), file2.Name()) + } +} + +func TestSimilarImages(t *testing.T) { + file1 := openFile("testdata/soccerball.jpg") + defer file1.Close() + + file2 := openFile("testdata/soccerball (scaled down).jpg") + defer file2.Close() + + file3 := openFile("testdata/soccerball (cropped).jpg") + defer file3.Close() + + file4 := openFile("testdata/soccerball (modifications).jpg") + defer file4.Close() + + file5 := openFile("testdata/soccerball (perspective).jpg") + defer file5.Close() + + phash1, _ := GetHash(file1) + phash2, _ := GetHash(file2) + phash3, _ := GetHash(file3) + phash4, _ := GetHash(file4) + phash5, _ := GetHash(file5) + + distance := GetDistance(phash1, phash2) + verifyDistanceInRange(t, file2.Name(), distance, 0, 1) + + distance = GetDistance(phash1, phash3) + verifyDistanceInRange(t, file3.Name(), distance, 0, 1) + + distance = GetDistance(phash1, phash4) + verifyDistanceInRange(t, file4.Name(), distance, 1, 3) + + distance = GetDistance(phash1, phash5) + verifyDistanceInRange(t, file5.Name(), distance, 2, 5) +} + +func TestGetDistance(t *testing.T) { + var distancetests = []struct { + hash1 string + hash2 string + distance int + }{ + {"0010011100100010000001000101001000101110100101110", "0010011100100010000001000101001000101110100101110", 0}, + {"0010011100100000000001000101001000101110100101110", "0010011100100010000001000101001000101110100101111", 2}, + {"1111111111111111111111111111111111111111111111111", "0000000000000000000000000000000000000000000000000", 49}, + } + + for _, distancetest := range distancetests { + distance := GetDistance(distancetest.hash1, distancetest.hash2) + if distance != distancetest.distance { + t.Errorf("distance between %s and %s => %d, want %d", distancetest.hash1, distancetest.hash2, distance, distancetest.distance) + } + } +} + +func openFile(filePath string) *os.File { + file, err := os.Open(filePath) + if err != nil { + panic(err) + } + + return file +} + +func verifyDistanceInRange(t *testing.T, comparedImageName string, distance, minDistance, maxDistance int) { + if distance < minDistance || distance > maxDistance { + t.Errorf("distance with %s => %d, want value between %d and %d", comparedImageName, distance, minDistance, maxDistance) + } +} + diff --git a/vendor/github.com/carlogit/phash/testdata/soccerball (copy).jpg b/vendor/github.com/carlogit/phash/testdata/soccerball (copy).jpg new file mode 100644 index 0000000..dde53ff Binary files /dev/null and b/vendor/github.com/carlogit/phash/testdata/soccerball (copy).jpg differ diff --git a/vendor/github.com/carlogit/phash/testdata/soccerball (cropped).jpg b/vendor/github.com/carlogit/phash/testdata/soccerball (cropped).jpg new file mode 100644 index 0000000..7e06599 Binary files /dev/null and b/vendor/github.com/carlogit/phash/testdata/soccerball (cropped).jpg differ diff --git a/vendor/github.com/carlogit/phash/testdata/soccerball (modifications).jpg b/vendor/github.com/carlogit/phash/testdata/soccerball (modifications).jpg new file mode 100644 index 0000000..84a1d03 Binary files /dev/null and b/vendor/github.com/carlogit/phash/testdata/soccerball (modifications).jpg differ diff --git a/vendor/github.com/carlogit/phash/testdata/soccerball (perspective).jpg b/vendor/github.com/carlogit/phash/testdata/soccerball (perspective).jpg new file mode 100644 index 0000000..084526d Binary files /dev/null and b/vendor/github.com/carlogit/phash/testdata/soccerball (perspective).jpg differ diff --git a/vendor/github.com/carlogit/phash/testdata/soccerball (scaled down).jpg b/vendor/github.com/carlogit/phash/testdata/soccerball (scaled down).jpg new file mode 100644 index 0000000..8c95738 Binary files /dev/null and b/vendor/github.com/carlogit/phash/testdata/soccerball (scaled down).jpg differ diff --git a/vendor/github.com/carlogit/phash/testdata/soccerball.jpg b/vendor/github.com/carlogit/phash/testdata/soccerball.jpg new file mode 100644 index 0000000..dde53ff Binary files /dev/null and b/vendor/github.com/carlogit/phash/testdata/soccerball.jpg differ diff --git a/vendor/github.com/disintegration/imaging/.travis.yml b/vendor/github.com/disintegration/imaging/.travis.yml new file mode 100644 index 0000000..1d4bdd5 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/.travis.yml @@ -0,0 +1,14 @@ +language: go +go: + - "1.7.x" + - "1.8.x" + - "1.9.x" + - "1.10.x" + - "1.11.x" + +before_install: + - go get github.com/mattn/goveralls + +script: + - go test -v -race -cover + - $GOPATH/bin/goveralls -service=travis-ci diff --git a/vendor/github.com/disintegration/imaging/LICENSE b/vendor/github.com/disintegration/imaging/LICENSE new file mode 100644 index 0000000..c68f7ab --- /dev/null +++ b/vendor/github.com/disintegration/imaging/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2012-2018 Grigory Dryapak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/disintegration/imaging/README.md b/vendor/github.com/disintegration/imaging/README.md new file mode 100644 index 0000000..6b0ffb7 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/README.md @@ -0,0 +1,198 @@ +# Imaging + +[![GoDoc](https://godoc.org/github.com/disintegration/imaging?status.svg)](https://godoc.org/github.com/disintegration/imaging) +[![Build Status](https://travis-ci.org/disintegration/imaging.svg?branch=master)](https://travis-ci.org/disintegration/imaging) +[![Coverage Status](https://coveralls.io/repos/github/disintegration/imaging/badge.svg?branch=master&service=github)](https://coveralls.io/github/disintegration/imaging?branch=master) +[![Go Report Card](https://goreportcard.com/badge/github.com/disintegration/imaging)](https://goreportcard.com/report/github.com/disintegration/imaging) + +Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.). + +All the image processing functions provided by the package accept any image type that implements `image.Image` interface +as an input, and return a new image of `*image.NRGBA` type (32bit RGBA colors, not premultiplied by alpha). + +## Installation + + go get -u github.com/disintegration/imaging + +## Documentation + +http://godoc.org/github.com/disintegration/imaging + +## Usage examples + +A few usage examples can be found below. See the documentation for the full list of supported functions. + +### Image resizing + +```go +// Resize srcImage to size = 128x128px using the Lanczos filter. +dstImage128 := imaging.Resize(srcImage, 128, 128, imaging.Lanczos) + +// Resize srcImage to width = 800px preserving the aspect ratio. +dstImage800 := imaging.Resize(srcImage, 800, 0, imaging.Lanczos) + +// Scale down srcImage to fit the 800x600px bounding box. +dstImageFit := imaging.Fit(srcImage, 800, 600, imaging.Lanczos) + +// Resize and crop the srcImage to fill the 100x100px area. +dstImageFill := imaging.Fill(srcImage, 100, 100, imaging.Center, imaging.Lanczos) +``` + +Imaging supports image resizing using various resampling filters. The most notable ones: +- `NearestNeighbor` - Fastest resampling filter, no antialiasing. +- `Box` - Simple and fast averaging filter appropriate for downscaling. When upscaling it's similar to NearestNeighbor. +- `Linear` - Bilinear filter, smooth and reasonably fast. +- `MitchellNetravali` - А smooth bicubic filter. +- `CatmullRom` - A sharp bicubic filter. +- `Gaussian` - Blurring filter that uses gaussian function, useful for noise removal. +- `Lanczos` - High-quality resampling filter for photographic images yielding sharp results, slower than cubic filters. + +The full list of supported filters: NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. Custom filters can be created using ResampleFilter struct. + +**Resampling filters comparison** + +Original image: + +![srcImage](testdata/branches.png) + +The same image resized from 600x400px to 150x100px using different resampling filters. +From faster (lower quality) to slower (higher quality): + +Filter | Resize result +--------------------------|--------------------------------------------- +`imaging.NearestNeighbor` | ![dstImage](testdata/out_resize_nearest.png) +`imaging.Linear` | ![dstImage](testdata/out_resize_linear.png) +`imaging.CatmullRom` | ![dstImage](testdata/out_resize_catrom.png) +`imaging.Lanczos` | ![dstImage](testdata/out_resize_lanczos.png) + + +### Gaussian Blur + +```go +dstImage := imaging.Blur(srcImage, 0.5) +``` + +Sigma parameter allows to control the strength of the blurring effect. + +Original image | Sigma = 0.5 | Sigma = 1.5 +-----------------------------------|----------------------------------------|--------------------------------------- +![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_blur_0.5.png) | ![dstImage](testdata/out_blur_1.5.png) + +### Sharpening + +```go +dstImage := imaging.Sharpen(srcImage, 0.5) +``` + +`Sharpen` uses gaussian function internally. Sigma parameter allows to control the strength of the sharpening effect. + +Original image | Sigma = 0.5 | Sigma = 1.5 +-----------------------------------|-------------------------------------------|------------------------------------------ +![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_sharpen_0.5.png) | ![dstImage](testdata/out_sharpen_1.5.png) + +### Gamma correction + +```go +dstImage := imaging.AdjustGamma(srcImage, 0.75) +``` + +Original image | Gamma = 0.75 | Gamma = 1.25 +-----------------------------------|------------------------------------------|----------------------------------------- +![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_gamma_0.75.png) | ![dstImage](testdata/out_gamma_1.25.png) + +### Contrast adjustment + +```go +dstImage := imaging.AdjustContrast(srcImage, 20) +``` + +Original image | Contrast = 15 | Contrast = -15 +-----------------------------------|--------------------------------------------|------------------------------------------- +![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_contrast_p15.png) | ![dstImage](testdata/out_contrast_m15.png) + +### Brightness adjustment + +```go +dstImage := imaging.AdjustBrightness(srcImage, 20) +``` + +Original image | Brightness = 10 | Brightness = -10 +-----------------------------------|----------------------------------------------|--------------------------------------------- +![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_brightness_p10.png) | ![dstImage](testdata/out_brightness_m10.png) + +### Saturation adjustment + +```go +dstImage := imaging.AdjustSaturation(srcImage, 20) +``` + +Original image | Saturation = 30 | Saturation = -30 +-----------------------------------|----------------------------------------------|--------------------------------------------- +![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_saturation_p30.png) | ![dstImage](testdata/out_saturation_m30.png) + +## Example code + +```go +package main + +import ( + "image" + "image/color" + "log" + + "github.com/disintegration/imaging" +) + +func main() { + // Open a test image. + src, err := imaging.Open("testdata/flowers.png") + if err != nil { + log.Fatalf("failed to open image: %v", err) + } + + // Crop the original image to 300x300px size using the center anchor. + src = imaging.CropAnchor(src, 300, 300, imaging.Center) + + // Resize the cropped image to width = 200px preserving the aspect ratio. + src = imaging.Resize(src, 200, 0, imaging.Lanczos) + + // Create a blurred version of the image. + img1 := imaging.Blur(src, 5) + + // Create a grayscale version of the image with higher contrast and sharpness. + img2 := imaging.Grayscale(src) + img2 = imaging.AdjustContrast(img2, 20) + img2 = imaging.Sharpen(img2, 2) + + // Create an inverted version of the image. + img3 := imaging.Invert(src) + + // Create an embossed version of the image using a convolution filter. + img4 := imaging.Convolve3x3( + src, + [9]float64{ + -1, -1, 0, + -1, 1, 1, + 0, 1, 1, + }, + nil, + ) + + // Create a new image and paste the four produced images into it. + dst := imaging.New(400, 400, color.NRGBA{0, 0, 0, 0}) + dst = imaging.Paste(dst, img1, image.Pt(0, 0)) + dst = imaging.Paste(dst, img2, image.Pt(0, 200)) + dst = imaging.Paste(dst, img3, image.Pt(200, 0)) + dst = imaging.Paste(dst, img4, image.Pt(200, 200)) + + // Save the resulting image as JPEG. + err = imaging.Save(dst, "testdata/out_example.jpg") + if err != nil { + log.Fatalf("failed to save image: %v", err) + } +} +``` + +Output: + +![dstImage](testdata/out_example.jpg) diff --git a/vendor/github.com/disintegration/imaging/adjust.go b/vendor/github.com/disintegration/imaging/adjust.go new file mode 100644 index 0000000..6d9df25 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/adjust.go @@ -0,0 +1,252 @@ +package imaging + +import ( + "image" + "image/color" + "math" +) + +// Grayscale produces a grayscale version of the image. +func Grayscale(img image.Image) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + parallel(0, src.h, func(ys <-chan int) { + for y := range ys { + i := y * dst.Stride + src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) + for x := 0; x < src.w; x++ { + d := dst.Pix[i : i+3 : i+3] + r := d[0] + g := d[1] + b := d[2] + f := 0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b) + y := uint8(f + 0.5) + d[0] = y + d[1] = y + d[2] = y + i += 4 + } + } + }) + return dst +} + +// Invert produces an inverted (negated) version of the image. +func Invert(img image.Image) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + parallel(0, src.h, func(ys <-chan int) { + for y := range ys { + i := y * dst.Stride + src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) + for x := 0; x < src.w; x++ { + d := dst.Pix[i : i+3 : i+3] + d[0] = 255 - d[0] + d[1] = 255 - d[1] + d[2] = 255 - d[2] + i += 4 + } + } + }) + return dst +} + +// AdjustSaturation changes the saturation of the image using the percentage parameter and returns the adjusted image. +// The percentage must be in the range (-100, 100). +// The percentage = 0 gives the original image. +// The percentage = 100 gives the image with the saturation value doubled for each pixel. +// The percentage = -100 gives the image with the saturation value zeroed for each pixel (grayscale). +// +// Examples: +// dstImage = imaging.AdjustSaturation(srcImage, 25) // increase image saturation by 25% +// dstImage = imaging.AdjustSaturation(srcImage, -10) // decrease image saturation by 10% +// +func AdjustSaturation(img image.Image, percentage float64) *image.NRGBA { + percentage = math.Min(math.Max(percentage, -100), 100) + multiplier := 1 + percentage/100 + + return AdjustFunc(img, func(c color.NRGBA) color.NRGBA { + h, s, l := rgbToHSL(c.R, c.G, c.B) + s *= multiplier + if s > 1 { + s = 1 + } + r, g, b := hslToRGB(h, s, l) + return color.NRGBA{r, g, b, c.A} + }) +} + +// AdjustContrast changes the contrast of the image using the percentage parameter and returns the adjusted image. +// The percentage must be in range (-100, 100). The percentage = 0 gives the original image. +// The percentage = -100 gives solid gray image. +// +// Examples: +// +// dstImage = imaging.AdjustContrast(srcImage, -10) // decrease image contrast by 10% +// dstImage = imaging.AdjustContrast(srcImage, 20) // increase image contrast by 20% +// +func AdjustContrast(img image.Image, percentage float64) *image.NRGBA { + percentage = math.Min(math.Max(percentage, -100.0), 100.0) + lut := make([]uint8, 256) + + v := (100.0 + percentage) / 100.0 + for i := 0; i < 256; i++ { + if 0 <= v && v <= 1 { + lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*v) * 255.0) + } else if 1 < v && v < 2 { + lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*(1/(2.0-v))) * 255.0) + } else { + lut[i] = uint8(float64(i)/255.0+0.5) * 255 + } + } + + return adjustLUT(img, lut) +} + +// AdjustBrightness changes the brightness of the image using the percentage parameter and returns the adjusted image. +// The percentage must be in range (-100, 100). The percentage = 0 gives the original image. +// The percentage = -100 gives solid black image. The percentage = 100 gives solid white image. +// +// Examples: +// +// dstImage = imaging.AdjustBrightness(srcImage, -15) // decrease image brightness by 15% +// dstImage = imaging.AdjustBrightness(srcImage, 10) // increase image brightness by 10% +// +func AdjustBrightness(img image.Image, percentage float64) *image.NRGBA { + percentage = math.Min(math.Max(percentage, -100.0), 100.0) + lut := make([]uint8, 256) + + shift := 255.0 * percentage / 100.0 + for i := 0; i < 256; i++ { + lut[i] = clamp(float64(i) + shift) + } + + return adjustLUT(img, lut) +} + +// AdjustGamma performs a gamma correction on the image and returns the adjusted image. +// Gamma parameter must be positive. Gamma = 1.0 gives the original image. +// Gamma less than 1.0 darkens the image and gamma greater than 1.0 lightens it. +// +// Example: +// +// dstImage = imaging.AdjustGamma(srcImage, 0.7) +// +func AdjustGamma(img image.Image, gamma float64) *image.NRGBA { + e := 1.0 / math.Max(gamma, 0.0001) + lut := make([]uint8, 256) + + for i := 0; i < 256; i++ { + lut[i] = clamp(math.Pow(float64(i)/255.0, e) * 255.0) + } + + return adjustLUT(img, lut) +} + +// AdjustSigmoid changes the contrast of the image using a sigmoidal function and returns the adjusted image. +// It's a non-linear contrast change useful for photo adjustments as it preserves highlight and shadow detail. +// The midpoint parameter is the midpoint of contrast that must be between 0 and 1, typically 0.5. +// The factor parameter indicates how much to increase or decrease the contrast, typically in range (-10, 10). +// If the factor parameter is positive the image contrast is increased otherwise the contrast is decreased. +// +// Examples: +// +// dstImage = imaging.AdjustSigmoid(srcImage, 0.5, 3.0) // increase the contrast +// dstImage = imaging.AdjustSigmoid(srcImage, 0.5, -3.0) // decrease the contrast +// +func AdjustSigmoid(img image.Image, midpoint, factor float64) *image.NRGBA { + if factor == 0 { + return Clone(img) + } + + lut := make([]uint8, 256) + a := math.Min(math.Max(midpoint, 0.0), 1.0) + b := math.Abs(factor) + sig0 := sigmoid(a, b, 0) + sig1 := sigmoid(a, b, 1) + e := 1.0e-6 + + if factor > 0 { + for i := 0; i < 256; i++ { + x := float64(i) / 255.0 + sigX := sigmoid(a, b, x) + f := (sigX - sig0) / (sig1 - sig0) + lut[i] = clamp(f * 255.0) + } + } else { + for i := 0; i < 256; i++ { + x := float64(i) / 255.0 + arg := math.Min(math.Max((sig1-sig0)*x+sig0, e), 1.0-e) + f := a - math.Log(1.0/arg-1.0)/b + lut[i] = clamp(f * 255.0) + } + } + + return adjustLUT(img, lut) +} + +func sigmoid(a, b, x float64) float64 { + return 1 / (1 + math.Exp(b*(a-x))) +} + +// adjustLUT applies the given lookup table to the colors of the image. +func adjustLUT(img image.Image, lut []uint8) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + lut = lut[0:256] + parallel(0, src.h, func(ys <-chan int) { + for y := range ys { + i := y * dst.Stride + src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) + for x := 0; x < src.w; x++ { + d := dst.Pix[i : i+3 : i+3] + d[0] = lut[d[0]] + d[1] = lut[d[1]] + d[2] = lut[d[2]] + i += 4 + } + } + }) + return dst +} + +// AdjustFunc applies the fn function to each pixel of the img image and returns the adjusted image. +// +// Example: +// +// dstImage = imaging.AdjustFunc( +// srcImage, +// func(c color.NRGBA) color.NRGBA { +// // shift the red channel by 16 +// r := int(c.R) + 16 +// if r > 255 { +// r = 255 +// } +// return color.NRGBA{uint8(r), c.G, c.B, c.A} +// } +// ) +// +func AdjustFunc(img image.Image, fn func(c color.NRGBA) color.NRGBA) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + parallel(0, src.h, func(ys <-chan int) { + for y := range ys { + i := y * dst.Stride + src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) + for x := 0; x < src.w; x++ { + d := dst.Pix[i : i+4 : i+4] + r := d[0] + g := d[1] + b := d[2] + a := d[3] + c := fn(color.NRGBA{r, g, b, a}) + d[0] = c.R + d[1] = c.G + d[2] = c.B + d[3] = c.A + i += 4 + } + } + }) + return dst +} diff --git a/vendor/github.com/disintegration/imaging/adjust_test.go b/vendor/github.com/disintegration/imaging/adjust_test.go new file mode 100644 index 0000000..251cef5 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/adjust_test.go @@ -0,0 +1,831 @@ +package imaging + +import ( + "image" + "image/color" + "testing" +) + +func TestGrayscale(t *testing.T) { + testCases := []struct { + name string + src image.Image + want *image.NRGBA + }{ + { + "Grayscale 3x3", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x3d, 0x3d, 0x3d, 0x01, 0x78, 0x78, 0x78, 0x02, 0x17, 0x17, 0x17, 0x03, + 0x1f, 0x1f, 0x1f, 0xff, 0x25, 0x25, 0x25, 0xff, 0x66, 0x66, 0x66, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Grayscale(tc.src) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkGrayscale(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Grayscale(testdataBranchesJPG) + } +} + +func TestInvert(t *testing.T) { + testCases := []struct { + name string + src image.Image + want *image.NRGBA + }{ + { + "Invert 3x3", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x33, 0xff, 0xff, 0x01, 0xff, 0x33, 0xff, 0x02, 0xff, 0xff, 0x33, 0x03, + 0xee, 0xdd, 0xcc, 0xff, 0xcc, 0xdd, 0xee, 0xff, 0x55, 0xcc, 0x44, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0x00, 0x00, 0x00, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Invert(tc.src) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkInvert(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Invert(testdataBranchesJPG) + } +} + +func TestAdjustSaturation(t *testing.T) { + testCases := []struct { + name string + src image.Image + p float64 + want *image.NRGBA + }{ + { + "AdjustSaturation 3x3 10", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 10, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x0f, 0x22, 0x35, 0xff, 0x35, 0x22, 0x0f, 0xff, 0xaf, 0x2c, 0xc2, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustSaturation 3x3 100", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 100, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x00, 0x22, 0x44, 0xff, 0x44, 0x22, 0x00, 0xff, 0xd0, 0x00, 0xee, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustSaturation 3x3 -10", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + -10, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xc2, 0x0a, 0x0a, 0x01, 0x0a, 0xc2, 0x0a, 0x02, 0x0a, 0x0a, 0xc2, 0x03, + 0x13, 0x22, 0x31, 0xff, 0x31, 0x22, 0x13, 0xff, 0xa5, 0x3a, 0xb4, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustSaturation 3x3 -100", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + -100, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x66, 0x66, 0x66, 0x01, 0x66, 0x66, 0x66, 0x02, 0x66, 0x66, 0x66, 0x03, + 0x22, 0x22, 0x22, 0xff, 0x22, 0x22, 0x22, 0xff, 0x77, 0x77, 0x77, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustSaturation 3x3 0", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 0, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := AdjustSaturation(tc.src, tc.p) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestAdjustSaturationGolden(t *testing.T) { + for name, p := range map[string]float64{ + "out_saturation_m30.png": -30, + "out_saturation_p30.png": 30, + } { + got := AdjustSaturation(testdataFlowersSmallPNG, p) + want, err := Open("testdata/" + name) + if err != nil { + t.Fatalf("failed to open image: %v", err) + } + if !compareNRGBA(got, toNRGBA(want), 0) { + t.Errorf("resulting image differs from golden: %s", name) + } + } +} + +func BenchmarkAdjustSaturation(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + AdjustSaturation(testdataBranchesJPG, 10) + } +} + +func TestAdjustContrast(t *testing.T) { + testCases := []struct { + name string + src image.Image + p float64 + want *image.NRGBA + }{ + { + "AdjustContrast 3x3 10", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 10, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xd5, 0x00, 0x00, 0x01, 0x00, 0xd5, 0x00, 0x02, 0x00, 0x00, 0xd5, 0x03, + 0x05, 0x18, 0x2b, 0xff, 0x2b, 0x18, 0x05, 0xff, 0xaf, 0x2b, 0xc2, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x2b, 0x2b, 0x2b, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustContrast 3x3 100", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 100, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0x02, 0x00, 0x00, 0xff, 0x03, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustContrast 3x3 -10", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + -10, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xc4, 0x0d, 0x0d, 0x01, 0x0d, 0xc4, 0x0d, 0x02, 0x0d, 0x0d, 0xc4, 0x03, + 0x1c, 0x2b, 0x3b, 0xff, 0x3b, 0x2b, 0x1c, 0xff, 0xa6, 0x3b, 0xb5, 0xff, + 0x0d, 0x0d, 0x0d, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xf2, 0xf2, 0xf2, 0xff, + }, + }, + }, + { + "AdjustContrast 3x3 -100", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + -100, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x80, 0x80, 0x80, 0x01, 0x80, 0x80, 0x80, 0x02, 0x80, 0x80, 0x80, 0x03, + 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff, + 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff, + }, + }, + }, + { + "AdjustContrast 3x3 0", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 0, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := AdjustContrast(tc.src, tc.p) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestAdjustContrastGolden(t *testing.T) { + for name, p := range map[string]float64{ + "out_contrast_m15.png": -15, + "out_contrast_p15.png": 15, + } { + got := AdjustContrast(testdataFlowersSmallPNG, p) + want, err := Open("testdata/" + name) + if err != nil { + t.Fatalf("failed to open image: %v", err) + } + if !compareNRGBA(got, toNRGBA(want), 0) { + t.Fatalf("resulting image differs from golden: %s", name) + } + } +} + +func BenchmarkAdjustContrast(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + AdjustContrast(testdataBranchesJPG, 10) + } +} + +func TestAdjustBrightness(t *testing.T) { + testCases := []struct { + name string + src image.Image + p float64 + want *image.NRGBA + }{ + { + "AdjustBrightness 3x3 10", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 10, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xe6, 0x1a, 0x1a, 0x01, 0x1a, 0xe6, 0x1a, 0x02, 0x1a, 0x1a, 0xe6, 0x03, + 0x2b, 0x3c, 0x4d, 0xff, 0x4d, 0x3c, 0x2b, 0xff, 0xc4, 0x4d, 0xd5, 0xff, + 0x1a, 0x1a, 0x1a, 0xff, 0x4d, 0x4d, 0x4d, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustBrightness 3x3 100", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 100, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0x03, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustBrightness 3x3 -10", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + -10, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xb3, 0x00, 0x00, 0x01, 0x00, 0xb3, 0x00, 0x02, 0x00, 0x00, 0xb3, 0x03, + 0x00, 0x09, 0x1a, 0xff, 0x1a, 0x09, 0x00, 0xff, 0x91, 0x1a, 0xa2, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x1a, 0x1a, 0x1a, 0xff, 0xe6, 0xe6, 0xe6, 0xff, + }, + }, + }, + { + "AdjustBrightness 3x3 -100", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + -100, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + }, + }, + }, + { + "AdjustBrightness 3x3 0", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 0, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := AdjustBrightness(tc.src, tc.p) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestAdjustBrightnessGolden(t *testing.T) { + for name, p := range map[string]float64{ + "out_brightness_m10.png": -10, + "out_brightness_p10.png": 10, + } { + got := AdjustBrightness(testdataFlowersSmallPNG, p) + want, err := Open("testdata/" + name) + if err != nil { + t.Fatalf("failed to open image: %v", err) + } + if !compareNRGBA(got, toNRGBA(want), 0) { + t.Fatalf("resulting image differs from golden: %s", name) + } + } +} + +func BenchmarkAdjustBrightness(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + AdjustBrightness(testdataBranchesJPG, 10) + } +} + +func TestAdjustGamma(t *testing.T) { + testCases := []struct { + name string + src image.Image + p float64 + want *image.NRGBA + }{ + { + "AdjustGamma 3x3 0.75", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 0.75, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xbd, 0x00, 0x00, 0x01, 0x00, 0xbd, 0x00, 0x02, 0x00, 0x00, 0xbd, 0x03, + 0x07, 0x11, 0x1e, 0xff, 0x1e, 0x11, 0x07, 0xff, 0x95, 0x1e, 0xa9, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x1e, 0x1e, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustGamma 3x3 1.5", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 1.5, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xdc, 0x00, 0x00, 0x01, 0x00, 0xdc, 0x00, 0x02, 0x00, 0x00, 0xdc, 0x03, + 0x2a, 0x43, 0x57, 0xff, 0x57, 0x43, 0x2a, 0xff, 0xc3, 0x57, 0xcf, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x57, 0x57, 0x57, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustGamma 3x3 1.0", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 1.0, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := AdjustGamma(tc.src, tc.p) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestAdjustGammaGolden(t *testing.T) { + for name, g := range map[string]float64{ + "out_gamma_0.75.png": 0.75, + "out_gamma_1.25.png": 1.25, + } { + got := AdjustGamma(testdataFlowersSmallPNG, g) + want, err := Open("testdata/" + name) + if err != nil { + t.Fatalf("failed to open image: %v", err) + } + if !compareNRGBA(got, toNRGBA(want), 0) { + t.Fatalf("resulting image differs from golden: %s", name) + } + } +} + +func BenchmarkAdjustGamma(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + AdjustGamma(testdataBranchesJPG, 1.5) + } +} + +func TestAdjustSigmoid(t *testing.T) { + testCases := []struct { + name string + src image.Image + m float64 + p float64 + want *image.NRGBA + }{ + { + "AdjustSigmoid 3x3 0.5 3.0", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 0.5, + 3.0, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xd4, 0x00, 0x00, 0x01, 0x00, 0xd4, 0x00, 0x02, 0x00, 0x00, 0xd4, 0x03, + 0x0d, 0x1b, 0x2b, 0xff, 0x2b, 0x1b, 0x0d, 0xff, 0xb1, 0x2b, 0xc3, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x2b, 0x2b, 0x2b, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustSigmoid 3x3 0.5 -3.0", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 0.5, + -3.0, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xc4, 0x00, 0x00, 0x01, 0x00, 0xc4, 0x00, 0x02, 0x00, 0x00, 0xc4, 0x03, + 0x16, 0x2a, 0x3b, 0xff, 0x3b, 0x2a, 0x16, 0xff, 0xa4, 0x3b, 0xb3, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "AdjustSigmoid 3x3 0.5 0.0", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 0.5, + 0.0, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := AdjustSigmoid(tc.src, tc.m, tc.p) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkAdjustSigmoid(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + AdjustSigmoid(testdataBranchesJPG, 0.5, 3.0) + } +} + +func TestAdjustFunc(t *testing.T) { + testCases := []struct { + name string + src image.Image + fn func(c color.NRGBA) color.NRGBA + want *image.NRGBA + }{ + { + "invert", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + func(c color.NRGBA) color.NRGBA { + return color.NRGBA{255 - c.R, 255 - c.G, 255 - c.B, c.A} + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x33, 0xff, 0xff, 0x01, 0xff, 0x33, 0xff, 0x02, 0xff, 0xff, 0x33, 0x03, + 0xee, 0xdd, 0xcc, 0xff, 0xcc, 0xdd, 0xee, 0xff, 0x55, 0xcc, 0x44, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0x00, 0x00, 0x00, 0xff, + }, + }, + }, + { + "threshold", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03, + 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + func(c color.NRGBA) color.NRGBA { + y := 0.299*float64(c.R) + 0.587*float64(c.G) + 0.114*float64(c.B) + if y > 0x55 { + return color.NRGBA{0xff, 0xff, 0xff, c.A} + } + return color.NRGBA{0x00, 0x00, 0x00, c.A} + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := AdjustFunc(tc.src, tc.fn) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkAdjustFunc(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + AdjustFunc(testdataBranchesJPG, func(c color.NRGBA) color.NRGBA { + return color.NRGBA{c.B, c.G, c.R, c.A} + }) + } +} diff --git a/vendor/github.com/disintegration/imaging/convolution.go b/vendor/github.com/disintegration/imaging/convolution.go new file mode 100644 index 0000000..11eddc1 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/convolution.go @@ -0,0 +1,148 @@ +package imaging + +import ( + "image" +) + +// ConvolveOptions are convolution parameters. +type ConvolveOptions struct { + // If Normalize is true the kernel is normalized before convolution. + Normalize bool + + // If Abs is true the absolute value of each color channel is taken after convolution. + Abs bool + + // Bias is added to each color channel value after convolution. + Bias int +} + +// Convolve3x3 convolves the image with the specified 3x3 convolution kernel. +// Default parameters are used if a nil *ConvolveOptions is passed. +func Convolve3x3(img image.Image, kernel [9]float64, options *ConvolveOptions) *image.NRGBA { + return convolve(img, kernel[:], options) +} + +// Convolve5x5 convolves the image with the specified 5x5 convolution kernel. +// Default parameters are used if a nil *ConvolveOptions is passed. +func Convolve5x5(img image.Image, kernel [25]float64, options *ConvolveOptions) *image.NRGBA { + return convolve(img, kernel[:], options) +} + +func convolve(img image.Image, kernel []float64, options *ConvolveOptions) *image.NRGBA { + src := toNRGBA(img) + w := src.Bounds().Max.X + h := src.Bounds().Max.Y + dst := image.NewNRGBA(image.Rect(0, 0, w, h)) + + if w < 1 || h < 1 { + return dst + } + + if options == nil { + options = &ConvolveOptions{} + } + + if options.Normalize { + normalizeKernel(kernel) + } + + type coef struct { + x, y int + k float64 + } + var coefs []coef + var m int + + switch len(kernel) { + case 9: + m = 1 + case 25: + m = 2 + } + + i := 0 + for y := -m; y <= m; y++ { + for x := -m; x <= m; x++ { + if kernel[i] != 0 { + coefs = append(coefs, coef{x: x, y: y, k: kernel[i]}) + } + i++ + } + } + + parallel(0, h, func(ys <-chan int) { + for y := range ys { + for x := 0; x < w; x++ { + var r, g, b float64 + for _, c := range coefs { + ix := x + c.x + if ix < 0 { + ix = 0 + } else if ix >= w { + ix = w - 1 + } + + iy := y + c.y + if iy < 0 { + iy = 0 + } else if iy >= h { + iy = h - 1 + } + + off := iy*src.Stride + ix*4 + s := src.Pix[off : off+3 : off+3] + r += float64(s[0]) * c.k + g += float64(s[1]) * c.k + b += float64(s[2]) * c.k + } + + if options.Abs { + if r < 0 { + r = -r + } + if g < 0 { + g = -g + } + if b < 0 { + b = -b + } + } + + if options.Bias != 0 { + r += float64(options.Bias) + g += float64(options.Bias) + b += float64(options.Bias) + } + + srcOff := y*src.Stride + x*4 + dstOff := y*dst.Stride + x*4 + d := dst.Pix[dstOff : dstOff+4 : dstOff+4] + d[0] = clamp(r) + d[1] = clamp(g) + d[2] = clamp(b) + d[3] = src.Pix[srcOff+3] + } + } + }) + + return dst +} + +func normalizeKernel(kernel []float64) { + var sum, sumpos float64 + for i := range kernel { + sum += kernel[i] + if kernel[i] > 0 { + sumpos += kernel[i] + } + } + if sum != 0 { + for i := range kernel { + kernel[i] /= sum + } + } else if sumpos != 0 { + for i := range kernel { + kernel[i] /= sumpos + } + } +} diff --git a/vendor/github.com/disintegration/imaging/convolution_test.go b/vendor/github.com/disintegration/imaging/convolution_test.go new file mode 100644 index 0000000..2f30bd7 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/convolution_test.go @@ -0,0 +1,338 @@ +package imaging + +import ( + "image" + "testing" +) + +func TestConvolve3x3(t *testing.T) { + testCases := []struct { + name string + src image.Image + kernel [9]float64 + options *ConvolveOptions + want *image.NRGBA + }{ + { + "Convolve3x3 0x0", + &image.NRGBA{ + Rect: image.Rect(0, 0, 0, 0), + Stride: 0, + Pix: []uint8{}, + }, + [9]float64{ + 0, 0, 0, + 0, 1, 0, + 0, 0, 0, + }, + nil, + &image.NRGBA{Rect: image.Rect(0, 0, 0, 0)}, + }, + { + "Convolve3x3 4x4 identity", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + [9]float64{ + 0, 0, 0, + 0, 1, 0, + 0, 0, 0, + }, + nil, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + { + "Convolve3x3 4x4 abs", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + [9]float64{ + 0, 0, 0, + 0, -1, 0, + 0, 0, 0, + }, + &ConvolveOptions{Abs: true}, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + { + "Convolve3x3 4x4 bias", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + [9]float64{ + 0, 0, 0, + 0, 1, 0, + 0, 0, 0, + }, + &ConvolveOptions{Bias: 0x10}, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0x10, 0x11, 0x12, 0x03, 0x14, 0x15, 0x16, 0x07, 0x18, 0x19, 0x1a, 0x0b, 0x1c, 0x1d, 0x1e, 0x0f, + 0x20, 0x21, 0x22, 0x13, 0x24, 0x25, 0x26, 0x17, 0x28, 0x29, 0x2a, 0x1b, 0x2c, 0x2d, 0x2e, 0x1f, + 0x30, 0x31, 0x32, 0x23, 0x34, 0x35, 0x36, 0x27, 0x38, 0x39, 0x3a, 0x2b, 0x3c, 0x3d, 0x3e, 0x2f, + 0x40, 0x41, 0x42, 0x33, 0x44, 0x45, 0x46, 0x37, 0x48, 0x49, 0x4a, 0x3b, 0x4c, 0x4d, 0x4e, 0x3f, + }, + }, + }, + { + "Convolve3x3 4x4 norm", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + [9]float64{ + 1, 1, 1, + 1, 1, 1, + 1, 1, 1, + }, + &ConvolveOptions{Normalize: true}, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0x07, 0x08, 0x09, 0x03, 0x09, 0x0a, 0x0b, 0x07, 0x0d, 0x0e, 0x0f, 0x0b, 0x10, 0x11, 0x12, 0x0f, + 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1b, 0x1c, 0x1d, 0x1f, + 0x21, 0x22, 0x23, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c, 0x2d, 0x2f, + 0x2c, 0x2d, 0x2e, 0x33, 0x2f, 0x30, 0x31, 0x37, 0x33, 0x34, 0x35, 0x3b, 0x35, 0x36, 0x37, 0x3f, + }, + }, + }, + { + "Convolve3x3 3x3 laplacian", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x01, 0xff, 0x00, 0x01, 0x02, 0xff, 0x00, 0x01, 0x03, 0xff, + 0x00, 0x01, 0x04, 0xff, 0x10, 0x10, 0x10, 0xff, 0x00, 0x01, 0x05, 0xff, + 0x00, 0x01, 0x06, 0xff, 0x00, 0x01, 0x07, 0xff, 0x00, 0x01, 0x08, 0xff, + }, + }, + [9]float64{ + -1, -1, -1, + -1, 8, -1, + -1, -1, -1, + }, + nil, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x80, 0x78, 0x5c, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Convolve3x3(tc.src, tc.kernel, tc.options) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestConvolve5x5(t *testing.T) { + testCases := []struct { + name string + src image.Image + kernel [25]float64 + options *ConvolveOptions + want *image.NRGBA + }{ + { + "Convolve5x5 4x4 translate", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + [25]float64{ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, + }, + nil, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0x28, 0x29, 0x2a, 0x03, 0x2c, 0x2d, 0x2e, 0x07, 0x2c, 0x2d, 0x2e, 0x0b, 0x2c, 0x2d, 0x2e, 0x0f, + 0x38, 0x39, 0x3a, 0x13, 0x3c, 0x3d, 0x3e, 0x17, 0x3c, 0x3d, 0x3e, 0x1b, 0x3c, 0x3d, 0x3e, 0x1f, + 0x38, 0x39, 0x3a, 0x23, 0x3c, 0x3d, 0x3e, 0x27, 0x3c, 0x3d, 0x3e, 0x2b, 0x3c, 0x3d, 0x3e, 0x2f, + 0x38, 0x39, 0x3a, 0x33, 0x3c, 0x3d, 0x3e, 0x37, 0x3c, 0x3d, 0x3e, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Convolve5x5(tc.src, tc.kernel, tc.options) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestNormalizeKernel(t *testing.T) { + testCases := []struct { + name string + kernel []float64 + want []float64 + }{ + { + name: "positive sum", + kernel: []float64{ + 2, 0, 2, + 0, 2, 0, + 2, 0, 2, + }, + want: []float64{ + 0.2, 0, 0.2, + 0, 0.2, 0, + 0.2, 0, 0.2, + }, + }, + { + name: "negative sum", + kernel: []float64{ + -2, 0, -2, + 2, 2, 2, + -2, 0, -2, + }, + want: []float64{ + 1, 0, 1, + -1, -1, -1, + 1, 0, 1, + }, + }, + { + name: "zero sum", + kernel: []float64{ + 0, 2, 0, + 2, 0, -2, + 0, -2, 0, + }, + want: []float64{ + 0, 0.5, 0, + 0.5, 0, -0.5, + 0, -0.5, 0, + }, + }, + { + name: "all zero", + kernel: []float64{ + 0, 0, 0, + 0, 0, 0, + 0, 0, 0, + }, + want: []float64{ + 0, 0, 0, + 0, 0, 0, + 0, 0, 0, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + normalizeKernel(tc.kernel) + for i := range tc.kernel { + if tc.kernel[i] != tc.want[i] { + t.Fatalf("got kernel %v want %v", tc.kernel, tc.want) + } + } + }) + } +} + +func BenchmarkConvolve3x3(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Convolve3x3( + testdataBranchesJPG, + [9]float64{ + -1, -1, 0, + -1, 0, 1, + 0, 1, 1, + }, + nil, + ) + } +} + +func BenchmarkConvolve5x5(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Convolve5x5( + testdataBranchesJPG, + [25]float64{ + -1, -1, -1, -1, 0, + -1, -1, -1, 0, 1, + -1, -1, 0, 1, 1, + -1, 0, 1, 1, 1, + 0, 1, 1, 1, 1, + }, + nil, + ) + } +} diff --git a/vendor/github.com/disintegration/imaging/doc.go b/vendor/github.com/disintegration/imaging/doc.go new file mode 100644 index 0000000..5d59b46 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/doc.go @@ -0,0 +1,7 @@ +/* +Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.). + +All the image processing functions provided by the package accept any image type that implements image.Image interface +as an input, and return a new image of *image.NRGBA type (32bit RGBA colors, not premultiplied by alpha). +*/ +package imaging diff --git a/vendor/github.com/disintegration/imaging/effects.go b/vendor/github.com/disintegration/imaging/effects.go new file mode 100644 index 0000000..a4b17df --- /dev/null +++ b/vendor/github.com/disintegration/imaging/effects.go @@ -0,0 +1,169 @@ +package imaging + +import ( + "image" + "math" +) + +func gaussianBlurKernel(x, sigma float64) float64 { + return math.Exp(-(x*x)/(2*sigma*sigma)) / (sigma * math.Sqrt(2*math.Pi)) +} + +// Blur produces a blurred version of the image using a Gaussian function. +// Sigma parameter must be positive and indicates how much the image will be blurred. +// +// Usage example: +// +// dstImage := imaging.Blur(srcImage, 3.5) +// +func Blur(img image.Image, sigma float64) *image.NRGBA { + if sigma <= 0 { + return Clone(img) + } + + radius := int(math.Ceil(sigma * 3.0)) + kernel := make([]float64, radius+1) + + for i := 0; i <= radius; i++ { + kernel[i] = gaussianBlurKernel(float64(i), sigma) + } + + return blurVertical(blurHorizontal(img, kernel), kernel) +} + +func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + radius := len(kernel) - 1 + + parallel(0, src.h, func(ys <-chan int) { + scanLine := make([]uint8, src.w*4) + scanLineF := make([]float64, len(scanLine)) + for y := range ys { + src.scan(0, y, src.w, y+1, scanLine) + for i, v := range scanLine { + scanLineF[i] = float64(v) + } + for x := 0; x < src.w; x++ { + min := x - radius + if min < 0 { + min = 0 + } + max := x + radius + if max > src.w-1 { + max = src.w - 1 + } + var r, g, b, a, wsum float64 + for ix := min; ix <= max; ix++ { + i := ix * 4 + weight := kernel[absint(x-ix)] + wsum += weight + s := scanLineF[i : i+4 : i+4] + wa := s[3] * weight + r += s[0] * wa + g += s[1] * wa + b += s[2] * wa + a += wa + } + if a != 0 { + aInv := 1 / a + j := y*dst.Stride + x*4 + d := dst.Pix[j : j+4 : j+4] + d[0] = clamp(r * aInv) + d[1] = clamp(g * aInv) + d[2] = clamp(b * aInv) + d[3] = clamp(a / wsum) + } + } + } + }) + + return dst +} + +func blurVertical(img image.Image, kernel []float64) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + radius := len(kernel) - 1 + + parallel(0, src.w, func(xs <-chan int) { + scanLine := make([]uint8, src.h*4) + scanLineF := make([]float64, len(scanLine)) + for x := range xs { + src.scan(x, 0, x+1, src.h, scanLine) + for i, v := range scanLine { + scanLineF[i] = float64(v) + } + for y := 0; y < src.h; y++ { + min := y - radius + if min < 0 { + min = 0 + } + max := y + radius + if max > src.h-1 { + max = src.h - 1 + } + var r, g, b, a, wsum float64 + for iy := min; iy <= max; iy++ { + i := iy * 4 + weight := kernel[absint(y-iy)] + wsum += weight + s := scanLineF[i : i+4 : i+4] + wa := s[3] * weight + r += s[0] * wa + g += s[1] * wa + b += s[2] * wa + a += wa + } + if a != 0 { + aInv := 1 / a + j := y*dst.Stride + x*4 + d := dst.Pix[j : j+4 : j+4] + d[0] = clamp(r * aInv) + d[1] = clamp(g * aInv) + d[2] = clamp(b * aInv) + d[3] = clamp(a / wsum) + } + } + } + }) + + return dst +} + +// Sharpen produces a sharpened version of the image. +// Sigma parameter must be positive and indicates how much the image will be sharpened. +// +// Usage example: +// +// dstImage := imaging.Sharpen(srcImage, 3.5) +// +func Sharpen(img image.Image, sigma float64) *image.NRGBA { + if sigma <= 0 { + return Clone(img) + } + + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + blurred := Blur(img, sigma) + + parallel(0, src.h, func(ys <-chan int) { + scanLine := make([]uint8, src.w*4) + for y := range ys { + src.scan(0, y, src.w, y+1, scanLine) + j := y * dst.Stride + for i := 0; i < src.w*4; i++ { + val := int(scanLine[i])<<1 - int(blurred.Pix[j]) + if val < 0 { + val = 0 + } else if val > 0xff { + val = 0xff + } + dst.Pix[j] = uint8(val) + j++ + } + } + }) + + return dst +} diff --git a/vendor/github.com/disintegration/imaging/effects_test.go b/vendor/github.com/disintegration/imaging/effects_test.go new file mode 100644 index 0000000..d403b61 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/effects_test.go @@ -0,0 +1,238 @@ +package imaging + +import ( + "image" + "testing" +) + +func TestBlur(t *testing.T) { + testCases := []struct { + name string + src image.Image + sigma float64 + want *image.NRGBA + }{ + { + "Blur 3x3 0", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + 0.0, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + }, + { + "Blur 3x3 0.5", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + 0.5, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x66, 0xaa, 0xff, 0x04, 0x66, 0xaa, 0xff, 0x18, 0x66, 0xaa, 0xff, 0x04, + 0x66, 0xaa, 0xff, 0x18, 0x66, 0xaa, 0xff, 0x9e, 0x66, 0xaa, 0xff, 0x18, + 0x66, 0xaa, 0xff, 0x04, 0x66, 0xaa, 0xff, 0x18, 0x66, 0xaa, 0xff, 0x04, + }, + }, + }, + { + "Blur 3x3 10", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + 10, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c, + 0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c, + 0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Blur(tc.src, tc.sigma) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestBlurGolden(t *testing.T) { + for name, sigma := range map[string]float64{ + "out_blur_0.5.png": 0.5, + "out_blur_1.5.png": 1.5, + } { + got := Blur(testdataFlowersSmallPNG, sigma) + want, err := Open("testdata/" + name) + if err != nil { + t.Fatalf("failed to open image: %v", err) + } + if !compareNRGBA(got, toNRGBA(want), 0) { + t.Fatalf("resulting image differs from golden: %s", name) + } + } +} + +func BenchmarkBlur(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Blur(testdataBranchesJPG, 3) + } +} + +func TestSharpen(t *testing.T) { + testCases := []struct { + name string + src image.Image + sigma float64 + want *image.NRGBA + }{ + { + "Sharpen 3x3 0", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + }, + }, + 0, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + }, + }, + }, + { + "Sharpen 3x3 0.5", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + }, + }, + 0.5, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x66, 0x66, 0x66, 0x66, 0x64, 0x64, 0x64, 0x64, 0x66, 0x66, 0x66, 0x66, + 0x64, 0x64, 0x64, 0x64, 0x7d, 0x7d, 0x7d, 0x7e, 0x64, 0x64, 0x64, 0x64, + 0x66, 0x66, 0x66, 0x66, 0x64, 0x64, 0x64, 0x64, 0x66, 0x66, 0x66, 0x66, + }, + }, + }, + { + "Sharpen 3x3 100", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + }, + }, + 100, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x86, 0x86, 0x86, 0x86, 0x64, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + }, + }, + }, + { + "Sharpen 3x1 10", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 0), + Stride: 3 * 4, + Pix: []uint8{ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + }, + }, + 10, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 1), + Stride: 3 * 4, + Pix: []uint8{ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Sharpen(tc.src, tc.sigma) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestSharpenGolden(t *testing.T) { + for name, sigma := range map[string]float64{ + "out_sharpen_0.5.png": 0.5, + "out_sharpen_1.5.png": 1.5, + } { + got := Sharpen(testdataFlowersSmallPNG, sigma) + want, err := Open("testdata/" + name) + if err != nil { + t.Fatalf("failed to open image: %v", err) + } + if !compareNRGBA(got, toNRGBA(want), 0) { + t.Fatalf("resulting image differs from golden: %s", name) + } + } +} + +func BenchmarkSharpen(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Sharpen(testdataBranchesJPG, 3) + } +} diff --git a/vendor/github.com/disintegration/imaging/example_test.go b/vendor/github.com/disintegration/imaging/example_test.go new file mode 100644 index 0000000..f241aed --- /dev/null +++ b/vendor/github.com/disintegration/imaging/example_test.go @@ -0,0 +1,58 @@ +package imaging_test + +import ( + "image" + "image/color" + "log" + + "github.com/disintegration/imaging" +) + +func Example() { + // Open a test image. + src, err := imaging.Open("testdata/flowers.png") + if err != nil { + log.Fatalf("failed to open image: %v", err) + } + + // Crop the original image to 300x300px size using the center anchor. + src = imaging.CropAnchor(src, 300, 300, imaging.Center) + + // Resize the cropped image to width = 200px preserving the aspect ratio. + src = imaging.Resize(src, 200, 0, imaging.Lanczos) + + // Create a blurred version of the image. + img1 := imaging.Blur(src, 5) + + // Create a grayscale version of the image with higher contrast and sharpness. + img2 := imaging.Grayscale(src) + img2 = imaging.AdjustContrast(img2, 20) + img2 = imaging.Sharpen(img2, 2) + + // Create an inverted version of the image. + img3 := imaging.Invert(src) + + // Create an embossed version of the image using a convolution filter. + img4 := imaging.Convolve3x3( + src, + [9]float64{ + -1, -1, 0, + -1, 1, 1, + 0, 1, 1, + }, + nil, + ) + + // Create a new image and paste the four produced images into it. + dst := imaging.New(400, 400, color.NRGBA{0, 0, 0, 0}) + dst = imaging.Paste(dst, img1, image.Pt(0, 0)) + dst = imaging.Paste(dst, img2, image.Pt(0, 200)) + dst = imaging.Paste(dst, img3, image.Pt(200, 0)) + dst = imaging.Paste(dst, img4, image.Pt(200, 200)) + + // Save the resulting image as JPEG. + err = imaging.Save(dst, "testdata/out_example.jpg") + if err != nil { + log.Fatalf("failed to save image: %v", err) + } +} diff --git a/vendor/github.com/disintegration/imaging/go.mod b/vendor/github.com/disintegration/imaging/go.mod new file mode 100644 index 0000000..126e8cc --- /dev/null +++ b/vendor/github.com/disintegration/imaging/go.mod @@ -0,0 +1,3 @@ +module github.com/disintegration/imaging + +require golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81 diff --git a/vendor/github.com/disintegration/imaging/go.sum b/vendor/github.com/disintegration/imaging/go.sum new file mode 100644 index 0000000..20c92e4 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/go.sum @@ -0,0 +1,2 @@ +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81 h1:00VmoueYNlNz/aHIilyyQz/MHSqGoWJzpFv/HW8xpzI= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= diff --git a/vendor/github.com/disintegration/imaging/histogram.go b/vendor/github.com/disintegration/imaging/histogram.go new file mode 100644 index 0000000..c547fe8 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/histogram.go @@ -0,0 +1,52 @@ +package imaging + +import ( + "image" + "sync" +) + +// Histogram returns a normalized histogram of an image. +// +// Resulting histogram is represented as an array of 256 floats, where +// histogram[i] is a probability of a pixel being of a particular luminance i. +func Histogram(img image.Image) [256]float64 { + var mu sync.Mutex + var histogram [256]float64 + var total float64 + + src := newScanner(img) + if src.w == 0 || src.h == 0 { + return histogram + } + + parallel(0, src.h, func(ys <-chan int) { + var tmpHistogram [256]float64 + var tmpTotal float64 + scanLine := make([]uint8, src.w*4) + for y := range ys { + src.scan(0, y, src.w, y+1, scanLine) + i := 0 + for x := 0; x < src.w; x++ { + s := scanLine[i : i+3 : i+3] + r := s[0] + g := s[1] + b := s[2] + y := 0.299*float32(r) + 0.587*float32(g) + 0.114*float32(b) + tmpHistogram[int(y+0.5)]++ + tmpTotal++ + i += 4 + } + } + mu.Lock() + for i := 0; i < 256; i++ { + histogram[i] += tmpHistogram[i] + } + total += tmpTotal + mu.Unlock() + }) + + for i := 0; i < 256; i++ { + histogram[i] = histogram[i] / total + } + return histogram +} diff --git a/vendor/github.com/disintegration/imaging/histogram_test.go b/vendor/github.com/disintegration/imaging/histogram_test.go new file mode 100644 index 0000000..ffc410a --- /dev/null +++ b/vendor/github.com/disintegration/imaging/histogram_test.go @@ -0,0 +1,59 @@ +package imaging + +import ( + "image" + "testing" +) + +func TestHistogram(t *testing.T) { + testCases := []struct { + name string + img image.Image + want [256]float64 + }{ + { + name: "grayscale", + img: &image.RGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x80, 0x80, 0xff, + }, + }, + want: [256]float64{0x00: 0.25, 0x80: 0.25, 0xff: 0.5}, + }, + { + name: "colorful", + img: &image.RGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0xff, 0x33, 0x44, 0x55, 0xff, + 0x55, 0x44, 0x33, 0xff, 0x77, 0x66, 0x55, 0xff, + }, + }, + want: [256]float64{0x00: 0.25, 0x41: 0.25, 0x47: 0.25, 0x69: 0.25}, + }, + { + name: "zero", + img: &image.RGBA{}, + want: [256]float64{}, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Histogram(tc.img) + if got != tc.want { + t.Fatalf("got histogram %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkHistogram(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Histogram(testdataBranchesJPG) + } +} diff --git a/vendor/github.com/disintegration/imaging/io.go b/vendor/github.com/disintegration/imaging/io.go new file mode 100644 index 0000000..557bf2f --- /dev/null +++ b/vendor/github.com/disintegration/imaging/io.go @@ -0,0 +1,463 @@ +package imaging + +import ( + "encoding/binary" + "errors" + "image" + "image/draw" + "image/gif" + "image/jpeg" + "image/png" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "golang.org/x/image/bmp" + "golang.org/x/image/tiff" +) + +// Format is an image file format. +type Format int + +// Image file formats. +const ( + JPEG Format = iota + PNG + GIF + TIFF + BMP +) + +func (f Format) String() string { + switch f { + case JPEG: + return "JPEG" + case PNG: + return "PNG" + case GIF: + return "GIF" + case TIFF: + return "TIFF" + case BMP: + return "BMP" + default: + return "Unsupported" + } +} + +var formatFromExt = map[string]Format{ + "jpg": JPEG, + "jpeg": JPEG, + "png": PNG, + "tif": TIFF, + "tiff": TIFF, + "bmp": BMP, + "gif": GIF, +} + +// FormatFromExtension parses image format from extension: +// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported. +func FormatFromExtension(ext string) (Format, error) { + if f, ok := formatFromExt[strings.ToLower(strings.TrimPrefix(ext, "."))]; ok { + return f, nil + } + return -1, ErrUnsupportedFormat +} + +// FormatFromFilename parses image format from filename extension: +// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported. +func FormatFromFilename(filename string) (Format, error) { + ext := filepath.Ext(filename) + return FormatFromExtension(ext) +} + +var ( + // ErrUnsupportedFormat means the given image format (or file extension) is unsupported. + ErrUnsupportedFormat = errors.New("imaging: unsupported image format") +) + +type fileSystem interface { + Create(string) (io.WriteCloser, error) + Open(string) (io.ReadCloser, error) +} + +type localFS struct{} + +func (localFS) Create(name string) (io.WriteCloser, error) { return os.Create(name) } +func (localFS) Open(name string) (io.ReadCloser, error) { return os.Open(name) } + +var fs fileSystem = localFS{} + +type decodeConfig struct { + autoOrientation bool +} + +var defaultDecodeConfig = decodeConfig{ + autoOrientation: false, +} + +// DecodeOption sets an optional parameter for the Decode and Open functions. +type DecodeOption func(*decodeConfig) + +// AutoOrientation returns a DecodeOption that sets the auto-orientation mode. +// If auto-orientation is enabled, the image will be transformed after decoding +// according to the EXIF orientation tag (if present). By default it's disabled. +func AutoOrientation(enabled bool) DecodeOption { + return func(c *decodeConfig) { + c.autoOrientation = enabled + } +} + +// Decode reads an image from r. +func Decode(r io.Reader, opts ...DecodeOption) (image.Image, error) { + cfg := defaultDecodeConfig + for _, option := range opts { + option(&cfg) + } + + if !cfg.autoOrientation { + img, _, err := image.Decode(r) + return img, err + } + + var orient orientation + pr, pw := io.Pipe() + r = io.TeeReader(r, pw) + done := make(chan struct{}) + go func() { + defer close(done) + orient = readOrientation(pr) + io.Copy(ioutil.Discard, pr) + }() + + img, _, err := image.Decode(r) + pw.Close() + <-done + if err != nil { + return nil, err + } + + return fixOrientation(img, orient), nil +} + +// Open loads an image from file. +// +// Examples: +// +// // Load an image from file. +// img, err := imaging.Open("test.jpg") +// +// // Load an image and transform it depending on the EXIF orientation tag (if present). +// img, err := imaging.Open("test.jpg", imaging.AutoOrientation(true)) +// +func Open(filename string, opts ...DecodeOption) (image.Image, error) { + file, err := fs.Open(filename) + if err != nil { + return nil, err + } + defer file.Close() + return Decode(file, opts...) +} + +type encodeConfig struct { + jpegQuality int + gifNumColors int + gifQuantizer draw.Quantizer + gifDrawer draw.Drawer + pngCompressionLevel png.CompressionLevel +} + +var defaultEncodeConfig = encodeConfig{ + jpegQuality: 95, + gifNumColors: 256, + gifQuantizer: nil, + gifDrawer: nil, + pngCompressionLevel: png.DefaultCompression, +} + +// EncodeOption sets an optional parameter for the Encode and Save functions. +type EncodeOption func(*encodeConfig) + +// JPEGQuality returns an EncodeOption that sets the output JPEG quality. +// Quality ranges from 1 to 100 inclusive, higher is better. Default is 95. +func JPEGQuality(quality int) EncodeOption { + return func(c *encodeConfig) { + c.jpegQuality = quality + } +} + +// GIFNumColors returns an EncodeOption that sets the maximum number of colors +// used in the GIF-encoded image. It ranges from 1 to 256. Default is 256. +func GIFNumColors(numColors int) EncodeOption { + return func(c *encodeConfig) { + c.gifNumColors = numColors + } +} + +// GIFQuantizer returns an EncodeOption that sets the quantizer that is used to produce +// a palette of the GIF-encoded image. +func GIFQuantizer(quantizer draw.Quantizer) EncodeOption { + return func(c *encodeConfig) { + c.gifQuantizer = quantizer + } +} + +// GIFDrawer returns an EncodeOption that sets the drawer that is used to convert +// the source image to the desired palette of the GIF-encoded image. +func GIFDrawer(drawer draw.Drawer) EncodeOption { + return func(c *encodeConfig) { + c.gifDrawer = drawer + } +} + +// PNGCompressionLevel returns an EncodeOption that sets the compression level +// of the PNG-encoded image. Default is png.DefaultCompression. +func PNGCompressionLevel(level png.CompressionLevel) EncodeOption { + return func(c *encodeConfig) { + c.pngCompressionLevel = level + } +} + +// Encode writes the image img to w in the specified format (JPEG, PNG, GIF, TIFF or BMP). +func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) error { + cfg := defaultEncodeConfig + for _, option := range opts { + option(&cfg) + } + + var err error + switch format { + case JPEG: + var rgba *image.RGBA + if nrgba, ok := img.(*image.NRGBA); ok { + if nrgba.Opaque() { + rgba = &image.RGBA{ + Pix: nrgba.Pix, + Stride: nrgba.Stride, + Rect: nrgba.Rect, + } + } + } + if rgba != nil { + err = jpeg.Encode(w, rgba, &jpeg.Options{Quality: cfg.jpegQuality}) + } else { + err = jpeg.Encode(w, img, &jpeg.Options{Quality: cfg.jpegQuality}) + } + + case PNG: + enc := png.Encoder{CompressionLevel: cfg.pngCompressionLevel} + err = enc.Encode(w, img) + + case GIF: + err = gif.Encode(w, img, &gif.Options{ + NumColors: cfg.gifNumColors, + Quantizer: cfg.gifQuantizer, + Drawer: cfg.gifDrawer, + }) + + case TIFF: + err = tiff.Encode(w, img, &tiff.Options{Compression: tiff.Deflate, Predictor: true}) + + case BMP: + err = bmp.Encode(w, img) + + default: + err = ErrUnsupportedFormat + } + return err +} + +// Save saves the image to file with the specified filename. +// The format is determined from the filename extension: +// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported. +// +// Examples: +// +// // Save the image as PNG. +// err := imaging.Save(img, "out.png") +// +// // Save the image as JPEG with optional quality parameter set to 80. +// err := imaging.Save(img, "out.jpg", imaging.JPEGQuality(80)) +// +func Save(img image.Image, filename string, opts ...EncodeOption) (err error) { + f, err := FormatFromFilename(filename) + if err != nil { + return err + } + file, err := fs.Create(filename) + if err != nil { + return err + } + + defer func() { + cerr := file.Close() + if err == nil { + err = cerr + } + }() + + return Encode(file, img, f, opts...) +} + +// orientation is an EXIF flag that specifies the transformation +// that should be applied to image to display it correctly. +type orientation int + +const ( + orientationUnspecified = 0 + orientationNormal = 1 + orientationFlipH = 2 + orientationRotate180 = 3 + orientationFlipV = 4 + orientationTranspose = 5 + orientationRotate270 = 6 + orientationTransverse = 7 + orientationRotate90 = 8 +) + +// readOrientation tries to read the orientation EXIF flag from image data in r. +// If the EXIF data block is not found or the orientation flag is not found +// or any other error occures while reading the data, it returns the +// orientationUnspecified (0) value. +func readOrientation(r io.Reader) orientation { + const ( + markerSOI = 0xffd8 + markerAPP1 = 0xffe1 + exifHeader = 0x45786966 + byteOrderBE = 0x4d4d + byteOrderLE = 0x4949 + orientationTag = 0x0112 + ) + + // Check if JPEG SOI marker is present. + var soi uint16 + if err := binary.Read(r, binary.BigEndian, &soi); err != nil { + return orientationUnspecified + } + if soi != markerSOI { + return orientationUnspecified // Missing JPEG SOI marker. + } + + // Find JPEG APP1 marker. + for { + var marker, size uint16 + if err := binary.Read(r, binary.BigEndian, &marker); err != nil { + return orientationUnspecified + } + if err := binary.Read(r, binary.BigEndian, &size); err != nil { + return orientationUnspecified + } + if marker>>8 != 0xff { + return orientationUnspecified // Invalid JPEG marker. + } + if marker == markerAPP1 { + break + } + if size < 2 { + return orientationUnspecified // Invalid block size. + } + if _, err := io.CopyN(ioutil.Discard, r, int64(size-2)); err != nil { + return orientationUnspecified + } + } + + // Check if EXIF header is present. + var header uint32 + if err := binary.Read(r, binary.BigEndian, &header); err != nil { + return orientationUnspecified + } + if header != exifHeader { + return orientationUnspecified + } + if _, err := io.CopyN(ioutil.Discard, r, 2); err != nil { + return orientationUnspecified + } + + // Read byte order information. + var ( + byteOrderTag uint16 + byteOrder binary.ByteOrder + ) + if err := binary.Read(r, binary.BigEndian, &byteOrderTag); err != nil { + return orientationUnspecified + } + switch byteOrderTag { + case byteOrderBE: + byteOrder = binary.BigEndian + case byteOrderLE: + byteOrder = binary.LittleEndian + default: + return orientationUnspecified // Invalid byte order flag. + } + if _, err := io.CopyN(ioutil.Discard, r, 2); err != nil { + return orientationUnspecified + } + + // Skip the EXIF offset. + var offset uint32 + if err := binary.Read(r, byteOrder, &offset); err != nil { + return orientationUnspecified + } + if offset < 8 { + return orientationUnspecified // Invalid offset value. + } + if _, err := io.CopyN(ioutil.Discard, r, int64(offset-8)); err != nil { + return orientationUnspecified + } + + // Read the number of tags. + var numTags uint16 + if err := binary.Read(r, byteOrder, &numTags); err != nil { + return orientationUnspecified + } + + // Find the orientation tag. + for i := 0; i < int(numTags); i++ { + var tag uint16 + if err := binary.Read(r, byteOrder, &tag); err != nil { + return orientationUnspecified + } + if tag != orientationTag { + if _, err := io.CopyN(ioutil.Discard, r, 10); err != nil { + return orientationUnspecified + } + continue + } + if _, err := io.CopyN(ioutil.Discard, r, 6); err != nil { + return orientationUnspecified + } + var val uint16 + if err := binary.Read(r, byteOrder, &val); err != nil { + return orientationUnspecified + } + if val < 1 || val > 8 { + return orientationUnspecified // Invalid tag value. + } + return orientation(val) + } + return orientationUnspecified // Missing orientation tag. +} + +// fixOrientation applies a transform to img corresponding to the given orientation flag. +func fixOrientation(img image.Image, o orientation) image.Image { + switch o { + case orientationNormal: + case orientationFlipH: + img = FlipH(img) + case orientationFlipV: + img = FlipV(img) + case orientationRotate90: + img = Rotate90(img) + case orientationRotate180: + img = Rotate180(img) + case orientationRotate270: + img = Rotate270(img) + case orientationTranspose: + img = Transpose(img) + case orientationTransverse: + img = Transverse(img) + } + return img +} diff --git a/vendor/github.com/disintegration/imaging/io_test.go b/vendor/github.com/disintegration/imaging/io_test.go new file mode 100644 index 0000000..e7b7087 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/io_test.go @@ -0,0 +1,435 @@ +package imaging + +import ( + "bytes" + "errors" + "image" + "image/color" + "image/color/palette" + "image/draw" + "image/png" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" +) + +var ( + errCreate = errors.New("failed to create file") + errClose = errors.New("failed to close file") + errOpen = errors.New("failed to open file") +) + +type badFS struct{} + +func (badFS) Create(name string) (io.WriteCloser, error) { + if name == "badFile.jpg" { + return badFile{ioutil.Discard}, nil + } + return nil, errCreate +} + +func (badFS) Open(name string) (io.ReadCloser, error) { + return nil, errOpen +} + +type badFile struct { + io.Writer +} + +func (badFile) Close() error { + return errClose +} + +type quantizer struct { + palette []color.Color +} + +func (q quantizer) Quantize(p color.Palette, m image.Image) color.Palette { + pal := make([]color.Color, len(p), cap(p)) + copy(pal, p) + n := cap(p) - len(p) + if n > len(q.palette) { + n = len(q.palette) + } + for i := 0; i < n; i++ { + pal = append(pal, q.palette[i]) + } + return pal +} + +func TestOpenSave(t *testing.T) { + imgWithoutAlpha := image.NewNRGBA(image.Rect(0, 0, 4, 6)) + imgWithoutAlpha.Pix = []uint8{ + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x88, 0x88, 0x88, 0xff, 0x88, 0x88, 0x88, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x88, 0x88, 0x88, 0xff, 0x88, 0x88, 0x88, 0xff, + } + imgWithAlpha := image.NewNRGBA(image.Rect(0, 0, 4, 6)) + imgWithAlpha.Pix = []uint8{ + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0x00, 0xff, 0x00, 0x80, 0x00, 0xff, 0x00, 0x80, + 0xff, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0x00, 0xff, 0x00, 0x80, 0x00, 0xff, 0x00, 0x80, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x88, 0x88, 0x88, 0x00, 0x88, 0x88, 0x88, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x88, 0x88, 0x88, 0x00, 0x88, 0x88, 0x88, 0x00, + } + + options := [][]EncodeOption{ + { + JPEGQuality(100), + }, + { + JPEGQuality(99), + GIFDrawer(draw.FloydSteinberg), + GIFNumColors(256), + GIFQuantizer(quantizer{palette.Plan9}), + PNGCompressionLevel(png.BestSpeed), + }, + } + + dir, err := ioutil.TempDir("", "imaging") + if err != nil { + t.Fatalf("failed to create temporary directory: %v", err) + } + defer os.RemoveAll(dir) + + for _, ext := range []string{"jpg", "jpeg", "png", "gif", "bmp", "tif", "tiff"} { + filename := filepath.Join(dir, "test."+ext) + + img := imgWithoutAlpha + if ext == "png" { + img = imgWithAlpha + } + + for _, opts := range options { + err := Save(img, filename, opts...) + if err != nil { + t.Fatalf("failed to save image (%q): %v", filename, err) + } + + img2, err := Open(filename) + if err != nil { + t.Fatalf("failed to open image (%q): %v", filename, err) + } + got := Clone(img2) + + delta := 0 + if ext == "jpg" || ext == "jpeg" || ext == "gif" { + delta = 3 + } + + if !compareNRGBA(got, img, delta) { + t.Fatalf("bad encode-decode result (ext=%q): got %#v want %#v", ext, got, img) + } + } + } + + buf := &bytes.Buffer{} + err = Encode(buf, imgWithAlpha, JPEG) + if err != nil { + t.Fatalf("failed to encode alpha to JPEG: %v", err) + } + + buf = &bytes.Buffer{} + err = Encode(buf, imgWithAlpha, Format(100)) + if err != ErrUnsupportedFormat { + t.Fatalf("got %v want ErrUnsupportedFormat", err) + } + + buf = bytes.NewBuffer([]byte("bad data")) + _, err = Decode(buf) + if err == nil { + t.Fatalf("decoding bad data: expected error got nil") + } + + err = Save(imgWithAlpha, filepath.Join(dir, "test.unknown")) + if err != ErrUnsupportedFormat { + t.Fatalf("got %v want ErrUnsupportedFormat", err) + } + + prevFS := fs + fs = badFS{} + defer func() { fs = prevFS }() + + err = Save(imgWithAlpha, "test.jpg") + if err != errCreate { + t.Fatalf("got error %v want errCreate", err) + } + + err = Save(imgWithAlpha, "badFile.jpg") + if err != errClose { + t.Fatalf("got error %v want errClose", err) + } + + _, err = Open("test.jpg") + if err != errOpen { + t.Fatalf("got error %v want errOpen", err) + } +} + +func TestFormats(t *testing.T) { + formatNames := map[Format]string{ + JPEG: "JPEG", + PNG: "PNG", + GIF: "GIF", + BMP: "BMP", + TIFF: "TIFF", + Format(-1): "Unsupported", + } + for format, name := range formatNames { + got := format.String() + if got != name { + t.Fatalf("got format name %q want %q", got, name) + } + } +} + +func TestFormatFromExtension(t *testing.T) { + testCases := []struct { + name string + ext string + want Format + err error + }{ + { + name: "jpg without leading dot", + ext: "jpg", + want: JPEG, + }, + { + name: "jpg with leading dot", + ext: ".jpg", + want: JPEG, + }, + { + name: "jpg uppercase", + ext: ".JPG", + want: JPEG, + }, + { + name: "unsupported", + ext: ".unsupportedextension", + want: -1, + err: ErrUnsupportedFormat, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got, err := FormatFromExtension(tc.ext) + if err != tc.err { + t.Errorf("got error %#v want %#v", err, tc.err) + } + if got != tc.want { + t.Errorf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestReadOrientation(t *testing.T) { + testCases := []struct { + path string + orient orientation + }{ + {"testdata/orientation_0.jpg", 0}, + {"testdata/orientation_1.jpg", 1}, + {"testdata/orientation_2.jpg", 2}, + {"testdata/orientation_3.jpg", 3}, + {"testdata/orientation_4.jpg", 4}, + {"testdata/orientation_5.jpg", 5}, + {"testdata/orientation_6.jpg", 6}, + {"testdata/orientation_7.jpg", 7}, + {"testdata/orientation_8.jpg", 8}, + } + for _, tc := range testCases { + f, err := os.Open(tc.path) + if err != nil { + t.Fatalf("%q: failed to open: %v", tc.path, err) + } + orient := readOrientation(f) + if orient != tc.orient { + t.Fatalf("%q: got orientation %d want %d", tc.path, orient, tc.orient) + } + } +} + +func TestReadOrientationFails(t *testing.T) { + testCases := []struct { + name string + data string + }{ + { + "empty", + "", + }, + { + "missing SOI marker", + "\xff\xe1", + }, + { + "missing APP1 marker", + "\xff\xd8", + }, + { + "short read marker", + "\xff\xd8\xff", + }, + { + "short read block size", + "\xff\xd8\xff\xe1\x00", + }, + { + "invalid marker", + "\xff\xd8\x00\xe1\x00\x00", + }, + { + "block size too small", + "\xff\xd8\xff\xe0\x00\x01", + }, + { + "short read block", + "\xff\xd8\xff\xe0\x00\x08\x00", + }, + { + "missing EXIF header", + "\xff\xd8\xff\xe1\x00\xff", + }, + { + "invalid EXIF header", + "\xff\xd8\xff\xe1\x00\xff\x00\x00\x00\x00", + }, + { + "missing EXIF header tail", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66", + }, + { + "missing byte order tag", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00", + }, + { + "invalid byte order tag", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x00\x00", + }, + { + "missing byte order tail", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x49\x49", + }, + { + "missing exif offset", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x49\x49\x00\x2a", + }, + { + "invalid exif offset", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x07", + }, + { + "read exif offset error", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x09", + }, + { + "missing number of tags", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08", + }, + { + "zero number of tags", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08\x00\x00", + }, + { + "missing tag", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08\x00\x01", + }, + { + "missing tag offset", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08\x00\x01\x00\x00", + }, + { + "missing orientation tag", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + }, + { + "missing orientation tag value offset", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08\x00\x01\x01\x12", + }, + { + "missing orientation value", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08\x00\x01\x01\x12\x00\x03\x00\x00\x00\x01", + }, + { + "invalid orientation value", + "\xff\xd8\xff\xe1\x00\xff\x45\x78\x69\x66\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08\x00\x01\x01\x12\x00\x03\x00\x00\x00\x01\x00\x09", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if o := readOrientation(strings.NewReader(tc.data)); o != orientationUnspecified { + t.Fatalf("got orientation %d want %d", o, orientationUnspecified) + } + }) + } +} + +func TestAutoOrientation(t *testing.T) { + toBW := func(img image.Image) []byte { + b := img.Bounds() + data := make([]byte, 0, b.Dx()*b.Dy()) + for x := b.Min.X; x < b.Max.X; x++ { + for y := b.Min.Y; y < b.Max.Y; y++ { + c := color.GrayModel.Convert(img.At(x, y)).(color.Gray) + if c.Y < 128 { + data = append(data, 1) + } else { + data = append(data, 0) + } + } + } + return data + } + + f, err := os.Open("testdata/orientation_0.jpg") + if err != nil { + t.Fatalf("os.Open(%q): %v", "testdata/orientation_0.jpg", err) + } + orig, _, err := image.Decode(f) + if err != nil { + t.Fatalf("image.Decode(%q): %v", "testdata/orientation_0.jpg", err) + } + origBW := toBW(orig) + + testCases := []struct { + path string + }{ + {"testdata/orientation_0.jpg"}, + {"testdata/orientation_1.jpg"}, + {"testdata/orientation_2.jpg"}, + {"testdata/orientation_3.jpg"}, + {"testdata/orientation_4.jpg"}, + {"testdata/orientation_5.jpg"}, + {"testdata/orientation_6.jpg"}, + {"testdata/orientation_7.jpg"}, + {"testdata/orientation_8.jpg"}, + } + for _, tc := range testCases { + img, err := Open(tc.path, AutoOrientation(true)) + if err != nil { + t.Fatal(err) + } + if img.Bounds() != orig.Bounds() { + t.Fatalf("%s: got bounds %v want %v", tc.path, img.Bounds(), orig.Bounds()) + } + imgBW := toBW(img) + if !bytes.Equal(imgBW, origBW) { + t.Fatalf("%s: got bw data %v want %v", tc.path, imgBW, origBW) + } + } + + if _, err := Decode(strings.NewReader("invalid data"), AutoOrientation(true)); err == nil { + t.Fatal("expected error got nil") + } +} diff --git a/vendor/github.com/disintegration/imaging/resize.go b/vendor/github.com/disintegration/imaging/resize.go new file mode 100644 index 0000000..4eaf604 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/resize.go @@ -0,0 +1,615 @@ +package imaging + +import ( + "image" + "math" +) + +type indexWeight struct { + index int + weight float64 +} + +func precomputeWeights(dstSize, srcSize int, filter ResampleFilter) [][]indexWeight { + du := float64(srcSize) / float64(dstSize) + scale := du + if scale < 1.0 { + scale = 1.0 + } + ru := math.Ceil(scale * filter.Support) + + out := make([][]indexWeight, dstSize) + tmp := make([]indexWeight, 0, dstSize*int(ru+2)*2) + + for v := 0; v < dstSize; v++ { + fu := (float64(v)+0.5)*du - 0.5 + + begin := int(math.Ceil(fu - ru)) + if begin < 0 { + begin = 0 + } + end := int(math.Floor(fu + ru)) + if end > srcSize-1 { + end = srcSize - 1 + } + + var sum float64 + for u := begin; u <= end; u++ { + w := filter.Kernel((float64(u) - fu) / scale) + if w != 0 { + sum += w + tmp = append(tmp, indexWeight{index: u, weight: w}) + } + } + if sum != 0 { + for i := range tmp { + tmp[i].weight /= sum + } + } + + out[v] = tmp + tmp = tmp[len(tmp):] + } + + return out +} + +// Resize resizes the image to the specified width and height using the specified resampling +// filter and returns the transformed image. If one of width or height is 0, the image aspect +// ratio is preserved. +// +// Supported resample filters: NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, +// CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. +// +// Usage example: +// +// dstImage := imaging.Resize(srcImage, 800, 600, imaging.Lanczos) +// +func Resize(img image.Image, width, height int, filter ResampleFilter) *image.NRGBA { + dstW, dstH := width, height + if dstW < 0 || dstH < 0 { + return &image.NRGBA{} + } + if dstW == 0 && dstH == 0 { + return &image.NRGBA{} + } + + srcW := img.Bounds().Dx() + srcH := img.Bounds().Dy() + if srcW <= 0 || srcH <= 0 { + return &image.NRGBA{} + } + + // If new width or height is 0 then preserve aspect ratio, minimum 1px. + if dstW == 0 { + tmpW := float64(dstH) * float64(srcW) / float64(srcH) + dstW = int(math.Max(1.0, math.Floor(tmpW+0.5))) + } + if dstH == 0 { + tmpH := float64(dstW) * float64(srcH) / float64(srcW) + dstH = int(math.Max(1.0, math.Floor(tmpH+0.5))) + } + + if filter.Support <= 0 { + // Nearest-neighbor special case. + return resizeNearest(img, dstW, dstH) + } + + if srcW != dstW && srcH != dstH { + return resizeVertical(resizeHorizontal(img, dstW, filter), dstH, filter) + } + if srcW != dstW { + return resizeHorizontal(img, dstW, filter) + } + if srcH != dstH { + return resizeVertical(img, dstH, filter) + } + return Clone(img) +} + +func resizeHorizontal(img image.Image, width int, filter ResampleFilter) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, width, src.h)) + weights := precomputeWeights(width, src.w, filter) + parallel(0, src.h, func(ys <-chan int) { + scanLine := make([]uint8, src.w*4) + for y := range ys { + src.scan(0, y, src.w, y+1, scanLine) + j0 := y * dst.Stride + for x := range weights { + var r, g, b, a float64 + for _, w := range weights[x] { + i := w.index * 4 + s := scanLine[i : i+4 : i+4] + aw := float64(s[3]) * w.weight + r += float64(s[0]) * aw + g += float64(s[1]) * aw + b += float64(s[2]) * aw + a += aw + } + if a != 0 { + aInv := 1 / a + j := j0 + x*4 + d := dst.Pix[j : j+4 : j+4] + d[0] = clamp(r * aInv) + d[1] = clamp(g * aInv) + d[2] = clamp(b * aInv) + d[3] = clamp(a) + } + } + } + }) + return dst +} + +func resizeVertical(img image.Image, height int, filter ResampleFilter) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, height)) + weights := precomputeWeights(height, src.h, filter) + parallel(0, src.w, func(xs <-chan int) { + scanLine := make([]uint8, src.h*4) + for x := range xs { + src.scan(x, 0, x+1, src.h, scanLine) + for y := range weights { + var r, g, b, a float64 + for _, w := range weights[y] { + i := w.index * 4 + s := scanLine[i : i+4 : i+4] + aw := float64(s[3]) * w.weight + r += float64(s[0]) * aw + g += float64(s[1]) * aw + b += float64(s[2]) * aw + a += aw + } + if a != 0 { + aInv := 1 / a + j := y*dst.Stride + x*4 + d := dst.Pix[j : j+4 : j+4] + d[0] = clamp(r * aInv) + d[1] = clamp(g * aInv) + d[2] = clamp(b * aInv) + d[3] = clamp(a) + } + } + } + }) + return dst +} + +// resizeNearest is a fast nearest-neighbor resize, no filtering. +func resizeNearest(img image.Image, width, height int) *image.NRGBA { + dst := image.NewNRGBA(image.Rect(0, 0, width, height)) + dx := float64(img.Bounds().Dx()) / float64(width) + dy := float64(img.Bounds().Dy()) / float64(height) + + if dx > 1 && dy > 1 { + src := newScanner(img) + parallel(0, height, func(ys <-chan int) { + for y := range ys { + srcY := int((float64(y) + 0.5) * dy) + dstOff := y * dst.Stride + for x := 0; x < width; x++ { + srcX := int((float64(x) + 0.5) * dx) + src.scan(srcX, srcY, srcX+1, srcY+1, dst.Pix[dstOff:dstOff+4]) + dstOff += 4 + } + } + }) + } else { + src := toNRGBA(img) + parallel(0, height, func(ys <-chan int) { + for y := range ys { + srcY := int((float64(y) + 0.5) * dy) + srcOff0 := srcY * src.Stride + dstOff := y * dst.Stride + for x := 0; x < width; x++ { + srcX := int((float64(x) + 0.5) * dx) + srcOff := srcOff0 + srcX*4 + copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4]) + dstOff += 4 + } + } + }) + } + + return dst +} + +// Fit scales down the image using the specified resample filter to fit the specified +// maximum width and height and returns the transformed image. +// +// Supported resample filters: NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, +// CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. +// +// Usage example: +// +// dstImage := imaging.Fit(srcImage, 800, 600, imaging.Lanczos) +// +func Fit(img image.Image, width, height int, filter ResampleFilter) *image.NRGBA { + maxW, maxH := width, height + + if maxW <= 0 || maxH <= 0 { + return &image.NRGBA{} + } + + srcBounds := img.Bounds() + srcW := srcBounds.Dx() + srcH := srcBounds.Dy() + + if srcW <= 0 || srcH <= 0 { + return &image.NRGBA{} + } + + if srcW <= maxW && srcH <= maxH { + return Clone(img) + } + + srcAspectRatio := float64(srcW) / float64(srcH) + maxAspectRatio := float64(maxW) / float64(maxH) + + var newW, newH int + if srcAspectRatio > maxAspectRatio { + newW = maxW + newH = int(float64(newW) / srcAspectRatio) + } else { + newH = maxH + newW = int(float64(newH) * srcAspectRatio) + } + + return Resize(img, newW, newH, filter) +} + +// Fill creates an image with the specified dimensions and fills it with the scaled source image. +// To achieve the correct aspect ratio without stretching, the source image will be cropped. +// +// Supported resample filters: NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, +// CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. +// +// Usage example: +// +// dstImage := imaging.Fill(srcImage, 800, 600, imaging.Center, imaging.Lanczos) +// +func Fill(img image.Image, width, height int, anchor Anchor, filter ResampleFilter) *image.NRGBA { + dstW, dstH := width, height + + if dstW <= 0 || dstH <= 0 { + return &image.NRGBA{} + } + + srcBounds := img.Bounds() + srcW := srcBounds.Dx() + srcH := srcBounds.Dy() + + if srcW <= 0 || srcH <= 0 { + return &image.NRGBA{} + } + + if srcW == dstW && srcH == dstH { + return Clone(img) + } + + if srcW >= 100 && srcH >= 100 { + return cropAndResize(img, dstW, dstH, anchor, filter) + } + return resizeAndCrop(img, dstW, dstH, anchor, filter) +} + +// cropAndResize crops the image to the smallest possible size that has the required aspect ratio using +// the given anchor point, then scales it to the specified dimensions and returns the transformed image. +// +// This is generally faster than resizing first, but may result in inaccuracies when used on small source images. +func cropAndResize(img image.Image, width, height int, anchor Anchor, filter ResampleFilter) *image.NRGBA { + dstW, dstH := width, height + + srcBounds := img.Bounds() + srcW := srcBounds.Dx() + srcH := srcBounds.Dy() + srcAspectRatio := float64(srcW) / float64(srcH) + dstAspectRatio := float64(dstW) / float64(dstH) + + var tmp *image.NRGBA + if srcAspectRatio < dstAspectRatio { + cropH := float64(srcW) * float64(dstH) / float64(dstW) + tmp = CropAnchor(img, srcW, int(math.Max(1, cropH)+0.5), anchor) + } else { + cropW := float64(srcH) * float64(dstW) / float64(dstH) + tmp = CropAnchor(img, int(math.Max(1, cropW)+0.5), srcH, anchor) + } + + return Resize(tmp, dstW, dstH, filter) +} + +// resizeAndCrop resizes the image to the smallest possible size that will cover the specified dimensions, +// crops the resized image to the specified dimensions using the given anchor point and returns +// the transformed image. +func resizeAndCrop(img image.Image, width, height int, anchor Anchor, filter ResampleFilter) *image.NRGBA { + dstW, dstH := width, height + + srcBounds := img.Bounds() + srcW := srcBounds.Dx() + srcH := srcBounds.Dy() + srcAspectRatio := float64(srcW) / float64(srcH) + dstAspectRatio := float64(dstW) / float64(dstH) + + var tmp *image.NRGBA + if srcAspectRatio < dstAspectRatio { + tmp = Resize(img, dstW, 0, filter) + } else { + tmp = Resize(img, 0, dstH, filter) + } + + return CropAnchor(tmp, dstW, dstH, anchor) +} + +// Thumbnail scales the image up or down using the specified resample filter, crops it +// to the specified width and hight and returns the transformed image. +// +// Supported resample filters: NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, +// CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. +// +// Usage example: +// +// dstImage := imaging.Thumbnail(srcImage, 100, 100, imaging.Lanczos) +// +func Thumbnail(img image.Image, width, height int, filter ResampleFilter) *image.NRGBA { + return Fill(img, width, height, Center, filter) +} + +// ResampleFilter is a resampling filter struct. It can be used to define custom filters. +// +// Supported resample filters: NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, +// CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. +// +// General filter recommendations: +// +// - Lanczos +// High-quality resampling filter for photographic images yielding sharp results. +// It's slower than cubic filters (see below). +// +// - CatmullRom +// A sharp cubic filter. It's a good filter for both upscaling and downscaling if sharp results are needed. +// +// - MitchellNetravali +// A high quality cubic filter that produces smoother results with less ringing artifacts than CatmullRom. +// +// - BSpline +// A good filter if a very smooth output is needed. +// +// - Linear +// Bilinear interpolation filter, produces reasonably good, smooth output. +// It's faster than cubic filters. +// +// - Box +// Simple and fast averaging filter appropriate for downscaling. +// When upscaling it's similar to NearestNeighbor. +// +// - NearestNeighbor +// Fastest resampling filter, no antialiasing. +// +type ResampleFilter struct { + Support float64 + Kernel func(float64) float64 +} + +// NearestNeighbor is a nearest-neighbor filter (no anti-aliasing). +var NearestNeighbor ResampleFilter + +// Box filter (averaging pixels). +var Box ResampleFilter + +// Linear filter. +var Linear ResampleFilter + +// Hermite cubic spline filter (BC-spline; B=0; C=0). +var Hermite ResampleFilter + +// MitchellNetravali is Mitchell-Netravali cubic filter (BC-spline; B=1/3; C=1/3). +var MitchellNetravali ResampleFilter + +// CatmullRom is a Catmull-Rom - sharp cubic filter (BC-spline; B=0; C=0.5). +var CatmullRom ResampleFilter + +// BSpline is a smooth cubic filter (BC-spline; B=1; C=0). +var BSpline ResampleFilter + +// Gaussian is a Gaussian blurring Filter. +var Gaussian ResampleFilter + +// Bartlett is a Bartlett-windowed sinc filter (3 lobes). +var Bartlett ResampleFilter + +// Lanczos filter (3 lobes). +var Lanczos ResampleFilter + +// Hann is a Hann-windowed sinc filter (3 lobes). +var Hann ResampleFilter + +// Hamming is a Hamming-windowed sinc filter (3 lobes). +var Hamming ResampleFilter + +// Blackman is a Blackman-windowed sinc filter (3 lobes). +var Blackman ResampleFilter + +// Welch is a Welch-windowed sinc filter (parabolic window, 3 lobes). +var Welch ResampleFilter + +// Cosine is a Cosine-windowed sinc filter (3 lobes). +var Cosine ResampleFilter + +func bcspline(x, b, c float64) float64 { + var y float64 + x = math.Abs(x) + if x < 1.0 { + y = ((12-9*b-6*c)*x*x*x + (-18+12*b+6*c)*x*x + (6 - 2*b)) / 6 + } else if x < 2.0 { + y = ((-b-6*c)*x*x*x + (6*b+30*c)*x*x + (-12*b-48*c)*x + (8*b + 24*c)) / 6 + } + return y +} + +func sinc(x float64) float64 { + if x == 0 { + return 1 + } + return math.Sin(math.Pi*x) / (math.Pi * x) +} + +func init() { + NearestNeighbor = ResampleFilter{ + Support: 0.0, // special case - not applying the filter + } + + Box = ResampleFilter{ + Support: 0.5, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x <= 0.5 { + return 1.0 + } + return 0 + }, + } + + Linear = ResampleFilter{ + Support: 1.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 1.0 { + return 1.0 - x + } + return 0 + }, + } + + Hermite = ResampleFilter{ + Support: 1.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 1.0 { + return bcspline(x, 0.0, 0.0) + } + return 0 + }, + } + + MitchellNetravali = ResampleFilter{ + Support: 2.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 2.0 { + return bcspline(x, 1.0/3.0, 1.0/3.0) + } + return 0 + }, + } + + CatmullRom = ResampleFilter{ + Support: 2.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 2.0 { + return bcspline(x, 0.0, 0.5) + } + return 0 + }, + } + + BSpline = ResampleFilter{ + Support: 2.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 2.0 { + return bcspline(x, 1.0, 0.0) + } + return 0 + }, + } + + Gaussian = ResampleFilter{ + Support: 2.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 2.0 { + return math.Exp(-2 * x * x) + } + return 0 + }, + } + + Bartlett = ResampleFilter{ + Support: 3.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 3.0 { + return sinc(x) * (3.0 - x) / 3.0 + } + return 0 + }, + } + + Lanczos = ResampleFilter{ + Support: 3.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 3.0 { + return sinc(x) * sinc(x/3.0) + } + return 0 + }, + } + + Hann = ResampleFilter{ + Support: 3.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 3.0 { + return sinc(x) * (0.5 + 0.5*math.Cos(math.Pi*x/3.0)) + } + return 0 + }, + } + + Hamming = ResampleFilter{ + Support: 3.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 3.0 { + return sinc(x) * (0.54 + 0.46*math.Cos(math.Pi*x/3.0)) + } + return 0 + }, + } + + Blackman = ResampleFilter{ + Support: 3.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 3.0 { + return sinc(x) * (0.42 - 0.5*math.Cos(math.Pi*x/3.0+math.Pi) + 0.08*math.Cos(2.0*math.Pi*x/3.0)) + } + return 0 + }, + } + + Welch = ResampleFilter{ + Support: 3.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 3.0 { + return sinc(x) * (1.0 - (x * x / 9.0)) + } + return 0 + }, + } + + Cosine = ResampleFilter{ + Support: 3.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 3.0 { + return sinc(x) * math.Cos((math.Pi/2.0)*(x/3.0)) + } + return 0 + }, + } +} diff --git a/vendor/github.com/disintegration/imaging/resize_test.go b/vendor/github.com/disintegration/imaging/resize_test.go new file mode 100644 index 0000000..2bdfa1a --- /dev/null +++ b/vendor/github.com/disintegration/imaging/resize_test.go @@ -0,0 +1,963 @@ +package imaging + +import ( + "fmt" + "image" + "path/filepath" + "testing" +) + +func TestResize(t *testing.T) { + testCases := []struct { + name string + src image.Image + w, h int + f ResampleFilter + want *image.NRGBA + }{ + { + "Resize 2x2 1x1 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 1, 1, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 1), + Stride: 1 * 4, + Pix: []uint8{0x55, 0x55, 0x55, 0xc0}, + }, + }, + { + "Resize 2x2 1x2 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 1, 2, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 2), + Stride: 1 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0x80, + 0x00, 0x80, 0x80, 0xff, + }, + }, + }, + { + "Resize 2x2 2x1 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 2, 1, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0xff, 0x00, 0x80, 0x80, 0x00, 0x80, 0xff, + }, + }, + }, + { + "Resize 2x2 2x2 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 2, 2, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + }, + { + "Resize 3x1 1x1 nearest", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 0), + Stride: 3 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 1, 1, + NearestNeighbor, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 1), + Stride: 1 * 4, + Pix: []uint8{0x00, 0xff, 0x00, 0xff}, + }, + }, + { + "Resize 2x2 0x4 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 0, 4, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + }, + { + "Resize 2x2 4x0 linear", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 4, 0, + Linear, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x40, 0xff, 0x00, 0x00, 0xbf, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0x40, 0x6e, 0x6d, 0x25, 0x70, 0xb0, 0x14, 0x3b, 0xcf, 0xbf, 0x00, 0x40, 0xff, + 0x00, 0xff, 0x00, 0xbf, 0x14, 0xb0, 0x3b, 0xcf, 0x33, 0x33, 0x99, 0xef, 0x40, 0x00, 0xbf, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xbf, 0x40, 0xff, 0x00, 0x40, 0xbf, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + }, + { + "Resize 0x0 1x1 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, -1, -1), + Stride: 0, + Pix: []uint8{}, + }, + 1, 1, + Box, + &image.NRGBA{}, + }, + { + "Resize 2x2 0x0 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 0, 0, + Box, + &image.NRGBA{}, + }, + { + "Resize 2x2 -1x0 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + -1, 0, + Box, + &image.NRGBA{}, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Resize(tc.src, tc.w, tc.h, tc.f) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestResampleFilters(t *testing.T) { + for _, filter := range []ResampleFilter{ + NearestNeighbor, + Box, + Linear, + Hermite, + MitchellNetravali, + CatmullRom, + BSpline, + Gaussian, + Lanczos, + Hann, + Hamming, + Blackman, + Bartlett, + Welch, + Cosine, + } { + t.Run("", func(t *testing.T) { + src := image.NewNRGBA(image.Rect(-1, -1, 2, 3)) + got := Resize(src, 5, 6, filter) + want := image.NewNRGBA(image.Rect(0, 0, 5, 6)) + if !compareNRGBA(got, want, 0) { + t.Fatalf("got result %#v want %#v", got, want) + } + if filter.Kernel != nil { + if x := filter.Kernel(filter.Support + 0.0001); x != 0 { + t.Fatalf("got kernel value %f want 0", x) + } + } + }) + } +} + +func TestResizeGolden(t *testing.T) { + for name, filter := range map[string]ResampleFilter{ + "out_resize_nearest.png": NearestNeighbor, + "out_resize_linear.png": Linear, + "out_resize_catrom.png": CatmullRom, + "out_resize_lanczos.png": Lanczos, + } { + got := Resize(testdataBranchesPNG, 150, 0, filter) + want, err := Open("testdata/" + name) + if err != nil { + t.Fatalf("failed to open image: %v", err) + } + if !compareNRGBA(got, toNRGBA(want), 0) { + t.Fatalf("resulting image differs from golden: %s", name) + } + } +} + +func TestFit(t *testing.T) { + testCases := []struct { + name string + src image.Image + w, h int + f ResampleFilter + want *image.NRGBA + }{ + { + "Fit 2x2 1x10 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 1, 10, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 1), + Stride: 1 * 4, + Pix: []uint8{0x55, 0x55, 0x55, 0xc0}, + }, + }, + { + "Fit 2x2 10x1 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 10, 1, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 1), + Stride: 1 * 4, + Pix: []uint8{0x55, 0x55, 0x55, 0xc0}, + }, + }, + { + "Fit 2x2 10x10 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 10, 10, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + }, + { + "Fit 0x0 1x1 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, -1, -1), + Stride: 0, + Pix: []uint8{}, + }, + 1, 1, + Box, + &image.NRGBA{}, + }, + { + "Fit 2x2 0x0 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + 0, 0, + Box, + &image.NRGBA{}, + }, + { + "Fit 2x2 -1x0 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + }, + }, + -1, 0, + Box, + &image.NRGBA{}, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Fit(tc.src, tc.w, tc.h, tc.f) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestFitGolden(t *testing.T) { + got := Fit(testdataBranchesPNG, 150, 150, Box) + name := filepath.Join("testdata", "out_fit.png") + want, err := Open(name) + if err != nil { + t.Fatalf("failed to open image: %v", err) + } + if !compareNRGBA(got, toNRGBA(want), 0) { + t.Fatalf("resulting image differs from golden: %s", name) + } +} + +func TestFill(t *testing.T) { + testCases := []struct { + name string + src image.Image + w, h int + a Anchor + f ResampleFilter + want *image.NRGBA + }{ + { + "Fill 4x4 4x4 TopRight Box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 4, 4, + TopRight, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + { + "Fill 4x4 0x4 Left Box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 0, 4, + Left, + Box, + &image.NRGBA{}, + }, + { + "Fill 0x0 4x4 Right Box", + &image.NRGBA{}, + 4, 4, + Right, + Box, + &image.NRGBA{}, + }, + { + "Fill 100x200 20x10 Center Linear", + image.NewRGBA(image.Rect(0, 0, 100, 200)), + 20, 10, + Center, + Linear, + image.NewNRGBA(image.Rect(0, 0, 20, 10)), + }, + { + "Fill 10x20 20x10 Center Linear", + image.NewRGBA(image.Rect(0, 0, 10, 20)), + 20, 10, + Center, + Linear, + image.NewNRGBA(image.Rect(0, 0, 20, 10)), + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Fill(tc.src, tc.w, tc.h, tc.a, tc.f) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestFillGolden(t *testing.T) { + anchorPoints := map[string]Anchor{ + "left": Left, + "center": Center, + "right": Right, + } + for apName, ap := range anchorPoints { + got := Fill(testdataBranchesPNG, 150, 150, ap, Box) + name := filepath.Join("testdata", "out_fill_"+apName+".png") + want, err := Open(name) + if err != nil { + t.Fatalf("failed to open image: %v", err) + } + if !compareNRGBA(got, toNRGBA(want), 0) { + t.Fatalf("resulting image differs from golden: %s", name) + } + } +} + +func TestResizeAndCrop(t *testing.T) { + testCases := []struct { + name string + src image.Image + w, h int + a Anchor + f ResampleFilter + want *image.NRGBA + }{ + { + "resizeAndCrop 4x4 2x2 Center Nearest", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 2, + Center, + NearestNeighbor, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x14, 0x15, 0x16, 0x17, 0x1c, 0x1d, 0x1e, 0x1f, + 0x34, 0x35, 0x36, 0x37, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + { + "resizeAndCrop 4x4 1x4 TopLeft Nearest", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 1, 4, + TopLeft, + NearestNeighbor, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 4), + Stride: 1 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, + 0x10, 0x11, 0x12, 0x13, + 0x20, 0x21, 0x22, 0x23, + 0x30, 0x31, 0x32, 0x33, + }, + }, + }, + { + "resizeAndCrop 4x4 8x2 Bottom Nearest", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 8, 2, + Bottom, + NearestNeighbor, + &image.NRGBA{ + Rect: image.Rect(0, 0, 8, 2), + Stride: 8 * 4, + Pix: []uint8{ + 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f, + 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + { + "resizeAndCrop 4x4 2x8 Top Nearest", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 8, + Top, + NearestNeighbor, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 8), + Stride: 2 * 4, + Pix: []uint8{ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + }, + }, + }, + { + "resizeAndCrop 4x4 4x4 TopRight Box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 4, 4, + TopRight, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := resizeAndCrop(tc.src, tc.w, tc.h, tc.a, tc.f) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestCropAndResize(t *testing.T) { + testCases := []struct { + name string + src image.Image + w, h int + a Anchor + f ResampleFilter + want *image.NRGBA + }{ + { + "cropAndResize 4x4 2x2 Center Nearest", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 2, + Center, + NearestNeighbor, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x14, 0x15, 0x16, 0x17, 0x1c, 0x1d, 0x1e, 0x1f, + 0x34, 0x35, 0x36, 0x37, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + { + "cropAndResize 4x4 1x4 TopLeft Nearest", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 1, 4, + TopLeft, + NearestNeighbor, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 4), + Stride: 1 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, + 0x10, 0x11, 0x12, 0x13, + 0x20, 0x21, 0x22, 0x23, + 0x30, 0x31, 0x32, 0x33, + }, + }, + }, + { + "cropAndResize 4x4 8x2 Bottom Nearest", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 8, 2, + Bottom, + NearestNeighbor, + &image.NRGBA{ + Rect: image.Rect(0, 0, 8, 2), + Stride: 8 * 4, + Pix: []uint8{ + 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f, + 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + { + "cropAndResize 4x4 2x8 Top Nearest", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 8, + Top, + NearestNeighbor, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 8), + Stride: 2 * 4, + Pix: []uint8{ + 0x04, 0x05, 0x06, 0x07, 0x04, 0x05, 0x06, 0x07, + 0x04, 0x05, 0x06, 0x07, 0x04, 0x05, 0x06, 0x07, + 0x14, 0x15, 0x16, 0x17, 0x14, 0x15, 0x16, 0x17, + 0x14, 0x15, 0x16, 0x17, 0x14, 0x15, 0x16, 0x17, + 0x24, 0x25, 0x26, 0x27, 0x24, 0x25, 0x26, 0x27, + 0x24, 0x25, 0x26, 0x27, 0x24, 0x25, 0x26, 0x27, + 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, + 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, + }, + }, + }, + { + "cropAndResize 4x4 4x4 TopRight Box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 4, 4, + TopRight, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := cropAndResize(tc.src, tc.w, tc.h, tc.a, tc.f) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestThumbnail(t *testing.T) { + testCases := []struct { + name string + src image.Image + w, h int + f ResampleFilter + want *image.NRGBA + }{ + { + "Thumbnail 6x2 1x1 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 5, 1), + Stride: 6 * 4, + Pix: []uint8{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 1, 1, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 1), + Stride: 1 * 4, + Pix: []uint8{0x55, 0x55, 0x55, 0xc0}, + }, + }, + { + "Thumbnail 2x6 1x1 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 5), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 1, 1, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 1), + Stride: 1 * 4, + Pix: []uint8{0x55, 0x55, 0x55, 0xc0}, + }, + }, + { + "Thumbnail 1x3 2x2 box", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 0, 2), + Stride: 1 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, + }, + }, + 2, 2, + Box, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Thumbnail(tc.src, tc.w, tc.h, tc.f) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkResize(b *testing.B) { + for _, dir := range []string{"Down", "Up"} { + for _, filter := range []string{"NearestNeighbor", "Linear", "CatmullRom", "Lanczos"} { + for _, format := range []string{"JPEG", "PNG"} { + var size int + switch dir { + case "Down": + size = 100 + case "Up": + size = 1000 + } + + var f ResampleFilter + switch filter { + case "NearestNeighbor": + f = NearestNeighbor + case "Linear": + f = Linear + case "CatmullRom": + f = CatmullRom + case "Lanczos": + f = Lanczos + } + + var img image.Image + switch format { + case "JPEG": + img = testdataBranchesJPG + case "PNG": + img = testdataBranchesPNG + } + + b.Run(fmt.Sprintf("%s %s %s", dir, filter, format), func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Resize(img, size, size, f) + } + }) + } + } + } +} + +func BenchmarkFill(b *testing.B) { + for _, dir := range []string{"Vertical", "Horizontal"} { + for _, filter := range []string{"NearestNeighbor", "Linear", "CatmullRom", "Lanczos"} { + for _, format := range []string{"JPEG", "PNG"} { + var width, height int + switch dir { + case "Vertical": + width = 100 + height = 1000 + case "Horizontal": + width = 1000 + height = 100 + } + + var f ResampleFilter + switch filter { + case "NearestNeighbor": + f = NearestNeighbor + case "Linear": + f = Linear + case "CatmullRom": + f = CatmullRom + case "Lanczos": + f = Lanczos + } + + var img image.Image + switch format { + case "JPEG": + img = testdataBranchesJPG + case "PNG": + img = testdataBranchesPNG + } + + b.Run(fmt.Sprintf("%s %s %s", dir, filter, format), func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Fill(img, width, height, Center, f) + } + }) + } + } + } +} diff --git a/vendor/github.com/disintegration/imaging/scanner.go b/vendor/github.com/disintegration/imaging/scanner.go new file mode 100644 index 0000000..37d92ce --- /dev/null +++ b/vendor/github.com/disintegration/imaging/scanner.go @@ -0,0 +1,285 @@ +package imaging + +import ( + "image" + "image/color" +) + +type scanner struct { + image image.Image + w, h int + palette []color.NRGBA +} + +func newScanner(img image.Image) *scanner { + s := &scanner{ + image: img, + w: img.Bounds().Dx(), + h: img.Bounds().Dy(), + } + if img, ok := img.(*image.Paletted); ok { + s.palette = make([]color.NRGBA, len(img.Palette)) + for i := 0; i < len(img.Palette); i++ { + s.palette[i] = color.NRGBAModel.Convert(img.Palette[i]).(color.NRGBA) + } + } + return s +} + +// scan scans the given rectangular region of the image into dst. +func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) { + switch img := s.image.(type) { + case *image.NRGBA: + size := (x2 - x1) * 4 + j := 0 + i := y1*img.Stride + x1*4 + if size == 4 { + for y := y1; y < y2; y++ { + d := dst[j : j+4 : j+4] + s := img.Pix[i : i+4 : i+4] + d[0] = s[0] + d[1] = s[1] + d[2] = s[2] + d[3] = s[3] + j += size + i += img.Stride + } + } else { + for y := y1; y < y2; y++ { + copy(dst[j:j+size], img.Pix[i:i+size]) + j += size + i += img.Stride + } + } + + case *image.NRGBA64: + j := 0 + for y := y1; y < y2; y++ { + i := y*img.Stride + x1*8 + for x := x1; x < x2; x++ { + s := img.Pix[i : i+8 : i+8] + d := dst[j : j+4 : j+4] + d[0] = s[0] + d[1] = s[2] + d[2] = s[4] + d[3] = s[6] + j += 4 + i += 8 + } + } + + case *image.RGBA: + j := 0 + for y := y1; y < y2; y++ { + i := y*img.Stride + x1*4 + for x := x1; x < x2; x++ { + d := dst[j : j+4 : j+4] + a := img.Pix[i+3] + switch a { + case 0: + d[0] = 0 + d[1] = 0 + d[2] = 0 + d[3] = a + case 0xff: + s := img.Pix[i : i+4 : i+4] + d[0] = s[0] + d[1] = s[1] + d[2] = s[2] + d[3] = a + default: + s := img.Pix[i : i+4 : i+4] + r16 := uint16(s[0]) + g16 := uint16(s[1]) + b16 := uint16(s[2]) + a16 := uint16(a) + d[0] = uint8(r16 * 0xff / a16) + d[1] = uint8(g16 * 0xff / a16) + d[2] = uint8(b16 * 0xff / a16) + d[3] = a + } + j += 4 + i += 4 + } + } + + case *image.RGBA64: + j := 0 + for y := y1; y < y2; y++ { + i := y*img.Stride + x1*8 + for x := x1; x < x2; x++ { + s := img.Pix[i : i+8 : i+8] + d := dst[j : j+4 : j+4] + a := s[6] + switch a { + case 0: + d[0] = 0 + d[1] = 0 + d[2] = 0 + case 0xff: + d[0] = s[0] + d[1] = s[2] + d[2] = s[4] + default: + r32 := uint32(s[0])<<8 | uint32(s[1]) + g32 := uint32(s[2])<<8 | uint32(s[3]) + b32 := uint32(s[4])<<8 | uint32(s[5]) + a32 := uint32(s[6])<<8 | uint32(s[7]) + d[0] = uint8((r32 * 0xffff / a32) >> 8) + d[1] = uint8((g32 * 0xffff / a32) >> 8) + d[2] = uint8((b32 * 0xffff / a32) >> 8) + } + d[3] = a + j += 4 + i += 8 + } + } + + case *image.Gray: + j := 0 + for y := y1; y < y2; y++ { + i := y*img.Stride + x1 + for x := x1; x < x2; x++ { + c := img.Pix[i] + d := dst[j : j+4 : j+4] + d[0] = c + d[1] = c + d[2] = c + d[3] = 0xff + j += 4 + i++ + } + } + + case *image.Gray16: + j := 0 + for y := y1; y < y2; y++ { + i := y*img.Stride + x1*2 + for x := x1; x < x2; x++ { + c := img.Pix[i] + d := dst[j : j+4 : j+4] + d[0] = c + d[1] = c + d[2] = c + d[3] = 0xff + j += 4 + i += 2 + } + } + + case *image.YCbCr: + j := 0 + x1 += img.Rect.Min.X + x2 += img.Rect.Min.X + y1 += img.Rect.Min.Y + y2 += img.Rect.Min.Y + + hy := img.Rect.Min.Y / 2 + hx := img.Rect.Min.X / 2 + for y := y1; y < y2; y++ { + iy := (y-img.Rect.Min.Y)*img.YStride + (x1 - img.Rect.Min.X) + + var yBase int + switch img.SubsampleRatio { + case image.YCbCrSubsampleRatio444, image.YCbCrSubsampleRatio422: + yBase = (y - img.Rect.Min.Y) * img.CStride + case image.YCbCrSubsampleRatio420, image.YCbCrSubsampleRatio440: + yBase = (y/2 - hy) * img.CStride + } + + for x := x1; x < x2; x++ { + var ic int + switch img.SubsampleRatio { + case image.YCbCrSubsampleRatio444, image.YCbCrSubsampleRatio440: + ic = yBase + (x - img.Rect.Min.X) + case image.YCbCrSubsampleRatio422, image.YCbCrSubsampleRatio420: + ic = yBase + (x/2 - hx) + default: + ic = img.COffset(x, y) + } + + yy1 := int32(img.Y[iy]) * 0x10101 + cb1 := int32(img.Cb[ic]) - 128 + cr1 := int32(img.Cr[ic]) - 128 + + r := yy1 + 91881*cr1 + if uint32(r)&0xff000000 == 0 { + r >>= 16 + } else { + r = ^(r >> 31) + } + + g := yy1 - 22554*cb1 - 46802*cr1 + if uint32(g)&0xff000000 == 0 { + g >>= 16 + } else { + g = ^(g >> 31) + } + + b := yy1 + 116130*cb1 + if uint32(b)&0xff000000 == 0 { + b >>= 16 + } else { + b = ^(b >> 31) + } + + d := dst[j : j+4 : j+4] + d[0] = uint8(r) + d[1] = uint8(g) + d[2] = uint8(b) + d[3] = 0xff + + iy++ + j += 4 + } + } + + case *image.Paletted: + j := 0 + for y := y1; y < y2; y++ { + i := y*img.Stride + x1 + for x := x1; x < x2; x++ { + c := s.palette[img.Pix[i]] + d := dst[j : j+4 : j+4] + d[0] = c.R + d[1] = c.G + d[2] = c.B + d[3] = c.A + j += 4 + i++ + } + } + + default: + j := 0 + b := s.image.Bounds() + x1 += b.Min.X + x2 += b.Min.X + y1 += b.Min.Y + y2 += b.Min.Y + for y := y1; y < y2; y++ { + for x := x1; x < x2; x++ { + r16, g16, b16, a16 := s.image.At(x, y).RGBA() + d := dst[j : j+4 : j+4] + switch a16 { + case 0xffff: + d[0] = uint8(r16 >> 8) + d[1] = uint8(g16 >> 8) + d[2] = uint8(b16 >> 8) + d[3] = 0xff + case 0: + d[0] = 0 + d[1] = 0 + d[2] = 0 + d[3] = 0 + default: + d[0] = uint8(((r16 * 0xffff) / a16) >> 8) + d[1] = uint8(((g16 * 0xffff) / a16) >> 8) + d[2] = uint8(((b16 * 0xffff) / a16) >> 8) + d[3] = uint8(a16 >> 8) + } + j += 4 + } + } + } +} diff --git a/vendor/github.com/disintegration/imaging/scanner_test.go b/vendor/github.com/disintegration/imaging/scanner_test.go new file mode 100644 index 0000000..6ce4b34 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/scanner_test.go @@ -0,0 +1,229 @@ +package imaging + +import ( + "fmt" + "image" + "image/color" + "image/color/palette" + "image/draw" + "testing" +) + +func TestScanner(t *testing.T) { + rect := image.Rect(-1, -1, 15, 15) + colors := palette.Plan9 + testCases := []struct { + name string + img image.Image + }{ + { + name: "NRGBA", + img: makeNRGBAImage(rect, colors), + }, + { + name: "NRGBA64", + img: makeNRGBA64Image(rect, colors), + }, + { + name: "RGBA", + img: makeRGBAImage(rect, colors), + }, + { + name: "RGBA64", + img: makeRGBA64Image(rect, colors), + }, + { + name: "Gray", + img: makeGrayImage(rect, colors), + }, + { + name: "Gray16", + img: makeGray16Image(rect, colors), + }, + { + name: "YCbCr-444", + img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio444), + }, + { + name: "YCbCr-422", + img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio422), + }, + { + name: "YCbCr-420", + img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio420), + }, + { + name: "YCbCr-440", + img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio440), + }, + { + name: "YCbCr-410", + img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio410), + }, + { + name: "YCbCr-411", + img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio411), + }, + { + name: "Paletted", + img: makePalettedImage(rect, colors), + }, + { + name: "Alpha", + img: makeAlphaImage(rect, colors), + }, + { + name: "Alpha16", + img: makeAlpha16Image(rect, colors), + }, + { + name: "Generic", + img: makeGenericImage(rect, colors), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + r := tc.img.Bounds() + s := newScanner(tc.img) + for y := r.Min.Y; y < r.Max.Y; y++ { + buf := make([]byte, r.Dx()*4) + s.scan(0, y-r.Min.Y, r.Dx(), y+1-r.Min.Y, buf) + wantBuf := readRow(tc.img, y) + if !compareBytes(buf, wantBuf, 1) { + fmt.Println(tc.img) + t.Fatalf("scan horizontal line (y=%d): got %v want %v", y, buf, wantBuf) + } + } + for x := r.Min.X; x < r.Max.X; x++ { + buf := make([]byte, r.Dy()*4) + s.scan(x-r.Min.X, 0, x+1-r.Min.X, r.Dy(), buf) + wantBuf := readColumn(tc.img, x) + if !compareBytes(buf, wantBuf, 1) { + t.Fatalf("scan vertical line (x=%d): got %v want %v", x, buf, wantBuf) + } + } + }) + } +} + +func makeYCbCrImage(rect image.Rectangle, colors []color.Color, sr image.YCbCrSubsampleRatio) *image.YCbCr { + img := image.NewYCbCr(rect, sr) + j := 0 + for y := rect.Min.Y; y < rect.Max.Y; y++ { + for x := rect.Min.X; x < rect.Max.X; x++ { + iy := img.YOffset(x, y) + ic := img.COffset(x, y) + c := color.NRGBAModel.Convert(colors[j]).(color.NRGBA) + img.Y[iy], img.Cb[ic], img.Cr[ic] = color.RGBToYCbCr(c.R, c.G, c.B) + j++ + } + } + return img +} + +func makeNRGBAImage(rect image.Rectangle, colors []color.Color) *image.NRGBA { + img := image.NewNRGBA(rect) + fillDrawImage(img, colors) + return img +} + +func makeNRGBA64Image(rect image.Rectangle, colors []color.Color) *image.NRGBA64 { + img := image.NewNRGBA64(rect) + fillDrawImage(img, colors) + return img +} + +func makeRGBAImage(rect image.Rectangle, colors []color.Color) *image.RGBA { + img := image.NewRGBA(rect) + fillDrawImage(img, colors) + return img +} + +func makeRGBA64Image(rect image.Rectangle, colors []color.Color) *image.RGBA64 { + img := image.NewRGBA64(rect) + fillDrawImage(img, colors) + return img +} + +func makeGrayImage(rect image.Rectangle, colors []color.Color) *image.Gray { + img := image.NewGray(rect) + fillDrawImage(img, colors) + return img +} + +func makeGray16Image(rect image.Rectangle, colors []color.Color) *image.Gray16 { + img := image.NewGray16(rect) + fillDrawImage(img, colors) + return img +} + +func makePalettedImage(rect image.Rectangle, colors []color.Color) *image.Paletted { + img := image.NewPaletted(rect, colors) + fillDrawImage(img, colors) + return img +} + +func makeAlphaImage(rect image.Rectangle, colors []color.Color) *image.Alpha { + img := image.NewAlpha(rect) + fillDrawImage(img, colors) + return img +} + +func makeAlpha16Image(rect image.Rectangle, colors []color.Color) *image.Alpha16 { + img := image.NewAlpha16(rect) + fillDrawImage(img, colors) + return img +} + +func makeGenericImage(rect image.Rectangle, colors []color.Color) image.Image { + img := image.NewRGBA(rect) + fillDrawImage(img, colors) + type genericImage struct{ *image.RGBA } + return &genericImage{img} +} + +func fillDrawImage(img draw.Image, colors []color.Color) { + colorsNRGBA := make([]color.NRGBA, len(colors)) + for i, c := range colors { + nrgba := color.NRGBAModel.Convert(c).(color.NRGBA) + nrgba.A = uint8(i % 256) + colorsNRGBA[i] = nrgba + } + rect := img.Bounds() + i := 0 + for y := rect.Min.Y; y < rect.Max.Y; y++ { + for x := rect.Min.X; x < rect.Max.X; x++ { + img.Set(x, y, colorsNRGBA[i]) + i++ + } + } +} + +func readRow(img image.Image, y int) []uint8 { + row := make([]byte, img.Bounds().Dx()*4) + i := 0 + for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ { + c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA) + row[i+0] = c.R + row[i+1] = c.G + row[i+2] = c.B + row[i+3] = c.A + i += 4 + } + return row +} + +func readColumn(img image.Image, x int) []uint8 { + column := make([]byte, img.Bounds().Dy()*4) + i := 0 + for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ { + c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA) + column[i+0] = c.R + column[i+1] = c.G + column[i+2] = c.B + column[i+3] = c.A + i += 4 + } + return column +} diff --git a/vendor/github.com/disintegration/imaging/testdata/branches.jpg b/vendor/github.com/disintegration/imaging/testdata/branches.jpg new file mode 100644 index 0000000..42807ff Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/branches.jpg differ diff --git a/vendor/github.com/disintegration/imaging/testdata/branches.png b/vendor/github.com/disintegration/imaging/testdata/branches.png new file mode 100644 index 0000000..522976b Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/branches.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/flowers.png b/vendor/github.com/disintegration/imaging/testdata/flowers.png new file mode 100644 index 0000000..8214216 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/flowers.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/flowers_small.png b/vendor/github.com/disintegration/imaging/testdata/flowers_small.png new file mode 100644 index 0000000..8c31c72 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/flowers_small.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/orientation_0.jpg b/vendor/github.com/disintegration/imaging/testdata/orientation_0.jpg new file mode 100644 index 0000000..441da0f Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/orientation_0.jpg differ diff --git a/vendor/github.com/disintegration/imaging/testdata/orientation_1.jpg b/vendor/github.com/disintegration/imaging/testdata/orientation_1.jpg new file mode 100644 index 0000000..519d60f Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/orientation_1.jpg differ diff --git a/vendor/github.com/disintegration/imaging/testdata/orientation_2.jpg b/vendor/github.com/disintegration/imaging/testdata/orientation_2.jpg new file mode 100644 index 0000000..2ef6fa7 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/orientation_2.jpg differ diff --git a/vendor/github.com/disintegration/imaging/testdata/orientation_3.jpg b/vendor/github.com/disintegration/imaging/testdata/orientation_3.jpg new file mode 100644 index 0000000..cf3fe02 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/orientation_3.jpg differ diff --git a/vendor/github.com/disintegration/imaging/testdata/orientation_4.jpg b/vendor/github.com/disintegration/imaging/testdata/orientation_4.jpg new file mode 100644 index 0000000..4e2c97a Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/orientation_4.jpg differ diff --git a/vendor/github.com/disintegration/imaging/testdata/orientation_5.jpg b/vendor/github.com/disintegration/imaging/testdata/orientation_5.jpg new file mode 100644 index 0000000..6c7352b Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/orientation_5.jpg differ diff --git a/vendor/github.com/disintegration/imaging/testdata/orientation_6.jpg b/vendor/github.com/disintegration/imaging/testdata/orientation_6.jpg new file mode 100644 index 0000000..67016fe Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/orientation_6.jpg differ diff --git a/vendor/github.com/disintegration/imaging/testdata/orientation_7.jpg b/vendor/github.com/disintegration/imaging/testdata/orientation_7.jpg new file mode 100644 index 0000000..3100112 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/orientation_7.jpg differ diff --git a/vendor/github.com/disintegration/imaging/testdata/orientation_8.jpg b/vendor/github.com/disintegration/imaging/testdata/orientation_8.jpg new file mode 100644 index 0000000..ec6e3db Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/orientation_8.jpg differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_blur_0.5.png b/vendor/github.com/disintegration/imaging/testdata/out_blur_0.5.png new file mode 100644 index 0000000..dadb010 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_blur_0.5.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_blur_1.5.png b/vendor/github.com/disintegration/imaging/testdata/out_blur_1.5.png new file mode 100644 index 0000000..576feb5 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_blur_1.5.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_brightness_m10.png b/vendor/github.com/disintegration/imaging/testdata/out_brightness_m10.png new file mode 100644 index 0000000..134d10c Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_brightness_m10.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_brightness_p10.png b/vendor/github.com/disintegration/imaging/testdata/out_brightness_p10.png new file mode 100644 index 0000000..f834cd3 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_brightness_p10.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_contrast_m15.png b/vendor/github.com/disintegration/imaging/testdata/out_contrast_m15.png new file mode 100644 index 0000000..a8632d1 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_contrast_m15.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_contrast_p15.png b/vendor/github.com/disintegration/imaging/testdata/out_contrast_p15.png new file mode 100644 index 0000000..0dd0eee Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_contrast_p15.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_example.jpg b/vendor/github.com/disintegration/imaging/testdata/out_example.jpg new file mode 100644 index 0000000..36f9cd1 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_example.jpg differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_fill_center.png b/vendor/github.com/disintegration/imaging/testdata/out_fill_center.png new file mode 100644 index 0000000..78d4780 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_fill_center.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_fill_left.png b/vendor/github.com/disintegration/imaging/testdata/out_fill_left.png new file mode 100644 index 0000000..3947ea4 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_fill_left.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_fill_right.png b/vendor/github.com/disintegration/imaging/testdata/out_fill_right.png new file mode 100644 index 0000000..d56a0c2 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_fill_right.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_fit.png b/vendor/github.com/disintegration/imaging/testdata/out_fit.png new file mode 100644 index 0000000..f7e70a1 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_fit.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_gamma_0.75.png b/vendor/github.com/disintegration/imaging/testdata/out_gamma_0.75.png new file mode 100644 index 0000000..01fb52e Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_gamma_0.75.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_gamma_1.25.png b/vendor/github.com/disintegration/imaging/testdata/out_gamma_1.25.png new file mode 100644 index 0000000..e8e979b Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_gamma_1.25.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_resize_catrom.png b/vendor/github.com/disintegration/imaging/testdata/out_resize_catrom.png new file mode 100644 index 0000000..1435697 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_resize_catrom.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_resize_lanczos.png b/vendor/github.com/disintegration/imaging/testdata/out_resize_lanczos.png new file mode 100644 index 0000000..f87f4c6 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_resize_lanczos.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_resize_linear.png b/vendor/github.com/disintegration/imaging/testdata/out_resize_linear.png new file mode 100644 index 0000000..b039044 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_resize_linear.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_resize_nearest.png b/vendor/github.com/disintegration/imaging/testdata/out_resize_nearest.png new file mode 100644 index 0000000..573ebc7 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_resize_nearest.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_saturation_m30.png b/vendor/github.com/disintegration/imaging/testdata/out_saturation_m30.png new file mode 100644 index 0000000..d0212b7 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_saturation_m30.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_saturation_p30.png b/vendor/github.com/disintegration/imaging/testdata/out_saturation_p30.png new file mode 100644 index 0000000..c4928bd Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_saturation_p30.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_sharpen_0.5.png b/vendor/github.com/disintegration/imaging/testdata/out_sharpen_0.5.png new file mode 100644 index 0000000..314b354 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_sharpen_0.5.png differ diff --git a/vendor/github.com/disintegration/imaging/testdata/out_sharpen_1.5.png b/vendor/github.com/disintegration/imaging/testdata/out_sharpen_1.5.png new file mode 100644 index 0000000..4dfe220 Binary files /dev/null and b/vendor/github.com/disintegration/imaging/testdata/out_sharpen_1.5.png differ diff --git a/vendor/github.com/disintegration/imaging/tools.go b/vendor/github.com/disintegration/imaging/tools.go new file mode 100644 index 0000000..e39f86f --- /dev/null +++ b/vendor/github.com/disintegration/imaging/tools.go @@ -0,0 +1,249 @@ +package imaging + +import ( + "bytes" + "image" + "image/color" + "math" +) + +// New creates a new image with the specified width and height, and fills it with the specified color. +func New(width, height int, fillColor color.Color) *image.NRGBA { + if width <= 0 || height <= 0 { + return &image.NRGBA{} + } + + c := color.NRGBAModel.Convert(fillColor).(color.NRGBA) + if (c == color.NRGBA{0, 0, 0, 0}) { + return image.NewNRGBA(image.Rect(0, 0, width, height)) + } + + return &image.NRGBA{ + Pix: bytes.Repeat([]byte{c.R, c.G, c.B, c.A}, width*height), + Stride: 4 * width, + Rect: image.Rect(0, 0, width, height), + } +} + +// Clone returns a copy of the given image. +func Clone(img image.Image) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + size := src.w * 4 + parallel(0, src.h, func(ys <-chan int) { + for y := range ys { + i := y * dst.Stride + src.scan(0, y, src.w, y+1, dst.Pix[i:i+size]) + } + }) + return dst +} + +// Anchor is the anchor point for image alignment. +type Anchor int + +// Anchor point positions. +const ( + Center Anchor = iota + TopLeft + Top + TopRight + Left + Right + BottomLeft + Bottom + BottomRight +) + +func anchorPt(b image.Rectangle, w, h int, anchor Anchor) image.Point { + var x, y int + switch anchor { + case TopLeft: + x = b.Min.X + y = b.Min.Y + case Top: + x = b.Min.X + (b.Dx()-w)/2 + y = b.Min.Y + case TopRight: + x = b.Max.X - w + y = b.Min.Y + case Left: + x = b.Min.X + y = b.Min.Y + (b.Dy()-h)/2 + case Right: + x = b.Max.X - w + y = b.Min.Y + (b.Dy()-h)/2 + case BottomLeft: + x = b.Min.X + y = b.Max.Y - h + case Bottom: + x = b.Min.X + (b.Dx()-w)/2 + y = b.Max.Y - h + case BottomRight: + x = b.Max.X - w + y = b.Max.Y - h + default: + x = b.Min.X + (b.Dx()-w)/2 + y = b.Min.Y + (b.Dy()-h)/2 + } + return image.Pt(x, y) +} + +// Crop cuts out a rectangular region with the specified bounds +// from the image and returns the cropped image. +func Crop(img image.Image, rect image.Rectangle) *image.NRGBA { + r := rect.Intersect(img.Bounds()).Sub(img.Bounds().Min) + if r.Empty() { + return &image.NRGBA{} + } + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, r.Dx(), r.Dy())) + rowSize := r.Dx() * 4 + parallel(r.Min.Y, r.Max.Y, func(ys <-chan int) { + for y := range ys { + i := (y - r.Min.Y) * dst.Stride + src.scan(r.Min.X, y, r.Max.X, y+1, dst.Pix[i:i+rowSize]) + } + }) + return dst +} + +// CropAnchor cuts out a rectangular region with the specified size +// from the image using the specified anchor point and returns the cropped image. +func CropAnchor(img image.Image, width, height int, anchor Anchor) *image.NRGBA { + srcBounds := img.Bounds() + pt := anchorPt(srcBounds, width, height, anchor) + r := image.Rect(0, 0, width, height).Add(pt) + b := srcBounds.Intersect(r) + return Crop(img, b) +} + +// CropCenter cuts out a rectangular region with the specified size +// from the center of the image and returns the cropped image. +func CropCenter(img image.Image, width, height int) *image.NRGBA { + return CropAnchor(img, width, height, Center) +} + +// Paste pastes the img image to the background image at the specified position and returns the combined image. +func Paste(background, img image.Image, pos image.Point) *image.NRGBA { + dst := Clone(background) + pos = pos.Sub(background.Bounds().Min) + pasteRect := image.Rectangle{Min: pos, Max: pos.Add(img.Bounds().Size())} + interRect := pasteRect.Intersect(dst.Bounds()) + if interRect.Empty() { + return dst + } + src := newScanner(img) + parallel(interRect.Min.Y, interRect.Max.Y, func(ys <-chan int) { + for y := range ys { + x1 := interRect.Min.X - pasteRect.Min.X + x2 := interRect.Max.X - pasteRect.Min.X + y1 := y - pasteRect.Min.Y + y2 := y1 + 1 + i1 := y*dst.Stride + interRect.Min.X*4 + i2 := i1 + interRect.Dx()*4 + src.scan(x1, y1, x2, y2, dst.Pix[i1:i2]) + } + }) + return dst +} + +// PasteCenter pastes the img image to the center of the background image and returns the combined image. +func PasteCenter(background, img image.Image) *image.NRGBA { + bgBounds := background.Bounds() + bgW := bgBounds.Dx() + bgH := bgBounds.Dy() + bgMinX := bgBounds.Min.X + bgMinY := bgBounds.Min.Y + + centerX := bgMinX + bgW/2 + centerY := bgMinY + bgH/2 + + x0 := centerX - img.Bounds().Dx()/2 + y0 := centerY - img.Bounds().Dy()/2 + + return Paste(background, img, image.Pt(x0, y0)) +} + +// Overlay draws the img image over the background image at given position +// and returns the combined image. Opacity parameter is the opacity of the img +// image layer, used to compose the images, it must be from 0.0 to 1.0. +// +// Usage examples: +// +// // Draw spriteImage over backgroundImage at the given position (x=50, y=50). +// dstImage := imaging.Overlay(backgroundImage, spriteImage, image.Pt(50, 50), 1.0) +// +// // Blend two opaque images of the same size. +// dstImage := imaging.Overlay(imageOne, imageTwo, image.Pt(0, 0), 0.5) +// +func Overlay(background, img image.Image, pos image.Point, opacity float64) *image.NRGBA { + opacity = math.Min(math.Max(opacity, 0.0), 1.0) // Ensure 0.0 <= opacity <= 1.0. + dst := Clone(background) + pos = pos.Sub(background.Bounds().Min) + pasteRect := image.Rectangle{Min: pos, Max: pos.Add(img.Bounds().Size())} + interRect := pasteRect.Intersect(dst.Bounds()) + if interRect.Empty() { + return dst + } + src := newScanner(img) + parallel(interRect.Min.Y, interRect.Max.Y, func(ys <-chan int) { + scanLine := make([]uint8, interRect.Dx()*4) + for y := range ys { + x1 := interRect.Min.X - pasteRect.Min.X + x2 := interRect.Max.X - pasteRect.Min.X + y1 := y - pasteRect.Min.Y + y2 := y1 + 1 + src.scan(x1, y1, x2, y2, scanLine) + i := y*dst.Stride + interRect.Min.X*4 + j := 0 + for x := interRect.Min.X; x < interRect.Max.X; x++ { + d := dst.Pix[i : i+4 : i+4] + r1 := float64(d[0]) + g1 := float64(d[1]) + b1 := float64(d[2]) + a1 := float64(d[3]) + + s := scanLine[j : j+4 : j+4] + r2 := float64(s[0]) + g2 := float64(s[1]) + b2 := float64(s[2]) + a2 := float64(s[3]) + + coef2 := opacity * a2 / 255 + coef1 := (1 - coef2) * a1 / 255 + coefSum := coef1 + coef2 + coef1 /= coefSum + coef2 /= coefSum + + d[0] = uint8(r1*coef1 + r2*coef2) + d[1] = uint8(g1*coef1 + g2*coef2) + d[2] = uint8(b1*coef1 + b2*coef2) + d[3] = uint8(math.Min(a1+a2*opacity*(255-a1)/255, 255)) + + i += 4 + j += 4 + } + } + }) + return dst +} + +// OverlayCenter overlays the img image to the center of the background image and +// returns the combined image. Opacity parameter is the opacity of the img +// image layer, used to compose the images, it must be from 0.0 to 1.0. +func OverlayCenter(background, img image.Image, opacity float64) *image.NRGBA { + bgBounds := background.Bounds() + bgW := bgBounds.Dx() + bgH := bgBounds.Dy() + bgMinX := bgBounds.Min.X + bgMinY := bgBounds.Min.Y + + centerX := bgMinX + bgW/2 + centerY := bgMinY + bgH/2 + + x0 := centerX - img.Bounds().Dx()/2 + y0 := centerY - img.Bounds().Dy()/2 + + return Overlay(background, img, image.Point{x0, y0}, opacity) +} diff --git a/vendor/github.com/disintegration/imaging/tools_test.go b/vendor/github.com/disintegration/imaging/tools_test.go new file mode 100644 index 0000000..a714f6f --- /dev/null +++ b/vendor/github.com/disintegration/imaging/tools_test.go @@ -0,0 +1,1124 @@ +package imaging + +import ( + "bytes" + "image" + "image/color" + "testing" +) + +func TestNew(t *testing.T) { + testCases := []struct { + name string + w, h int + c color.Color + dstBounds image.Rectangle + dstPix []uint8 + }{ + { + "New 1x1 transparent", + 1, 1, + color.Transparent, + image.Rect(0, 0, 1, 1), + []uint8{0x00, 0x00, 0x00, 0x00}, + }, + { + "New 1x2 red", + 1, 2, + color.RGBA{255, 0, 0, 255}, + image.Rect(0, 0, 1, 2), + []uint8{0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff}, + }, + { + "New 2x1 white", + 2, 1, + color.White, + image.Rect(0, 0, 2, 1), + []uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, + { + "New 3x3 with alpha", + 3, 3, + color.NRGBA{0x01, 0x23, 0x45, 0x67}, + image.Rect(0, 0, 3, 3), + []uint8{ + 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, + 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, + 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, + }, + }, + { + "New 0x0 white", + 0, 0, + color.White, + image.Rect(0, 0, 0, 0), + nil, + }, + { + "New 800x600 custom", + 800, 600, + color.NRGBA{1, 2, 3, 4}, + image.Rect(0, 0, 800, 600), + bytes.Repeat([]byte{1, 2, 3, 4}, 800*600), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := New(tc.w, tc.h, tc.c) + want := image.NewNRGBA(tc.dstBounds) + want.Pix = tc.dstPix + if !compareNRGBA(got, want, 0) { + t.Fatalf("got result %#v want %#v", got, want) + } + }) + } +} + +func BenchmarkNew(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + New(1024, 1024, color.White) + } +} + +func TestClone(t *testing.T) { + testCases := []struct { + name string + src image.Image + want *image.NRGBA + }{ + { + "Clone NRGBA", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 4, + Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff}, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 2), + Stride: 1 * 4, + Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff}, + }, + }, + { + "Clone NRGBA64", + &image.NRGBA64{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 8, + Pix: []uint8{ + 0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33, + 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 2), + Stride: 1 * 4, + Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff}, + }, + }, + { + "Clone RGBA", + &image.RGBA{ + Rect: image.Rect(-1, -1, 0, 2), + Stride: 1 * 4, + Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff}, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 3), + Stride: 1 * 4, + Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff}, + }, + }, + { + "Clone RGBA64", + &image.RGBA64{ + Rect: image.Rect(-1, -1, 0, 2), + Stride: 1 * 8, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33, + 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 3), + Stride: 1 * 4, + Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff}, + }, + }, + { + "Clone Gray", + &image.Gray{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 1, + Pix: []uint8{0x11, 0xee}, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 2), + Stride: 1 * 4, + Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff}, + }, + }, + { + "Clone Gray16", + &image.Gray16{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 2, + Pix: []uint8{0x11, 0x11, 0xee, 0xee}, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 2), + Stride: 1 * 4, + Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff}, + }, + }, + { + "Clone Alpha", + &image.Alpha{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 1, + Pix: []uint8{0x11, 0xee}, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 2), + Stride: 1 * 4, + Pix: []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee}, + }, + }, + { + "Clone YCbCr", + &image.YCbCr{ + Rect: image.Rect(-1, -1, 5, 0), + SubsampleRatio: image.YCbCrSubsampleRatio444, + YStride: 6, + CStride: 6, + Y: []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e}, + Cb: []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0}, + Cr: []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76}, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 6, 1), + Stride: 6 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x7f, 0x7f, 0xff, + 0x7f, 0x00, 0x00, 0xff, + 0x00, 0x7f, 0x00, 0xff, + 0x00, 0x00, 0x7f, 0xff, + }, + }, + }, + { + "Clone YCbCr 444", + &image.YCbCr{ + Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff}, + Cb: []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80}, + Cr: []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80}, + YStride: 4, + CStride: 4, + SubsampleRatio: image.YCbCrSubsampleRatio444, + Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}}, + }, + &image.NRGBA{ + Pix: []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff}, + Stride: 16, + Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}}, + }, + }, + { + "Clone YCbCr 440", + &image.YCbCr{ + Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff}, + Cb: []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80}, + Cr: []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80}, + YStride: 4, + CStride: 4, + SubsampleRatio: image.YCbCrSubsampleRatio440, + Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}}, + }, + &image.NRGBA{ + Pix: []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff}, + Stride: 16, + Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}}, + }, + }, + { + "Clone YCbCr 422", + &image.YCbCr{ + Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff}, + Cb: []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80}, + Cr: []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80}, + YStride: 4, + CStride: 2, + SubsampleRatio: image.YCbCrSubsampleRatio422, + Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}}, + }, + &image.NRGBA{ + Pix: []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff}, + Stride: 16, + Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}}, + }, + }, + { + "Clone YCbCr 420", + &image.YCbCr{ + Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff}, + Cb: []uint8{0x01, 0xaa, 0x80, 0x80}, + Cr: []uint8{0x95, 0xb5, 0x80, 0x80}, + YStride: 4, CStride: 2, + SubsampleRatio: image.YCbCrSubsampleRatio420, + Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}}, + }, + &image.NRGBA{ + Pix: []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff}, + Stride: 16, + Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}}, + }, + }, + { + "Clone Paletted", + &image.Paletted{ + Rect: image.Rect(-1, -1, 5, 0), + Stride: 6 * 1, + Palette: color.Palette{ + color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff}, + color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}, + color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff}, + color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff}, + color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff}, + color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff}, + }, + Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5}, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 6, 1), + Stride: 6 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x7f, 0x7f, 0xff, + 0x7f, 0x00, 0x00, 0xff, + 0x00, 0x7f, 0x00, 0xff, + 0x00, 0x00, 0x7f, 0xff, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Clone(tc.src) + delta := 0 + if _, ok := tc.src.(*image.YCbCr); ok { + delta = 1 + } + if !compareNRGBA(got, tc.want, delta) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestCrop(t *testing.T) { + testCases := []struct { + name string + src image.Image + r image.Rectangle + want *image.NRGBA + }{ + { + "Crop 2x3 2x1", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + image.Rect(-1, 0, 1, 1), + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Crop(tc.src, tc.r) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkCrop(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Crop(testdataBranchesJPG, image.Rect(100, 100, 300, 300)) + } +} + +func TestCropCenter(t *testing.T) { + testCases := []struct { + name string + src image.Image + w, h int + want *image.NRGBA + }{ + { + "CropCenter 2x3 2x1", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + 2, 1, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + }, + }, + }, + { + "CropCenter 2x3 0x1", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + 0, 1, + &image.NRGBA{ + Rect: image.Rect(0, 0, 0, 0), + Stride: 0, + Pix: []uint8{}, + }, + }, + { + "CropCenter 2x3 5x5", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + 5, 5, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 3), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := CropCenter(tc.src, tc.w, tc.h) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestCropAnchor(t *testing.T) { + testCases := []struct { + name string + src image.Image + w, h int + anchor Anchor + want *image.NRGBA + }{ + { + "CropAnchor 4x4 2x2 TopLeft", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 2, + TopLeft, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + }, + }, + }, + { + "CropAnchor 4x4 2x2 Top", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 2, + Top, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + }, + }, + }, + { + "CropAnchor 4x4 2x2 TopRight", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 2, + TopRight, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + }, + }, + }, + { + "CropAnchor 4x4 2x2 Left", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 2, + Left, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + }, + }, + }, + { + "CropAnchor 4x4 2x2 Center", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 2, + Center, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + }, + }, + }, + { + "CropAnchor 4x4 2x2 Right", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 2, + Right, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + }, + }, + }, + { + "CropAnchor 4x4 2x2 BottomLeft", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 2, + BottomLeft, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + }, + }, + }, + { + "CropAnchor 4x4 2x2 Bottom", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 2, + Bottom, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + }, + }, + }, + { + "CropAnchor 4x4 2x2 BottomRight", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 2, 2, + BottomRight, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + { + "CropAnchor 4x4 0x0 BottomRight", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 0, 0, + BottomRight, + &image.NRGBA{ + Rect: image.Rect(0, 0, 0, 0), + Stride: 0, + Pix: []uint8{}, + }, + }, + { + "CropAnchor 4x4 100x100 BottomRight", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 100, 100, + BottomRight, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + { + "CropAnchor 4x4 1x100 BottomRight", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 1, 100, + BottomRight, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 4), + Stride: 1 * 4, + Pix: []uint8{ + 0x0c, 0x0d, 0x0e, 0x0f, + 0x1c, 0x1d, 0x1e, 0x1f, + 0x2c, 0x2d, 0x2e, 0x2f, + 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + }, + { + "CropAnchor 4x4 0x100 BottomRight", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + }, + 0, 100, + BottomRight, + &image.NRGBA{ + Rect: image.Rect(0, 0, 0, 0), + Stride: 0, + Pix: []uint8{}, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := CropAnchor(tc.src, tc.w, tc.h, tc.anchor) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestPaste(t *testing.T) { + testCases := []struct { + name string + src1 image.Image + src2 image.Image + p image.Point + want *image.NRGBA + }{ + { + "Paste 2x3 2x1", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(1, 1, 3, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + }, + }, + image.Pt(-1, 0), + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 3), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + }, + { + "Paste 3x4 4x3 bottom right intersection", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + }, + }, + &image.NRGBA{ + Rect: image.Rect(1, 1, 5, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + }, + }, + image.Pt(0, 1), + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 4), + Stride: 3 * 4, + Pix: []uint8{ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x30, 0x31, 0x32, 0x33, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0x40, 0x41, 0x42, 0x43, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + }, + }, + }, + { + "Paste 3x4 4x3 top left intersection", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + }, + }, + &image.NRGBA{ + Rect: image.Rect(1, 1, 5, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + }, + }, + image.Pt(-3, -2), + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 4), + Stride: 3 * 4, + Pix: []uint8{ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0x18, 0x19, 0x1a, 0x1b, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0x28, 0x29, 0x2a, 0x2b, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + }, + }, + }, + { + "Paste 3x4 4x3 no intersection", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 2, 3), + Stride: 3 * 4, + Pix: []uint8{ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + }, + }, + &image.NRGBA{ + Rect: image.Rect(1, 1, 5, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + }, + }, + image.Pt(-20, 20), + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 4), + Stride: 3 * 4, + Pix: []uint8{ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Paste(tc.src1, tc.src2, tc.p) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkPaste(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Paste(testdataBranchesJPG, testdataFlowersSmallPNG, image.Pt(100, 100)) + } +} + +func TestPasteCenter(t *testing.T) { + testCases := []struct { + name string + src1 image.Image + src2 image.Image + want *image.NRGBA + }{ + { + "PasteCenter 2x3 2x1", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(1, 1, 3, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 3), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := PasteCenter(tc.src1, tc.src2) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func TestOverlay(t *testing.T) { + testCases := []struct { + name string + src1 image.Image + src2 image.Image + p image.Point + a float64 + want *image.NRGBA + }{ + { + "Overlay 2x3 2x1 1.0", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0x60, 0x00, 0x90, 0xff, 0xff, 0x00, 0x99, 0x7f, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(1, 1, 3, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x20, 0x40, 0x80, 0x7f, 0xaa, 0xbb, 0xcc, 0xff, + }, + }, + image.Pt(-1, 0), + 1.0, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 3), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0x40, 0x1f, 0x88, 0xff, 0xaa, 0xbb, 0xcc, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + }, + { + "Overlay 2x2 2x2 0.5", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00, + }, + }, + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0xff, 0x20, 0x20, 0x20, 0xff, + }, + }, + image.Pt(-1, -1), + 0.5, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0x7f, 0x7f, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x7f, 0x7f, 0x7f, 0xff, 0x20, 0x20, 0x20, 0x7f, + }, + }, + }, + { + "Overlay 2x2 2x2 0.5 no intersection", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00, + }, + }, + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0xff, 0x20, 0x20, 0x20, 0xff, + }, + }, + image.Pt(-10, 10), + 0.5, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Overlay(tc.src1, tc.src2, tc.p, tc.a) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkOverlay(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Overlay(testdataBranchesJPG, testdataFlowersSmallPNG, image.Pt(100, 100), 0.5) + } +} + +func TestOverlayCenter(t *testing.T) { + testCases := []struct { + name string + src1 image.Image + src2 image.Image + a float64 + want *image.NRGBA + }{ + { + "OverlayCenter 2x3 2x1", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(1, 1, 3, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + }, + }, + 0.5, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 3), + Stride: 2 * 4, + Pix: []uint8{ + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := OverlayCenter(tc.src1, tc.src2, 0.5) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} diff --git a/vendor/github.com/disintegration/imaging/transform.go b/vendor/github.com/disintegration/imaging/transform.go new file mode 100644 index 0000000..fe4a92f --- /dev/null +++ b/vendor/github.com/disintegration/imaging/transform.go @@ -0,0 +1,268 @@ +package imaging + +import ( + "image" + "image/color" + "math" +) + +// FlipH flips the image horizontally (from left to right) and returns the transformed image. +func FlipH(img image.Image) *image.NRGBA { + src := newScanner(img) + dstW := src.w + dstH := src.h + rowSize := dstW * 4 + dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) + parallel(0, dstH, func(ys <-chan int) { + for dstY := range ys { + i := dstY * dst.Stride + srcY := dstY + src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize]) + reverse(dst.Pix[i : i+rowSize]) + } + }) + return dst +} + +// FlipV flips the image vertically (from top to bottom) and returns the transformed image. +func FlipV(img image.Image) *image.NRGBA { + src := newScanner(img) + dstW := src.w + dstH := src.h + rowSize := dstW * 4 + dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) + parallel(0, dstH, func(ys <-chan int) { + for dstY := range ys { + i := dstY * dst.Stride + srcY := dstH - dstY - 1 + src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize]) + } + }) + return dst +} + +// Transpose flips the image horizontally and rotates 90 degrees counter-clockwise. +func Transpose(img image.Image) *image.NRGBA { + src := newScanner(img) + dstW := src.h + dstH := src.w + rowSize := dstW * 4 + dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) + parallel(0, dstH, func(ys <-chan int) { + for dstY := range ys { + i := dstY * dst.Stride + srcX := dstY + src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize]) + } + }) + return dst +} + +// Transverse flips the image vertically and rotates 90 degrees counter-clockwise. +func Transverse(img image.Image) *image.NRGBA { + src := newScanner(img) + dstW := src.h + dstH := src.w + rowSize := dstW * 4 + dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) + parallel(0, dstH, func(ys <-chan int) { + for dstY := range ys { + i := dstY * dst.Stride + srcX := dstH - dstY - 1 + src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize]) + reverse(dst.Pix[i : i+rowSize]) + } + }) + return dst +} + +// Rotate90 rotates the image 90 degrees counter-clockwise and returns the transformed image. +func Rotate90(img image.Image) *image.NRGBA { + src := newScanner(img) + dstW := src.h + dstH := src.w + rowSize := dstW * 4 + dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) + parallel(0, dstH, func(ys <-chan int) { + for dstY := range ys { + i := dstY * dst.Stride + srcX := dstH - dstY - 1 + src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize]) + } + }) + return dst +} + +// Rotate180 rotates the image 180 degrees counter-clockwise and returns the transformed image. +func Rotate180(img image.Image) *image.NRGBA { + src := newScanner(img) + dstW := src.w + dstH := src.h + rowSize := dstW * 4 + dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) + parallel(0, dstH, func(ys <-chan int) { + for dstY := range ys { + i := dstY * dst.Stride + srcY := dstH - dstY - 1 + src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize]) + reverse(dst.Pix[i : i+rowSize]) + } + }) + return dst +} + +// Rotate270 rotates the image 270 degrees counter-clockwise and returns the transformed image. +func Rotate270(img image.Image) *image.NRGBA { + src := newScanner(img) + dstW := src.h + dstH := src.w + rowSize := dstW * 4 + dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) + parallel(0, dstH, func(ys <-chan int) { + for dstY := range ys { + i := dstY * dst.Stride + srcX := dstY + src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize]) + reverse(dst.Pix[i : i+rowSize]) + } + }) + return dst +} + +// Rotate rotates an image by the given angle counter-clockwise . +// The angle parameter is the rotation angle in degrees. +// The bgColor parameter specifies the color of the uncovered zone after the rotation. +func Rotate(img image.Image, angle float64, bgColor color.Color) *image.NRGBA { + angle = angle - math.Floor(angle/360)*360 + + switch angle { + case 0: + return Clone(img) + case 90: + return Rotate90(img) + case 180: + return Rotate180(img) + case 270: + return Rotate270(img) + } + + src := toNRGBA(img) + srcW := src.Bounds().Max.X + srcH := src.Bounds().Max.Y + dstW, dstH := rotatedSize(srcW, srcH, angle) + dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) + + if dstW <= 0 || dstH <= 0 { + return dst + } + + srcXOff := float64(srcW)/2 - 0.5 + srcYOff := float64(srcH)/2 - 0.5 + dstXOff := float64(dstW)/2 - 0.5 + dstYOff := float64(dstH)/2 - 0.5 + + bgColorNRGBA := color.NRGBAModel.Convert(bgColor).(color.NRGBA) + sin, cos := math.Sincos(math.Pi * angle / 180) + + parallel(0, dstH, func(ys <-chan int) { + for dstY := range ys { + for dstX := 0; dstX < dstW; dstX++ { + xf, yf := rotatePoint(float64(dstX)-dstXOff, float64(dstY)-dstYOff, sin, cos) + xf, yf = xf+srcXOff, yf+srcYOff + interpolatePoint(dst, dstX, dstY, src, xf, yf, bgColorNRGBA) + } + } + }) + + return dst +} + +func rotatePoint(x, y, sin, cos float64) (float64, float64) { + return x*cos - y*sin, x*sin + y*cos +} + +func rotatedSize(w, h int, angle float64) (int, int) { + if w <= 0 || h <= 0 { + return 0, 0 + } + + sin, cos := math.Sincos(math.Pi * angle / 180) + x1, y1 := rotatePoint(float64(w-1), 0, sin, cos) + x2, y2 := rotatePoint(float64(w-1), float64(h-1), sin, cos) + x3, y3 := rotatePoint(0, float64(h-1), sin, cos) + + minx := math.Min(x1, math.Min(x2, math.Min(x3, 0))) + maxx := math.Max(x1, math.Max(x2, math.Max(x3, 0))) + miny := math.Min(y1, math.Min(y2, math.Min(y3, 0))) + maxy := math.Max(y1, math.Max(y2, math.Max(y3, 0))) + + neww := maxx - minx + 1 + if neww-math.Floor(neww) > 0.1 { + neww++ + } + newh := maxy - miny + 1 + if newh-math.Floor(newh) > 0.1 { + newh++ + } + + return int(neww), int(newh) +} + +func interpolatePoint(dst *image.NRGBA, dstX, dstY int, src *image.NRGBA, xf, yf float64, bgColor color.NRGBA) { + j := dstY*dst.Stride + dstX*4 + d := dst.Pix[j : j+4 : j+4] + + x0 := int(math.Floor(xf)) + y0 := int(math.Floor(yf)) + bounds := src.Bounds() + if !image.Pt(x0, y0).In(image.Rect(bounds.Min.X-1, bounds.Min.Y-1, bounds.Max.X, bounds.Max.Y)) { + d[0] = bgColor.R + d[1] = bgColor.G + d[2] = bgColor.B + d[3] = bgColor.A + return + } + + xq := xf - float64(x0) + yq := yf - float64(y0) + points := [4]image.Point{ + {x0, y0}, + {x0 + 1, y0}, + {x0, y0 + 1}, + {x0 + 1, y0 + 1}, + } + weights := [4]float64{ + (1 - xq) * (1 - yq), + xq * (1 - yq), + (1 - xq) * yq, + xq * yq, + } + + var r, g, b, a float64 + for i := 0; i < 4; i++ { + p := points[i] + w := weights[i] + if p.In(bounds) { + i := p.Y*src.Stride + p.X*4 + s := src.Pix[i : i+4 : i+4] + wa := float64(s[3]) * w + r += float64(s[0]) * wa + g += float64(s[1]) * wa + b += float64(s[2]) * wa + a += wa + } else { + wa := float64(bgColor.A) * w + r += float64(bgColor.R) * wa + g += float64(bgColor.G) * wa + b += float64(bgColor.B) * wa + a += wa + } + } + if a != 0 { + aInv := 1 / a + d[0] = clamp(r * aInv) + d[1] = clamp(g * aInv) + d[2] = clamp(b * aInv) + d[3] = clamp(a) + } +} diff --git a/vendor/github.com/disintegration/imaging/transform_test.go b/vendor/github.com/disintegration/imaging/transform_test.go new file mode 100644 index 0000000..81be8ed --- /dev/null +++ b/vendor/github.com/disintegration/imaging/transform_test.go @@ -0,0 +1,645 @@ +package imaging + +import ( + "image" + "image/color" + "testing" +) + +func TestFlipH(t *testing.T) { + testCases := []struct { + name string + src image.Image + want *image.NRGBA + }{ + { + "FlipH 2x3", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 3), + Stride: 2 * 4, + Pix: []uint8{ + 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := FlipH(tc.src) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkFlipH(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + FlipH(testdataBranchesJPG) + } +} + +func TestFlipV(t *testing.T) { + testCases := []struct { + name string + src image.Image + want *image.NRGBA + }{ + { + "FlipV 2x3", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 3), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := FlipV(tc.src) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkFlipV(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + FlipV(testdataBranchesJPG) + } +} + +func TestTranspose(t *testing.T) { + testCases := []struct { + name string + src image.Image + want *image.NRGBA + }{ + { + "Transpose 2x3", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0xcc, 0xdd, 0xee, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Transpose(tc.src) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkTranspose(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Transpose(testdataBranchesJPG) + } +} + +func TestTransverse(t *testing.T) { + testCases := []struct { + name string + src image.Image + want *image.NRGBA + }{ + { + "Transverse 2x3", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xcc, 0xdd, 0xee, 0xff, + 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Transverse(tc.src) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkTransverse(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Transverse(testdataBranchesJPG) + } +} + +func TestRotate90(t *testing.T) { + testCases := []struct { + name string + src image.Image + want *image.NRGBA + }{ + { + "Rotate90 2x3", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0xcc, 0xdd, 0xee, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x11, 0x22, 0x33, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Rotate90(tc.src) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkRotate90(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Rotate90(testdataBranchesJPG) + } +} + +func TestRotate180(t *testing.T) { + testCases := []struct { + name string + src image.Image + want *image.NRGBA + }{ + { + "Rotate180 2x3", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 3), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Rotate180(tc.src) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkRotate180(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Rotate180(testdataBranchesJPG) + } +} + +func TestRotate270(t *testing.T) { + testCases := []struct { + name string + src image.Image + want *image.NRGBA + }{ + { + "Rotate270 2x3", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 1, 2), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + }, + }, + &image.NRGBA{ + Rect: image.Rect(0, 0, 3, 2), + Stride: 3 * 4, + Pix: []uint8{ + 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, + 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xcc, 0xdd, 0xee, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Rotate270(tc.src) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkRotate270(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Rotate270(testdataBranchesJPG) + } +} + +func TestRotate(t *testing.T) { + testCases := []struct { + name string + src image.Image + angle float64 + bg color.Color + want *image.NRGBA + }{ + { + "Rotate 0", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 0, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "Rotate 90", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 90, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + { + "Rotate 180", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 180, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 4, 4), + Stride: 4 * 4, + Pix: []uint8{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + }, + }, + }, + { + "Rotate 45", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 3, 3), + Stride: 4 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + 45, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 6, 6), + Stride: 6 * 4, + Pix: []uint8{ + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x61, 0x00, 0x00, 0xff, 0x58, 0x08, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x61, 0x00, 0x00, 0xff, 0xe9, 0x16, 0x00, 0xff, 0x35, 0xca, 0x00, 0xff, 0x00, 0x30, 0x30, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x61, 0x00, 0x00, 0xff, 0xe9, 0x16, 0x00, 0xff, 0x35, 0xca, 0x00, 0xff, 0x00, 0x80, 0x80, 0xff, 0x35, 0x35, 0xff, 0xff, 0x58, 0x58, 0x61, 0xff, + 0x58, 0x08, 0x00, 0xff, 0x35, 0xca, 0x00, 0xff, 0x00, 0x80, 0x80, 0xff, 0x35, 0x35, 0xff, 0xff, 0xe9, 0xe9, 0xff, 0xff, 0x61, 0x61, 0x61, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x30, 0x30, 0xff, 0x35, 0x35, 0xff, 0xff, 0xe9, 0xe9, 0xff, 0xff, 0x61, 0x61, 0x61, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x58, 0x58, 0x61, 0xff, 0x61, 0x61, 0x61, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + }, + }, + }, + { + "Rotate 0x0", + &image.NRGBA{ + Rect: image.Rect(0, 0, 0, 0), + Stride: 0, + Pix: []uint8{}, + }, + 123, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 0, 0), + Stride: 0, + Pix: []uint8{}, + }, + }, + { + "Rotate -90", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, + }, + }, + -90, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + }, + }, + }, + { + "Rotate -360*10", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 4, + Pix: []uint8{ + 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, + }, + }, + -360 * 10, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 2), + Stride: 1 * 4, + Pix: []uint8{ + 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, + }, + }, + }, + { + "Rotate -360*10 + 90", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, + }, + }, + -360*10 + 90, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + }, + }, + }, + { + "Rotate -360*10 + 180", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, + }, + }, + -360*10 + 180, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 2), + Stride: 1 * 4, + Pix: []uint8{ + 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, + }, + }, + }, + { + "Rotate -360*10 + 270", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, + }, + }, + -360*10 + 270, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + }, + }, + }, + { + "Rotate 360*10", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 4, + Pix: []uint8{ + 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, + }, + }, + 360 * 10, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 2), + Stride: 1 * 4, + Pix: []uint8{ + 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, + }, + }, + }, + { + "Rotate 360*10 + 90", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, + }, + }, + 360*10 + 90, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + }, + }, + }, + { + "Rotate 360*10 + 180", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, + }, + }, + 360*10 + 180, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 1, 2), + Stride: 1 * 4, + Pix: []uint8{ + 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, + }, + }, + }, + { + "Rotate 360*10 + 270", + &image.NRGBA{ + Rect: image.Rect(-1, -1, 0, 1), + Stride: 1 * 4, + Pix: []uint8{ + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, + }, + }, + 360*10 + 270, + color.Black, + &image.NRGBA{ + Rect: image.Rect(0, 0, 2, 1), + Stride: 2 * 4, + Pix: []uint8{ + 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := Rotate(tc.src, tc.angle, tc.bg) + if !compareNRGBA(got, tc.want, 0) { + t.Fatalf("got result %#v want %#v", got, tc.want) + } + }) + } +} + +func BenchmarkRotate(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Rotate(testdataBranchesJPG, 30, color.Transparent) + } +} diff --git a/vendor/github.com/disintegration/imaging/utils.go b/vendor/github.com/disintegration/imaging/utils.go new file mode 100644 index 0000000..6c7af1a --- /dev/null +++ b/vendor/github.com/disintegration/imaging/utils.go @@ -0,0 +1,167 @@ +package imaging + +import ( + "image" + "math" + "runtime" + "sync" +) + +// parallel processes the data in separate goroutines. +func parallel(start, stop int, fn func(<-chan int)) { + count := stop - start + if count < 1 { + return + } + + procs := runtime.GOMAXPROCS(0) + if procs > count { + procs = count + } + + c := make(chan int, count) + for i := start; i < stop; i++ { + c <- i + } + close(c) + + var wg sync.WaitGroup + for i := 0; i < procs; i++ { + wg.Add(1) + go func() { + defer wg.Done() + fn(c) + }() + } + wg.Wait() +} + +// absint returns the absolute value of i. +func absint(i int) int { + if i < 0 { + return -i + } + return i +} + +// clamp rounds and clamps float64 value to fit into uint8. +func clamp(x float64) uint8 { + v := int64(x + 0.5) + if v > 255 { + return 255 + } + if v > 0 { + return uint8(v) + } + return 0 +} + +func reverse(pix []uint8) { + if len(pix) <= 4 { + return + } + i := 0 + j := len(pix) - 4 + for i < j { + pi := pix[i : i+4 : i+4] + pj := pix[j : j+4 : j+4] + pi[0], pj[0] = pj[0], pi[0] + pi[1], pj[1] = pj[1], pi[1] + pi[2], pj[2] = pj[2], pi[2] + pi[3], pj[3] = pj[3], pi[3] + i += 4 + j -= 4 + } +} + +func toNRGBA(img image.Image) *image.NRGBA { + if img, ok := img.(*image.NRGBA); ok { + return &image.NRGBA{ + Pix: img.Pix, + Stride: img.Stride, + Rect: img.Rect.Sub(img.Rect.Min), + } + } + return Clone(img) +} + +// rgbToHSL converts a color from RGB to HSL. +func rgbToHSL(r, g, b uint8) (float64, float64, float64) { + rr := float64(r) / 255 + gg := float64(g) / 255 + bb := float64(b) / 255 + + max := math.Max(rr, math.Max(gg, bb)) + min := math.Min(rr, math.Min(gg, bb)) + + l := (max + min) / 2 + + if max == min { + return 0, 0, l + } + + var h, s float64 + d := max - min + if l > 0.5 { + s = d / (2 - max - min) + } else { + s = d / (max + min) + } + + switch max { + case rr: + h = (gg - bb) / d + if g < b { + h += 6 + } + case gg: + h = (bb-rr)/d + 2 + case bb: + h = (rr-gg)/d + 4 + } + h /= 6 + + return h, s, l +} + +// hslToRGB converts a color from HSL to RGB. +func hslToRGB(h, s, l float64) (uint8, uint8, uint8) { + var r, g, b float64 + if s == 0 { + v := clamp(l * 255) + return v, v, v + } + + var q float64 + if l < 0.5 { + q = l * (1 + s) + } else { + q = l + s - l*s + } + p := 2*l - q + + r = hueToRGB(p, q, h+1/3.0) + g = hueToRGB(p, q, h) + b = hueToRGB(p, q, h-1/3.0) + + return clamp(r * 255), clamp(g * 255), clamp(b * 255) +} + +func hueToRGB(p, q, t float64) float64 { + if t < 0 { + t++ + } + if t > 1 { + t-- + } + if t < 1/6.0 { + return p + (q-p)*6*t + } + if t < 1/2.0 { + return q + } + if t < 2/3.0 { + return p + (q-p)*(2/3.0-t)*6 + } + return p +} diff --git a/vendor/github.com/disintegration/imaging/utils_test.go b/vendor/github.com/disintegration/imaging/utils_test.go new file mode 100644 index 0000000..ee5e7f8 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/utils_test.go @@ -0,0 +1,287 @@ +package imaging + +import ( + "image" + "math" + "runtime" + "testing" +) + +var ( + testdataBranchesJPG = mustOpen("testdata/branches.jpg") + testdataBranchesPNG = mustOpen("testdata/branches.png") + testdataFlowersSmallPNG = mustOpen("testdata/flowers_small.png") +) + +func mustOpen(filename string) image.Image { + img, err := Open(filename) + if err != nil { + panic(err) + } + return img +} + +func TestParallel(t *testing.T) { + for _, n := range []int{0, 1, 10, 100, 1000} { + for _, p := range []int{1, 2, 4, 8, 16, 100} { + if !testParallelN(n, p) { + t.Fatalf("test [parallel %d %d] failed", n, p) + } + } + } +} + +func testParallelN(n, procs int) bool { + data := make([]bool, n) + before := runtime.GOMAXPROCS(0) + runtime.GOMAXPROCS(procs) + parallel(0, n, func(is <-chan int) { + for i := range is { + data[i] = true + } + }) + runtime.GOMAXPROCS(before) + for i := 0; i < n; i++ { + if !data[i] { + return false + } + } + return true +} + +func TestClamp(t *testing.T) { + testCases := []struct { + f float64 + u uint8 + }{ + {0, 0}, + {255, 255}, + {128, 128}, + {0.49, 0}, + {0.50, 1}, + {254.9, 255}, + {254.0, 254}, + {256, 255}, + {2500, 255}, + {-10, 0}, + {127.6, 128}, + } + + for _, tc := range testCases { + if clamp(tc.f) != tc.u { + t.Fatalf("test [clamp %v %v] failed: %v", tc.f, tc.u, clamp(tc.f)) + } + } +} + +func TestReverse(t *testing.T) { + testCases := []struct { + pix []uint8 + want []uint8 + }{ + { + pix: []uint8{}, + want: []uint8{}, + }, + { + pix: []uint8{1, 2, 3, 4}, + want: []uint8{1, 2, 3, 4}, + }, + { + pix: []uint8{1, 2, 3, 4, 5, 6, 7, 8}, + want: []uint8{5, 6, 7, 8, 1, 2, 3, 4}, + }, + { + pix: []uint8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, + want: []uint8{9, 10, 11, 12, 5, 6, 7, 8, 1, 2, 3, 4}, + }, + } + + for _, tc := range testCases { + t.Run("", func(t *testing.T) { + reverse(tc.pix) + if !compareBytes(tc.pix, tc.want, 0) { + t.Fatalf("got pix %v want %v", tc.pix, tc.want) + } + }) + } +} + +func compareNRGBA(img1, img2 *image.NRGBA, delta int) bool { + if !img1.Rect.Eq(img2.Rect) { + return false + } + return compareBytes(img1.Pix, img2.Pix, delta) +} + +func compareBytes(a, b []uint8, delta int) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if absint(int(a[i])-int(b[i])) > delta { + return false + } + } + return true +} + +func compareFloat64(a, b, delta float64) bool { + return math.Abs(a-b) <= delta +} + +var rgbHSLTestCases = []struct { + r, g, b uint8 + h, s, l float64 +}{ + { + r: 255, + g: 0, + b: 0, + h: 0.000, + s: 1.000, + l: 0.500, + }, + { + r: 191, + g: 191, + b: 0, + h: 0.167, + s: 1.000, + l: 0.375, + }, + { + r: 0, + g: 128, + b: 0, + h: 0.333, + s: 1.000, + l: 0.251, + }, + { + r: 128, + g: 255, + b: 255, + h: 0.500, + s: 1.000, + l: 0.751, + }, + { + r: 128, + g: 128, + b: 255, + h: 0.667, + s: 1.000, + l: 0.751, + }, + { + r: 191, + g: 64, + b: 191, + h: 0.833, + s: 0.498, + l: 0.500, + }, + { + r: 160, + g: 164, + b: 36, + h: 0.172, + s: 0.640, + l: 0.392, + }, + { + r: 65, + g: 27, + b: 234, + h: 0.697, + s: 0.831, + l: 0.512, + }, + { + r: 30, + g: 172, + b: 65, + h: 0.374, + s: 0.703, + l: 0.396, + }, + { + r: 240, + g: 200, + b: 14, + h: 0.137, + s: 0.890, + l: 0.498, + }, + { + r: 180, + g: 48, + b: 229, + h: 0.788, + s: 0.777, + l: 0.543, + }, + { + r: 237, + g: 119, + b: 81, + h: 0.040, + s: 0.813, + l: 0.624, + }, + { + r: 254, + g: 248, + b: 136, + h: 0.158, + s: 0.983, + l: 0.765, + }, + { + r: 25, + g: 203, + b: 151, + h: 0.451, + s: 0.781, + l: 0.447, + }, + { + r: 54, + g: 38, + b: 152, + h: 0.690, + s: 0.600, + l: 0.373, + }, + { + r: 126, + g: 126, + b: 184, + h: 0.667, + s: 0.290, + l: 0.608, + }, +} + +func TestRGBToHSL(t *testing.T) { + for _, tc := range rgbHSLTestCases { + t.Run("", func(t *testing.T) { + h, s, l := rgbToHSL(tc.r, tc.g, tc.b) + if !compareFloat64(h, tc.h, 0.001) || !compareFloat64(s, tc.s, 0.001) || !compareFloat64(l, tc.l, 0.001) { + t.Fatalf("(%d, %d, %d): got (%.3f, %.3f, %.3f) want (%.3f, %.3f, %.3f)", tc.r, tc.g, tc.b, h, s, l, tc.h, tc.s, tc.l) + } + }) + } +} + +func TestHSLToRGB(t *testing.T) { + for _, tc := range rgbHSLTestCases { + t.Run("", func(t *testing.T) { + r, g, b := hslToRGB(tc.h, tc.s, tc.l) + if r != tc.r || g != tc.g || b != tc.b { + t.Fatalf("(%.3f, %.3f, %.3f): got (%d, %d, %d) want (%d, %d, %d)", tc.h, tc.s, tc.l, r, g, b, tc.r, tc.g, tc.b) + } + }) + } +} diff --git a/vttest/test-cursor-movement-1 b/vttest/test-cursor-movement-1 new file mode 100644 index 0000000..054a1ab Binary files /dev/null and b/vttest/test-cursor-movement-1 differ diff --git a/vttest/test-cursor-movement-2.png b/vttest/test-cursor-movement-2.png new file mode 100644 index 0000000..abfe168 Binary files /dev/null and b/vttest/test-cursor-movement-2.png differ