fogleman / gg

Go Graphics - 2D rendering in Go with a simple API.
https://godoc.org/github.com/fogleman/gg
MIT License
4.37k stars 354 forks source link

Fill and stroke operations fail on parts of subimage #140

Open AntiMS opened 3 years ago

AntiMS commented 3 years ago

It looks like gg doesn't play well with *image.RGBA subimages. Clear operations work on subimages as expected as far as I can tell, but fill and stroke operations appear not to be able to affect parts of the subimage (that, unless I'm missing something, and that's entirely possible) they should be able to affect.

Minimal example: https://play.golang.org/p/GdMqfdh0Tmc

It should, I think, be drawing a circle with arcs clipped off on the top, bottom, left, and right. But it only draws a quarter of the circle for some reason. I added the blue and red pixels at the bottom right to demonstrate that those pixels to which gg apparently can't draw (with fill/stroke) can be manipulated directly by directly setting the pixel information.

If you comment out line 23 so that it doesn't make a subimage, everything works as expected. (It draws the circle as expected, though the .Clear() on line 26 then affects the whole image and the circle isn't clipped, both as expected.)

I believe the margin on the bottom of the subimage that it can't draw is subBounds.Min.Y pixels tall and the margin on the right is subBounds.Min.X pixels tall.

I'm not just missing something obvious, am I?

Thanks!

AntiMS commented 3 years ago

Well, I looked a little deeper and I think I've found the (relatively obvious) cause.

github.com/golang/freetype/raster doesn't really have support for *image.RGBAs with non-zero .Bounds().Min .

Seems like there are quite a few ways to approach this. One of which would be for gg to intentionally not support images with non-zero .Bounds().Min and let users work around it with .Clip() or some other solution.

For my own use case, I think probably the workaround I'll use (because I don't want to pass gg.Context's around my whole application -- I'd rather just pass image.RGBA's around) is to, rather than using .SubImage(...), allocate a new RGBA of the required size with its .Bounds().Min at (0, 0), have some other function somewhere else in the application draw to that image, and then draw the resulting new image onto the original image at the proper location. If/when gg and/or freetype/raster gets support for *image.RGBA's with non-zero .Bounds().Min, I can simplify my code later just by swapping back to the .SubImage(...) solution.

Thanks again!