| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- /*Package clone provides image cloning function.*/
- package clone
- import (
- "image"
- "image/draw"
- "github.com/anthonynsimon/bild/parallel"
- )
- // PadMethod is the method used to fill padded pixels.
- type PadMethod uint8
- const (
- // NoFill leaves the padded pixels empty.
- NoFill = iota
- // EdgeExtend extends the closest edge pixel.
- EdgeExtend
- // EdgeWrap wraps around the pixels of an image.
- EdgeWrap
- )
- // AsRGBA returns an RGBA copy of the supplied image.
- func AsRGBA(src image.Image) *image.RGBA {
- bounds := src.Bounds()
- img := image.NewRGBA(bounds)
- draw.Draw(img, bounds, src, bounds.Min, draw.Src)
- return img
- }
- // AsShallowRGBA tries to cast to image.RGBA to get reference. Otherwise makes a copy
- func AsShallowRGBA(src image.Image) *image.RGBA {
- if rgba, ok := src.(*image.RGBA); ok {
- return rgba
- }
- return AsRGBA(src)
- }
- // Pad returns an RGBA copy of the src image parameter with its edges padded
- // using the supplied PadMethod.
- // Parameter padX and padY correspond to the amount of padding to be applied
- // on each side.
- // Parameter m is the PadMethod to fill the new pixels.
- //
- // Usage example:
- //
- // result := Pad(img, 5,5, EdgeExtend)
- func Pad(src image.Image, padX, padY int, m PadMethod) *image.RGBA {
- var result *image.RGBA
- switch m {
- case EdgeExtend:
- result = extend(src, padX, padY)
- case NoFill:
- result = noFill(src, padX, padY)
- case EdgeWrap:
- result = wrap(src, padX, padY)
- default:
- result = extend(src, padX, padY)
- }
- return result
- }
- func noFill(img image.Image, padX, padY int) *image.RGBA {
- srcBounds := img.Bounds()
- paddedW, paddedH := srcBounds.Dx()+2*padX, srcBounds.Dy()+2*padY
- newBounds := image.Rect(0, 0, paddedW, paddedH)
- fillBounds := image.Rect(padX, padY, padX+srcBounds.Dx(), padY+srcBounds.Dy())
- dst := image.NewRGBA(newBounds)
- draw.Draw(dst, fillBounds, img, srcBounds.Min, draw.Src)
- return dst
- }
- func extend(img image.Image, padX, padY int) *image.RGBA {
- dst := noFill(img, padX, padY)
- paddedW, paddedH := dst.Bounds().Dx(), dst.Bounds().Dy()
- parallel.Line(paddedH, func(start, end int) {
- for y := start; y < end; y++ {
- iy := y
- if iy < padY {
- iy = padY
- } else if iy >= paddedH-padY {
- iy = paddedH - padY - 1
- }
- for x := 0; x < paddedW; x++ {
- ix := x
- if ix < padX {
- ix = padX
- } else if x >= paddedW-padX {
- ix = paddedW - padX - 1
- } else if iy == y {
- // This only enters if we are not in a y-padded area or
- // x-padded area, so nothing to extend here.
- // So simply jump to the next padded-x index.
- x = paddedW - padX - 1
- continue
- }
- dstPos := y*dst.Stride + x*4
- edgePos := iy*dst.Stride + ix*4
- dst.Pix[dstPos+0] = dst.Pix[edgePos+0]
- dst.Pix[dstPos+1] = dst.Pix[edgePos+1]
- dst.Pix[dstPos+2] = dst.Pix[edgePos+2]
- dst.Pix[dstPos+3] = dst.Pix[edgePos+3]
- }
- }
- })
- return dst
- }
- func wrap(img image.Image, padX, padY int) *image.RGBA {
- dst := noFill(img, padX, padY)
- paddedW, paddedH := dst.Bounds().Dx(), dst.Bounds().Dy()
- parallel.Line(paddedH, func(start, end int) {
- for y := start; y < end; y++ {
- iy := y
- if iy < padY {
- iy = (paddedH - padY) - ((padY - y) % (paddedH - padY*2))
- } else if iy >= paddedH-padY {
- iy = padY - ((padY - y) % (paddedH - padY*2))
- }
- for x := 0; x < paddedW; x++ {
- ix := x
- if ix < padX {
- ix = (paddedW - padX) - ((padX - x) % (paddedW - padX*2))
- } else if ix >= paddedW-padX {
- ix = padX - ((padX - x) % (paddedW - padX*2))
- } else if iy == y {
- // This only enters if we are not in a y-padded area or
- // x-padded area, so nothing to extend here.
- // So simply jump to the next padded-x index.
- x = paddedW - padX - 1
- continue
- }
- dstPos := y*dst.Stride + x*4
- edgePos := iy*dst.Stride + ix*4
- dst.Pix[dstPos+0] = dst.Pix[edgePos+0]
- dst.Pix[dstPos+1] = dst.Pix[edgePos+1]
- dst.Pix[dstPos+2] = dst.Pix[edgePos+2]
- dst.Pix[dstPos+3] = dst.Pix[edgePos+3]
- }
- }
- })
- return dst
- }
|