mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 17:22:26 -05:00 
			
		
		
		
	Grand test fixup (#138)
* start fixing up tests * fix up tests + automate with drone * fiddle with linting * messing about with drone.yml * some more fiddling * hmmm * add cache * add vendor directory * verbose * ci updates * update some little things * update sig
This commit is contained in:
		
					parent
					
						
							
								329a5e8144
							
						
					
				
			
			
				commit
				
					
						98263a7de6
					
				
			
		
					 2677 changed files with 1090869 additions and 219 deletions
				
			
		
							
								
								
									
										620
									
								
								vendor/github.com/nfnt/resize/resize.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										620
									
								
								vendor/github.com/nfnt/resize/resize.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,620 @@ | |||
| /* | ||||
| 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 implements various image resizing methods. | ||||
| // | ||||
| // The package works with the Image interface described in the image package. | ||||
| // Various interpolation methods are provided and multiple processors may be | ||||
| // utilized in the computations. | ||||
| // | ||||
| // Example: | ||||
| //     imgResized := resize.Resize(1000, 0, imgOld, resize.MitchellNetravali) | ||||
| package resize | ||||
| 
 | ||||
| import ( | ||||
| 	"image" | ||||
| 	"runtime" | ||||
| 	"sync" | ||||
| ) | ||||
| 
 | ||||
| // An InterpolationFunction provides the parameters that describe an | ||||
| // interpolation kernel. It returns the number of samples to take | ||||
| // and the kernel function to use for sampling. | ||||
| type InterpolationFunction int | ||||
| 
 | ||||
| // InterpolationFunction constants | ||||
| const ( | ||||
| 	// Nearest-neighbor interpolation | ||||
| 	NearestNeighbor InterpolationFunction = iota | ||||
| 	// Bilinear interpolation | ||||
| 	Bilinear | ||||
| 	// Bicubic interpolation (with cubic hermite spline) | ||||
| 	Bicubic | ||||
| 	// Mitchell-Netravali interpolation | ||||
| 	MitchellNetravali | ||||
| 	// Lanczos interpolation (a=2) | ||||
| 	Lanczos2 | ||||
| 	// Lanczos interpolation (a=3) | ||||
| 	Lanczos3 | ||||
| ) | ||||
| 
 | ||||
| // kernal, returns an InterpolationFunctions taps and kernel. | ||||
| func (i InterpolationFunction) kernel() (int, func(float64) float64) { | ||||
| 	switch i { | ||||
| 	case Bilinear: | ||||
| 		return 2, linear | ||||
| 	case Bicubic: | ||||
| 		return 4, cubic | ||||
| 	case MitchellNetravali: | ||||
| 		return 4, mitchellnetravali | ||||
| 	case Lanczos2: | ||||
| 		return 4, lanczos2 | ||||
| 	case Lanczos3: | ||||
| 		return 6, lanczos3 | ||||
| 	default: | ||||
| 		// Default to NearestNeighbor. | ||||
| 		return 2, nearest | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // values <1 will sharpen the image | ||||
| var blur = 1.0 | ||||
| 
 | ||||
| // Resize scales an image to new width and height using the interpolation function interp. | ||||
| // A new image with the given dimensions will be returned. | ||||
| // If one of the parameters width or height is set to 0, its size will be calculated so that | ||||
| // the aspect ratio is that of the originating image. | ||||
| // The resizing algorithm uses channels for parallel computation. | ||||
| // If the input image has width or height of 0, it is returned unchanged. | ||||
| func Resize(width, height uint, img image.Image, interp InterpolationFunction) image.Image { | ||||
| 	scaleX, scaleY := calcFactors(width, height, float64(img.Bounds().Dx()), float64(img.Bounds().Dy())) | ||||
| 	if width == 0 { | ||||
| 		width = uint(0.7 + float64(img.Bounds().Dx())/scaleX) | ||||
| 	} | ||||
| 	if height == 0 { | ||||
| 		height = uint(0.7 + float64(img.Bounds().Dy())/scaleY) | ||||
| 	} | ||||
| 
 | ||||
| 	// Trivial case: return input image | ||||
| 	if int(width) == img.Bounds().Dx() && int(height) == img.Bounds().Dy() { | ||||
| 		return img | ||||
| 	} | ||||
| 
 | ||||
| 	// Input image has no pixels | ||||
| 	if img.Bounds().Dx() <= 0 || img.Bounds().Dy() <= 0 { | ||||
| 		return img | ||||
| 	} | ||||
| 
 | ||||
| 	if interp == NearestNeighbor { | ||||
| 		return resizeNearest(width, height, scaleX, scaleY, img, interp) | ||||
| 	} | ||||
| 
 | ||||
| 	taps, kernel := interp.kernel() | ||||
| 	cpus := runtime.GOMAXPROCS(0) | ||||
| 	wg := sync.WaitGroup{} | ||||
| 
 | ||||
| 	// Generic access to image.Image is slow in tight loops. | ||||
| 	// The optimal access has to be determined from the concrete image type. | ||||
| 	switch input := img.(type) { | ||||
| 	case *image.RGBA: | ||||
| 		// 8-bit precision | ||||
| 		temp := image.NewRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewRGBA(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.RGBA) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeRGBA(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.RGBA) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeRGBA(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	case *image.NRGBA: | ||||
| 		// 8-bit precision | ||||
| 		temp := image.NewRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewRGBA(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.RGBA) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeNRGBA(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.RGBA) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeRGBA(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 
 | ||||
| 	case *image.YCbCr: | ||||
| 		// 8-bit precision | ||||
| 		// accessing the YCbCr arrays in a tight loop is slow. | ||||
| 		// converting the image to ycc increases performance by 2x. | ||||
| 		temp := newYCC(image.Rect(0, 0, input.Bounds().Dy(), int(width)), input.SubsampleRatio) | ||||
| 		result := newYCC(image.Rect(0, 0, int(width), int(height)), image.YCbCrSubsampleRatio444) | ||||
| 
 | ||||
| 		coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel) | ||||
| 		in := imageYCbCrToYCC(input) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*ycc) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeYCbCr(in, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*ycc) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeYCbCr(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result.YCbCr() | ||||
| 	case *image.RGBA64: | ||||
| 		// 16-bit precision | ||||
| 		temp := image.NewRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.RGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeRGBA64(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.RGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeRGBA64(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	case *image.NRGBA64: | ||||
| 		// 16-bit precision | ||||
| 		temp := image.NewRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.RGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeNRGBA64(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.RGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeRGBA64(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	case *image.Gray: | ||||
| 		// 8-bit precision | ||||
| 		temp := image.NewGray(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewGray(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.Gray) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeGray(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.Gray) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeGray(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	case *image.Gray16: | ||||
| 		// 16-bit precision | ||||
| 		temp := image.NewGray16(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewGray16(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.Gray16) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeGray16(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.Gray16) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeGray16(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	default: | ||||
| 		// 16-bit precision | ||||
| 		temp := image.NewRGBA64(image.Rect(0, 0, img.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.RGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeGeneric(img, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.RGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				resizeRGBA64(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func resizeNearest(width, height uint, scaleX, scaleY float64, img image.Image, interp InterpolationFunction) image.Image { | ||||
| 	taps, _ := interp.kernel() | ||||
| 	cpus := runtime.GOMAXPROCS(0) | ||||
| 	wg := sync.WaitGroup{} | ||||
| 
 | ||||
| 	switch input := img.(type) { | ||||
| 	case *image.RGBA: | ||||
| 		// 8-bit precision | ||||
| 		temp := image.NewRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewRGBA(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.RGBA) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestRGBA(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.RGBA) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestRGBA(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	case *image.NRGBA: | ||||
| 		// 8-bit precision | ||||
| 		temp := image.NewNRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewNRGBA(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.NRGBA) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestNRGBA(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.NRGBA) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestNRGBA(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	case *image.YCbCr: | ||||
| 		// 8-bit precision | ||||
| 		// accessing the YCbCr arrays in a tight loop is slow. | ||||
| 		// converting the image to ycc increases performance by 2x. | ||||
| 		temp := newYCC(image.Rect(0, 0, input.Bounds().Dy(), int(width)), input.SubsampleRatio) | ||||
| 		result := newYCC(image.Rect(0, 0, int(width), int(height)), image.YCbCrSubsampleRatio444) | ||||
| 
 | ||||
| 		coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX) | ||||
| 		in := imageYCbCrToYCC(input) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*ycc) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestYCbCr(in, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*ycc) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestYCbCr(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result.YCbCr() | ||||
| 	case *image.RGBA64: | ||||
| 		// 16-bit precision | ||||
| 		temp := image.NewRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.RGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestRGBA64(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.RGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestRGBA64(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	case *image.NRGBA64: | ||||
| 		// 16-bit precision | ||||
| 		temp := image.NewNRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewNRGBA64(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.NRGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestNRGBA64(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.NRGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestNRGBA64(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	case *image.Gray: | ||||
| 		// 8-bit precision | ||||
| 		temp := image.NewGray(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewGray(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.Gray) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestGray(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.Gray) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestGray(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	case *image.Gray16: | ||||
| 		// 16-bit precision | ||||
| 		temp := image.NewGray16(image.Rect(0, 0, input.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewGray16(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.Gray16) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestGray16(input, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.Gray16) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestGray16(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	default: | ||||
| 		// 16-bit precision | ||||
| 		temp := image.NewRGBA64(image.Rect(0, 0, img.Bounds().Dy(), int(width))) | ||||
| 		result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height))) | ||||
| 
 | ||||
| 		// horizontal filter, results in transposed temporary image | ||||
| 		coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(temp, i, cpus).(*image.RGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestGeneric(img, slice, scaleX, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 
 | ||||
| 		// horizontal filter on transposed image, result is not transposed | ||||
| 		coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY) | ||||
| 		wg.Add(cpus) | ||||
| 		for i := 0; i < cpus; i++ { | ||||
| 			slice := makeSlice(result, i, cpus).(*image.RGBA64) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				nearestRGBA64(temp, slice, scaleY, coeffs, offset, filterLength) | ||||
| 			}() | ||||
| 		} | ||||
| 		wg.Wait() | ||||
| 		return result | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Calculates scaling factors using old and new image dimensions. | ||||
| func calcFactors(width, height uint, oldWidth, oldHeight float64) (scaleX, scaleY float64) { | ||||
| 	if width == 0 { | ||||
| 		if height == 0 { | ||||
| 			scaleX = 1.0 | ||||
| 			scaleY = 1.0 | ||||
| 		} else { | ||||
| 			scaleY = oldHeight / float64(height) | ||||
| 			scaleX = scaleY | ||||
| 		} | ||||
| 	} else { | ||||
| 		scaleX = oldWidth / float64(width) | ||||
| 		if height == 0 { | ||||
| 			scaleY = scaleX | ||||
| 		} else { | ||||
| 			scaleY = oldHeight / float64(height) | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| type imageWithSubImage interface { | ||||
| 	image.Image | ||||
| 	SubImage(image.Rectangle) image.Image | ||||
| } | ||||
| 
 | ||||
| func makeSlice(img imageWithSubImage, i, n int) image.Image { | ||||
| 	return img.SubImage(image.Rect(img.Bounds().Min.X, img.Bounds().Min.Y+i*img.Bounds().Dy()/n, img.Bounds().Max.X, img.Bounds().Min.Y+(i+1)*img.Bounds().Dy()/n)) | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue