Best way to write a (possibly GPU backed) SkCanvas to PNG

1,286 views
Skip to first unread message

Dean McNamee

unread,
Feb 5, 2015, 4:55:25 PM2/5/15
to skia-d...@googlegroups.com
What's the best way to write an SkCanvas to a PNG? A look at
SkImageEncoder looks like it works on an SkBitmap, however I would
also like it to work for GPU backed canvases. I realize this can mean
a readback and that's fine. Currently I am using
SkCanvas::readPixels() and an external PNG encoder but there are a few
disadvantages and I'd prefer to using an SkImageEncoder if possible.

Thanks,
-- dean

Mike Reed

unread,
Feb 5, 2015, 4:58:47 PM2/5/15
to skia-d...@googlegroups.com
Good question (because we now have a good answer :)

SkSurface* surface = .... // some factory, either CPU or GPU backed
SkCanvas* canvas = surface->getCanvas();
... // draw into canvas
SkImage* image = surface->newImageSnapshot();
SkData* data = image->encode(SkImageEncoder::kPNG_Type, 100);

... // write data whereever you want it 

data->unref();
image->unref();
surface->unref();



--
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 post to this group, send email to skia-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/skia-discuss.
For more options, visit https://groups.google.com/d/optout.

Dean McNamee

unread,
Feb 6, 2015, 3:04:31 AM2/6/15
to skia-d...@googlegroups.com
Hey Mike,

Thanks for the quick response. In my case it would be a lot more
convenient to just hold on to the SkCanvas in this piece of code, not
both the SkCanvas and the SkSurface. If I remember correctly there
isn't a good way to get the SkSurface from the SkCanvas. Is there a
way to do an image snapshot on the canvas itself?

Thanks!

Mike Reed

unread,
Feb 6, 2015, 10:28:16 AM2/6/15
to skia-d...@googlegroups.com
One reason we created the extra layer of Surface was precisely to support this notion of a "free" snapshot of a drawing canvas. The Surface manages both the allocation/reference to the returned image, *and* knows when it must detach that image if there is subsequent drawing to the canvas (so we don't pollute the first image with later drawing). Without this, you'd always have to (deep) copy the pixels out of the canvas... which is supported (even for GPU backed canvas) via canvas->readPixels().

Dean McNamee

unread,
Feb 8, 2015, 4:22:45 PM2/8/15
to skia-d...@googlegroups.com
Hey Mike,

Thanks for explaining that, I'll admit I haven't spent enough time to
look at how the surface abstraction works. The GPU accelerated path
in my code is using an SkSurface, but now looking at my old bitmap
backed canvases, it is just creating an SkBitmap and creating a new
SkCanvas with the SkBitmap. What's the new correct bitmap canvas
construction approach to also have the SkSurface layer for the non-GPU
path?

Thanks!

On Fri, Feb 6, 2015 at 4:27 PM, 'Mike Reed' via skia-discuss

Mike Klein

unread,
Feb 8, 2015, 6:47:21 PM2/8/15
to skia-d...@googlegroups.com
Have a look at the SkSurface::NewRaster*() functions.  Depending on how you create and initialize your SkBitmap, one of those NewRaster functions should be a drop-in replacement.

SkSurface::NewRasterN32Premul() -- simplest, allocates the (most commonly used) native 8888 pixel format
SkSurface::NewRaster()   -- like NewRasterN32Premul() for any supported color / alpha type combination
SkSurface::NewRasterDirect()  -- like NewRaster() but takes pre-allocated pixel storage instead of allocating it
SkSurface::NewRasterDirectReleaseProc() -- like NewRasterDirect(), with a hook for a cleanup method to call when destroyed


>> >> To post to this group, send email to skia-d...@googlegroups.com.
>> >> Visit this group at http://groups.google.com/group/skia-discuss.
>> >> For more options, visit https://groups.google.com/d/optout.
>> >
>> >
>> > --
>> > 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

>> > To post to this group, send email to skia-d...@googlegroups.com.
>> > Visit this group at http://groups.google.com/group/skia-discuss.
>> > For more options, visit https://groups.google.com/d/optout.
>>
>> --
>> 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

>> To post to this group, send email to skia-d...@googlegroups.com.
>> Visit this group at http://groups.google.com/group/skia-discuss.
>> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> 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

> To post to this group, send email to skia-d...@googlegroups.com.
> Visit this group at http://groups.google.com/group/skia-discuss.
> For more options, visit https://groups.google.com/d/optout.

--
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+unsubscribe@googlegroups.com.

Dean McNamee

unread,
Mar 4, 2015, 5:39:38 AM3/4/15
to skia-d...@googlegroups.com
Thanks for that, sorry for the additional questions, I am moving from
the (deprecated) SkBitmap APIs... I would like to keep a writeable
pointer to the allocated pixels, I could const_cast out the pointer
from peekPixels, but that doesn't sound very nice. I could also go
through the canvas and use accessTopLayerPixels, but that seems to
make even less sense. Is there an easy way to get to the pixels
behind an SkSurface when using something like NewRasterN32Premul? Or
do I have to allocate the memory myself and use
NewRasterDirectReleaseProc for taking care of deallocation? Would be
nice to avoid the manual book keeping but really not a big deal.

I am using a slightly older Skia so it looks like NewRasterN32Premul
etc aren't there, but I will either upgrade or just go through
NewRaster().

Thanks again,
>> >> >> email to skia-discuss...@googlegroups.com.
>> >> >> To post to this group, send email to skia-d...@googlegroups.com.
>> >> >> Visit this group at http://groups.google.com/group/skia-discuss.
>> >> >> For more options, visit https://groups.google.com/d/optout.
>> >> >
>> >> >
>> >> > --
>> >> > 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 post to this group, send email to skia-d...@googlegroups.com.
>> >> > Visit this group at http://groups.google.com/group/skia-discuss.
>> >> > For more options, visit https://groups.google.com/d/optout.
>> >>
>> >> --
>> >> 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 post to this group, send email to skia-d...@googlegroups.com.
>> >> Visit this group at http://groups.google.com/group/skia-discuss.
>> >> For more options, visit https://groups.google.com/d/optout.
>> >
>> >
>> > --
>> > 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 post to this group, send email to skia-d...@googlegroups.com.
>> > Visit this group at http://groups.google.com/group/skia-discuss.
>> > For more options, visit https://groups.google.com/d/optout.
>>
>> --
>> 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 post to this group, send email to skia-d...@googlegroups.com.
>> Visit this group at http://groups.google.com/group/skia-discuss.
>> For more options, visit https://groups.google.com/d/optout.
>
> --
> 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.

Mike Reed

unread,
Mar 4, 2015, 10:54:11 AM3/4/15
to skia-d...@googlegroups.com
A writable ptr is easy using NewRasterDirect[ReleaseProc].

Its a little tricky since at any given point the canvas associated w/ the surface might be drawing into a layer, and not into the memory of the base, but if you're ok with that, I think NewRasterDirect should be fine.

Dean McNamee

unread,
Mar 5, 2015, 2:22:27 AM3/5/15
to skia-d...@googlegroups.com
Hey Mike,

That only happens if you explicitly use layers right? Or are there
any situations where layers are used that aren't obvious?

Thanks!

On Wed, Mar 4, 2015 at 4:53 PM, 'Mike Reed' via skia-discuss

Mike Reed

unread,
Mar 5, 2015, 10:19:36 AM3/5/15
to skia-d...@googlegroups.com
For a raster-backed canvas, the only tricky time will be if there are layers.

Dean McNamee

unread,
Mar 10, 2015, 6:06:15 AM3/10/15
to skia-d...@googlegroups.com
Hey Mike,

That's what I thought. I just wanted to make sure there weren't any
non-obvious cases where possibly the layering mechanism was used under
the hood, and there might be a place where a layer is used that I
would realize. But I couldn't think of any so it seems like something
I wouldn't have to worry about.

Thanks again,

On Thu, Mar 5, 2015 at 4:19 PM, 'Mike Reed' via skia-discuss

Dean McNamee

unread,
Mar 10, 2015, 6:13:21 AM3/10/15
to skia-d...@googlegroups.com
And as a follow up question. The way I used the old API, you could
draw into the canvas, and then later write it out to the file with
appendPage(). Has the API now changed in a way in which you must call
beginPage() first before drawing to the canvas? Is there a way to
have some compatibility with the old ordering?

For example, you could previously draw something to a canvas, write it
out, then continuing with more operations on the same canvas, write it
out again, etc.

Thanks,

Mike Reed

unread,
Mar 10, 2015, 9:18:48 AM3/10/15
to skia-d...@googlegroups.com, Hal Canary, Ben Wagner
I think the new SkDocument pattern requires beginPage, and orphans the canvas on endPage, but Hal/Ben may have a better answer.
Reply all
Reply to author
Forward
0 new messages