123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- /*
- Copyright (c) 2014, Charlie Vieth <charlie.vieth@gmail.com>
-
- Permission to use, copy, modify, and/or distribute this software for any purpose
- with or without fee is hereby granted, provided that the above copyright notice
- and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
- THIS SOFTWARE.
- */
-
- 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) {
- 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]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 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()
- 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) {
- 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 *= 4
- case xi >= maxX:
- xi = 4 * maxX
- default:
- xi = 0
- }
- 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 nearestNRGBA(in *image.NRGBA, out *image.NRGBA, 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 *= 4
- case xi >= maxX:
- xi = 4 * maxX
- default:
- xi = 0
- }
- 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) {
- 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 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 nearestGray(in *image.Gray, out *image.Gray, 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 gray 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 xi < 0:
- xi = 0
- case xi >= maxX:
- xi = maxX
- }
- 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) {
- 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 gray 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 *= 2
- case xi >= maxX:
- xi = 2 * maxX
- default:
- xi = 0
- }
- 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)
- }
- }
- }
|