Get bounds of drawn area and save cropped image

157 views
Skip to first unread message

Bruno

unread,
Feb 3, 2020, 6:35:46 AM2/3/20
to skia-discuss
Is it possible to get the exact bounds of what was drawn in a canvas?

For example, I have:

auto surface = SkSurface::MakeRasterN32Premul(1000, 1000);
auto canvas = surface->getCanvas();

and then I have calls like canvas->scale(a, b), canvas->translate(c, d), bitmap drawings etc... So, all kinds of drawings.

What I need to do is a basically get the bounds of what was drawn so I can draw a frame around it and save a cropped version to a png file, where the dimensions will be exactly what it needs to be. I don't want to save a 1000x1000 image with just 20x20 drawn for example.

Is it possible?

Thanks!

Mike Klein

unread,
Feb 3, 2020, 9:37:46 AM2/3/20
to skia-discuss
Skia does not provide an exact API for this sort of thing.

However, if you record an SkPicture of all your content, and when recording pass an SkRTreeFactory to beginRecording(), after you call endRecording() the cull rectangle you passed in will be trimmed down to approximate, conservative bounds of the draws you have made.  You can retrieve that possibly-smaller rectangle with SkPicture::cullRect().  These bounds may change at any time as we improve Skia; they're only guaranteed to be a bounds, not _the_ bounds.

--
You received this message because you are subscribed to the Google Groups "skia-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to skia-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/62d42ce8-bfc8-411a-94c1-7a099224fb16%40googlegroups.com.

Bruno

unread,
Feb 3, 2020, 6:52:08 PM2/3/20
to skia-discuss
Hi Mike, thanks for your help!

In case I need the exact bounds, I believe I would need to to it manually, probably by reading pixel by pixel and checking whether the color is different from transparent, then in that case I will know where each side of a rect starts.

Would you please suggest me what's the most efficient/fastest way to get access to the pixels? canvas->readPixels, peekPixels?

thank you!


On Tuesday, February 4, 2020 at 12:37:46 AM UTC+10, Mike Klein wrote:
Skia does not provide an exact API for this sort of thing.

However, if you record an SkPicture of all your content, and when recording pass an SkRTreeFactory to beginRecording(), after you call endRecording() the cull rectangle you passed in will be trimmed down to approximate, conservative bounds of the draws you have made.  You can retrieve that possibly-smaller rectangle with SkPicture::cullRect().  These bounds may change at any time as we improve Skia; they're only guaranteed to be a bounds, not _the_ bounds.

On Mon, Feb 3, 2020 at 5:35 AM Bruno <bruno...@gmail.com> wrote:
Is it possible to get the exact bounds of what was drawn in a canvas?

For example, I have:

auto surface = SkSurface::MakeRasterN32Premul(1000, 1000);
auto canvas = surface->getCanvas();

and then I have calls like canvas->scale(a, b), canvas->translate(c, d), bitmap drawings etc... So, all kinds of drawings.

What I need to do is a basically get the bounds of what was drawn so I can draw a frame around it and save a cropped version to a png file, where the dimensions will be exactly what it needs to be. I don't want to save a 1000x1000 image with just 20x20 drawn for example.

Is it possible?

Thanks!

--
You received this message because you are subscribed to the Google Groups "skia-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to skia-d...@googlegroups.com.

Mike Klein

unread,
Feb 3, 2020, 6:54:08 PM2/3/20
to skia-discuss
Yeah, if peekPixels() returns true, that's a good way to read them.  It won't if you're using deferred or GPU rendering.  In that case, readPixels() is a good choice.

To unsubscribe from this group and stop receiving emails from it, send an email to skia-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/2b5e9b6f-474c-4486-aec2-5491d701ff70%40googlegroups.com.

Bruno

unread,
Feb 3, 2020, 6:59:02 PM2/3/20
to skia-discuss

Shawn Riordan

unread,
Feb 3, 2020, 8:46:10 PM2/3/20
to skia-discuss
I think testing each pixel is a bit of a performance hit.

Wouldn't it be easier to take every object you draw and run it through a matrix and ask for the bounds for each transformed item?

Mike Klein

unread,
Feb 3, 2020, 8:47:25 PM2/3/20
to skia-d...@googlegroups.com
Yep, that’s a good idea.

To unsubscribe from this group and stop receiving emails from it, send an email to skia-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/c9270824-be48-4602-9d1d-1ca3076f78b1%40googlegroups.com.

Bruno

unread,
Feb 3, 2020, 9:01:31 PM2/3/20
to skia-discuss
Is there any example on how to do that?

Shawn Riordan

unread,
Feb 3, 2020, 9:29:28 PM2/3/20
to skia-discuss
Lets say you just drew path to a canvas that has more than one transform operation on it.

Call this code next:

const SkMatrix &matrix = canvas.getTotalMatrix();
SkPath transformed_path;
path.transform(matrix, &transformed_path);
SkRect bounds = transformed_path.computeTightBounds();

Then accumulate each drawn item's bounds into a single rectangle that describes the area of the canvas that was drawn to.

You might need to also factor in stroke widths used, if items were stroked.  Also, if so, you would need to transform that stroke width to screenspace too.

Bruno

unread,
Feb 3, 2020, 9:33:44 PM2/3/20
to skia-discuss
Thanks Shawn! I will give this a try!

Shawn Riordan

unread,
Feb 3, 2020, 9:36:18 PM2/3/20
to skia-discuss
That first sentence should have ended "that has ANY transform operations on it."

Also, if some of things you draw are rectangles or point lists, the SkMatrix class has several map functions that can generate the transformed versions.
Reply all
Reply to author
Forward
0 new messages