From 82a81bb26e4c6a83734c87fbbae0ded584e09eae Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 16:19:16 -0800 Subject: [PATCH] Support scale factor to buffer APIs --- atom/common/api/atom_api_native_image.cc | 93 ++++++++++++++++-------- atom/common/api/atom_api_native_image.h | 8 +- spec/api-native-image-spec.js | 12 +++ 3 files changed, 79 insertions(+), 34 deletions(-) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 7437090111..e63fff3a0c 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -230,28 +230,46 @@ HICON NativeImage::GetHICON(int size) { } #endif -v8::Local NativeImage::ToPNG(v8::Isolate* isolate) { - scoped_refptr png = image_.As1xPNGBytes(); - if (IsEmpty() || png->size() > 0) { - const char* data = reinterpret_cast(png->front()); - const size_t length = static_cast(png->size()); - return node::Buffer::Copy(isolate, data, length).ToLocalChecked(); - } else { - std::vector encoded; - gfx::PNGCodec::EncodeBGRASkBitmap(image_.AsBitmap(), false, &encoded); - const char* data = reinterpret_cast(encoded.data()); - return node::Buffer::Copy(isolate, data, encoded.size()).ToLocalChecked(); +v8::Local NativeImage::ToPNG(mate::Arguments* args) { + float scale_factor = 1.0f; + mate::Dictionary options; + if (args->GetNext(&options)) + options.Get("scaleFactor", &scale_factor); + + if (scale_factor == 1.0f) { + // Use raw 1x PNG bytes when available + scoped_refptr png = image_.As1xPNGBytes(); + if (png->size() > 0) { + const char* data = reinterpret_cast(png->front()); + size_t size = png->size(); + return node::Buffer::Copy(args->isolate(), data, size).ToLocalChecked(); + } } + + const SkBitmap bitmap = + image_.AsImageSkia().GetRepresentation(scale_factor).sk_bitmap(); + std::unique_ptr> encoded( + new std::vector()); + gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, encoded.get()); + const char* data = reinterpret_cast(encoded->data()); + size_t size = encoded->size(); + return node::Buffer::Copy(args->isolate(), data, size).ToLocalChecked(); } -v8::Local NativeImage::ToBitmap(v8::Isolate* isolate) { - if (IsEmpty()) return node::Buffer::New(isolate, 0).ToLocalChecked(); +v8::Local NativeImage::ToBitmap(mate::Arguments* args) { + float scale_factor = 1.0f; + mate::Dictionary options; + if (args->GetNext(&options)) + options.Get("scaleFactor", &scale_factor); - const SkBitmap* bitmap = image_.ToSkBitmap(); - SkPixelRef* ref = bitmap->pixelRef(); - return node::Buffer::Copy(isolate, + const SkBitmap bitmap = + image_.AsImageSkia().GetRepresentation(scale_factor).sk_bitmap(); + SkPixelRef* ref = bitmap.pixelRef(); + if (!ref) + return node::Buffer::New(args->isolate(), 0).ToLocalChecked(); + return node::Buffer::Copy(args->isolate(), reinterpret_cast(ref->pixels()), - bitmap->getSafeSize()).ToLocalChecked(); + bitmap.getSafeSize()).ToLocalChecked(); } v8::Local NativeImage::ToJPEG(v8::Isolate* isolate, int quality) { @@ -260,25 +278,40 @@ v8::Local NativeImage::ToJPEG(v8::Isolate* isolate, int quality) { return node::Buffer::Copy( isolate, reinterpret_cast(&output.front()), - static_cast(output.size())).ToLocalChecked(); + output.size()).ToLocalChecked(); } -std::string NativeImage::ToDataURL() { - scoped_refptr png = image_.As1xPNGBytes(); - if (IsEmpty() || png->size() > 0) - return webui::GetPngDataUrl(png->front(), png->size()); - else - return webui::GetBitmapDataUrl(image_.AsBitmap()); +std::string NativeImage::ToDataURL(mate::Arguments* args) { + float scale_factor = 1.0f; + mate::Dictionary options; + if (args->GetNext(&options)) + options.Get("scaleFactor", &scale_factor); + + if (scale_factor == 1.0f) { + // Use raw 1x PNG bytes when available + scoped_refptr png = image_.As1xPNGBytes(); + if (png->size() > 0) + return webui::GetPngDataUrl(png->front(), png->size()); + } + + return webui::GetBitmapDataUrl( + image_.AsImageSkia().GetRepresentation(scale_factor).sk_bitmap()); } -v8::Local NativeImage::GetBitmap(v8::Isolate* isolate) { - if (IsEmpty()) return node::Buffer::New(isolate, 0).ToLocalChecked(); +v8::Local NativeImage::GetBitmap(mate::Arguments* args) { + float scale_factor = 1.0f; + mate::Dictionary options; + if (args->GetNext(&options)) + options.Get("scaleFactor", &scale_factor); - const SkBitmap* bitmap = image_.ToSkBitmap(); - SkPixelRef* ref = bitmap->pixelRef(); - return node::Buffer::New(isolate, + const SkBitmap bitmap = + image_.AsImageSkia().GetRepresentation(scale_factor).sk_bitmap(); + SkPixelRef* ref = bitmap.pixelRef(); + if (!ref) + return node::Buffer::New(args->isolate(), 0).ToLocalChecked(); + return node::Buffer::New(args->isolate(), reinterpret_cast(ref->pixels()), - bitmap->getSafeSize(), + bitmap.getSafeSize(), &Noop, nullptr).ToLocalChecked(); } diff --git a/atom/common/api/atom_api_native_image.h b/atom/common/api/atom_api_native_image.h index ee1b5f5d4b..a6614a81b0 100644 --- a/atom/common/api/atom_api_native_image.h +++ b/atom/common/api/atom_api_native_image.h @@ -70,10 +70,10 @@ class NativeImage : public mate::Wrappable { ~NativeImage() override; private: - v8::Local ToPNG(v8::Isolate* isolate); + v8::Local ToPNG(mate::Arguments* args); v8::Local ToJPEG(v8::Isolate* isolate, int quality); - v8::Local ToBitmap(v8::Isolate* isolate); - v8::Local GetBitmap(v8::Isolate* isolate); + v8::Local ToBitmap(mate::Arguments* args); + v8::Local GetBitmap(mate::Arguments* args); v8::Local GetNativeHandle( v8::Isolate* isolate, mate::Arguments* args); @@ -81,7 +81,7 @@ class NativeImage : public mate::Wrappable { const base::DictionaryValue& options); mate::Handle Crop(v8::Isolate* isolate, const gfx::Rect& rect); - std::string ToDataURL(); + std::string ToDataURL(mate::Arguments* args); bool IsEmpty(); gfx::Size GetSize(); float GetAspectRatio(); diff --git a/spec/api-native-image-spec.js b/spec/api-native-image-spec.js index 7e32fef561..f8a5708edc 100644 --- a/spec/api-native-image-spec.js +++ b/spec/api-native-image-spec.js @@ -11,11 +11,15 @@ describe('nativeImage module', () => { assert.equal(empty.isEmpty(), true) assert.equal(empty.getAspectRatio(), 1) assert.equal(empty.toDataURL(), 'data:image/png;base64,') + assert.equal(empty.toDataURL({scaleFactor: 2.0}), 'data:image/png;base64,') assert.deepEqual(empty.getSize(), {width: 0, height: 0}) assert.deepEqual(empty.getBitmap(), []) + assert.deepEqual(empty.getBitmap({scaleFactor: 2.0}), []) assert.deepEqual(empty.toBitmap(), []) + assert.deepEqual(empty.toBitmap({scaleFactor: 2.0}), []) assert.deepEqual(empty.toJPEG(100), []) assert.deepEqual(empty.toPNG(), []) + assert.deepEqual(empty.toPNG({scaleFactor: 2.0}), []) if (process.platform === 'darwin') { assert.deepEqual(empty.getNativeHandle(), []) @@ -98,6 +102,14 @@ describe('nativeImage module', () => { assert.deepEqual(imageC.getSize(), {width: 538, height: 190}) assert(imageB.toBitmap().equals(imageC.toBitmap())) }) + + it('supports a scale factor', () => { + const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')) + const imageB = nativeImage.createFromDataURL(imageA.toDataURL({scaleFactor: 1.0})) + assert.deepEqual(imageB.getSize(), {width: 538, height: 190}) + const imageC = nativeImage.createFromDataURL(imageA.toDataURL({scaleFactor: 2.0})) + assert.deepEqual(imageC.getSize(), {width: 538, height: 190}) + }) }) describe('toPNG()', () => {