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:
parent
53e9ca890b
commit
daa7cf45d3
94
converter.go
94
converter.go
|
@ -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
|
||||||
|
|
||||||
|
|
32
resize.go
32
resize.go
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user