mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 09:44:21 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			439 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			439 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
/*
 | 
						|
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"
 | 
						|
 | 
						|
// Keep value in [0,255] range.
 | 
						|
func clampUint8(in int32) uint8 {
 | 
						|
	// casting a negative int to an uint will result in an overflown
 | 
						|
	// large uint. this behavior will be exploited here and in other functions
 | 
						|
	// to achieve a higher performance.
 | 
						|
	if uint32(in) < 256 {
 | 
						|
		return uint8(in)
 | 
						|
	}
 | 
						|
	if in > 255 {
 | 
						|
		return 255
 | 
						|
	}
 | 
						|
	return 0
 | 
						|
}
 | 
						|
 | 
						|
// Keep value in [0,65535] range.
 | 
						|
func clampUint16(in int64) uint16 {
 | 
						|
	if uint64(in) < 65536 {
 | 
						|
		return uint16(in)
 | 
						|
	}
 | 
						|
	if in > 65535 {
 | 
						|
		return 65535
 | 
						|
	}
 | 
						|
	return 0
 | 
						|
}
 | 
						|
 | 
						|
func resizeGeneric(in image.Image, 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++ {
 | 
						|
		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()
 | 
						|
 | 
						|
					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, 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 resizeNRGBA(in *image.NRGBA, out *image.RGBA, 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
 | 
						|
					}
 | 
						|
 | 
						|
					// Forward alpha-premultiplication
 | 
						|
					a := int32(row[xi+3])
 | 
						|
					r := int32(row[xi+0]) * a
 | 
						|
					r /= 0xff
 | 
						|
					g := int32(row[xi+1]) * a
 | 
						|
					g /= 0xff
 | 
						|
					b := int32(row[xi+2]) * a
 | 
						|
					b /= 0xff
 | 
						|
 | 
						|
					rgba[0] += int32(coeff) * r
 | 
						|
					rgba[1] += int32(coeff) * g
 | 
						|
					rgba[2] += int32(coeff) * b
 | 
						|
					rgba[3] += int32(coeff) * a
 | 
						|
					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.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
 | 
						|
					}
 | 
						|
 | 
						|
					rgba[0] += int64(coeff) * (int64(row[xi+0])<<8 | int64(row[xi+1]))
 | 
						|
					rgba[1] += int64(coeff) * (int64(row[xi+2])<<8 | int64(row[xi+3]))
 | 
						|
					rgba[2] += int64(coeff) * (int64(row[xi+4])<<8 | int64(row[xi+5]))
 | 
						|
					rgba[3] += int64(coeff) * (int64(row[xi+6])<<8 | int64(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.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 resizeGray(in *image.Gray, out *image.Gray, 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-newBounds.Min.X)*in.Stride:]
 | 
						|
		for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
 | 
						|
			var gray 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 xi < 0:
 | 
						|
						xi = 0
 | 
						|
					case xi >= maxX:
 | 
						|
						xi = maxX
 | 
						|
					}
 | 
						|
					gray += int32(coeff) * int32(row[xi])
 | 
						|
					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, 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 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 *= 2
 | 
						|
					case xi >= maxX:
 | 
						|
						xi = 2 * maxX
 | 
						|
					default:
 | 
						|
						xi = 0
 | 
						|
					}
 | 
						|
					gray += int64(coeff) * int64(uint16(row[xi+0])<<8|uint16(row[xi+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 resizeYCbCr(in *ycc, out *ycc, 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 p [3]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 *= 3
 | 
						|
					case xi >= maxX:
 | 
						|
						xi = 3 * maxX
 | 
						|
					default:
 | 
						|
						xi = 0
 | 
						|
					}
 | 
						|
					p[0] += int32(coeff) * int32(row[xi+0])
 | 
						|
					p[1] += int32(coeff) * int32(row[xi+1])
 | 
						|
					p[2] += int32(coeff) * int32(row[xi+2])
 | 
						|
					sum += int32(coeff)
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*3
 | 
						|
			out.Pix[xo+0] = clampUint8(p[0] / sum)
 | 
						|
			out.Pix[xo+1] = clampUint8(p[1] / sum)
 | 
						|
			out.Pix[xo+2] = clampUint8(p[2] / sum)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func nearestYCbCr(in *ycc, out *ycc, 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 p [3]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 *= 3
 | 
						|
					case xi >= maxX:
 | 
						|
						xi = 3 * maxX
 | 
						|
					default:
 | 
						|
						xi = 0
 | 
						|
					}
 | 
						|
					p[0] += float32(row[xi+0])
 | 
						|
					p[1] += float32(row[xi+1])
 | 
						|
					p[2] += float32(row[xi+2])
 | 
						|
					sum++
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*3
 | 
						|
			out.Pix[xo+0] = floatToUint8(p[0] / sum)
 | 
						|
			out.Pix[xo+1] = floatToUint8(p[1] / sum)
 | 
						|
			out.Pix[xo+2] = floatToUint8(p[2] / sum)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |