Replies: 2 comments 4 replies
-
Yep, that's entirely possible if you create your own IPixelTransform implementation. I'm not clear what such a transform would do, though. Typically a 3x2 matrix transform is something you'd apply to vectors, not to pixels. |
Beta Was this translation helpful? Give feedback.
-
I took some time to write a naive IPixelTransform that does more or less what I was looking for: class MatrixTransform : IPixelTransform
{
public MatrixTransform(Matrix3x2 transform, int dstWidth, int dstHeight)
{
Width = dstWidth;
Height = dstHeight;
Matrix3x2.Invert(transform, out _Transform);
}
public void Init(IPixelSource source)
{
_Source = source;
_SourceBpp = 0;
if (source.Format == PixelFormats.Grey8bpp) _SourceBpp = 1;
if (source.Format == PixelFormats.Bgr24bpp) _SourceBpp = 3;
if (source.Format == PixelFormats.Bgra32bpp) _SourceBpp = 4;
}
private IPixelSource _Source;
private int _SourceBpp;
private Matrix3x2 _Transform;
public Guid Format => _Source.Format;
public int Width { get; }
public int Height { get; }
public void CopyPixels(Rectangle sourceArea, int cbStride, Span<byte> buffer)
{
// sampling one pixel at a time.
var srcRect = new Rectangle(0, 0, 1, 1);
// step vector to the next pixel in source.
Vector2 srcV = Vector2.TransformNormal(Vector2.UnitX, _Transform);
for (int y=0; y < sourceArea.Height; ++y)
{
var dstP = new Vector2(sourceArea.X, sourceArea.Y + y);
var srcP = Vector2.Transform(dstP, _Transform);
var dstRow = buffer.Slice(y * cbStride, cbStride);
for (int x = 0; x < sourceArea.Width; ++x)
{
var dstPixel = dstRow.Slice(x * _SourceBpp, _SourceBpp);
// set source sampling pixel.
srcRect.X = (int)srcP.X;
srcRect.Y = (int)srcP.Y;
// sample the pixel at Src and copy it to Dst
if (srcRect.X < 0 || srcRect.X >= _Source.Width-1 || srcRect.Y < 0 || srcRect.Y >= _Source.Height-1)
{
dstPixel.Fill(0);
}
else
{
_Source.CopyPixels(srcRect, dstPixel.Length, dstPixel);
}
srcP += srcV; // advance to the next pixel in the source bitmap
}
}
}
} The result of applying this transform with a matrix that has translation, rotation and scaling looks like this: The biggest problem is that it's using a very naive "point" sampling mechanism, and ideally it would have to use bilinear interpolation or maybe something more advanced. Now, many things of MagicScaler are internal, and I don't know if doing this with a IPixelTransform is the right approach, but as I understand it, part of the process of scaling an image implies "sampling" the source image. What it would just need is to apply a matrix transform to the coordinates of these "sampled" pixels. My plan for now is to use this to rotate the image keeping the scale, and then resize it to its final dimensions, but it's a two step operation. Just leaving this here for reference and proof of concept. |
Beta Was this translation helpful? Give feedback.
-
Could it be possible to transform an image by an arbitrary matrix?
Something like this:
Beta Was this translation helpful? Give feedback.
All reactions