Skip to content

Commit 72d128b

Browse files
Fix XY transforms
1 parent 17ef18c commit 72d128b

3 files changed

Lines changed: 55 additions & 60 deletions

File tree

samples/ImageSharp.Web.Sample/wwwroot/index.html

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -272,59 +272,59 @@ <h2>EXIF Handling Portrait</h2>
272272
<p>Demonstrates that the middleware handles EXIF orientation correctly for portrait images.</p>
273273
<div>
274274
<p>
275-
<code>Portrait_0.jpg?width=60&height=50&rxy=25,25</code>
275+
<code>Portrait_0.jpg?width=60&height=50&rxy=0.25,0.25</code>
276276
</p>
277-
<p><img src="Portrait_0.jpg?width=60&height=50&rxy=25,25" /></p>
277+
<p><img src="Portrait_0.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
278278
</div>
279279
<div>
280280
<p>
281-
<code>Portrait_1.jpg?width=60&height=50&rxy=25,25</code>
281+
<code>Portrait_1.jpg?width=60&height=50&rxy=0.25,0.25</code>
282282
</p>
283-
<p><img src="Portrait_1.jpg?width=60&height=50&rxy=25,25" /></p>
283+
<p><img src="Portrait_1.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
284284
</div>
285285
<div>
286286
<p>
287-
<code>Portrait_2.jpg?width=60&height=50&rxy=25,25</code>
287+
<code>Portrait_2.jpg?width=60&height=50&rxy=0.25,0.25</code>
288288
</p>
289-
<p><img src="Portrait_2.jpg?width=60&height=50&rxy=25,25" /></p>
289+
<p><img src="Portrait_2.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
290290
</div>
291291

292292
<div>
293293
<p>
294-
<code>Portrait_3.jpg?width=60&height=50&rxy=25,25</code>
294+
<code>Portrait_3.jpg?width=60&height=50&rxy=0.25,0.25</code>
295295
</p>
296-
<p><img src="Portrait_3.jpg?width=60&height=50&rxy=25,25" /></p>
296+
<p><img src="Portrait_3.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
297297
</div>
298298
<div>
299299
<p>
300-
<code>Portrait_4.jpg?width=60&height=50&rxy=25,25</code>
300+
<code>Portrait_4.jpg?width=60&height=50&rxy=0.25,0.25</code>
301301
</p>
302-
<p><img src="Portrait_4.jpg?width=60&height=50&rxy=25,25" /></p>
302+
<p><img src="Portrait_4.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
303303
</div>
304304
<div>
305305
<p>
306-
<code>Portrait_5.jpg?width=60&height=50&rxy=25,25</code>
306+
<code>Portrait_5.jpg?width=60&height=50&rxy=0.25,0.25</code>
307307
</p>
308-
<p><img src="Portrait_5.jpg?width=60&height=50&rxy=25,25" /></p>
308+
<p><img src="Portrait_5.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
309309
</div>
310310

311311
<div>
312312
<p>
313-
<code>Portrait_6.jpg?width=60&height=50&rxy=25,25</code>
313+
<code>Portrait_6.jpg?width=60&height=50&rxy=0.25,0.25</code>
314314
</p>
315-
<p><img src="Portrait_6.jpg?width=60&height=50&rxy=25,25" /></p>
315+
<p><img src="Portrait_6.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
316316
</div>
317317
<div>
318318
<p>
319-
<code>Portrait_7.jpg?width=60&height=50&rxy=25,25</code>
319+
<code>Portrait_7.jpg?width=60&height=50&rxy=0.25,0.25</code>
320320
</p>
321-
<p><img src="Portrait_7.jpg?width=60&height=50&rxy=25,25" /></p>
321+
<p><img src="Portrait_7.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
322322
</div>
323323
<div>
324324
<p>
325-
<code>Portrait_8.jpg?width=60&height=50&rxy=25,25</code>
325+
<code>Portrait_8.jpg?width=60&height=50&rxy=0.25,0.25</code>
326326
</p>
327-
<p><img src="Portrait_8.jpg?width=60&height=50&rxy=25,25" /></p>
327+
<p><img src="Portrait_8.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
328328
</div>
329329
</section>
330330

@@ -639,59 +639,59 @@ <h2>EXIF Handling : Landscape</h2>
639639
<p>Demonstrates that the middleware handles EXIF orientation correctly for landscape images.</p>
640640
<div>
641641
<p>
642-
<code>Landscape_0.jpg?width=60&height=50&rxy=25,25</code>
642+
<code>Landscape_0.jpg?width=60&height=50&rxy=0.25,0.25</code>
643643
</p>
644-
<p><img src="Landscape_0.jpg?width=60&height=50&rxy=25,25" /></p>
644+
<p><img src="Landscape_0.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
645645
</div>
646646
<div>
647647
<p>
648-
<code>Landscape_1.jpg?width=60&height=50&rxy=25,25</code>
648+
<code>Landscape_1.jpg?width=60&height=50&rxy=0.25,0.25</code>
649649
</p>
650-
<p><img src="Landscape_1.jpg?width=60&height=50&rxy=25,25" /></p>
650+
<p><img src="Landscape_1.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
651651
</div>
652652
<div>
653653
<p>
654-
<code>Landscape_2.jpg?width=60&height=50&rxy=25,25</code>
654+
<code>Landscape_2.jpg?width=60&height=50&rxy=0.25,0.25</code>
655655
</p>
656-
<p><img src="Landscape_2.jpg?width=60&height=50&rxy=25,25" /></p>
656+
<p><img src="Landscape_2.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
657657
</div>
658658

659659
<div>
660660
<p>
661-
<code>Landscape_3.jpg?width=60&height=50&rxy=25,25</code>
661+
<code>Landscape_3.jpg?width=60&height=50&rxy=0.25,0.25</code>
662662
</p>
663-
<p><img src="Landscape_3.jpg?width=60&height=50&rxy=25,25" /></p>
663+
<p><img src="Landscape_3.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
664664
</div>
665665
<div>
666666
<p>
667-
<code>Landscape_4.jpg?width=60&height=50&rxy=25,25</code>
667+
<code>Landscape_4.jpg?width=60&height=50&rxy=0.25,0.25</code>
668668
</p>
669-
<p><img src="Landscape_4.jpg?width=60&height=50&rxy=25,25" /></p>
669+
<p><img src="Landscape_4.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
670670
</div>
671671
<div>
672672
<p>
673-
<code>Landscape_5.jpg?width=60&height=50&rxy=25,25</code>
673+
<code>Landscape_5.jpg?width=60&height=50&rxy=0.25,0.25</code>
674674
</p>
675-
<p><img src="Landscape_5.jpg?width=60&height=50&rxy=25,25" /></p>
675+
<p><img src="Landscape_5.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
676676
</div>
677677

678678
<div>
679679
<p>
680-
<code>Landscape_6.jpg?width=60&height=50&rxy=25,25</code>
680+
<code>Landscape_6.jpg?width=60&height=50&rxy=0.25,0.25</code>
681681
</p>
682-
<p><img src="Landscape_6.jpg?width=60&height=50&rxy=25,25" /></p>
682+
<p><img src="Landscape_6.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
683683
</div>
684684
<div>
685685
<p>
686-
<code>Landscape_7.jpg?width=60&height=50&rxy=25,25</code>
686+
<code>Landscape_7.jpg?width=60&height=50&rxy=0.25,0.25</code>
687687
</p>
688-
<p><img src="Landscape_7.jpg?width=60&height=50&rxy=25,25" /></p>
688+
<p><img src="Landscape_7.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
689689
</div>
690690
<div>
691691
<p>
692-
<code>Landscape_8.jpg?width=60&height=50&rxy=25,25</code>
692+
<code>Landscape_8.jpg?width=60&height=50&rxy=0.25,0.25</code>
693693
</p>
694-
<p><img src="Landscape_8.jpg?width=60&height=50&rxy=25,25" /></p>
694+
<p><img src="Landscape_8.jpg?width=60&height=50&rxy=0.25,0.25" /></p>
695695
</div>
696696
</section>
697697

src/ImageSharp.Web/Processors/ResizeWebProcessor.cs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ internal static ResizeOptions GetResizeOptions(
124124
ResizeOptions options = new()
125125
{
126126
Size = size,
127-
CenterCoordinates = GetCenter(image, orientation, commands, parser, culture),
127+
CenterCoordinates = GetCenter(orientation, commands, parser, culture),
128128
Position = GetAnchor(orientation, commands, parser, culture),
129129
Mode = GetMode(commands, parser, culture),
130130
Compand = GetCompandMode(commands, parser, culture),
@@ -152,7 +152,6 @@ private static Size ParseSize(
152152
}
153153

154154
private static PointF? GetCenter(
155-
FormattedImage image,
156155
ushort orientation,
157156
CommandCollection commands,
158157
CommandParser parser,
@@ -171,38 +170,34 @@ private static Size ParseSize(
171170
return center;
172171
}
173172

174-
AffineTransformBuilder builder = new();
175-
Size size = image.Image.Size();
176-
177173
// New XY is calculated based on flipping and rotating the input XY.
178-
// Operations are based upon AutoOrientProcessor implementation.
174+
// Coordinates range from 0-1, hence the matching source size.
175+
AffineTransformBuilder builder = new();
176+
Size size = new(1, 1);
179177
switch (orientation)
180178
{
181179
case ExifOrientationMode.TopRight:
182180
builder.AppendTranslation(new PointF(size.Width - center.X, 0));
183181
break;
184182
case ExifOrientationMode.BottomRight:
185183
builder.AppendRotationDegrees(180);
186-
builder.AppendTranslation(new PointF(0, -(size.Height - center.Y)));
187184
break;
188185
case ExifOrientationMode.BottomLeft:
189-
builder.AppendRotationDegrees(180);
190-
builder.AppendTranslation(new PointF(size.Width - center.X, -(size.Height - center.Y)));
186+
builder.AppendTranslation(new PointF(0, size.Height - center.Y));
191187
break;
192188
case ExifOrientationMode.LeftTop:
193-
builder.AppendRotationDegrees(90);
194189
builder.AppendTranslation(new PointF(size.Width - center.X, 0));
190+
builder.AppendRotationDegrees(270);
195191
break;
196192
case ExifOrientationMode.RightTop:
197193
builder.AppendRotationDegrees(270);
198194
break;
199195
case ExifOrientationMode.RightBottom:
200-
builder.AppendRotationDegrees(270);
201-
builder.AppendTranslation(new PointF(-(size.Width - center.X), -(size.Height - center.Y)));
196+
builder.AppendTranslation(new PointF(size.Width - center.X, 0));
197+
builder.AppendRotationDegrees(90);
202198
break;
203199
case ExifOrientationMode.LeftBottom:
204200
builder.AppendRotationDegrees(90);
205-
builder.AppendTranslation(new PointF(-(size.Width - center.X), 0));
206201
break;
207202
default:
208203
return center;

tests/ImageSharp.Web.Tests/Processors/ResizeWebProcessorTests.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ public void ResizeWebProcessor_RespectsOrientation_Center(ushort orientation)
137137
{
138138
const int width = 4;
139139
const int height = 6;
140-
const float x = 1;
141-
const float y = 2;
140+
const float x = .25F;
141+
const float y = .5F;
142142

143143
var converters = new List<ICommandConverter>
144144
{
@@ -165,7 +165,7 @@ public void ResizeWebProcessor_RespectsOrientation_Center(ushort orientation)
165165
image.Metadata.ExifProfile.SetValue(ExifTag.Orientation, orientation);
166166
using var formatted = new FormattedImage(image, PngFormat.Instance);
167167

168-
PointF expected = GetExpectedCenter(orientation, image.Size(), new PointF(x, y));
168+
PointF expected = GetExpectedCenter(orientation, new PointF(x, y));
169169
ResizeOptions options = ResizeWebProcessor.GetResizeOptions(formatted, commands, parser, culture);
170170
Assert.Equal(expected, options.CenterCoordinates);
171171
}
@@ -261,36 +261,36 @@ public void ResizeWebProcessor_CanIgnoreOrientation(ushort orientation)
261261
Assert.Equal(height, image.Height);
262262
}
263263

264-
private static PointF GetExpectedCenter(ushort orientation, Size size, PointF center)
264+
private static PointF GetExpectedCenter(ushort orientation, PointF center)
265265
{
266+
// New XY is calculated based on flipping and rotating the input XY.
267+
// Coordinates range from 0-1, hence the matching source size.
266268
AffineTransformBuilder builder = new();
269+
Size size = new(1, 1);
267270
switch (orientation)
268271
{
269272
case ExifOrientationMode.TopRight:
270273
builder.AppendTranslation(new PointF(size.Width - center.X, 0));
271274
break;
272275
case ExifOrientationMode.BottomRight:
273276
builder.AppendRotationDegrees(180);
274-
builder.AppendTranslation(new PointF(0, -(size.Height - center.Y)));
275277
break;
276278
case ExifOrientationMode.BottomLeft:
277-
builder.AppendRotationDegrees(180);
278-
builder.AppendTranslation(new PointF(size.Width - center.X, -(size.Height - center.Y)));
279+
builder.AppendTranslation(new PointF(0, size.Height - center.Y));
279280
break;
280281
case ExifOrientationMode.LeftTop:
281-
builder.AppendRotationDegrees(90);
282282
builder.AppendTranslation(new PointF(size.Width - center.X, 0));
283+
builder.AppendRotationDegrees(270);
283284
break;
284285
case ExifOrientationMode.RightTop:
285286
builder.AppendRotationDegrees(270);
286287
break;
287288
case ExifOrientationMode.RightBottom:
288-
builder.AppendRotationDegrees(270);
289-
builder.AppendTranslation(new PointF(-(size.Width - center.X), -(size.Height - center.Y)));
289+
builder.AppendTranslation(new PointF(size.Width - center.X, 0));
290+
builder.AppendRotationDegrees(90);
290291
break;
291292
case ExifOrientationMode.LeftBottom:
292293
builder.AppendRotationDegrees(90);
293-
builder.AppendTranslation(new PointF(-(size.Width - center.X), 0));
294294
break;
295295
default:
296296
return center;

0 commit comments

Comments
 (0)