func AverageNRGBA64(rect image.Rectangle, img *image.NRGBA64) color.NRGBA64 { // Only use the area of the rectangle that overlaps with the image bounds. rect = rect.Intersect(img.Bounds()) // Determine whether or not there's any area over which to determine an // average. d := uint64(rect.Dx() * rect.Dy()) if d == 0 { return color.NRGBA64{} } var r, g, b, a uint64 AllPointsRP( func(pt image.Point) { c := img.NRGBA64At(pt.X, pt.Y) r += uint64(c.R) g += uint64(c.G) b += uint64(c.B) a += uint64(c.A) }, )(rect) return color.NRGBA64{ R: uint16(r / d), G: uint16(g / d), B: uint16(b / d), A: uint16(a / d), } }
func resizeNRGBA64(in *image.NRGBA64, out *image.RGBA64, 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 } // Forward alpha-premultiplication a := int64(uint16(row[xi+6])<<8 | uint16(row[xi+7])) r := int64(uint16(row[xi+0])<<8|uint16(row[xi+1])) * a r /= 0xffff g := int64(uint16(row[xi+2])<<8|uint16(row[xi+3])) * a g /= 0xffff b := int64(uint16(row[xi+4])<<8|uint16(row[xi+5])) * a b /= 0xffff rgba[0] += int64(coeff) * r rgba[1] += int64(coeff) * g rgba[2] += int64(coeff) * b rgba[3] += int64(coeff) * a 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 resizeGeneric(in image.Image, 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++ { 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 xi < 0: xi = 0 case xi >= maxX: xi = maxX } r, g, b, a := in.At(xi+in.Bounds().Min.X, x+in.Bounds().Min.Y).RGBA() // reverse alpha-premultiplication. if a != 0 { r *= 0xffff r /= a g *= 0xffff g /= a b *= 0xffff b /= a } rgba[0] += int64(coeff) * int64(r) rgba[1] += int64(coeff) * int64(g) rgba[2] += int64(coeff) * int64(b) rgba[3] += int64(coeff) * int64(a) sum += int64(coeff) } } offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8 value := clampUint16(rgba[0] / sum) out.Pix[offset+0] = uint8(value >> 8) out.Pix[offset+1] = uint8(value) value = clampUint16(rgba[1] / sum) out.Pix[offset+2] = uint8(value >> 8) out.Pix[offset+3] = uint8(value) value = clampUint16(rgba[2] / sum) out.Pix[offset+4] = uint8(value >> 8) out.Pix[offset+5] = uint8(value) value = clampUint16(rgba[3] / sum) out.Pix[offset+6] = uint8(value >> 8) out.Pix[offset+7] = uint8(value) } } }
// Interpolate uint64/pixel images. func interpolate1x64(src *image.NRGBA64, dstW, dstH int) image.Image { srcRect := src.Bounds() srcW := srcRect.Dx() srcH := srcRect.Dy() ww, hh := uint64(dstW), uint64(dstH) dx, dy := uint64(srcW), uint64(srcH) n, sum := dx*dy, make([]uint64, dstW*dstH) for y := 0; y < srcH; y++ { pixOffset := src.PixOffset(0, y) for x := 0; x < srcW; x++ { // Get the source pixel. val64 := binary.BigEndian.Uint64([]byte(src.Pix[pixOffset+0 : pixOffset+8])) pixOffset += 8 // Spread the source pixel over 1 or more destination rows. py := uint64(y) * hh for remy := hh; remy > 0; { qy := dy - (py % dy) if qy > remy { qy = remy } // Spread the source pixel over 1 or more destination columns. px := uint64(x) * ww index := (py/dy)*ww + (px / dx) for remx := ww; remx > 0; { qx := dx - (px % dx) if qx > remx { qx = remx } qxy := qx * qy sum[index] += val64 * qxy index++ px += qx remx -= qx } py += qy remy -= qy } } } dst := image.NewNRGBA64(image.Rect(0, 0, dstW, dstH)) index := 0 for y := 0; y < dstH; y++ { pixOffset := dst.PixOffset(0, y) for x := 0; x < dstW; x++ { binary.BigEndian.PutUint64(dst.Pix[pixOffset+0:pixOffset+8], sum[index]/n) pixOffset += 8 index++ } } return dst }
func putLineNRGBA64(flipXY bool, column []f32RGBA, x int, dst *image.NRGBA64) { dy := dst.Bounds().Min.Y dx := dst.Bounds().Min.X for y, dst_c := range column { dst_nrgba := color.NRGBA64{ R: clampF32ToUint16(f32_to_uint16 * dst_c.R), G: clampF32ToUint16(f32_to_uint16 * dst_c.G), B: clampF32ToUint16(f32_to_uint16 * dst_c.B), A: clampF32ToUint16(f32_to_uint16 * dst_c.A), } if flipXY { dst.SetNRGBA64(y+dx, x+dy, dst_nrgba) } else { dst.SetNRGBA64(x+dx, y+dy, dst_nrgba) } } }
func fetchLineNRGBA64(flipXY bool, column []f32RGBA, x int, src *image.NRGBA64) { dy := src.Bounds().Min.Y dx := src.Bounds().Min.X pix := src.Pix var idx int for y := 0; y != len(column); y++ { if flipXY { idx = src.PixOffset(y+dx, x+dy) } else { idx = src.PixOffset(x+dx, y+dy) } column[y].R = uint16_to_f32 * float32(uint16(pix[idx+0])<<8|uint16(pix[idx+1])) column[y].G = uint16_to_f32 * float32(uint16(pix[idx+2])<<8|uint16(pix[idx+3])) column[y].B = uint16_to_f32 * float32(uint16(pix[idx+4])<<8|uint16(pix[idx+5])) column[y].A = uint16_to_f32 * float32(uint16(pix[idx+6])<<8|uint16(pix[idx+7])) } }
func nearestNRGBA64(in *image.NRGBA64, out *image.NRGBA64, scale float64, coeffs []bool, 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]float32 var sum float32 start := offset[y] ci := y * filterLength for i := 0; i < filterLength; i++ { if coeffs[ci+i] { xi := start + i switch { case uint(xi) < uint(maxX): xi *= 8 case xi >= maxX: xi = 8 * maxX default: xi = 0 } rgba[0] += float32(uint16(row[xi+0])<<8 | uint16(row[xi+1])) rgba[1] += float32(uint16(row[xi+2])<<8 | uint16(row[xi+3])) rgba[2] += float32(uint16(row[xi+4])<<8 | uint16(row[xi+5])) rgba[3] += float32(uint16(row[xi+6])<<8 | uint16(row[xi+7])) sum++ } } xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8 value := floatToUint16(rgba[0] / sum) out.Pix[xo+0] = uint8(value >> 8) out.Pix[xo+1] = uint8(value) value = floatToUint16(rgba[1] / sum) out.Pix[xo+2] = uint8(value >> 8) out.Pix[xo+3] = uint8(value) value = floatToUint16(rgba[2] / sum) out.Pix[xo+4] = uint8(value >> 8) out.Pix[xo+5] = uint8(value) value = floatToUint16(rgba[3] / sum) out.Pix[xo+6] = uint8(value >> 8) out.Pix[xo+7] = uint8(value) } } }
func resize64(src *image.NRGBA64, dstW, dstH int) image.Image { srcRect := src.Bounds() srcW := srcRect.Dx() srcH := srcRect.Dy() dstW64, dstH64 := uint64(dstW), uint64(dstH) srcW64, srcH64 := uint64(srcW), uint64(srcH) dst := image.NewNRGBA64(image.Rect(0, 0, dstW, dstH)) var x, y uint64 dstI := 0 for y = 0; y < dstH64; y++ { srcY := int(y * srcH64 / dstH64) for x = 0; x < dstW64; x++ { srcX := int(x * srcW64 / dstW64) srcI := 8 * (srcY*srcW + srcX) copy(dst.Pix[dstI:dstI+8], src.Pix[srcI:srcI+8]) dstI += 8 } } return dst }
// Interpolate 4 interleaved uint16 per pixel images. func interpolate4x16(src *image.NRGBA64, dstW, dstH int) image.Image { srcRect := src.Bounds() srcW := srcRect.Dx() srcH := srcRect.Dy() ww, hh := uint64(dstW), uint64(dstH) dx, dy := uint64(srcW), uint64(srcH) n, sum := dx*dy, make([]uint64, 4*dstW*dstH) for y := 0; y < srcH; y++ { pixOffset := src.PixOffset(0, y) for x := 0; x < srcW; x++ { // Get the source pixel. r64 := uint64(binary.BigEndian.Uint16([]byte(src.Pix[pixOffset+0 : pixOffset+2]))) g64 := uint64(binary.BigEndian.Uint16([]byte(src.Pix[pixOffset+2 : pixOffset+4]))) b64 := uint64(binary.BigEndian.Uint16([]byte(src.Pix[pixOffset+4 : pixOffset+6]))) a64 := uint64(binary.BigEndian.Uint16([]byte(src.Pix[pixOffset+6 : pixOffset+8]))) pixOffset += 8 // Spread the source pixel over 1 or more destination rows. py := uint64(y) * hh for remy := hh; remy > 0; { qy := dy - (py % dy) if qy > remy { qy = remy } // Spread the source pixel over 1 or more destination columns. px := uint64(x) * ww index := 4 * ((py/dy)*ww + (px / dx)) for remx := ww; remx > 0; { qx := dx - (px % dx) if qx > remx { qx = remx } qxy := qx * qy sum[index+0] += r64 * qxy sum[index+1] += g64 * qxy sum[index+2] += b64 * qxy sum[index+3] += a64 * qxy index += 4 px += qx remx -= qx } py += qy remy -= qy } } } dst := image.NewNRGBA64(image.Rect(0, 0, dstW, dstH)) for y := 0; y < dstH; y++ { pixOffset := dst.PixOffset(0, y) index := 4 * y * dstW for x := 0; x < dstW; x++ { binary.BigEndian.PutUint16(dst.Pix[pixOffset+0:pixOffset+2], uint16(sum[index+0]/n)) binary.BigEndian.PutUint16(dst.Pix[pixOffset+2:pixOffset+4], uint16(sum[index+1]/n)) binary.BigEndian.PutUint16(dst.Pix[pixOffset+4:pixOffset+6], uint16(sum[index+2]/n)) binary.BigEndian.PutUint16(dst.Pix[pixOffset+6:pixOffset+8], uint16(sum[index+3]/n)) pixOffset += 8 index += 4 } } return dst }