summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/disintegration/imaging/resize.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/disintegration/imaging/resize.go')
-rw-r--r--vendor/github.com/disintegration/imaging/resize.go221
1 files changed, 99 insertions, 122 deletions
diff --git a/vendor/github.com/disintegration/imaging/resize.go b/vendor/github.com/disintegration/imaging/resize.go
index cd5bfb5d8..97f498a0a 100644
--- a/vendor/github.com/disintegration/imaging/resize.go
+++ b/vendor/github.com/disintegration/imaging/resize.go
@@ -24,17 +24,17 @@ func precomputeWeights(dstSize, srcSize int, filter ResampleFilter) [][]indexWei
for v := 0; v < dstSize; v++ {
fu := (float64(v)+0.5)*du - 0.5
- startu := int(math.Ceil(fu - ru))
- if startu < 0 {
- startu = 0
+ begin := int(math.Ceil(fu - ru))
+ if begin < 0 {
+ begin = 0
}
- endu := int(math.Floor(fu + ru))
- if endu > srcSize-1 {
- endu = srcSize - 1
+ end := int(math.Floor(fu + ru))
+ if end > srcSize-1 {
+ end = srcSize - 1
}
var sum float64
- for u := startu; u <= endu; u++ {
+ for u := begin; u <= end; u++ {
w := filter.Kernel((float64(u) - fu) / scale)
if w != 0 {
sum += w
@@ -67,7 +67,6 @@ func precomputeWeights(dstSize, srcSize int, filter ResampleFilter) [][]indexWei
//
func Resize(img image.Image, width, height int, filter ResampleFilter) *image.NRGBA {
dstW, dstH := width, height
-
if dstW < 0 || dstH < 0 {
return &image.NRGBA{}
}
@@ -75,16 +74,13 @@ func Resize(img image.Image, width, height int, filter ResampleFilter) *image.NR
return &image.NRGBA{}
}
- src := toNRGBA(img)
-
- srcW := src.Bounds().Max.X
- srcH := src.Bounds().Max.Y
-
+ 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 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)))
@@ -94,57 +90,45 @@ func Resize(img image.Image, width, height int, filter ResampleFilter) *image.NR
dstH = int(math.Max(1.0, math.Floor(tmpH+0.5)))
}
- var dst *image.NRGBA
-
- if filter.Support <= 0.0 {
- // nearest-neighbor special case
- dst = resizeNearest(src, dstW, dstH)
-
- } else {
- // two-pass resize
- if srcW != dstW {
- dst = resizeHorizontal(src, dstW, filter)
- } else {
- dst = src
- }
-
- if srcH != dstH {
- dst = resizeVertical(dst, dstH, filter)
- }
+ if filter.Support <= 0 {
+ // Nearest-neighbor special case.
+ return resizeNearest(img, dstW, dstH)
}
- return dst
+ 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(src *image.NRGBA, width int, filter ResampleFilter) *image.NRGBA {
- srcBounds := src.Bounds()
- srcW := srcBounds.Max.X
- srcH := srcBounds.Max.Y
-
- dstW := width
- dstH := srcH
-
- dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
-
- weights := precomputeWeights(dstW, srcW, filter)
-
- parallel(dstH, func(partStart, partEnd int) {
- for dstY := partStart; dstY < partEnd; dstY++ {
- i0 := dstY * src.Stride
- j0 := dstY * dst.Stride
- for dstX := 0; dstX < dstW; dstX++ {
+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 := 0; x < width; x++ {
var r, g, b, a float64
- for _, w := range weights[dstX] {
- i := i0 + w.index*4
- aw := float64(src.Pix[i+3]) * w.weight
- r += float64(src.Pix[i+0]) * aw
- g += float64(src.Pix[i+1]) * aw
- b += float64(src.Pix[i+2]) * aw
+ for _, w := range weights[x] {
+ i := w.index * 4
+ aw := float64(scanLine[i+3]) * w.weight
+ r += float64(scanLine[i+0]) * aw
+ g += float64(scanLine[i+1]) * aw
+ b += float64(scanLine[i+2]) * aw
a += aw
}
if a != 0 {
aInv := 1 / a
- j := j0 + dstX*4
+ j := j0 + x*4
dst.Pix[j+0] = clamp(r * aInv)
dst.Pix[j+1] = clamp(g * aInv)
dst.Pix[j+2] = clamp(b * aInv)
@@ -153,37 +137,30 @@ func resizeHorizontal(src *image.NRGBA, width int, filter ResampleFilter) *image
}
}
})
-
return dst
}
-func resizeVertical(src *image.NRGBA, height int, filter ResampleFilter) *image.NRGBA {
- srcBounds := src.Bounds()
- srcW := srcBounds.Max.X
- srcH := srcBounds.Max.Y
-
- dstW := srcW
- dstH := height
-
- dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
-
- weights := precomputeWeights(dstH, srcH, filter)
-
- parallel(dstW, func(partStart, partEnd int) {
- for dstX := partStart; dstX < partEnd; dstX++ {
- for dstY := 0; dstY < dstH; dstY++ {
+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 := 0; y < height; y++ {
var r, g, b, a float64
- for _, w := range weights[dstY] {
- i := w.index*src.Stride + dstX*4
- aw := float64(src.Pix[i+3]) * w.weight
- r += float64(src.Pix[i+0]) * aw
- g += float64(src.Pix[i+1]) * aw
- b += float64(src.Pix[i+2]) * aw
+ for _, w := range weights[y] {
+ i := w.index * 4
+ aw := float64(scanLine[i+3]) * w.weight
+ r += float64(scanLine[i+0]) * aw
+ g += float64(scanLine[i+1]) * aw
+ b += float64(scanLine[i+2]) * aw
a += aw
}
if a != 0 {
aInv := 1 / a
- j := dstY*dst.Stride + dstX*4
+ j := y*dst.Stride + x*4
dst.Pix[j+0] = clamp(r * aInv)
dst.Pix[j+1] = clamp(g * aInv)
dst.Pix[j+2] = clamp(b * aInv)
@@ -192,45 +169,44 @@ func resizeVertical(src *image.NRGBA, height int, filter ResampleFilter) *image.
}
}
})
-
return dst
}
// resizeNearest is a fast nearest-neighbor resize, no filtering.
-func resizeNearest(src *image.NRGBA, width, height int) *image.NRGBA {
- dstW, dstH := width, height
-
- srcBounds := src.Bounds()
- srcW := srcBounds.Max.X
- srcH := srcBounds.Max.Y
-
- dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
-
- dx := float64(srcW) / float64(dstW)
- dy := float64(srcH) / float64(dstH)
-
- parallel(dstH, func(partStart, partEnd int) {
-
- for dstY := partStart; dstY < partEnd; dstY++ {
- srcY := int((float64(dstY) + 0.5) * dy)
- if srcY > srcH-1 {
- srcY = srcH - 1
+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
+ }
}
-
- for dstX := 0; dstX < dstW; dstX++ {
- srcX := int((float64(dstX) + 0.5) * dx)
- if srcX > srcW-1 {
- srcX = srcW - 1
+ })
+ } 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
}
-
- srcOff := srcY*src.Stride + srcX*4
- dstOff := dstY*dst.Stride + dstX*4
-
- copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
}
- }
-
- })
+ })
+ }
return dst
}
@@ -344,27 +320,28 @@ func Thumbnail(img image.Image, width, height int, filter ResampleFilter) *image
// General filter recommendations:
//
// - Lanczos
-// Probably the best resampling filter for photographic images yielding sharp results,
-// but it's slower than cubic filters (see below).
+// 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 than CatmullRom.
+// 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.
+// Bilinear interpolation filter, produces reasonably good, smooth output.
+// It's faster than cubic filters.
//
// - Box
-// Simple and fast resampling filter appropriate for downscaling.
+// Simple and fast averaging filter appropriate for downscaling.
// When upscaling it's similar to NearestNeighbor.
//
// - NearestNeighbor
-// Fastest resample filter, no antialiasing at all. Rarely used.
+// Fastest resampling filter, no antialiasing.
//
type ResampleFilter struct {
Support float64
@@ -417,14 +394,14 @@ var Welch ResampleFilter
var Cosine ResampleFilter
func bcspline(x, b, c float64) float64 {
+ var y float64
x = math.Abs(x)
if x < 1.0 {
- return ((12-9*b-6*c)*x*x*x + (-18+12*b+6*c)*x*x + (6 - 2*b)) / 6
- }
- if x < 2.0 {
- return ((-b-6*c)*x*x*x + (6*b+30*c)*x*x + (-12*b-48*c)*x + (8*b + 24*c)) / 6
+ 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 0
+ return y
}
func sinc(x float64) float64 {