diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index a5360c633975..a95dcf666e60 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -1337,15 +1337,10 @@ bool WebContents::IsOffScreen() const { return type_ == OFF_SCREEN; } -void WebContents::OnPaint(const gfx::Rect& dirty_rect, - const SkBitmap& bitmap) { - v8::MaybeLocal buffer = node::Buffer::Copy( - isolate(), - reinterpret_cast(bitmap.getPixels()), bitmap.getSize()); - if (!buffer.IsEmpty()) { - Emit("paint", dirty_rect, buffer.ToLocalChecked(), - gfx::Size(bitmap.width(), bitmap.height())); - } +void WebContents::OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap) { + mate::Handle image = + NativeImage::Create(isolate(), gfx::Image::CreateFrom1xBitmap(bitmap)); + Emit("paint", dirty_rect, image); } void WebContents::StartPainting() { diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index bd97ea338504..b08c9a95d3a7 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -172,6 +172,9 @@ bool ReadImageSkiaFromICO(gfx::ImageSkia* image, HICON icon) { } #endif +void Noop(char*, void*) { +} + } // namespace NativeImage::NativeImage(v8::Isolate* isolate, const gfx::Image& image) @@ -246,6 +249,16 @@ std::string NativeImage::ToDataURL() { return data_url; } +v8::Local NativeImage::GetBitmap(v8::Isolate* isolate) { + const SkBitmap* bitmap = image_.ToSkBitmap(); + SkPixelRef* ref = bitmap->pixelRef(); + return node::Buffer::New(isolate, + reinterpret_cast(ref->pixels()), + bitmap->getSafeSize(), + &Noop, + nullptr).ToLocalChecked(); +} + v8::Local NativeImage::GetNativeHandle(v8::Isolate* isolate, mate::Arguments* args) { #if defined(OS_MACOSX) @@ -361,6 +374,7 @@ void NativeImage::BuildPrototype( .SetMethod("toPNG", &NativeImage::ToPNG) .SetMethod("toJPEG", &NativeImage::ToJPEG) .SetMethod("toBitmap", &NativeImage::ToBitmap) + .SetMethod("getBitmap", &NativeImage::GetBitmap) .SetMethod("getNativeHandle", &NativeImage::GetNativeHandle) .SetMethod("toDataURL", &NativeImage::ToDataURL) .SetMethod("isEmpty", &NativeImage::IsEmpty) diff --git a/atom/common/api/atom_api_native_image.h b/atom/common/api/atom_api_native_image.h index d6fddd10763d..743a3c599b7e 100644 --- a/atom/common/api/atom_api_native_image.h +++ b/atom/common/api/atom_api_native_image.h @@ -71,6 +71,7 @@ class NativeImage : public mate::Wrappable { v8::Local ToPNG(v8::Isolate* isolate); v8::Local ToJPEG(v8::Isolate* isolate, int quality); v8::Local ToBitmap(v8::Isolate* isolate); + v8::Local GetBitmap(v8::Isolate* isolate); v8::Local GetNativeHandle( v8::Isolate* isolate, mate::Arguments* args); diff --git a/docs/api/native-image.md b/docs/api/native-image.md index d0c9a3b62f97..947a5b77b038 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -163,12 +163,21 @@ Returns a [Buffer][buffer] that contains the image's `JPEG` encoded data. #### `image.toBitmap()` -Returns a [Buffer][buffer] that contains the image's raw pixel data. +Returns a [Buffer][buffer] that contains a copy of the image's raw bitmap pixel +data. #### `image.toDataURL()` Returns the data URL of the image. +#### `image.getBitmap()` + +Returns a [Buffer][buffer] that contains the image's raw bitmap pixel data. + +The difference between `getBitmap()` and `toBitmap()` is, `getBitmap()` does not +copy the bitmap data, so you have to use the returned Buffer immediately in +current event loop tick, otherwise the data might be changed or destroyed. + #### `image.getNativeHandle()` _macOS_ Returns a [Buffer][buffer] that stores C pointer to underlying native handle of diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 81e5a14b0745..f000193b8390 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -463,14 +463,11 @@ Returns: * `event` Event * `dirtyRect` Object - * `x` Number - the x coordinate on the bitmap - * `y` Number - the y coordinate on the bitmap - * `width` Number - the width of the dirty area - * `height` Number - the height of the dirty area -* `data` Buffer - the bitmap data of the dirty rect -* `bitmapSize` Object - * `width` Number - the width of the whole bitmap - * `height` Number - the height of the whole bitmap + * `x` Integer - The x coordinate on the image. + * `y` Integer - The y coordinate on the image. + * `width` Integer - The width of the dirty area. + * `height` Integer - The height of the dirty area. +* `image` [NativeImage](native-image.md) - The image data of the whole frame. Emitted when a new frame is generated. Only the dirty area is passed in the buffer. @@ -478,18 +475,11 @@ buffer. ```javascript const {BrowserWindow} = require('electron') -let win = new BrowserWindow({ - width: 800, - height: 1500, - webPreferences: { - offscreen: true - } +let win = new BrowserWindow({webPreferences: {offscreen: true}}) +win.webContents.on('paint', (event, dirty, image) => { + // updateBitmap(dirty, image.getBitmap()) }) win.loadURL('http://github.com') - -win.webContents.on('paint', (event, dirty, data) => { - // updateBitmap(dirty, data) -}) ``` ### Instance Methods diff --git a/docs/tutorial/offscreen-rendering.md b/docs/tutorial/offscreen-rendering.md index 8edcb573756e..e47967bd35bb 100644 --- a/docs/tutorial/offscreen-rendering.md +++ b/docs/tutorial/offscreen-rendering.md @@ -37,19 +37,18 @@ const {app, BrowserWindow} = require('electron') app.disableHardwareAcceleration() -let win = new BrowserWindow({ - width: 800, - height: 1500, - webPreferences: { - offscreen: true - } -}) -win.loadURL('http://github.com') - -win.webContents.setFrameRate(30) - -win.webContents.on('paint', (event, dirty, data) => { - // updateBitmap(dirty, data) +let win +app.once('ready', () => { + win = new BrowserWindow({ + webPreferences: { + offscreen: true + } + }) + win.loadURL('http://github.com') + win.webContents.on('paint', (event, dirty, image) => { + // updateBitmap(dirty, image.getBitmap()) + }) + win.webContents.setFrameRate(30) }) ```