summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/disintegration/imaging/tools.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/disintegration/imaging/tools.go')
-rw-r--r--vendor/github.com/disintegration/imaging/tools.go249
1 files changed, 249 insertions, 0 deletions
diff --git a/vendor/github.com/disintegration/imaging/tools.go b/vendor/github.com/disintegration/imaging/tools.go
new file mode 100644
index 00000000..0ec19a03
--- /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.
+//
+// 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)
+}