1010
1111
1212"""
13- ScaleRatio(minlengths ) <: ProjectiveTransform
13+ ScaleRatio(ratios ) <: ProjectiveTransform
1414
1515Scales the aspect ratio
1616"""
1717struct ScaleRatio{N} <: ProjectiveTransform
1818 ratios:: NTuple{N}
1919end
2020
21+ # This allows for roundtrip through ScaleFixed and avoids code duplication
22+ fixed_sizes(scale:: ScaleRatio , bounds:: Bounds ) = round.(Int, scale. ratios .* length.(bounds. rs))
2123
22- function getprojection(scale:: ScaleRatio , bounds; randstate = nothing )
23- return scaleprojection(scale. ratios)
24+ function getprojection(scale:: ScaleRatio{N} , bounds:: Bounds{N} ; randstate = nothing ) where N
25+ return getprojection(ScaleFixed{N}(fixed_sizes(scale, bounds)), bounds; randstate)
26+ end
27+
28+ function projectionbounds(tfm:: ScaleRatio{N} , P, bounds:: Bounds{N} ; randstate = nothing ) where N
29+ projectionbounds(ScaleFixed{N}(fixed_sizes(tfm, bounds)), P, bounds; randstate)
2430end
2531
2632"""
2733 ScaleKeepAspect(minlengths) <: ProjectiveTransform
2834
29- Scales the shortest side of `item` to `minlengths`, keeping the
30- original aspect ratio.
35+ Scales the sides of `item` to be as least as large as `minlengths`,
36+ keeping the original aspect ratio.
3137
3238## Examples
3339
@@ -42,28 +48,15 @@ struct ScaleKeepAspect{N} <: ProjectiveTransform
4248 minlengths:: NTuple{N, Int}
4349end
4450
51+ # This allows for roundtrip through ScaleFixed and avoids code duplication
52+ fixed_sizes(scale:: ScaleKeepAspect , bounds:: Bounds ) = round.(Int, maximum(scale. minlengths ./ length.(bounds. rs)) .* length.(bounds. rs))
4553
4654function getprojection(scale:: ScaleKeepAspect{N} , bounds:: Bounds{N} ; randstate = nothing ) where N
47- # If no scaling needs to be done, return a noop transform
48- scale. minlengths == length.(bounds. rs) && return IdentityTransformation()
49-
50- # Offset `minlengths` by 1 to avoid black border on one side
51- ratio = maximum((scale. minlengths .+ 1 ) ./ length.(bounds. rs))
52- upperleft = SVector{N, Float32}(minimum.(bounds. rs)) .- 0.5
53- P = scaleprojection(Tuple(ratio for _ in 1 : N))
54- if any(upperleft .!= 0 )
55- P = P ∘ Translation((Float32.(P(upperleft)) .+ 0.5f0 ))
56- end
57- return P
55+ getprojection(ScaleFixed{N}(fixed_sizes(scale, bounds)), bounds; randstate)
5856end
5957
6058function projectionbounds(tfm:: ScaleKeepAspect{N} , P, bounds:: Bounds{N} ; randstate = nothing ) where N
61- origsz = length.(bounds. rs)
62- ratio = maximum((tfm. minlengths) ./ origsz)
63- sz = round.(Int, ratio .* origsz)
64- bounds_ = transformbounds(bounds, P)
65- bs_ = offsetcropbounds(sz, bounds_, ntuple(_ -> 0.5 , N))
66- return bs_
59+ projectionbounds(ScaleFixed{N}(fixed_sizes(tfm, bounds)), P, bounds; randstate)
6760end
6861
6962"""
8073
8174
8275function getprojection(scale:: ScaleFixed , bounds:: Bounds{N} ; randstate = nothing ) where N
76+ # If no scaling needs to be done, return a noop transform
77+ (scale. sizes == length.(bounds. rs)) && return IdentityTransformation()
78+
8379 ratios = (scale. sizes .+ 1 ) ./ length.(bounds. rs)
8480 upperleft = SVector{N, Float32}(minimum.(bounds. rs)) .- 1
8581 P = scaleprojection(ratios)
9288
9389function projectionbounds(tfm:: ScaleFixed{N} , P, bounds:: Bounds{N} ; randstate = nothing ) where N
9490 bounds_ = transformbounds(bounds, P)
95- return offsetcropbounds(tfm. sizes, bounds_, ntuple(_ -> 1. , N))
91+ return offsetcropbounds(tfm. sizes, bounds_, ntuple(_ -> 0.5 , N))
9692end
9793
9894"""
0 commit comments