electron_api_native_image.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. // Copyright (c) 2015 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/common/api/electron_api_native_image.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/files/file_util.h"
  10. #include "base/logging.h"
  11. #include "base/memory/ref_counted_memory.h"
  12. #include "base/strings/pattern.h"
  13. #include "base/strings/utf_string_conversions.h"
  14. #include "gin/arguments.h"
  15. #include "gin/handle.h"
  16. #include "gin/object_template_builder.h"
  17. #include "gin/per_isolate_data.h"
  18. #include "net/base/data_url.h"
  19. #include "shell/browser/browser.h"
  20. #include "shell/common/asar/asar_util.h"
  21. #include "shell/common/gin_converters/file_path_converter.h"
  22. #include "shell/common/gin_converters/gfx_converter.h"
  23. #include "shell/common/gin_converters/gurl_converter.h"
  24. #include "shell/common/gin_converters/value_converter.h"
  25. #include "shell/common/gin_helper/dictionary.h"
  26. #include "shell/common/gin_helper/error_thrower.h"
  27. #include "shell/common/gin_helper/function_template_extensions.h"
  28. #include "shell/common/gin_helper/object_template_builder.h"
  29. #include "shell/common/node_includes.h"
  30. #include "shell/common/node_util.h"
  31. #include "shell/common/process_util.h"
  32. #include "shell/common/skia_util.h"
  33. #include "shell/common/thread_restrictions.h"
  34. #include "third_party/skia/include/core/SkBitmap.h"
  35. #include "third_party/skia/include/core/SkImageInfo.h"
  36. #include "third_party/skia/include/core/SkPixelRef.h"
  37. #include "ui/base/layout.h"
  38. #include "ui/base/resource/resource_scale_factor.h"
  39. #include "ui/base/webui/web_ui_util.h"
  40. #include "ui/gfx/codec/jpeg_codec.h"
  41. #include "ui/gfx/codec/png_codec.h"
  42. #include "ui/gfx/geometry/size.h"
  43. #include "ui/gfx/image/image_skia.h"
  44. #include "ui/gfx/image/image_skia_operations.h"
  45. #include "ui/gfx/image/image_util.h"
  46. #if BUILDFLAG(IS_WIN)
  47. #include "base/win/scoped_gdi_object.h"
  48. #include "shell/common/asar/archive.h"
  49. #include "ui/gfx/icon_util.h"
  50. #endif
  51. namespace electron::api {
  52. namespace {
  53. // This is needed to avoid a hard CHECK when certain aspects of
  54. // ImageSkia are invoked before the browser process is ready,
  55. // since supported scales are normally set by
  56. // ui::ResourceBundle::InitSharedInstance during browser process startup.
  57. void EnsureSupportedScaleFactors() {
  58. if (!electron::IsBrowserProcess())
  59. return;
  60. if (!Browser::Get()->is_ready())
  61. ui::SetSupportedResourceScaleFactors({ui::k100Percent});
  62. }
  63. // Get the scale factor from options object at the first argument
  64. float GetScaleFactorFromOptions(gin::Arguments* args) {
  65. float scale_factor = 1.0f;
  66. gin_helper::Dictionary options;
  67. if (args->GetNext(&options))
  68. options.Get("scaleFactor", &scale_factor);
  69. return scale_factor;
  70. }
  71. base::FilePath NormalizePath(const base::FilePath& path) {
  72. if (!path.ReferencesParent()) {
  73. return path;
  74. }
  75. ScopedAllowBlockingForElectron allow_blocking;
  76. base::FilePath absolute_path = MakeAbsoluteFilePath(path);
  77. // MakeAbsoluteFilePath returns an empty path on failures so use original path
  78. if (absolute_path.empty()) {
  79. return path;
  80. } else {
  81. return absolute_path;
  82. }
  83. }
  84. #if BUILDFLAG(IS_MAC)
  85. bool IsTemplateFilename(const base::FilePath& path) {
  86. return (base::MatchPattern(path.value(), "*Template.*") ||
  87. base::MatchPattern(path.value(), "*Template@*x.*"));
  88. }
  89. #endif
  90. #if BUILDFLAG(IS_WIN)
  91. base::win::ScopedHICON ReadICOFromPath(int size, const base::FilePath& path) {
  92. // If file is in asar archive, we extract it to a temp file so LoadImage can
  93. // load it.
  94. base::FilePath asar_path, relative_path;
  95. base::FilePath image_path(path);
  96. if (asar::GetAsarArchivePath(image_path, &asar_path, &relative_path)) {
  97. std::shared_ptr<asar::Archive> archive =
  98. asar::GetOrCreateAsarArchive(asar_path);
  99. if (archive)
  100. archive->CopyFileOut(relative_path, &image_path);
  101. }
  102. // Load the icon from file.
  103. return base::win::ScopedHICON(
  104. static_cast<HICON>(LoadImage(nullptr, image_path.value().c_str(),
  105. IMAGE_ICON, size, size, LR_LOADFROMFILE)));
  106. }
  107. #endif
  108. } // namespace
  109. NativeImage::NativeImage(v8::Isolate* isolate, const gfx::Image& image)
  110. : image_(image), isolate_(isolate) {
  111. EnsureSupportedScaleFactors();
  112. UpdateExternalAllocatedMemoryUsage();
  113. }
  114. #if BUILDFLAG(IS_WIN)
  115. NativeImage::NativeImage(v8::Isolate* isolate, const base::FilePath& hicon_path)
  116. : hicon_path_(hicon_path), isolate_(isolate) {
  117. EnsureSupportedScaleFactors();
  118. // Use the 256x256 icon as fallback icon.
  119. gfx::ImageSkia image_skia;
  120. electron::util::ReadImageSkiaFromICO(&image_skia, GetHICON(256));
  121. image_ = gfx::Image(image_skia);
  122. UpdateExternalAllocatedMemoryUsage();
  123. }
  124. #endif
  125. NativeImage::~NativeImage() {
  126. isolate_->AdjustAmountOfExternalAllocatedMemory(-memory_usage_);
  127. }
  128. void NativeImage::UpdateExternalAllocatedMemoryUsage() {
  129. int32_t new_memory_usage = 0;
  130. if (image_.HasRepresentation(gfx::Image::kImageRepSkia)) {
  131. auto* const image_skia = image_.ToImageSkia();
  132. if (!image_skia->isNull()) {
  133. new_memory_usage = image_skia->bitmap()->computeByteSize();
  134. }
  135. }
  136. isolate_->AdjustAmountOfExternalAllocatedMemory(new_memory_usage -
  137. memory_usage_);
  138. memory_usage_ = new_memory_usage;
  139. }
  140. // static
  141. bool NativeImage::TryConvertNativeImage(v8::Isolate* isolate,
  142. v8::Local<v8::Value> image,
  143. NativeImage** native_image,
  144. OnConvertError on_error) {
  145. std::string error_message;
  146. base::FilePath icon_path;
  147. if (gin::ConvertFromV8(isolate, image, &icon_path)) {
  148. *native_image = NativeImage::CreateFromPath(isolate, icon_path).get();
  149. if ((*native_image)->image().IsEmpty()) {
  150. #if BUILDFLAG(IS_WIN)
  151. const auto img_path = base::WideToUTF8(icon_path.value());
  152. #else
  153. const auto img_path = icon_path.value();
  154. #endif
  155. error_message = "Failed to load image from path '" + img_path + "'";
  156. }
  157. } else {
  158. if (!gin::ConvertFromV8(isolate, image, native_image)) {
  159. error_message = "Argument must be a file path or a NativeImage";
  160. }
  161. }
  162. if (!error_message.empty()) {
  163. switch (on_error) {
  164. case OnConvertError::kThrow:
  165. isolate->ThrowException(
  166. v8::Exception::Error(gin::StringToV8(isolate, error_message)));
  167. break;
  168. case OnConvertError::kWarn:
  169. LOG(WARNING) << error_message;
  170. break;
  171. }
  172. return false;
  173. }
  174. return true;
  175. }
  176. #if BUILDFLAG(IS_WIN)
  177. HICON NativeImage::GetHICON(int size) {
  178. if (auto iter = hicons_.find(size); iter != hicons_.end())
  179. return iter->second.get();
  180. // First try loading the icon with specified size.
  181. if (!hicon_path_.empty()) {
  182. auto& hicon = hicons_[size];
  183. hicon = ReadICOFromPath(size, hicon_path_);
  184. return hicon.get();
  185. }
  186. // Then convert the image to ICO.
  187. if (image_.IsEmpty())
  188. return nullptr;
  189. auto& hicon = hicons_[size];
  190. hicon = IconUtil::CreateHICONFromSkBitmap(image_.AsBitmap());
  191. return hicon.get();
  192. }
  193. #endif
  194. v8::Local<v8::Value> NativeImage::ToPNG(gin::Arguments* args) {
  195. float scale_factor = GetScaleFactorFromOptions(args);
  196. if (scale_factor == 1.0f) {
  197. // Use raw 1x PNG bytes when available
  198. scoped_refptr<base::RefCountedMemory> png = image_.As1xPNGBytes();
  199. if (png->size() > 0) {
  200. const char* data = reinterpret_cast<const char*>(png->front());
  201. size_t size = png->size();
  202. return node::Buffer::Copy(args->isolate(), data, size).ToLocalChecked();
  203. }
  204. }
  205. const SkBitmap bitmap =
  206. image_.AsImageSkia().GetRepresentation(scale_factor).GetBitmap();
  207. std::optional<std::vector<uint8_t>> encoded =
  208. gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false);
  209. if (!encoded.has_value())
  210. return node::Buffer::New(args->isolate(), 0).ToLocalChecked();
  211. const char* data = reinterpret_cast<char*>(encoded->data());
  212. size_t size = encoded->size();
  213. return node::Buffer::Copy(args->isolate(), data, size).ToLocalChecked();
  214. }
  215. v8::Local<v8::Value> NativeImage::ToBitmap(gin::Arguments* args) {
  216. float scale_factor = GetScaleFactorFromOptions(args);
  217. const SkBitmap bitmap =
  218. image_.AsImageSkia().GetRepresentation(scale_factor).GetBitmap();
  219. SkImageInfo info =
  220. SkImageInfo::MakeN32Premul(bitmap.width(), bitmap.height());
  221. auto array_buffer =
  222. v8::ArrayBuffer::New(args->isolate(), info.computeMinByteSize());
  223. if (bitmap.readPixels(info, array_buffer->Data(), info.minRowBytes(), 0, 0)) {
  224. return node::Buffer::New(args->isolate(), array_buffer, 0,
  225. info.computeMinByteSize())
  226. .ToLocalChecked();
  227. }
  228. return node::Buffer::New(args->isolate(), 0).ToLocalChecked();
  229. }
  230. v8::Local<v8::Value> NativeImage::ToJPEG(v8::Isolate* isolate, int quality) {
  231. std::optional<std::vector<uint8_t>> encoded_image =
  232. gfx::JPEG1xEncodedDataFromImage(image_, quality);
  233. if (!encoded_image.has_value())
  234. return node::Buffer::New(isolate, 0).ToLocalChecked();
  235. return node::Buffer::Copy(
  236. isolate, reinterpret_cast<const char*>(&encoded_image->front()),
  237. encoded_image->size())
  238. .ToLocalChecked();
  239. }
  240. std::string NativeImage::ToDataURL(gin::Arguments* args) {
  241. float scale_factor = GetScaleFactorFromOptions(args);
  242. return webui::GetBitmapDataUrl(
  243. image_.AsImageSkia().GetRepresentation(scale_factor).GetBitmap());
  244. }
  245. v8::Local<v8::Value> NativeImage::GetBitmap(gin::Arguments* args) {
  246. float scale_factor = GetScaleFactorFromOptions(args);
  247. const SkBitmap bitmap =
  248. image_.AsImageSkia().GetRepresentation(scale_factor).GetBitmap();
  249. SkPixelRef* ref = bitmap.pixelRef();
  250. if (!ref)
  251. return node::Buffer::New(args->isolate(), 0).ToLocalChecked();
  252. return node::Buffer::Copy(args->isolate(),
  253. reinterpret_cast<char*>(ref->pixels()),
  254. bitmap.computeByteSize())
  255. .ToLocalChecked();
  256. }
  257. v8::Local<v8::Value> NativeImage::GetNativeHandle(
  258. gin_helper::ErrorThrower thrower) {
  259. #if BUILDFLAG(IS_MAC)
  260. if (IsEmpty())
  261. return node::Buffer::New(thrower.isolate(), 0).ToLocalChecked();
  262. NSImage* ptr = image_.AsNSImage();
  263. return node::Buffer::Copy(thrower.isolate(), reinterpret_cast<char*>(ptr),
  264. sizeof(void*))
  265. .ToLocalChecked();
  266. #else
  267. thrower.ThrowError("Not implemented");
  268. return v8::Undefined(thrower.isolate());
  269. #endif
  270. }
  271. bool NativeImage::IsEmpty() {
  272. return image_.IsEmpty();
  273. }
  274. gfx::Size NativeImage::GetSize(const std::optional<float> scale_factor) {
  275. float sf = scale_factor.value_or(1.0f);
  276. gfx::ImageSkiaRep image_rep = image_.AsImageSkia().GetRepresentation(sf);
  277. return gfx::Size(image_rep.GetWidth(), image_rep.GetHeight());
  278. }
  279. std::vector<float> NativeImage::GetScaleFactors() {
  280. gfx::ImageSkia image_skia = image_.AsImageSkia();
  281. std::vector<float> scale_factors;
  282. for (const auto& rep : image_skia.image_reps()) {
  283. scale_factors.push_back(rep.scale());
  284. }
  285. return scale_factors;
  286. }
  287. float NativeImage::GetAspectRatio(const std::optional<float> scale_factor) {
  288. float sf = scale_factor.value_or(1.0f);
  289. gfx::Size size = GetSize(sf);
  290. if (size.IsEmpty())
  291. return 1.f;
  292. else
  293. return static_cast<float>(size.width()) / static_cast<float>(size.height());
  294. }
  295. gin::Handle<NativeImage> NativeImage::Resize(gin::Arguments* args,
  296. base::Value::Dict options) {
  297. float scale_factor = GetScaleFactorFromOptions(args);
  298. gfx::Size size = GetSize(scale_factor);
  299. std::optional<int> new_width = options.FindInt("width");
  300. std::optional<int> new_height = options.FindInt("height");
  301. int width = new_width.value_or(size.width());
  302. int height = new_height.value_or(size.height());
  303. size.SetSize(width, height);
  304. if (width <= 0 && height <= 0) {
  305. return CreateEmpty(args->isolate());
  306. } else if (new_width && !new_height) {
  307. // Scale height to preserve original aspect ratio
  308. size.set_height(width);
  309. size =
  310. gfx::ScaleToRoundedSize(size, 1.f, 1.f / GetAspectRatio(scale_factor));
  311. } else if (new_height && !new_width) {
  312. // Scale width to preserve original aspect ratio
  313. size.set_width(height);
  314. size = gfx::ScaleToRoundedSize(size, GetAspectRatio(scale_factor), 1.f);
  315. }
  316. skia::ImageOperations::ResizeMethod method =
  317. skia::ImageOperations::ResizeMethod::RESIZE_BEST;
  318. std::string* quality = options.FindString("quality");
  319. if (quality && *quality == "good")
  320. method = skia::ImageOperations::ResizeMethod::RESIZE_GOOD;
  321. else if (quality && *quality == "better")
  322. method = skia::ImageOperations::ResizeMethod::RESIZE_BETTER;
  323. return Create(args->isolate(),
  324. gfx::Image{gfx::ImageSkiaOperations::CreateResizedImage(
  325. image_.AsImageSkia(), method, size)});
  326. }
  327. gin::Handle<NativeImage> NativeImage::Crop(v8::Isolate* isolate,
  328. const gfx::Rect& rect) {
  329. return Create(isolate, gfx::Image{gfx::ImageSkiaOperations::ExtractSubset(
  330. image_.AsImageSkia(), rect)});
  331. }
  332. void NativeImage::AddRepresentation(const gin_helper::Dictionary& options) {
  333. int width = 0;
  334. int height = 0;
  335. float scale_factor = 1.0f;
  336. options.Get("width", &width);
  337. options.Get("height", &height);
  338. options.Get("scaleFactor", &scale_factor);
  339. bool skia_rep_added = false;
  340. gfx::ImageSkia image_skia = image_.AsImageSkia();
  341. v8::Local<v8::Value> buffer;
  342. GURL url;
  343. if (options.Get("buffer", &buffer) && node::Buffer::HasInstance(buffer)) {
  344. skia_rep_added = electron::util::AddImageSkiaRepFromBuffer(
  345. &image_skia, electron::util::as_byte_span(buffer), width, height,
  346. scale_factor);
  347. } else if (options.Get("dataURL", &url)) {
  348. std::string mime_type, charset, data;
  349. if (net::DataURL::Parse(url, &mime_type, &charset, &data)) {
  350. if (mime_type == "image/png") {
  351. skia_rep_added = electron::util::AddImageSkiaRepFromPNG(
  352. &image_skia, base::as_byte_span(data), scale_factor);
  353. } else if (mime_type == "image/jpeg") {
  354. skia_rep_added = electron::util::AddImageSkiaRepFromJPEG(
  355. &image_skia, base::as_byte_span(data), scale_factor);
  356. }
  357. }
  358. }
  359. // Re-initialize image when first representation is added to an empty image
  360. if (skia_rep_added && IsEmpty()) {
  361. gfx::Image image(image_skia);
  362. image_ = std::move(image);
  363. }
  364. }
  365. #if !BUILDFLAG(IS_MAC)
  366. void NativeImage::SetTemplateImage(bool setAsTemplate) {}
  367. bool NativeImage::IsTemplateImage() {
  368. return false;
  369. }
  370. #endif
  371. // static
  372. gin::Handle<NativeImage> NativeImage::CreateEmpty(v8::Isolate* isolate) {
  373. return Create(isolate, gfx::Image{});
  374. }
  375. // static
  376. gin::Handle<NativeImage> NativeImage::Create(v8::Isolate* isolate,
  377. const gfx::Image& image) {
  378. return gin::CreateHandle(isolate, new NativeImage(isolate, image));
  379. }
  380. // static
  381. gin::Handle<NativeImage> NativeImage::CreateFromPNG(
  382. v8::Isolate* isolate,
  383. const base::span<const uint8_t> data) {
  384. gfx::ImageSkia image_skia;
  385. electron::util::AddImageSkiaRepFromPNG(&image_skia, data, 1.0);
  386. return Create(isolate, gfx::Image(image_skia));
  387. }
  388. // static
  389. gin::Handle<NativeImage> NativeImage::CreateFromJPEG(
  390. v8::Isolate* isolate,
  391. const base::span<const uint8_t> buffer) {
  392. gfx::ImageSkia image_skia;
  393. electron::util::AddImageSkiaRepFromJPEG(&image_skia, buffer, 1.0);
  394. return Create(isolate, gfx::Image(image_skia));
  395. }
  396. // static
  397. gin::Handle<NativeImage> NativeImage::CreateFromPath(
  398. v8::Isolate* isolate,
  399. const base::FilePath& path) {
  400. base::FilePath image_path = NormalizePath(path);
  401. #if BUILDFLAG(IS_WIN)
  402. if (image_path.MatchesExtension(FILE_PATH_LITERAL(".ico"))) {
  403. return gin::CreateHandle(isolate, new NativeImage(isolate, image_path));
  404. }
  405. #endif
  406. gfx::ImageSkia image_skia;
  407. electron::util::PopulateImageSkiaRepsFromPath(&image_skia, image_path);
  408. gfx::Image image(image_skia);
  409. gin::Handle<NativeImage> handle = Create(isolate, image);
  410. #if BUILDFLAG(IS_MAC)
  411. if (IsTemplateFilename(image_path))
  412. handle->SetTemplateImage(true);
  413. #endif
  414. return handle;
  415. }
  416. // static
  417. gin::Handle<NativeImage> NativeImage::CreateFromBitmap(
  418. gin_helper::ErrorThrower thrower,
  419. v8::Local<v8::Value> buffer,
  420. const gin_helper::Dictionary& options) {
  421. if (!node::Buffer::HasInstance(buffer)) {
  422. thrower.ThrowError("buffer must be a node Buffer");
  423. return gin::Handle<NativeImage>();
  424. }
  425. unsigned int width = 0;
  426. unsigned int height = 0;
  427. double scale_factor = 1.;
  428. if (!options.Get("width", &width)) {
  429. thrower.ThrowError("width is required");
  430. return gin::Handle<NativeImage>();
  431. }
  432. if (!options.Get("height", &height)) {
  433. thrower.ThrowError("height is required");
  434. return gin::Handle<NativeImage>();
  435. }
  436. auto info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType);
  437. auto size_bytes = info.computeMinByteSize();
  438. const auto buffer_data = electron::util::as_byte_span(buffer);
  439. if (size_bytes != buffer_data.size()) {
  440. thrower.ThrowError("invalid buffer size");
  441. return gin::Handle<NativeImage>();
  442. }
  443. options.Get("scaleFactor", &scale_factor);
  444. if (width == 0 || height == 0) {
  445. return CreateEmpty(thrower.isolate());
  446. }
  447. SkBitmap bitmap;
  448. bitmap.allocN32Pixels(width, height, false);
  449. bitmap.writePixels({info, buffer_data.data(), bitmap.rowBytes()});
  450. gfx::ImageSkia image_skia =
  451. gfx::ImageSkia::CreateFromBitmap(bitmap, scale_factor);
  452. return Create(thrower.isolate(), gfx::Image(image_skia));
  453. }
  454. // static
  455. gin::Handle<NativeImage> NativeImage::CreateFromBuffer(
  456. gin_helper::ErrorThrower thrower,
  457. v8::Local<v8::Value> buffer,
  458. gin::Arguments* args) {
  459. if (!node::Buffer::HasInstance(buffer)) {
  460. thrower.ThrowError("buffer must be a node Buffer");
  461. return gin::Handle<NativeImage>();
  462. }
  463. int width = 0;
  464. int height = 0;
  465. double scale_factor = 1.;
  466. gin_helper::Dictionary options;
  467. if (args->GetNext(&options)) {
  468. options.Get("width", &width);
  469. options.Get("height", &height);
  470. options.Get("scaleFactor", &scale_factor);
  471. }
  472. gfx::ImageSkia image_skia;
  473. electron::util::AddImageSkiaRepFromBuffer(
  474. &image_skia, electron::util::as_byte_span(buffer), width, height,
  475. scale_factor);
  476. return Create(args->isolate(), gfx::Image(image_skia));
  477. }
  478. // static
  479. gin::Handle<NativeImage> NativeImage::CreateFromDataURL(v8::Isolate* isolate,
  480. const GURL& url) {
  481. std::string mime_type, charset, data;
  482. if (net::DataURL::Parse(url, &mime_type, &charset, &data)) {
  483. if (mime_type == "image/png")
  484. return CreateFromPNG(isolate, base::as_byte_span(data));
  485. if (mime_type == "image/jpeg")
  486. return CreateFromJPEG(isolate, base::as_byte_span(data));
  487. }
  488. return CreateEmpty(isolate);
  489. }
  490. #if !BUILDFLAG(IS_MAC)
  491. gin::Handle<NativeImage> NativeImage::CreateFromNamedImage(gin::Arguments* args,
  492. std::string name) {
  493. return CreateEmpty(args->isolate());
  494. }
  495. #endif
  496. // static
  497. gin::ObjectTemplateBuilder NativeImage::GetObjectTemplateBuilder(
  498. v8::Isolate* isolate) {
  499. gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
  500. auto* wrapper_info = &kWrapperInfo;
  501. v8::Local<v8::FunctionTemplate> constructor =
  502. data->GetFunctionTemplate(wrapper_info);
  503. if (constructor.IsEmpty()) {
  504. constructor = v8::FunctionTemplate::New(isolate);
  505. constructor->SetClassName(gin::StringToV8(isolate, GetTypeName()));
  506. data->SetFunctionTemplate(wrapper_info, constructor);
  507. }
  508. return gin::ObjectTemplateBuilder(isolate, GetTypeName(),
  509. constructor->InstanceTemplate())
  510. .SetMethod("toPNG", &NativeImage::ToPNG)
  511. .SetMethod("toJPEG", &NativeImage::ToJPEG)
  512. .SetMethod("toBitmap", &NativeImage::ToBitmap)
  513. .SetMethod("getBitmap", &NativeImage::GetBitmap)
  514. .SetMethod("getScaleFactors", &NativeImage::GetScaleFactors)
  515. .SetMethod("getNativeHandle", &NativeImage::GetNativeHandle)
  516. .SetMethod("toDataURL", &NativeImage::ToDataURL)
  517. .SetMethod("isEmpty", &NativeImage::IsEmpty)
  518. .SetMethod("getSize", &NativeImage::GetSize)
  519. .SetMethod("setTemplateImage", &NativeImage::SetTemplateImage)
  520. .SetMethod("isTemplateImage", &NativeImage::IsTemplateImage)
  521. .SetProperty("isMacTemplateImage", &NativeImage::IsTemplateImage,
  522. &NativeImage::SetTemplateImage)
  523. .SetMethod("resize", &NativeImage::Resize)
  524. .SetMethod("crop", &NativeImage::Crop)
  525. .SetMethod("getAspectRatio", &NativeImage::GetAspectRatio)
  526. .SetMethod("addRepresentation", &NativeImage::AddRepresentation);
  527. }
  528. const char* NativeImage::GetTypeName() {
  529. return "NativeImage";
  530. }
  531. // static
  532. gin::WrapperInfo NativeImage::kWrapperInfo = {gin::kEmbedderNativeGin};
  533. } // namespace electron::api
  534. namespace {
  535. using electron::api::NativeImage;
  536. void Initialize(v8::Local<v8::Object> exports,
  537. v8::Local<v8::Value> unused,
  538. v8::Local<v8::Context> context,
  539. void* priv) {
  540. v8::Isolate* isolate = context->GetIsolate();
  541. gin_helper::Dictionary dict(isolate, exports);
  542. auto native_image = gin_helper::Dictionary::CreateEmpty(isolate);
  543. dict.Set("nativeImage", native_image);
  544. native_image.SetMethod("createEmpty", &NativeImage::CreateEmpty);
  545. native_image.SetMethod("createFromPath", &NativeImage::CreateFromPath);
  546. native_image.SetMethod("createFromBitmap", &NativeImage::CreateFromBitmap);
  547. native_image.SetMethod("createFromBuffer", &NativeImage::CreateFromBuffer);
  548. native_image.SetMethod("createFromDataURL", &NativeImage::CreateFromDataURL);
  549. native_image.SetMethod("createFromNamedImage",
  550. &NativeImage::CreateFromNamedImage);
  551. #if !BUILDFLAG(IS_LINUX)
  552. native_image.SetMethod("createThumbnailFromPath",
  553. &NativeImage::CreateThumbnailFromPath);
  554. #endif
  555. }
  556. } // namespace
  557. NODE_LINKED_BINDING_CONTEXT_AWARE(electron_common_native_image, Initialize)