I've been working on wonky cropping/placing of images for a bit, and here is the solution that seems to be working for me. I haven't had a chance yet to test it against the repo that Kensands linked, although that looks like a good spot to start. Thought I'd post here as this thread was really helpful in getting me pointed in the right direction:
Code:
...
PdfTilingPattern BuildPattern(ImageBrush brush, XMatrix transform)
{
// Bounding box lays always at (0,0)
XRect bbox = new XRect(0, 0, brush.Viewport.Width, brush.Viewport.Height);
#if true
XMatrix matrix = transform;
//adjust pixel width dimensions from viewBox to match the units of the viewport
var translateOffsetX = brush.Viewport.Width * brush.Viewbox.X / brush.Viewbox.Width * -1;
var translateOffsetY = brush.Viewport.Height * brush.Viewbox.Y / brush.Viewbox.Height * -1;
matrix.Prepend(new XMatrix(1, 0, 0, 1, brush.Viewport.X + translateOffsetX, brush.Viewport.Y + translateOffsetY));
if (brush.Transform != null)
{
matrix.Prepend(new XMatrix(brush.Transform.Matrix.m11, brush.Transform.Matrix.m12, brush.Transform.Matrix.m21,
brush.Transform.Matrix.m22, brush.Transform.Matrix.offsetX, brush.Transform.Matrix.offsetY));
}
#else
double c = 1;
XMatrix matrix = new XMatrix(1 * c, 0, 0, 1 * c, brush.Viewport.X * c, brush.Viewport.Y * c); // HACK: 480
XMatrix t = transform;
//t.Invert();
t.Prepend(matrix);
//t.TranslateAppend(brush.Viewport.X , brush.Viewport.Y);
//matrix.Append(t);
matrix = t;
#endif
double xStep = brush.Viewport.Width + 1;
double yStep = brush.Viewport.Height + 1;
// PdfTilingPattern
...
EDIT: on doing more testing this appears to work for portrait or landscape pictures that should be shrunk down to fit in a square viewport (letterboxed or pillarboxed) but there is still a problem when they should get clipped and fill the viewport (I'm converting from Xaml to XPS and then from XPS to PDF as described here:
https://nathanpjones.com/wp/2013/03/output-to-pdf-in-wpf-for-free/, and if I use the Stretch="Uniform" property on my imagebrush it letterboxes as I would expect, but if I use Stretch="UniformToFill" it does not behave as I would expect). I'm investigating more hoping to find a fix that works in both cases.