SixLabors / ImageSharp

:camera: A modern, cross-platform, 2D Graphics library for .NET
https://sixlabors.com/products/imagesharp/
Other
7.34k stars 847 forks source link

V3 - Correctly handle transform spaces when building transform matrices. #2791

Closed JimBobSquarePants closed 3 weeks ago

JimBobSquarePants commented 1 month ago

Prerequisites

Description

Fixes #2753
This is a rework of #2760 to correctly handle transforms that require working in the pixel transform space.

Previous attempts to fix these issues inadvertently introduced breaking changes for users who relied on the builder APIs to transform 2D paths. These changes affected how paths were handled, particularly in scenarios where the distinction between coordinate and pixel spaces wasn't explicitly managed. To mitigate this, the refactor introduces new configuration options within the builder APIs that allow users to specify which space (coordinate or pixel) they want to operate within. This ensures that developers can maintain control over how their transformations are applied, preserving existing workflows while also benefiting from the improved accuracy and flexibility of the new implementation. These options provide a smoother transition for users, allowing them to adapt to the changes without disrupting their existing codebases.

A little theory....

2D transforms take place in two different spaces:

  1. Coordinate Space:

    • Coordinate space is a continuous, mathematical grid where objects and positions are defined with precise, often fractional values. This space allows for high-precision transformations like scaling, rotation, and translation. In coordinate space, each pixel is treated as a square unit that can be positioned and transformed with exactness, even down to fractions of a unit. However, the final rendering to a screen (which operates in pixel space) requires careful handling to ensure that these precise transformations map correctly to the discrete grid of pixels.
  2. Pixel Space:

    • Pixel space is a discrete grid where each position corresponds to a specific pixel on the screen, defined by whole numbers. This space represents the actual grid of pixels that make up an image or rendering surface. Operations in pixel space are constrained to integer values, which means that any transformation needs to account for the fact that pixels are indivisible and cannot be positioned between grid points. This can introduce challenges when applying transformations like scaling or rotation, as the final positions must align with the pixel grid to avoid visual artifacts like clipping or misalignment.

Key Changes in This Refactor: