Open Socolin opened 3 weeks ago
I'm not 100% up on this area but wouldn't the bottom right location be (99, 99) as the pixels are zero indexed?
I can't remember fully correctly but it could be confusion caused by the difference in how Drawing vs pixel manipulation work where, I believe, one is pixel centre based on the other is pixel boundary based.
My caveat here is that I might be entirely wrong about all this as I'm trying to dredge up some memories from quite some time ago.
Yeah, I think you’re diagnosis is correct; it should be zero based.
Just to clarify because I'm not sure about what you said, is the problem with my example ? or is it a bug in ImageSharp ?
Just to clarify because I'm not sure about what you said, is the problem with my example ? or is it a bug in ImageSharp ?
Taking a closer look at your code examples it looks like a bug for the
.Transform(new AffineTransformBuilder().AppendRotationDegrees(180))
to me.
The .Transform(new AffineTransformBuilder().AppendRotationDegrees(i * 18, new Vector2(100, 100)))
case however looks more suspect as I would have expected that line to have been a rotation around [99, 99] but if there's a bug in of those call sites then there could very will be a bug that effects both.
Ok thanks.
The
.Transform(new AffineTransformBuilder().AppendRotationDegrees(i * 18, new Vector2(100, 100)))
case however looks more suspect as I would have expected that line to have been a rotation around [99, 99] but if there's a bug in of those call sites then there could very will be a bug that effects both.
When it's rotating arround 100, 100, as I understand it, it should rotate arround the bottom-right edge of the pixel 99,99
So here another example, I resized it and added a cross to show where I think the rotation point should be
Before rotation
After rotation
using (var img = new Image<Rgba32>(8, 8, Color.DimGray))
{
img.Mutate(c => c
.Transform(new AffineTransformBuilder().AppendTranslation(new Vector2(8, 8)))
.Transform(new AffineTransformBuilder().AppendRotationDegrees(180, new Vector2(8, 8)))
.Fill(Color.Aqua, new RectangleF(7, 7, 2, 2))
.Resize(new Size(800, 800), KnownResamplers.Box, true)
.DrawLine(Color.Red, 1, new PointF(400, 350), new PointF(400, 450))
.DrawLine(Color.Red, 1, new PointF(350, 400), new PointF(450, 400))
.BackgroundColor(Color.DarkGreen)
);
img.Save($"rotation-180.png");
}
I think I know what the issue is here. Will have a look over the weekend.
I was right.... I was hoping I wasn't.
The result is offset by 1 pixel in each direction because the transformation matrix is centered using a 1-based coordinate system, which assumes the image's center is at (width * 0.5, height * 0.5)
. However, image pixels are zero-based, meaning their coordinates start from 0. This discrepancy causes a misalignment, as the matrix does not account for the zero-based nature of pixel indices, leading to a 1-pixel offset when the transformation is applied.
To correct this issue, we need to use two separate matrices:
Transformation Matrix for Pixel Operations: This matrix accounts for the zero-based nature of pixel indices. It adjusts the center calculation to ensure the transformations (translation, rotation, etc.) align correctly with the pixel grid. This matrix is used to perform the actual image transformation.
Bounding Box Calculation Matrix: This matrix does not adjust for the zero-based pixel grid but instead accurately represents the intended transformation. It is used to compute the transformed image's size and bounds by transforming the image's corners and determining the extents.
By using these two matrices, we can ensure that both the pixel operations and the size/bounds calculations are handled correctly, resolving the 1-pixel offset issue and maintaining accurate and expected transformation results.
I'll get stuck in...
PR opened
Prerequisites
DEBUG
andRELEASE
modeImageSharp version
3.1.4
Other ImageSharp packages and versions
ImageSharp.Drawing 2.1.3
Environment (Operating system, version and so on)
Ubuntu 22.04, AMD Ryzen 9 7950X
.NET Framework version
8.0
Description
When using the rotation through the AffineTransformBuilder the result is not the same as the
.Rotate()
there seems to be 1 pixel offset.Here the sample code of what I would expect
Which give this result:![image](https://github.com/SixLabors/ImageSharp/assets/539620/33235f35-11e1-4702-a0e3-adf857f3a7ee)
Steps to Reproduce
When I do the same with the
.Transform()
I'm getting this:Another example with non centered rotation
The rotation seems to be centered 1 pixel too much toward the bottom-right
Images
No response