| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- package transform
- import (
- "image"
- "math"
- "github.com/anthonynsimon/bild/clone"
- "github.com/anthonynsimon/bild/parallel"
- )
- // ShearH applies a shear linear transformation along the horizontal axis,
- // the parameter angle is the shear angle to be applied.
- // The transformation will be applied with the center of the image as the pivot.
- func ShearH(img image.Image, angle float64) *image.RGBA {
- src := clone.AsShallowRGBA(img)
- srcW, srcH := src.Bounds().Dx(), src.Bounds().Dy()
- // Supersample, currently hard set to 2x
- srcW, srcH = srcW*2, srcH*2
- src = Resize(src, srcW, srcH, NearestNeighbor)
- // Calculate shear factor
- kx := math.Tan(angle * (math.Pi / 180))
- dstW, dstH := srcW+int(float64(srcH)*math.Abs(kx)), srcH
- dst := image.NewRGBA(image.Rect(0, 0, dstW, dstH))
- pivotX := float64(dstW) / 2
- pivotY := float64(dstH) / 2
- // Calculate offset since we are resizing the bounds to
- // fit the sheared image.
- dx := (dstW - srcW) / 2
- dy := (dstH - srcH) / 2
- parallel.Line(dstH, func(start, end int) {
- for y := start; y < end; y++ {
- for x := 0; x < dstW; x++ {
- // Move positions to revolve around pivot
- ix := x - int(pivotX) - dx
- iy := y - int(pivotY) - dy
- // Apply linear transformation
- ix = ix + int(float64(iy)*kx)
- // Move positions back to image coordinates
- ix += int(pivotX)
- iy += int(pivotY)
- if ix < 0 || ix >= srcW || iy < 0 || iy >= srcH {
- continue
- }
- srcPos := iy*src.Stride + ix*4
- dstPos := y*dst.Stride + x*4
- dst.Pix[dstPos+0] = src.Pix[srcPos+0]
- dst.Pix[dstPos+1] = src.Pix[srcPos+1]
- dst.Pix[dstPos+2] = src.Pix[srcPos+2]
- dst.Pix[dstPos+3] = src.Pix[srcPos+3]
- }
- }
- })
- // Downsample to original bounds as part of the Supersampling
- dst = Resize(dst, dstW/2, dstH/2, Linear)
- return dst
- }
- // ShearV applies a shear linear transformation along the vertical axis,
- // the parameter angle is the shear angle to be applied.
- // The transformation will be applied with the center of the image as the pivot.
- func ShearV(img image.Image, angle float64) *image.RGBA {
- src := clone.AsRGBA(img)
- srcW, srcH := src.Bounds().Dx(), src.Bounds().Dy()
- // Supersample, currently hard set to 2x
- srcW, srcH = srcW*2, srcH*2
- src = Resize(src, srcW, srcH, NearestNeighbor)
- // Calculate shear factor
- ky := math.Tan(angle * (math.Pi / 180))
- dstW, dstH := srcW, srcH+int(float64(srcW)*math.Abs(ky))
- dst := image.NewRGBA(image.Rect(0, 0, dstW, dstH))
- pivotX := float64(dstW) / 2
- pivotY := float64(dstH) / 2
- // Calculate offset since we are resizing the bounds to
- // fit the sheared image.
- dx := (dstW - srcW) / 2
- dy := (dstH - srcH) / 2
- parallel.Line(dstH, func(start, end int) {
- for y := start; y < end; y++ {
- for x := 0; x < dstW; x++ {
- // Move positions to revolve around pivot
- ix := x - int(pivotX) - dx
- iy := y - int(pivotY) - dy
- // Apply linear transformation
- iy = iy + int(float64(ix)*ky)
- // Move positions back to image coordinates
- ix += int(pivotX)
- iy += int(pivotY)
- if ix < 0 || ix >= srcW || iy < 0 || iy >= srcH {
- continue
- }
- srcPos := iy*src.Stride + ix*4
- dstPos := y*dst.Stride + x*4
- dst.Pix[dstPos+0] = src.Pix[srcPos+0]
- dst.Pix[dstPos+1] = src.Pix[srcPos+1]
- dst.Pix[dstPos+2] = src.Pix[srcPos+2]
- dst.Pix[dstPos+3] = src.Pix[srcPos+3]
- }
- }
- })
- // Downsample to original bounds as part of the Supersampling
- dst = Resize(dst, dstW/2, dstH/2, Linear)
- return dst
- }
|