Return NRGBA images.

Resizing images with alpha channels is easier for NRGBA, NRGBA64 image types.
Support for these is added by providing the necessary resize functions.
This commit is contained in:
jst 2015-03-25 18:38:23 +01:00
parent 53e9ca890b
commit daa7cf45d3
2 changed files with 107 additions and 19 deletions

View File

@ -43,7 +43,7 @@ func clampUint16(in int64) uint16 {
return 0 return 0
} }
func resizeGeneric(in image.Image, out *image.RGBA64, scale float64, coeffs []int32, offset []int, filterLength int) { func resizeGeneric(in image.Image, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
newBounds := out.Bounds() newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1 maxX := in.Bounds().Dx() - 1
@ -89,7 +89,7 @@ func resizeGeneric(in image.Image, out *image.RGBA64, scale float64, coeffs []in
} }
} }
func resizeRGBA(in *image.RGBA, out *image.RGBA, scale float64, coeffs []int16, offset []int, filterLength int) { func resizeRGBA(in *image.RGBA, out *image.NRGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
newBounds := out.Bounds() newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1 maxX := in.Bounds().Dx() - 1
@ -129,7 +129,95 @@ func resizeRGBA(in *image.RGBA, out *image.RGBA, scale float64, coeffs []int16,
} }
} }
func resizeRGBA64(in *image.RGBA64, out *image.RGBA64, scale float64, coeffs []int32, offset []int, filterLength int) { func resizeNRGBA(in *image.NRGBA, out *image.NRGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]int32
var sum int32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
coeff := coeffs[ci+i]
if coeff != 0 {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 4
case xi >= maxX:
xi = 4 * maxX
default:
xi = 0
}
rgba[0] += int32(coeff) * int32(row[xi+0])
rgba[1] += int32(coeff) * int32(row[xi+1])
rgba[2] += int32(coeff) * int32(row[xi+2])
rgba[3] += int32(coeff) * int32(row[xi+3])
sum += int32(coeff)
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
out.Pix[xo+0] = clampUint8(rgba[0] / sum)
out.Pix[xo+1] = clampUint8(rgba[1] / sum)
out.Pix[xo+2] = clampUint8(rgba[2] / sum)
out.Pix[xo+3] = clampUint8(rgba[3] / sum)
}
}
}
func resizeRGBA64(in *image.RGBA64, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]int64
var sum int64
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
coeff := coeffs[ci+i]
if coeff != 0 {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 8
case xi >= maxX:
xi = 8 * maxX
default:
xi = 0
}
rgba[0] += int64(coeff) * int64(uint16(row[xi+0])<<8|uint16(row[xi+1]))
rgba[1] += int64(coeff) * int64(uint16(row[xi+2])<<8|uint16(row[xi+3]))
rgba[2] += int64(coeff) * int64(uint16(row[xi+4])<<8|uint16(row[xi+5]))
rgba[3] += int64(coeff) * int64(uint16(row[xi+6])<<8|uint16(row[xi+7]))
sum += int64(coeff)
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
value := clampUint16(rgba[0] / sum)
out.Pix[xo+0] = uint8(value >> 8)
out.Pix[xo+1] = uint8(value)
value = clampUint16(rgba[1] / sum)
out.Pix[xo+2] = uint8(value >> 8)
out.Pix[xo+3] = uint8(value)
value = clampUint16(rgba[2] / sum)
out.Pix[xo+4] = uint8(value >> 8)
out.Pix[xo+5] = uint8(value)
value = clampUint16(rgba[3] / sum)
out.Pix[xo+6] = uint8(value >> 8)
out.Pix[xo+7] = uint8(value)
}
}
}
func resizeNRGBA64(in *image.NRGBA64, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
newBounds := out.Bounds() newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1 maxX := in.Bounds().Dx() - 1

View File

@ -105,14 +105,14 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
switch input := img.(type) { switch input := img.(type) {
case *image.RGBA: case *image.RGBA:
// 8-bit precision // 8-bit precision
temp := image.NewRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width))) temp := image.NewNRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewRGBA(image.Rect(0, 0, int(width), int(height))) result := image.NewNRGBA(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image // horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel) coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
wg.Add(cpus) wg.Add(cpus)
for i := 0; i < cpus; i++ { for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.RGBA) slice := makeSlice(temp, i, cpus).(*image.NRGBA)
go func() { go func() {
defer wg.Done() defer wg.Done()
resizeRGBA(input, slice, scaleX, coeffs, offset, filterLength) resizeRGBA(input, slice, scaleX, coeffs, offset, filterLength)
@ -124,10 +124,10 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel) coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel)
wg.Add(cpus) wg.Add(cpus)
for i := 0; i < cpus; i++ { for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.RGBA) slice := makeSlice(result, i, cpus).(*image.NRGBA)
go func() { go func() {
defer wg.Done() defer wg.Done()
resizeRGBA(temp, slice, scaleY, coeffs, offset, filterLength) resizeNRGBA(temp, slice, scaleY, coeffs, offset, filterLength)
}() }()
} }
wg.Wait() wg.Wait()
@ -164,14 +164,14 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
return result.YCbCr() return result.YCbCr()
case *image.RGBA64: case *image.RGBA64:
// 16-bit precision // 16-bit precision
temp := image.NewRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width))) temp := image.NewNRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height))) result := image.NewNRGBA64(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image // horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel) coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
wg.Add(cpus) wg.Add(cpus)
for i := 0; i < cpus; i++ { for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.RGBA64) slice := makeSlice(temp, i, cpus).(*image.NRGBA64)
go func() { go func() {
defer wg.Done() defer wg.Done()
resizeRGBA64(input, slice, scaleX, coeffs, offset, filterLength) resizeRGBA64(input, slice, scaleX, coeffs, offset, filterLength)
@ -183,10 +183,10 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel) coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel)
wg.Add(cpus) wg.Add(cpus)
for i := 0; i < cpus; i++ { for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.RGBA64) slice := makeSlice(result, i, cpus).(*image.NRGBA64)
go func() { go func() {
defer wg.Done() defer wg.Done()
resizeGeneric(temp, slice, scaleY, coeffs, offset, filterLength) resizeNRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
}() }()
} }
wg.Wait() wg.Wait()
@ -251,14 +251,14 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
return result return result
default: default:
// 16-bit precision // 16-bit precision
temp := image.NewRGBA64(image.Rect(0, 0, img.Bounds().Dy(), int(width))) temp := image.NewNRGBA64(image.Rect(0, 0, img.Bounds().Dy(), int(width)))
result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height))) result := image.NewNRGBA64(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image // horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel) coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
wg.Add(cpus) wg.Add(cpus)
for i := 0; i < cpus; i++ { for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.RGBA64) slice := makeSlice(temp, i, cpus).(*image.NRGBA64)
go func() { go func() {
defer wg.Done() defer wg.Done()
resizeGeneric(img, slice, scaleX, coeffs, offset, filterLength) resizeGeneric(img, slice, scaleX, coeffs, offset, filterLength)
@ -270,10 +270,10 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel) coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel)
wg.Add(cpus) wg.Add(cpus)
for i := 0; i < cpus; i++ { for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.RGBA64) slice := makeSlice(result, i, cpus).(*image.NRGBA64)
go func() { go func() {
defer wg.Done() defer wg.Done()
resizeRGBA64(temp, slice, scaleY, coeffs, offset, filterLength) resizeNRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
}() }()
} }
wg.Wait() wg.Wait()
@ -370,7 +370,7 @@ func resizeNearest(width, height uint, scaleX, scaleY float64, img image.Image,
slice := makeSlice(result, i, cpus).(*image.RGBA64) slice := makeSlice(result, i, cpus).(*image.RGBA64)
go func() { go func() {
defer wg.Done() defer wg.Done()
nearestGeneric(temp, slice, scaleY, coeffs, offset, filterLength) nearestRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
}() }()
} }
wg.Wait() wg.Wait()