diff options
Diffstat (limited to 'vendor/github.com/disintegration/imaging/tools.go')
-rw-r--r-- | vendor/github.com/disintegration/imaging/tools.go | 201 |
1 files changed, 201 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 000000000..76f14447b --- /dev/null +++ b/vendor/github.com/disintegration/imaging/tools.go @@ -0,0 +1,201 @@ +package imaging + +import ( + "image" + "math" +) + +// Anchor is the anchor point for image alignment. +type Anchor int + +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 { + src := toNRGBA(img) + srcRect := rect.Sub(img.Bounds().Min) + sub := src.SubImage(srcRect) + return Clone(sub) // New image Bounds().Min point will be (0, 0) +} + +// 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 { + src := toNRGBA(img) + dst := Clone(background) // cloned image bounds start at (0, 0) + startPt := pos.Sub(background.Bounds().Min) // so we should translate start point + endPt := startPt.Add(src.Bounds().Size()) + pasteBounds := image.Rectangle{startPt, endPt} + + if dst.Bounds().Overlaps(pasteBounds) { + intersectBounds := dst.Bounds().Intersect(pasteBounds) + + rowSize := intersectBounds.Dx() * 4 + numRows := intersectBounds.Dy() + + srcStartX := intersectBounds.Min.X - pasteBounds.Min.X + srcStartY := intersectBounds.Min.Y - pasteBounds.Min.Y + + i0 := dst.PixOffset(intersectBounds.Min.X, intersectBounds.Min.Y) + j0 := src.PixOffset(srcStartX, srcStartY) + + di := dst.Stride + dj := src.Stride + + for row := 0; row < numRows; row++ { + copy(dst.Pix[i0:i0+rowSize], src.Pix[j0:j0+rowSize]) + i0 += di + j0 += dj + } + } + + 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 the sprite over the background at position (50, 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) // check: 0.0 <= opacity <= 1.0 + + src := toNRGBA(img) + dst := Clone(background) // cloned image bounds start at (0, 0) + startPt := pos.Sub(background.Bounds().Min) // so we should translate start point + endPt := startPt.Add(src.Bounds().Size()) + pasteBounds := image.Rectangle{startPt, endPt} + + if dst.Bounds().Overlaps(pasteBounds) { + intersectBounds := dst.Bounds().Intersect(pasteBounds) + + for y := intersectBounds.Min.Y; y < intersectBounds.Max.Y; y++ { + for x := intersectBounds.Min.X; x < intersectBounds.Max.X; x++ { + i := y*dst.Stride + x*4 + + srcX := x - pasteBounds.Min.X + srcY := y - pasteBounds.Min.Y + j := srcY*src.Stride + srcX*4 + + a1 := float64(dst.Pix[i+3]) + a2 := float64(src.Pix[j+3]) + + coef2 := opacity * a2 / 255.0 + coef1 := (1 - coef2) * a1 / 255.0 + coefSum := coef1 + coef2 + coef1 /= coefSum + coef2 /= coefSum + + dst.Pix[i+0] = uint8(float64(dst.Pix[i+0])*coef1 + float64(src.Pix[j+0])*coef2) + dst.Pix[i+1] = uint8(float64(dst.Pix[i+1])*coef1 + float64(src.Pix[j+1])*coef2) + dst.Pix[i+2] = uint8(float64(dst.Pix[i+2])*coef1 + float64(src.Pix[j+2])*coef2) + dst.Pix[i+3] = uint8(math.Min(a1+a2*opacity*(255.0-a1)/255.0, 255.0)) + } + } + } + + 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) +} |