From b46e48cae1da2c20387ed6a5b0ad1829c08289ca Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 13:15:07 -0800 Subject: [PATCH 01/12] Add failing toDataURL spec --- spec/api-native-image-spec.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/spec/api-native-image-spec.js b/spec/api-native-image-spec.js index e28b37bebfe6..90d184508183 100644 --- a/spec/api-native-image-spec.js +++ b/spec/api-native-image-spec.js @@ -79,6 +79,23 @@ describe('nativeImage module', () => { }) }) + describe('toDataURL()', () => { + it('returns a data URL at 1x scale factor', () => { + const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')) + const imageB = nativeImage.createFromBuffer(imageA.toPNG(), { + width: imageA.getSize().width, + height: imageA.getSize().height, + scaleFactor: 2.0 + }) + assert.deepEqual(imageB.getSize(), {width: 269, height: 95}) + assert.equal(imageB.hasRepresentation(1.0), false) + + const imageC = nativeImage.createFromDataURL(imageB.toDataURL()) + assert.deepEqual(imageC.getSize(), {width: 538, height: 190}) + assert(imageB.toBitmap().equals(imageC.toBitmap())) + }) + }) + describe('createFromPath(path)', () => { it('returns an empty image for invalid paths', () => { assert(nativeImage.createFromPath('').isEmpty()) From 8eaf48e552cffef1b4c30676f15cfd67b27f3754 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 13:22:55 -0800 Subject: [PATCH 02/12] Add spec for 1x1 PNG data URL --- spec/api-native-image-spec.js | 5 +++++ spec/fixtures/assets/1x1.png | Bin 0 -> 68 bytes 2 files changed, 5 insertions(+) create mode 100644 spec/fixtures/assets/1x1.png diff --git a/spec/api-native-image-spec.js b/spec/api-native-image-spec.js index 90d184508183..94492ca40084 100644 --- a/spec/api-native-image-spec.js +++ b/spec/api-native-image-spec.js @@ -80,6 +80,11 @@ describe('nativeImage module', () => { }) describe('toDataURL()', () => { + it('returns a PNG data URL', () => { + const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', '1x1.png')) + assert.equal(imageA.toDataURL(), 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYlWNgAAIAAAUAAdafFs0AAAAASUVORK5CYII=') + }) + it('returns a data URL at 1x scale factor', () => { const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')) const imageB = nativeImage.createFromBuffer(imageA.toPNG(), { diff --git a/spec/fixtures/assets/1x1.png b/spec/fixtures/assets/1x1.png new file mode 100644 index 0000000000000000000000000000000000000000..427fb75b86287ab01a6feec0c2b402153671b6da GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6UNeMs>Cj+yj;LRsM O7K5j&pUXO@geCx0rwkSV literal 0 HcmV?d00001 From 0bbbeb307e1b756ff86f5ba5d2bdfe263c721f5e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 13:24:50 -0800 Subject: [PATCH 03/12] Support toDataURL without 1x representation --- atom/common/api/atom_api_native_image.cc | 18 ++++++++++++------ atom/common/api/atom_api_native_image.h | 1 + spec/api-native-image-spec.js | 1 + 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 0c174941dbf5..95531b1ddf10 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -21,6 +21,7 @@ #include "net/base/data_url.h" #include "third_party/skia/include/core/SkPixelRef.h" #include "ui/base/layout.h" +#include "ui/base/webui/web_ui_util.h" #include "ui/gfx/codec/jpeg_codec.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/geometry/size.h" @@ -257,12 +258,12 @@ v8::Local NativeImage::ToJPEG(v8::Isolate* isolate, int quality) { } std::string NativeImage::ToDataURL() { - scoped_refptr png = image_.As1xPNGBytes(); - std::string data_url; - data_url.insert(data_url.end(), png->front(), png->front() + png->size()); - base::Base64Encode(data_url, &data_url); - data_url.insert(0, "data:image/png;base64,"); - return data_url; + if (HasRepresentation(1.0)) { + scoped_refptr png = image_.As1xPNGBytes(); + return webui::GetPngDataUrl(png->front(), png->size()); + } else { + return webui::GetBitmapDataUrl(image_.AsBitmap()); + } } v8::Local NativeImage::GetBitmap(v8::Isolate* isolate) { @@ -297,6 +298,10 @@ bool NativeImage::IsEmpty() { return image_.IsEmpty(); } +bool NativeImage::HasRepresentation(float scale_factor) { + return image_.AsImageSkia().HasRepresentation(scale_factor); +} + gfx::Size NativeImage::GetSize() { return image_.Size(); } @@ -468,6 +473,7 @@ void NativeImage::BuildPrototype( .SetMethod("resize", &NativeImage::Resize) .SetMethod("crop", &NativeImage::Crop) .SetMethod("getAspectRatio", &NativeImage::GetAspectRatio) + .SetMethod("hasRepresentation", &NativeImage::HasRepresentation) // TODO(kevinsawicki): Remove in 2.0, deprecate before then with warnings .SetMethod("toPng", &NativeImage::ToPNG) .SetMethod("toJpeg", &NativeImage::ToJPEG); diff --git a/atom/common/api/atom_api_native_image.h b/atom/common/api/atom_api_native_image.h index ee1b5f5d4b81..a653f15e0a71 100644 --- a/atom/common/api/atom_api_native_image.h +++ b/atom/common/api/atom_api_native_image.h @@ -83,6 +83,7 @@ class NativeImage : public mate::Wrappable { const gfx::Rect& rect); std::string ToDataURL(); bool IsEmpty(); + bool HasRepresentation(float scale_factor); gfx::Size GetSize(); float GetAspectRatio(); diff --git a/spec/api-native-image-spec.js b/spec/api-native-image-spec.js index 94492ca40084..9aa0ced3ef6d 100644 --- a/spec/api-native-image-spec.js +++ b/spec/api-native-image-spec.js @@ -9,6 +9,7 @@ describe('nativeImage module', () => { it('returns an empty image', () => { const empty = nativeImage.createEmpty() assert.equal(empty.isEmpty(), true) + assert.equal(empty.hasRepresentation(1.0), false) assert.equal(empty.getAspectRatio(), 1) assert.equal(empty.toDataURL(), 'data:image/png;base64,') assert.deepEqual(empty.getSize(), {width: 0, height: 0}) From 50ade57700fe6e48f3a1b975ab484cc093376317 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 13:26:55 -0800 Subject: [PATCH 04/12] Add more hasRepresentation asserts --- spec/api-native-image-spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/api-native-image-spec.js b/spec/api-native-image-spec.js index 9aa0ced3ef6d..922717fab4c3 100644 --- a/spec/api-native-image-spec.js +++ b/spec/api-native-image-spec.js @@ -95,9 +95,11 @@ describe('nativeImage module', () => { }) assert.deepEqual(imageB.getSize(), {width: 269, height: 95}) assert.equal(imageB.hasRepresentation(1.0), false) + assert.equal(imageB.hasRepresentation(2.0), true) const imageC = nativeImage.createFromDataURL(imageB.toDataURL()) assert.deepEqual(imageC.getSize(), {width: 538, height: 190}) + assert.equal(imageC.hasRepresentation(1.0), false) assert(imageB.toBitmap().equals(imageC.toBitmap())) }) }) From 86babdd4122d7e7bea03a937f78de6ed051487cf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 13:36:40 -0800 Subject: [PATCH 05/12] Remove unused include --- atom/common/api/atom_api_native_image.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 95531b1ddf10..5859247574e9 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -12,7 +12,6 @@ #include "atom/common/native_mate_converters/gfx_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/value_converter.h" -#include "base/base64.h" #include "base/files/file_util.h" #include "base/strings/pattern.h" #include "base/strings/string_util.h" From 8bc65ef495437ddf5e3a974ccb787bcff7cf9915 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 13:47:19 -0800 Subject: [PATCH 06/12] Add failing spec for toPNG with scale factor --- spec/api-native-image-spec.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/spec/api-native-image-spec.js b/spec/api-native-image-spec.js index 922717fab4c3..fd6aee9f1eab 100644 --- a/spec/api-native-image-spec.js +++ b/spec/api-native-image-spec.js @@ -104,6 +104,25 @@ describe('nativeImage module', () => { }) }) + describe('toPNG()', () => { + it('returns a buffer at 1x scale factor', () => { + const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')) + const imageB = nativeImage.createFromBuffer(imageA.toPNG(), { + width: imageA.getSize().width, + height: imageA.getSize().height, + scaleFactor: 2.0 + }) + assert.deepEqual(imageB.getSize(), {width: 269, height: 95}) + assert.equal(imageB.hasRepresentation(1.0), false) + assert.equal(imageB.hasRepresentation(2.0), true) + + const imageC = nativeImage.createFromBuffer(imageB.toPNG()) + assert.deepEqual(imageC.getSize(), {width: 538, height: 190}) + assert.equal(imageC.hasRepresentation(1.0), true) + assert(imageB.toBitmap().equals(imageC.toBitmap())) + }) + }) + describe('createFromPath(path)', () => { it('returns an empty image for invalid paths', () => { assert(nativeImage.createFromPath('').isEmpty()) From c11cdf321bf99c73be81b92e54f28995a31f4ac2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 13:47:37 -0800 Subject: [PATCH 07/12] Support toPNG on image without 1x representation --- atom/common/api/atom_api_native_image.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 5859247574e9..b68ddda592c6 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -231,10 +231,17 @@ HICON NativeImage::GetHICON(int size) { #endif v8::Local NativeImage::ToPNG(v8::Isolate* isolate) { - scoped_refptr png = image_.As1xPNGBytes(); - return node::Buffer::Copy(isolate, - reinterpret_cast(png->front()), - static_cast(png->size())).ToLocalChecked(); + if (HasRepresentation(1.0)) { + scoped_refptr png = image_.As1xPNGBytes(); + 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::ToBitmap(v8::Isolate* isolate) { From e4ead6d0189938023b1c6a77f4aa76a8d98e6c9c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 14:55:57 -0800 Subject: [PATCH 08/12] Remove hasRepresentation and just use 1x png result --- atom/common/api/atom_api_native_image.cc | 16 +++++----------- atom/common/api/atom_api_native_image.h | 1 - spec/api-native-image-spec.js | 7 ------- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index b68ddda592c6..7437090111a1 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -231,8 +231,8 @@ HICON NativeImage::GetHICON(int size) { #endif v8::Local NativeImage::ToPNG(v8::Isolate* isolate) { - if (HasRepresentation(1.0)) { - scoped_refptr png = image_.As1xPNGBytes(); + 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(); @@ -264,12 +264,11 @@ v8::Local NativeImage::ToJPEG(v8::Isolate* isolate, int quality) { } std::string NativeImage::ToDataURL() { - if (HasRepresentation(1.0)) { - scoped_refptr png = image_.As1xPNGBytes(); + scoped_refptr png = image_.As1xPNGBytes(); + if (IsEmpty() || png->size() > 0) return webui::GetPngDataUrl(png->front(), png->size()); - } else { + else return webui::GetBitmapDataUrl(image_.AsBitmap()); - } } v8::Local NativeImage::GetBitmap(v8::Isolate* isolate) { @@ -304,10 +303,6 @@ bool NativeImage::IsEmpty() { return image_.IsEmpty(); } -bool NativeImage::HasRepresentation(float scale_factor) { - return image_.AsImageSkia().HasRepresentation(scale_factor); -} - gfx::Size NativeImage::GetSize() { return image_.Size(); } @@ -479,7 +474,6 @@ void NativeImage::BuildPrototype( .SetMethod("resize", &NativeImage::Resize) .SetMethod("crop", &NativeImage::Crop) .SetMethod("getAspectRatio", &NativeImage::GetAspectRatio) - .SetMethod("hasRepresentation", &NativeImage::HasRepresentation) // TODO(kevinsawicki): Remove in 2.0, deprecate before then with warnings .SetMethod("toPng", &NativeImage::ToPNG) .SetMethod("toJpeg", &NativeImage::ToJPEG); diff --git a/atom/common/api/atom_api_native_image.h b/atom/common/api/atom_api_native_image.h index a653f15e0a71..ee1b5f5d4b81 100644 --- a/atom/common/api/atom_api_native_image.h +++ b/atom/common/api/atom_api_native_image.h @@ -83,7 +83,6 @@ class NativeImage : public mate::Wrappable { const gfx::Rect& rect); std::string ToDataURL(); bool IsEmpty(); - bool HasRepresentation(float scale_factor); gfx::Size GetSize(); float GetAspectRatio(); diff --git a/spec/api-native-image-spec.js b/spec/api-native-image-spec.js index fd6aee9f1eab..7e32fef56123 100644 --- a/spec/api-native-image-spec.js +++ b/spec/api-native-image-spec.js @@ -9,7 +9,6 @@ describe('nativeImage module', () => { it('returns an empty image', () => { const empty = nativeImage.createEmpty() assert.equal(empty.isEmpty(), true) - assert.equal(empty.hasRepresentation(1.0), false) assert.equal(empty.getAspectRatio(), 1) assert.equal(empty.toDataURL(), 'data:image/png;base64,') assert.deepEqual(empty.getSize(), {width: 0, height: 0}) @@ -94,12 +93,9 @@ describe('nativeImage module', () => { scaleFactor: 2.0 }) assert.deepEqual(imageB.getSize(), {width: 269, height: 95}) - assert.equal(imageB.hasRepresentation(1.0), false) - assert.equal(imageB.hasRepresentation(2.0), true) const imageC = nativeImage.createFromDataURL(imageB.toDataURL()) assert.deepEqual(imageC.getSize(), {width: 538, height: 190}) - assert.equal(imageC.hasRepresentation(1.0), false) assert(imageB.toBitmap().equals(imageC.toBitmap())) }) }) @@ -113,12 +109,9 @@ describe('nativeImage module', () => { scaleFactor: 2.0 }) assert.deepEqual(imageB.getSize(), {width: 269, height: 95}) - assert.equal(imageB.hasRepresentation(1.0), false) - assert.equal(imageB.hasRepresentation(2.0), true) const imageC = nativeImage.createFromBuffer(imageB.toPNG()) assert.deepEqual(imageC.getSize(), {width: 538, height: 190}) - assert.equal(imageC.hasRepresentation(1.0), true) assert(imageB.toBitmap().equals(imageC.toBitmap())) }) }) From 82a81bb26e4c6a83734c87fbbae0ded584e09eae Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 16:19:16 -0800 Subject: [PATCH 09/12] 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 7437090111a1..e63fff3a0c9c 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 ee1b5f5d4b81..a6614a81b0ec 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 7e32fef56123..f8a5708edc5f 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()', () => { From 6d5fbe6be23ea6889be2c9bd14ce7a23c8660776 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 16:22:48 -0800 Subject: [PATCH 10/12] Document scale factor option --- docs/api/native-image.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/api/native-image.md b/docs/api/native-image.md index cc910cbb8a98..0350f13bc902 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -165,7 +165,10 @@ Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer The following methods are available on instances of the `NativeImage` class: -#### `image.toPNG()` +#### `image.toPNG([options])` + +* `options` Object (optional) + * `scaleFactor` Double (optional) - Defaults to 1.0. Returns `Buffer` - A [Buffer][buffer] that contains the image's `PNG` encoded data. @@ -175,16 +178,25 @@ Returns `Buffer` - A [Buffer][buffer] that contains the image's `PNG` encoded da Returns `Buffer` - A [Buffer][buffer] that contains the image's `JPEG` encoded data. -#### `image.toBitmap()` +#### `image.toBitmap([options])` + +* `options` Object (optional) + * `scaleFactor` Double (optional) - Defaults to 1.0. Returns `Buffer` - A [Buffer][buffer] that contains a copy of the image's raw bitmap pixel data. -#### `image.toDataURL()` +#### `image.toDataURL([options])` + +* `options` Object (optional) + * `scaleFactor` Double (optional) - Defaults to 1.0. Returns `String` - The data URL of the image. -#### `image.getBitmap()` +#### `image.getBitmap([options])` + +* `options` Object (optional) + * `scaleFactor` Double (optional) - Defaults to 1.0. Returns `Buffer` - A [Buffer][buffer] that contains the image's raw bitmap pixel data. From 8852b128ece9183317857c016631af7de27ac031 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Mar 2017 16:29:39 -0800 Subject: [PATCH 11/12] Add GetScaleFactorFromOptions helper --- atom/common/api/atom_api_native_image.cc | 29 +++++++++++------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index e63fff3a0c9c..98eac6b2ff68 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -76,6 +76,15 @@ float GetScaleFactorFromPath(const base::FilePath& path) { return 1.0f; } +// Get the scale factor from options object at the first argument +float GetScaleFactorFromOptions(mate::Arguments* args) { + float scale_factor = 1.0f; + mate::Dictionary options; + if (args->GetNext(&options)) + options.Get("scaleFactor", &scale_factor); + return scale_factor; +} + bool AddImageSkiaRep(gfx::ImageSkia* image, const unsigned char* data, size_t size, @@ -231,10 +240,7 @@ HICON NativeImage::GetHICON(int size) { #endif v8::Local NativeImage::ToPNG(mate::Arguments* args) { - float scale_factor = 1.0f; - mate::Dictionary options; - if (args->GetNext(&options)) - options.Get("scaleFactor", &scale_factor); + float scale_factor = GetScaleFactorFromOptions(args); if (scale_factor == 1.0f) { // Use raw 1x PNG bytes when available @@ -257,10 +263,7 @@ v8::Local NativeImage::ToPNG(mate::Arguments* args) { } v8::Local NativeImage::ToBitmap(mate::Arguments* args) { - float scale_factor = 1.0f; - mate::Dictionary options; - if (args->GetNext(&options)) - options.Get("scaleFactor", &scale_factor); + float scale_factor = GetScaleFactorFromOptions(args); const SkBitmap bitmap = image_.AsImageSkia().GetRepresentation(scale_factor).sk_bitmap(); @@ -282,10 +285,7 @@ v8::Local NativeImage::ToJPEG(v8::Isolate* isolate, int quality) { } std::string NativeImage::ToDataURL(mate::Arguments* args) { - float scale_factor = 1.0f; - mate::Dictionary options; - if (args->GetNext(&options)) - options.Get("scaleFactor", &scale_factor); + float scale_factor = GetScaleFactorFromOptions(args); if (scale_factor == 1.0f) { // Use raw 1x PNG bytes when available @@ -299,10 +299,7 @@ std::string NativeImage::ToDataURL(mate::Arguments* args) { } v8::Local NativeImage::GetBitmap(mate::Arguments* args) { - float scale_factor = 1.0f; - mate::Dictionary options; - if (args->GetNext(&options)) - options.Get("scaleFactor", &scale_factor); + float scale_factor = GetScaleFactorFromOptions(args); const SkBitmap bitmap = image_.AsImageSkia().GetRepresentation(scale_factor).sk_bitmap(); From 31cae8e1aaa2cf54c5c79c561d0be408890661af Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Mar 2017 12:34:31 -0800 Subject: [PATCH 12/12] Add more scale factor specs --- spec/api-native-image-spec.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/spec/api-native-image-spec.js b/spec/api-native-image-spec.js index f8a5708edc5f..22fe187b2d74 100644 --- a/spec/api-native-image-spec.js +++ b/spec/api-native-image-spec.js @@ -87,9 +87,10 @@ describe('nativeImage module', () => { it('returns a PNG data URL', () => { const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', '1x1.png')) assert.equal(imageA.toDataURL(), 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYlWNgAAIAAAUAAdafFs0AAAAASUVORK5CYII=') + assert.equal(imageA.toDataURL({scaleFactor: 2.0}), 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYlWNgAAIAAAUAAdafFs0AAAAASUVORK5CYII=') }) - it('returns a data URL at 1x scale factor', () => { + it('returns a data URL at 1x scale factor by default', () => { const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')) const imageB = nativeImage.createFromBuffer(imageA.toPNG(), { width: imageA.getSize().width, @@ -113,7 +114,7 @@ describe('nativeImage module', () => { }) describe('toPNG()', () => { - it('returns a buffer at 1x scale factor', () => { + it('returns a buffer at 1x scale factor by default', () => { const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')) const imageB = nativeImage.createFromBuffer(imageA.toPNG(), { width: imageA.getSize().width, @@ -126,6 +127,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.createFromBuffer(imageA.toPNG({scaleFactor: 1.0})) + assert.deepEqual(imageB.getSize(), {width: 538, height: 190}) + const imageC = nativeImage.createFromBuffer(imageA.toPNG({scaleFactor: 2.0}), {scaleFactor: 2.0}) + assert.deepEqual(imageC.getSize(), {width: 269, height: 95}) + }) }) describe('createFromPath(path)', () => {