| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- /*
- Copyright (c) 2012, Jan Schlicht <jan.schlicht@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"
- "image/color"
- )
- // Keep value in [0,255] range.
- func clampUint8(in int32) uint8 {
- if in < 0 {
- return 0
- }
- if in > 255 {
- return 255
- }
- return uint8(in)
- }
- // Keep value in [0,65535] range.
- func clampUint16(in int64) uint16 {
- if in < 0 {
- return 0
- }
- if in > 65535 {
- return 65535
- }
- return uint16(in)
- }
- func resizeGeneric(in image.Image, out *image.RGBA64, scale float64, coeffs []int32, 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++ {
- interpX := scale*(float64(y)+0.5) + float64(oldBounds.Min.X)
- start := int(interpX) - filterLength/2 + 1
- var rgba [4]int64
- var sum int64
- for i := 0; i < filterLength; i++ {
- xx := start + i
- if xx < oldBounds.Min.X {
- xx = oldBounds.Min.X
- } else if xx >= oldBounds.Max.X {
- xx = oldBounds.Max.X - 1
- }
- coeff := coeffs[(y-newBounds.Min.Y)*filterLength+i]
- r, g, b, a := in.At(xx, x).RGBA()
- 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)
- }
- }
- }
- func resizeRGBA(in *image.RGBA, out *image.RGBA, scale float64, coeffs []int16, filterLength int) {
- oldBounds := in.Bounds()
- newBounds := out.Bounds()
- 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++ {
- interpX := scale*(float64(y)+0.5) + float64(oldBounds.Min.X)
- start := int(interpX) - filterLength/2 + 1
- var rgba [4]int32
- var sum int32
- for i := 0; i < filterLength; i++ {
- xx := start + i
- if xx < oldBounds.Min.X {
- xx = oldBounds.Min.X
- } else if xx >= oldBounds.Max.X {
- xx = oldBounds.Max.X - 1
- }
- coeff := coeffs[(y-newBounds.Min.Y)*filterLength+i]
- offset := (xx - oldBounds.Min.X) * 4
- rgba[0] += int32(coeff) * int32(row[offset+0])
- rgba[1] += int32(coeff) * int32(row[offset+1])
- rgba[2] += int32(coeff) * int32(row[offset+2])
- rgba[3] += int32(coeff) * int32(row[offset+3])
- sum += int32(coeff)
- }
- offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
- out.Pix[offset+0] = clampUint8(rgba[0] / sum)
- out.Pix[offset+1] = clampUint8(rgba[1] / sum)
- out.Pix[offset+2] = clampUint8(rgba[2] / sum)
- out.Pix[offset+3] = clampUint8(rgba[3] / sum)
- }
- }
- }
- func resizeRGBA64(in *image.RGBA64, out *image.RGBA64, scale float64, coeffs []int32, filterLength int) {
- oldBounds := in.Bounds()
- newBounds := out.Bounds()
- 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++ {
- interpX := scale*(float64(y)+0.5) + float64(oldBounds.Min.X)
- start := int(interpX) - filterLength/2 + 1
- var rgba [4]int64
- var sum int64
- for i := 0; i < filterLength; i++ {
- xx := start + i
- if xx < oldBounds.Min.X {
- xx = oldBounds.Min.X
- } else if xx >= oldBounds.Max.X {
- xx = oldBounds.Max.X - 1
- }
- coeff := coeffs[(y-newBounds.Min.Y)*filterLength+i]
- offset := (xx - oldBounds.Min.X) * 8
- rgba[0] += int64(coeff) * int64(uint16(row[offset+0])<<8|uint16(row[offset+1]))
- rgba[1] += int64(coeff) * int64(uint16(row[offset+2])<<8|uint16(row[offset+3]))
- rgba[2] += int64(coeff) * int64(uint16(row[offset+4])<<8|uint16(row[offset+5]))
- rgba[3] += int64(coeff) * int64(uint16(row[offset+6])<<8|uint16(row[offset+7]))
- 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)
- }
- }
- }
- func resizeGray(in *image.Gray, out *image.Gray, scale float64, coeffs []int16, filterLength int) {
- oldBounds := in.Bounds()
- newBounds := out.Bounds()
- 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++ {
- interpX := scale*(float64(y)+0.5) + float64(oldBounds.Min.X)
- start := int(interpX) - filterLength/2 + 1
- var gray int32
- var sum int32
- for i := 0; i < filterLength; i++ {
- xx := start + i
- if xx < oldBounds.Min.X {
- xx = oldBounds.Min.X
- } else if xx >= oldBounds.Max.X {
- xx = oldBounds.Max.X - 1
- }
- coeff := coeffs[(y-newBounds.Min.Y)*filterLength+i]
- offset := (xx - oldBounds.Min.X)
- gray += int32(coeff) * int32(row[offset])
- sum += int32(coeff)
- }
- offset := (y-newBounds.Min.Y)*out.Stride + (x - newBounds.Min.X)
- out.Pix[offset] = clampUint8(gray / sum)
- }
- }
- }
- func resizeGray16(in *image.Gray16, out *image.Gray16, scale float64, coeffs []int32, filterLength int) {
- oldBounds := in.Bounds()
- newBounds := out.Bounds()
- 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++ {
- interpX := scale*(float64(y)+0.5) + float64(oldBounds.Min.X)
- start := int(interpX) - filterLength/2 + 1
- var gray int64
- var sum int64
- for i := 0; i < filterLength; i++ {
- xx := start + i
- if xx < oldBounds.Min.X {
- xx = oldBounds.Min.X
- } else if xx >= oldBounds.Max.X {
- xx = oldBounds.Max.X - 1
- }
- coeff := coeffs[(y-newBounds.Min.Y)*filterLength+i]
- offset := (xx - oldBounds.Min.X) * 2
- gray += int64(coeff) * int64(uint16(row[offset+0])<<8|uint16(row[offset+1]))
- sum += int64(coeff)
- }
- offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*2
- value := clampUint16(gray / sum)
- out.Pix[offset+0] = uint8(value >> 8)
- out.Pix[offset+1] = uint8(value)
- }
- }
- }
- func convertYCbCrToRGBA(in *image.YCbCr) *image.RGBA {
- out := image.NewRGBA(in.Bounds())
- for y := 0; y < out.Bounds().Dy(); y++ {
- for x := 0; x < out.Bounds().Dx(); x++ {
- p := out.Pix[y*out.Stride+4*x:]
- yi := in.YOffset(x, y)
- ci := in.COffset(x, y)
- r, g, b := color.YCbCrToRGB(in.Y[yi], in.Cb[ci], in.Cr[ci])
- p[0] = r
- p[1] = g
- p[2] = b
- p[3] = 0xff
- }
- }
- return out
- }
|