x/image/vector: rasterizer shifts alpha mask and is slow when target is offset and small relative image size #25657
Labels
NeedsInvestigation
Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Performance
Milestone
Please answer these questions before submitting your issue. Thanks!
What version of Go are you using (
go version
)?1.10.2
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?linux/amd64
What did you do?
In the golang.org/x/image/vector.go there is this function:
func (z *Rasterizer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point)
r is the target rectangle for rendering the image. When r is a smaller rectangle than the bounds of the destination image dst, and offset into the middle of dst, two problems emerge:
First, the alpha mask, which is the whole point of the Draw command shifts with the target rectangle rather than staying fixed to the upper left corner of the image. I believe this should not be the default behavior. It is not consistent with other rasterizers, such as the free type rasterizer. If the mask shifts with the target and you are rendering a path using, say, Bezier curves, and want to draw that path onto an image, you must either determine before hand the exact boundaries of the path and shift the coordinates accordingly, because as it is, a target drawn somewhere in the middle of an image will always draw the mask relative to the upper left corner of the target rectangle. Having to determine the boundaries before hand requires flattening the curves and either storing the resulting line segments or repeating the process when actually rendering the alpha mask. It is much simpler to keep the alpha mask fixed to the upper left corner of the image boundary rather than move with the target rectangle.
Second, no matter how big the target rectangle is relative to the entire image, the "accumulate step" traverses the entire image, which is inefficient when the target is a small fraction of the image.
I have created a modified version of the rasterizer here: https://github.com/srwiley/image
In the vector_test.go file are modified versions of the TestBasicPathDstAlpha and TestBasicPathDstRGBA test functions. These are changed to test for fixing the alpha mask to the image and not shifting with the target. They will fail with the current version of vector.go, but not the forked version.
There are also a series of benchmarks showing the improved performance when the target is small relative the destination image. This is what the benchmark output looks like:
BenchmarkDrawPathBoundsX draw only the path boundary for a path of a hexagon of the indicated radius X in a 2200x2200 sized image. BenchmarkDrawImageBoundsX draws the entire image, which is what the current vector.go file does. So, as the size of the path gets smaller the speed difference increases.
What did you expect to see?
Significantly greater speed when the target is small compared to the image size and the alpha mask fixed to the upper left of the destination image.
What did you see instead?
Inefficient speed for small target sizes relative the image size, and the alpha mask fixed relative the target rectangle upper left corner and not the destination image bounds.
The text was updated successfully, but these errors were encountered: