package resize import "image" func floatToUint8(x float32) uint8 { // Nearest-neighbor values are always // positive no need to check lower-bound. if x > 0xfe { return 0xff } return uint8(x) } func floatToUint16(x float32) uint16 { if x > 0xfffe { return 0xffff } return uint16(x) } func nearestGeneric(in image.Image, out *image.RGBA64, scale float64, coeffs []bool, offset []int, filterLength int) { oldBounds := in.Bounds() newBounds := out.Bounds() for x := newBounds.Min.X; x < newBounds.Max.X; x++ { for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ { var rgba [4]float32 var sum float32 start := offset[y] ci := (y - newBounds.Min.Y) * filterLength for i := 0; i < filterLength; i++ { if coeffs[ci+i] { xi := start + i switch { case uint(xi) < uint(oldBounds.Max.X): break case xi >= oldBounds.Max.X: xi = oldBounds.Min.X default: xi = oldBounds.Max.X - 1 } r, g, b, a := in.At(xi, x).RGBA() rgba[0] += float32(r) rgba[1] += float32(g) rgba[2] += float32(b) rgba[3] += float32(a) sum++ } } offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8 value := floatToUint16(rgba[0] / sum) out.Pix[offset+0] = uint8(value >> 8) out.Pix[offset+1] = uint8(value) value = floatToUint16(rgba[1] / sum) out.Pix[offset+2] = uint8(value >> 8) out.Pix[offset+3] = uint8(value) value = floatToUint16(rgba[2] / sum) out.Pix[offset+4] = uint8(value >> 8) out.Pix[offset+5] = uint8(value) value = floatToUint16(rgba[3] / sum) out.Pix[offset+6] = uint8(value >> 8) out.Pix[offset+7] = uint8(value) } } } func nearestRGBA(in *image.RGBA, out *image.RGBA, scale float64, coeffs []bool, offset []int, filterLength int) { oldBounds := in.Bounds() newBounds := out.Bounds() minX := oldBounds.Min.X * 4 maxX := (oldBounds.Max.X - oldBounds.Min.X - 1) * 4 for x := newBounds.Min.X; x < newBounds.Max.X; x++ { row := in.Pix[(x-oldBounds.Min.Y)*in.Stride:] for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ { var rgba [4]float32 var sum float32 start := offset[y] ci := (y - newBounds.Min.Y) * filterLength for i := 0; i < filterLength; i++ { if coeffs[ci+i] { xi := start + i switch { case uint(xi) < uint(oldBounds.Max.X): xi *= 4 case xi >= oldBounds.Max.X: xi = maxX default: xi = minX } rgba[0] += float32(row[xi+0]) rgba[1] += float32(row[xi+1]) rgba[2] += float32(row[xi+2]) rgba[3] += float32(row[xi+3]) sum++ } } xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4 out.Pix[xo+0] = floatToUint8(rgba[0] / sum) out.Pix[xo+1] = floatToUint8(rgba[1] / sum) out.Pix[xo+2] = floatToUint8(rgba[2] / sum) out.Pix[xo+3] = floatToUint8(rgba[3] / sum) } } } func nearestRGBA64(in *image.RGBA64, out *image.RGBA64, scale float64, coeffs []bool, offset []int, filterLength int) { oldBounds := in.Bounds() newBounds := out.Bounds() minX := oldBounds.Min.X * 8 maxX := (oldBounds.Max.X - oldBounds.Min.X - 1) * 8 for x := newBounds.Min.X; x < newBounds.Max.X; x++ { row := in.Pix[(x-oldBounds.Min.Y)*in.Stride:] for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ { var rgba [4]float32 var sum float32 start := offset[y] ci := (y - newBounds.Min.Y) * filterLength for i := 0; i < filterLength; i++ { if coeffs[ci+i] { xi := start + i switch { case uint(xi) < uint(oldBounds.Max.X): xi *= 8 case xi >= oldBounds.Max.X: xi = maxX default: xi = minX } 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 nearestGray(in *image.Gray, out *image.Gray, scale float64, coeffs []bool, offset []int, filterLength int) { oldBounds := in.Bounds() newBounds := out.Bounds() minX := oldBounds.Min.X maxX := (oldBounds.Max.X - oldBounds.Min.X - 1) for x := newBounds.Min.X; x < newBounds.Max.X; x++ { row := in.Pix[(x-oldBounds.Min.Y)*in.Stride:] for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ { var gray float32 var sum float32 start := offset[y] ci := (y - newBounds.Min.Y) * filterLength for i := 0; i < filterLength; i++ { if coeffs[ci+i] { xi := start + i switch { case uint(xi) < uint(oldBounds.Max.X): break case xi >= oldBounds.Max.X: xi = maxX default: xi = minX } gray += float32(row[xi]) sum++ } } offset := (y-newBounds.Min.Y)*out.Stride + (x - newBounds.Min.X) out.Pix[offset] = floatToUint8(gray / sum) } } } func nearestGray16(in *image.Gray16, out *image.Gray16, scale float64, coeffs []bool, offset []int, filterLength int) { oldBounds := in.Bounds() newBounds := out.Bounds() minX := oldBounds.Min.X * 2 maxX := (oldBounds.Max.X - oldBounds.Min.X - 1) * 2 for x := newBounds.Min.X; x < newBounds.Max.X; x++ { row := in.Pix[(x-oldBounds.Min.Y)*in.Stride:] for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ { var gray float32 var sum float32 start := offset[y] ci := (y - newBounds.Min.Y) * filterLength for i := 0; i < filterLength; i++ { if coeffs[ci+i] { xi := start + i switch { case uint(xi) < uint(oldBounds.Max.X): xi *= 2 case xi >= oldBounds.Max.X: xi = maxX default: xi = minX } gray += float32(uint16(row[xi+0])<<8 | uint16(row[xi+1])) sum++ } } offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*2 value := floatToUint16(gray / sum) out.Pix[offset+0] = uint8(value >> 8) out.Pix[offset+1] = uint8(value) } } }