44using System . Collections . Generic ;
55using System . Globalization ;
66using Microsoft . Extensions . Logging ;
7+ using SixLabors . ImageSharp . Metadata . Profiles . Exif ;
78using SixLabors . ImageSharp . Processing ;
89using SixLabors . ImageSharp . Processing . Processors . Transforms ;
910using SixLabors . ImageSharp . Web . Commands ;
@@ -41,10 +42,15 @@ public class ResizeWebProcessor : IImageWebProcessor
4142 public const string Sampler = "rsampler" ;
4243
4344 /// <summary>
44- /// The command constant for the resize sampler .
45+ /// The command constant for the resize anchor position .
4546 /// </summary>
4647 public const string Anchor = "ranchor" ;
4748
49+ /// <summary>
50+ /// The command constant for the resize orientation handling mode.
51+ /// </summary>
52+ public const string Orient = "rorient" ;
53+
4854 /// <summary>
4955 /// The command constant for the resize compand mode.
5056 /// </summary>
@@ -59,7 +65,8 @@ private static readonly IEnumerable<string> ResizeCommands
5965 Mode ,
6066 Sampler ,
6167 Anchor ,
62- Compand
68+ Compand ,
69+ Orient
6370 } ;
6471
6572 /// <inheritdoc/>
@@ -73,7 +80,7 @@ public FormattedImage Process(
7380 CommandParser parser ,
7481 CultureInfo culture )
7582 {
76- ResizeOptions options = GetResizeOptions ( commands , parser , culture ) ;
83+ ResizeOptions options = GetResizeOptions ( image . Image , commands , parser , culture ) ;
7784
7885 if ( options != null )
7986 {
@@ -84,6 +91,7 @@ public FormattedImage Process(
8491 }
8592
8693 private static ResizeOptions GetResizeOptions (
94+ Image image ,
8795 CommandCollection commands ,
8896 CommandParser parser ,
8997 CultureInfo culture )
@@ -93,7 +101,7 @@ private static ResizeOptions GetResizeOptions(
93101 return null ;
94102 }
95103
96- Size size = ParseSize ( commands , parser , culture ) ;
104+ Size size = ParseSize ( image , commands , parser , culture ) ;
97105
98106 if ( size . Width <= 0 && size . Height <= 0 )
99107 {
@@ -116,15 +124,38 @@ private static ResizeOptions GetResizeOptions(
116124 }
117125
118126 private static Size ParseSize (
127+ Image image ,
119128 CommandCollection commands ,
120129 CommandParser parser ,
121130 CultureInfo culture )
122131 {
123132 // The command parser will reject negative numbers as it clamps values to ranges.
124- uint width = parser . ParseValue < uint > ( commands . GetValueOrDefault ( Width ) , culture ) ;
125- uint height = parser . ParseValue < uint > ( commands . GetValueOrDefault ( Height ) , culture ) ;
133+ int width = ( int ) parser . ParseValue < uint > ( commands . GetValueOrDefault ( Width ) , culture ) ;
134+ int height = ( int ) parser . ParseValue < uint > ( commands . GetValueOrDefault ( Height ) , culture ) ;
135+
136+ // Browsers now implement 'image-orientation: from-image' by default.
137+ // https://developer.mozilla.org/en-US/docs/web/css/image-orientation
138+ // This makes orientation handling confusing for users who expect images to be resized in accordance
139+ // to what they observe rather than pure (and correct) methods.
140+ //
141+ // To accomodate this we parse the dimensions to use based upon decoded EXIF orientation values, switching
142+ // the width/height parameters when images are rotated (not flipped).
143+ // We default to 'true' for EXIF orientation handling. By passing 'false' it can be turned off.
144+ if ( ! commands . Contains ( Orient ) || parser . ParseValue < bool > ( commands . GetValueOrDefault ( Orient ) , culture ) )
145+ {
146+ if ( image . Metadata . ExifProfile != null )
147+ {
148+ IExifValue < ushort > orientation = image . Metadata . ExifProfile . GetValue ( ExifTag . Orientation ) ;
149+ return orientation . Value switch
150+ {
151+ // LeftTop, RightTop, RightBottom, LeftBottom
152+ 5 or 6 or 7 or 8 => new Size ( height , width ) ,
153+ _ => new Size ( width , height ) ,
154+ } ;
155+ }
156+ }
126157
127- return new Size ( ( int ) width , ( int ) height ) ;
158+ return new Size ( width , height ) ;
128159 }
129160
130161 private static PointF ? GetCenter (
@@ -166,40 +197,25 @@ private static IResampler GetSampler(CommandCollection commands)
166197
167198 if ( sampler != null )
168199 {
169- switch ( sampler . ToLowerInvariant ( ) )
200+ // No need to do a case test here. Parsed commands are automatically converted to lowercase.
201+ return sampler switch
170202 {
171- case "nearest" :
172- case "nearestneighbor" :
173- return KnownResamplers . NearestNeighbor ;
174- case "box" :
175- return KnownResamplers . Box ;
176- case "mitchell" :
177- case "mitchellnetravali" :
178- return KnownResamplers . MitchellNetravali ;
179- case "catmull" :
180- case "catmullrom" :
181- return KnownResamplers . CatmullRom ;
182- case "lanczos2" :
183- return KnownResamplers . Lanczos2 ;
184- case "lanczos3" :
185- return KnownResamplers . Lanczos3 ;
186- case "lanczos5" :
187- return KnownResamplers . Lanczos5 ;
188- case "lanczos8" :
189- return KnownResamplers . Lanczos8 ;
190- case "welch" :
191- return KnownResamplers . Welch ;
192- case "robidoux" :
193- return KnownResamplers . Robidoux ;
194- case "robidouxsharp" :
195- return KnownResamplers . RobidouxSharp ;
196- case "spline" :
197- return KnownResamplers . Spline ;
198- case "triangle" :
199- return KnownResamplers . Triangle ;
200- case "hermite" :
201- return KnownResamplers . Hermite ;
202- }
203+ "nearest" or "nearestneighbor" => KnownResamplers . NearestNeighbor ,
204+ "box" => KnownResamplers . Box ,
205+ "mitchell" or "mitchellnetravali" => KnownResamplers . MitchellNetravali ,
206+ "catmull" or "catmullrom" => KnownResamplers . CatmullRom ,
207+ "lanczos2" => KnownResamplers . Lanczos2 ,
208+ "lanczos3" => KnownResamplers . Lanczos3 ,
209+ "lanczos5" => KnownResamplers . Lanczos5 ,
210+ "lanczos8" => KnownResamplers . Lanczos8 ,
211+ "welch" => KnownResamplers . Welch ,
212+ "robidoux" => KnownResamplers . Robidoux ,
213+ "robidouxsharp" => KnownResamplers . RobidouxSharp ,
214+ "spline" => KnownResamplers . Spline ,
215+ "triangle" => KnownResamplers . Triangle ,
216+ "hermite" => KnownResamplers . Hermite ,
217+ _ => KnownResamplers . Bicubic ,
218+ } ;
203219 }
204220
205221 return KnownResamplers . Bicubic ;
0 commit comments