0
Fork 0
mirror of https://github.com/willnorris/imageproxy.git synced 2025-01-06 22:40:34 -05:00
imageproxy/vendor/github.com/disintegration/imaging/clone.go
2018-02-02 10:23:34 +00:00

312 lines
7.4 KiB
Go

package imaging
import (
"image"
"image/color"
)
// Clone returns a copy of the given image.
func Clone(img image.Image) *image.NRGBA {
dstBounds := img.Bounds().Sub(img.Bounds().Min)
dst := image.NewNRGBA(dstBounds)
switch src := img.(type) {
case *image.NRGBA:
copyNRGBA(dst, src)
case *image.NRGBA64:
copyNRGBA64(dst, src)
case *image.RGBA:
copyRGBA(dst, src)
case *image.RGBA64:
copyRGBA64(dst, src)
case *image.Gray:
copyGray(dst, src)
case *image.Gray16:
copyGray16(dst, src)
case *image.YCbCr:
copyYCbCr(dst, src)
case *image.Paletted:
copyPaletted(dst, src)
default:
copyImage(dst, src)
}
return dst
}
func copyNRGBA(dst *image.NRGBA, src *image.NRGBA) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
rowSize := dstW * 4
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
}
})
}
func copyNRGBA64(dst *image.NRGBA, src *image.NRGBA64) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
dst.Pix[di+0] = src.Pix[si+0]
dst.Pix[di+1] = src.Pix[si+2]
dst.Pix[di+2] = src.Pix[si+4]
dst.Pix[di+3] = src.Pix[si+6]
di += 4
si += 8
}
}
})
}
func copyRGBA(dst *image.NRGBA, src *image.RGBA) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
a := src.Pix[si+3]
dst.Pix[di+3] = a
switch a {
case 0:
dst.Pix[di+0] = 0
dst.Pix[di+1] = 0
dst.Pix[di+2] = 0
case 0xff:
dst.Pix[di+0] = src.Pix[si+0]
dst.Pix[di+1] = src.Pix[si+1]
dst.Pix[di+2] = src.Pix[si+2]
default:
var tmp uint16
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
dst.Pix[di+0] = uint8(tmp)
tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
dst.Pix[di+1] = uint8(tmp)
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
dst.Pix[di+2] = uint8(tmp)
}
di += 4
si += 4
}
}
})
}
func copyRGBA64(dst *image.NRGBA, src *image.RGBA64) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
a := src.Pix[si+6]
dst.Pix[di+3] = a
switch a {
case 0:
dst.Pix[di+0] = 0
dst.Pix[di+1] = 0
dst.Pix[di+2] = 0
case 0xff:
dst.Pix[di+0] = src.Pix[si+0]
dst.Pix[di+1] = src.Pix[si+2]
dst.Pix[di+2] = src.Pix[si+4]
default:
var tmp uint16
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
dst.Pix[di+0] = uint8(tmp)
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
dst.Pix[di+1] = uint8(tmp)
tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
dst.Pix[di+2] = uint8(tmp)
}
di += 4
si += 8
}
}
})
}
func copyGray(dst *image.NRGBA, src *image.Gray) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := src.Pix[si]
dst.Pix[di+0] = c
dst.Pix[di+1] = c
dst.Pix[di+2] = c
dst.Pix[di+3] = 0xff
di += 4
si++
}
}
})
}
func copyGray16(dst *image.NRGBA, src *image.Gray16) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := src.Pix[si]
dst.Pix[di+0] = c
dst.Pix[di+1] = c
dst.Pix[di+2] = c
dst.Pix[di+3] = 0xff
di += 4
si += 2
}
}
})
}
func copyYCbCr(dst *image.NRGBA, src *image.YCbCr) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
srcY := srcMinY + dstY
di := dst.PixOffset(0, dstY)
for dstX := 0; dstX < dstW; dstX++ {
srcX := srcMinX + dstX
siy := (srcY-srcMinY)*src.YStride + (srcX - srcMinX)
var sic int
switch src.SubsampleRatio {
case image.YCbCrSubsampleRatio444:
sic = (srcY-srcMinY)*src.CStride + (srcX - srcMinX)
case image.YCbCrSubsampleRatio422:
sic = (srcY-srcMinY)*src.CStride + (srcX/2 - srcMinX/2)
case image.YCbCrSubsampleRatio420:
sic = (srcY/2-srcMinY/2)*src.CStride + (srcX/2 - srcMinX/2)
case image.YCbCrSubsampleRatio440:
sic = (srcY/2-srcMinY/2)*src.CStride + (srcX - srcMinX)
default:
sic = src.COffset(srcX, srcY)
}
y := int32(src.Y[siy])
cb := int32(src.Cb[sic]) - 128
cr := int32(src.Cr[sic]) - 128
r := (y<<16 + 91881*cr + 1<<15) >> 16
if r > 255 {
r = 255
} else if r < 0 {
r = 0
}
g := (y<<16 - 22554*cb - 46802*cr + 1<<15) >> 16
if g > 255 {
g = 255
} else if g < 0 {
g = 0
}
b := (y<<16 + 116130*cb + 1<<15) >> 16
if b > 255 {
b = 255
} else if b < 0 {
b = 0
}
dst.Pix[di+0] = uint8(r)
dst.Pix[di+1] = uint8(g)
dst.Pix[di+2] = uint8(b)
dst.Pix[di+3] = 255
di += 4
}
}
})
}
func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
plen := len(src.Palette)
pnew := make([]color.NRGBA, plen)
for i := 0; i < plen; i++ {
pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
}
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := pnew[src.Pix[si]]
dst.Pix[di+0] = c.R
dst.Pix[di+1] = c.G
dst.Pix[di+2] = c.B
dst.Pix[di+3] = c.A
di += 4
si++
}
}
})
}
func copyImage(dst *image.NRGBA, src image.Image) {
srcMinX := src.Bounds().Min.X
srcMinY := src.Bounds().Min.Y
dstW := dst.Bounds().Dx()
dstH := dst.Bounds().Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
dst.Pix[di+0] = c.R
dst.Pix[di+1] = c.G
dst.Pix[di+2] = c.B
dst.Pix[di+3] = c.A
di += 4
}
}
})
}
// toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
func toNRGBA(img image.Image) *image.NRGBA {
if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
return img
}
return Clone(img)
}