-
Notifications
You must be signed in to change notification settings - Fork 76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve handling of ‘raw’ pixel buffers and ImageData #147
Improve handling of ‘raw’ pixel buffers and ImageData #147
Conversation
Hi Gleb, Just wanted to say thanks for the PR, which I pulled into my own fork and successfully tested. I also added a counterpart feature to export the whole canvas as raw data asynchronously. It's sort-of like Also added a feature to specify a crop rectangle when exporting in any raster format or raw. I'm using all this in a workflow that reads in various images formats with sharp, resizes and caches them in memory. Then later we draw them to a Skia Canvas (possibly with other elements, transforms, etc), export the canvas back to The drawing/compression/sending part can happen very often with multiple images possibly being requested in the same millisecond with refreshes at 10Hz or more being common. So, performance matters. Switching to raw processing, skipping unnecessary encoding steps, has been benchmarked as ~400% overall improvement in speed, w/out any extra CPU load or memory use. Nice win. Anyway, it's all published, and documented in the changelog and readme if anyone cares to take a look. There are 2 branches which contain the core changes, though one builds upon the other. I should mention that this is my first ever Rust project, so quite likely there are some prettier or more efficient ways of doing some things. The syntax and some concepts have a bit of a learning curve! Cheers, |
Oh I forgot to add one caveat I found when loading raw pixel data to SkImage. Skia doesn't support decoding 3-channel/24-bit color pixels like RGB. It can only handle 1, 2, 4 or 8 byte formats (reference). So when trying to "raw-load" some PNG I had which was RGB only, Skia returns nothing.
Luckily |
- colorType can be 'rgba' (the default), 'rgb', 'bgra', or 'argb' - colorSpace can currently only be 'srgb' but 'display-p3' support is on the todo list
- uses a common implementation with the Image.src loader (thus the weird callback design of `fetchData` to fulfill Image's expectations of sync loads for local files)
…ding step. Adds support for "raw" format to existing export options and adds specific `Canvas#toRaw()` method.
- dropped the alias from 'argb' to the odd-seeming 16 bit color type (is it actually commonly used though?)
1e7e09b
to
f280d58
Compare
Thanks so much to both of you for getting everything working on the raw-image front! I've tried to integrate the work from your branches to allow for un-encoded images to be used while trying to minimize the amount of new, non-standard syntax and behavior. Since the ImageData class already exists for this purpose, extending that rather than creating a new kind of raw-buffer-backed Image made more sense to me. Enhancements to ImageDataThe browser version of this class is always in 4-byte RGBA mode, but does take an options arg (which is currently just used for
I followed your lead in adding an optional The new read-only I've also added an asynchronous Enhancements to the Context's handling of ImageData objectsAccording to the spec, the only way to get an ImageData object drawn to the canvas is to use the The export methods ( Speedups for
|
- it's just so we can use the common parts of the encoded-image path
- the `.onload` and `.onerror` properties are still supported, but `on`, `once`, and `off` now work too - moved the fetchData routine back into Image as a static method so it can still be used by loadImageData
- previously img.src='./local/file/path' would synchronously load the data and the image would immediately be ready for use - now, even local files should wait for img.decode() or img.on('load') to resolve first
- the real way to judge success is complete==true *and* non-zero width/height
- it now just uses the closure's Result type
- since the output differs, use the version that will be stable across CI runs
- significantly faster for single `get`s and absurdly fast for subsequent gets of the same canvas content (since it's using a cached bitmap that's invalidated on the next drawing command) - required adding a reference to the ctx's Canvas to the call so it can access the current gpu::RenderingEngine mode (and initialize it if needed)
Description
Based on #113
This PR adds a new functionality to
loadImage()
andImage
to load images from already decoded pixel buffers. Currently there is no way to do that andskia-canvas
only supports loading images from encoded formats and does encoding on its own using Skia methods.There are many cases when loading raw pixel buffers are beneficial. For example, when reading images from web cams, reading video frames from ffmpeg or while using custom image decoders that Skia doesn't support.
Details
In this implementation I added a new optional parameter called
ImageOptions
that currently supports only one optional property calledraw
of typeImageData
. API consumer can provide this object toloadImage()
function and toImage
constructor. IfcolorType
and passedimage resolution
doesn't match pixel buffer data, a regularError
will be thrown using existing callbacks.Example with
loadImage()
:Example with
Image
constructor:In Rust code I created a new function called
load_pixel_data
that is responsible for creatingSkImage
. It doesn't align perfectly with existing code that uses getters/setters and I didn't find a suitable way of how to make it look better. May be we can removeset_data
setter and make it a function as well but I didn't want to do that without consulting with you first.Also currently only the most common pixel formats are supported (such as
rgba
,rgb
,bgra
andargb
) and I'm not sure if we need to expose other less popular formats that Skia supports.Tests
I added several tests that test different loading scenarios and also tested internally using different popular libraries that allow raw pixel buffer extraction (for example
sharp
andffmpeg
). Based on my simple benchmarks I didn't find anything unusual, CPU and RAM usage was normal.