Full Mattermost server source with integrated Community Enterprise features. Includes vendor directory for offline/air-gapped builds. Structure: - enterprise-impl/: Enterprise feature implementations - enterprise-community/: Init files that register implementations - enterprise/: Bridge imports (community_imports.go) - vendor/: All dependencies for offline builds Build (online): go build ./cmd/mattermost Build (offline/air-gapped): go build -mod=vendor ./cmd/mattermost 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
130 lines
3.4 KiB
Go
130 lines
3.4 KiB
Go
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
|
|
}
|