commit
				
					
						64622ceae3
					
				
			
		
					 20 changed files with 499 additions and 195 deletions
				
			
		
							
								
								
									
										5
									
								
								atom.gyp
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								atom.gyp
									
										
									
									
									
								
							|  | @ -38,6 +38,7 @@ | |||
|       'atom/common/api/lib/clipboard.coffee', | ||||
|       'atom/common/api/lib/crash-reporter.coffee', | ||||
|       'atom/common/api/lib/id-weak-map.coffee', | ||||
|       'atom/common/api/lib/native-image.coffee', | ||||
|       'atom/common/api/lib/original-fs.coffee', | ||||
|       'atom/common/api/lib/shell.coffee', | ||||
|       'atom/common/lib/init.coffee', | ||||
|  | @ -204,6 +205,9 @@ | |||
|       'atom/common/api/atom_api_crash_reporter.cc', | ||||
|       'atom/common/api/atom_api_id_weak_map.cc', | ||||
|       'atom/common/api/atom_api_id_weak_map.h', | ||||
|       'atom/common/api/atom_api_native_image.cc', | ||||
|       'atom/common/api/atom_api_native_image.h', | ||||
|       'atom/common/api/atom_api_native_image_mac.mm', | ||||
|       'atom/common/api/atom_api_shell.cc', | ||||
|       'atom/common/api/atom_api_v8_util.cc', | ||||
|       'atom/common/api/atom_bindings.cc', | ||||
|  | @ -242,7 +246,6 @@ | |||
|       'atom/common/native_mate_converters/gurl_converter.h', | ||||
|       'atom/common/native_mate_converters/image_converter.cc', | ||||
|       'atom/common/native_mate_converters/image_converter.h', | ||||
|       'atom/common/native_mate_converters/image_converter_mac.mm', | ||||
|       'atom/common/native_mate_converters/string16_converter.h', | ||||
|       'atom/common/native_mate_converters/v8_value_converter.cc', | ||||
|       'atom/common/native_mate_converters/v8_value_converter.h', | ||||
|  |  | |||
|  | @ -52,15 +52,11 @@ namespace { | |||
| 
 | ||||
| void OnCapturePageDone( | ||||
|     v8::Isolate* isolate, | ||||
|     const base::Callback<void(v8::Handle<v8::Value>)>& callback, | ||||
|     const base::Callback<void(const gfx::Image&)>& callback, | ||||
|     const std::vector<unsigned char>& data) { | ||||
|   v8::Locker locker(isolate); | ||||
|   v8::HandleScope handle_scope(isolate); | ||||
| 
 | ||||
|   v8::Local<v8::Value> buffer = node::Buffer::New( | ||||
|       reinterpret_cast<const char*>(data.data()), | ||||
|       data.size()); | ||||
|   callback.Run(buffer); | ||||
|   callback.Run(gfx::Image::CreateFrom1xPNGBytes(&data.front(), data.size())); | ||||
| } | ||||
| 
 | ||||
| }  // namespace
 | ||||
|  | @ -374,7 +370,7 @@ bool Window::IsDocumentEdited() { | |||
| 
 | ||||
| void Window::CapturePage(mate::Arguments* args) { | ||||
|   gfx::Rect rect; | ||||
|   base::Callback<void(v8::Handle<v8::Value>)> callback; | ||||
|   base::Callback<void(const gfx::Image&)> callback; | ||||
| 
 | ||||
|   if (!(args->Length() == 1 && args->GetNext(&callback)) && | ||||
|       !(args->Length() == 2 && args->GetNext(&rect) | ||||
|  |  | |||
|  | @ -54,13 +54,11 @@ TrayIconCocoa::~TrayIconCocoa() { | |||
| } | ||||
| 
 | ||||
| void TrayIconCocoa::SetImage(const gfx::Image& image) { | ||||
|   if (!image.IsEmpty()) | ||||
|     [item_ setImage:image.ToNSImage()]; | ||||
|   [item_ setImage:image.AsNSImage()]; | ||||
| } | ||||
| 
 | ||||
| void TrayIconCocoa::SetPressedImage(const gfx::Image& image) { | ||||
|   if (!image.IsEmpty()) | ||||
|     [item_ setAlternateImage:image.ToNSImage()]; | ||||
|   [item_ setAlternateImage:image.AsNSImage()]; | ||||
| } | ||||
| 
 | ||||
| void TrayIconCocoa::SetToolTip(const std::string& tool_tip) { | ||||
|  |  | |||
|  | @ -5,10 +5,13 @@ | |||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "atom/common/native_mate_converters/image_converter.h" | ||||
| #include "atom/common/native_mate_converters/string16_converter.h" | ||||
| #include "native_mate/dictionary.h" | ||||
| #include "third_party/skia/include/core/SkBitmap.h" | ||||
| #include "ui/base/clipboard/clipboard.h" | ||||
| #include "ui/base/clipboard/scoped_clipboard_writer.h" | ||||
| #include "ui/gfx/image/image.h" | ||||
| 
 | ||||
| #include "atom/common/node_includes.h" | ||||
| 
 | ||||
|  | @ -16,8 +19,7 @@ namespace mate { | |||
| 
 | ||||
| template<> | ||||
| struct Converter<ui::ClipboardType> { | ||||
|   static bool FromV8(v8::Isolate* isolate, | ||||
|                      v8::Handle<v8::Value> val, | ||||
|   static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, | ||||
|                      ui::ClipboardType* out) { | ||||
|     std::string type; | ||||
|     if (!Converter<std::string>::FromV8(isolate, val, &type)) | ||||
|  | @ -62,6 +64,11 @@ void WriteText(const base::string16& text, ui::ClipboardType type) { | |||
|   writer.WriteText(text); | ||||
| } | ||||
| 
 | ||||
| gfx::Image ReadImage(ui::ClipboardType type) { | ||||
|   SkBitmap bitmap = ui::Clipboard::GetForCurrentThread()->ReadImage(type); | ||||
|   return gfx::Image::CreateFrom1xBitmap(bitmap); | ||||
| } | ||||
| 
 | ||||
| void Clear(ui::ClipboardType type) { | ||||
|   ui::Clipboard::GetForCurrentThread()->Clear(type); | ||||
| } | ||||
|  | @ -73,6 +80,7 @@ void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused, | |||
|   dict.SetMethod("_read", &Read); | ||||
|   dict.SetMethod("_readText", &ReadText); | ||||
|   dict.SetMethod("_writeText", &WriteText); | ||||
|   dict.SetMethod("_readImage", &ReadImage); | ||||
|   dict.SetMethod("_clear", &Clear); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										266
									
								
								atom/common/api/atom_api_native_image.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								atom/common/api/atom_api_native_image.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,266 @@ | |||
| // Copyright (c) 2015 GitHub, Inc.
 | ||||
| // Use of this source code is governed by the MIT license that can be
 | ||||
| // found in the LICENSE file.
 | ||||
| 
 | ||||
| #include "atom/common/api/atom_api_native_image.h" | ||||
| 
 | ||||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "atom/common/native_mate_converters/file_path_converter.h" | ||||
| #include "atom/common/native_mate_converters/gfx_converter.h" | ||||
| #include "atom/common/native_mate_converters/gurl_converter.h" | ||||
| #include "base/base64.h" | ||||
| #include "base/files/file_util.h" | ||||
| #include "base/strings/string_util.h" | ||||
| #include "native_mate/dictionary.h" | ||||
| #include "native_mate/object_template_builder.h" | ||||
| #include "net/base/data_url.h" | ||||
| #include "ui/base/layout.h" | ||||
| #include "ui/gfx/codec/jpeg_codec.h" | ||||
| #include "ui/gfx/codec/png_codec.h" | ||||
| #include "ui/gfx/geometry/size.h" | ||||
| #include "ui/gfx/image/image_skia.h" | ||||
| #include "ui/gfx/image/image_util.h" | ||||
| 
 | ||||
| #include "atom/common/node_includes.h" | ||||
| 
 | ||||
| namespace atom { | ||||
| 
 | ||||
| namespace api { | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| struct ScaleFactorPair { | ||||
|   const char* name; | ||||
|   float scale; | ||||
| }; | ||||
| 
 | ||||
| ScaleFactorPair kScaleFactorPairs[] = { | ||||
|   // The "@2x" is put as first one to make scale matching faster.
 | ||||
|   { "@2x"    , 2.0f }, | ||||
|   { "@3x"    , 3.0f }, | ||||
|   { "@1x"    , 1.0f }, | ||||
|   { "@4x"    , 4.0f }, | ||||
|   { "@5x"    , 5.0f }, | ||||
|   { "@1.25x" , 1.25f }, | ||||
|   { "@1.33x" , 1.33f }, | ||||
|   { "@1.4x"  , 1.4f }, | ||||
|   { "@1.5x"  , 1.5f }, | ||||
|   { "@1.8x"  , 1.8f }, | ||||
|   { "@2.5x"  , 2.5f }, | ||||
| }; | ||||
| 
 | ||||
| float GetScaleFactorFromPath(const base::FilePath& path) { | ||||
|   std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe()); | ||||
| 
 | ||||
|   // We don't try to convert string to float here because it is very very
 | ||||
|   // expensive.
 | ||||
|   for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i) { | ||||
|     if (EndsWith(filename, kScaleFactorPairs[i].name, true)) | ||||
|       return kScaleFactorPairs[i].scale; | ||||
|   } | ||||
| 
 | ||||
|   return 1.0f; | ||||
| } | ||||
| 
 | ||||
| bool AddImageSkiaRep(gfx::ImageSkia* image, | ||||
|                      const unsigned char* data, | ||||
|                      size_t size, | ||||
|                      double scale_factor) { | ||||
|   scoped_ptr<SkBitmap> decoded(new SkBitmap()); | ||||
| 
 | ||||
|   // Try PNG first.
 | ||||
|   if (!gfx::PNGCodec::Decode(data, size, decoded.get())) | ||||
|     // Try JPEG.
 | ||||
|     decoded.reset(gfx::JPEGCodec::Decode(data, size)); | ||||
| 
 | ||||
|   if (!decoded) | ||||
|     return false; | ||||
| 
 | ||||
|   image->AddRepresentation(gfx::ImageSkiaRep(*decoded.release(), scale_factor)); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool AddImageSkiaRep(gfx::ImageSkia* image, | ||||
|                      const base::FilePath& path, | ||||
|                      double scale_factor) { | ||||
|   std::string file_contents; | ||||
|   if (!base::ReadFileToString(path, &file_contents)) | ||||
|     return false; | ||||
| 
 | ||||
|   const unsigned char* data = | ||||
|       reinterpret_cast<const unsigned char*>(file_contents.data()); | ||||
|   size_t size = file_contents.size(); | ||||
|   return AddImageSkiaRep(image, data, size, scale_factor); | ||||
| } | ||||
| 
 | ||||
| bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image, | ||||
|                                    const base::FilePath& path) { | ||||
|   bool succeed = false; | ||||
|   std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe()); | ||||
|   if (MatchPattern(filename, "*@*x")) | ||||
|     // Don't search for other representations if the DPI has been specified.
 | ||||
|     return AddImageSkiaRep(image, path, GetScaleFactorFromPath(path)); | ||||
|   else | ||||
|     succeed |= AddImageSkiaRep(image, path, 1.0f); | ||||
| 
 | ||||
|   for (const ScaleFactorPair& pair : kScaleFactorPairs) | ||||
|     succeed |= AddImageSkiaRep(image, | ||||
|                                path.InsertBeforeExtensionASCII(pair.name), | ||||
|                                pair.scale); | ||||
|   return succeed; | ||||
| } | ||||
| 
 | ||||
| #if defined(OS_MACOSX) | ||||
| bool IsTemplateImage(const base::FilePath& path) { | ||||
|   return (MatchPattern(path.value(), "*Template.*") || | ||||
|           MatchPattern(path.value(), "*Template@*x.*")); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| v8::Persistent<v8::ObjectTemplate> template_; | ||||
| 
 | ||||
| }  // namespace
 | ||||
| 
 | ||||
| NativeImage::NativeImage() {} | ||||
| 
 | ||||
| NativeImage::NativeImage(const gfx::Image& image) : image_(image) {} | ||||
| 
 | ||||
| NativeImage::~NativeImage() {} | ||||
| 
 | ||||
| mate::ObjectTemplateBuilder NativeImage::GetObjectTemplateBuilder( | ||||
|     v8::Isolate* isolate) { | ||||
|   if (template_.IsEmpty()) | ||||
|     template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate) | ||||
|         .SetMethod("toPng", &NativeImage::ToPNG) | ||||
|         .SetMethod("toJpeg", &NativeImage::ToJPEG) | ||||
|         .SetMethod("toDataUrl", &NativeImage::ToDataURL) | ||||
|         .SetMethod("isEmpty", &NativeImage::IsEmpty) | ||||
|         .SetMethod("getSize", &NativeImage::GetSize) | ||||
|         .Build()); | ||||
| 
 | ||||
|   return mate::ObjectTemplateBuilder( | ||||
|       isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_)); | ||||
| } | ||||
| 
 | ||||
| v8::Handle<v8::Value> NativeImage::ToPNG(v8::Isolate* isolate) { | ||||
|   scoped_refptr<base::RefCountedMemory> png = image_.As1xPNGBytes(); | ||||
|   return node::Buffer::New(isolate, | ||||
|                            reinterpret_cast<const char*>(png->front()), | ||||
|                            png->size()); | ||||
| } | ||||
| 
 | ||||
| v8::Handle<v8::Value> NativeImage::ToJPEG(v8::Isolate* isolate, int quality) { | ||||
|   std::vector<unsigned char> output; | ||||
|   gfx::JPEG1xEncodedDataFromImage(image_, quality, &output); | ||||
|   return node::Buffer::New(isolate, | ||||
|                            reinterpret_cast<const char*>(&output.front()), | ||||
|                            output.size()); | ||||
| } | ||||
| 
 | ||||
| std::string NativeImage::ToDataURL() { | ||||
|   scoped_refptr<base::RefCountedMemory> 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; | ||||
| } | ||||
| 
 | ||||
| bool NativeImage::IsEmpty() { | ||||
|   return image_.IsEmpty(); | ||||
| } | ||||
| 
 | ||||
| gfx::Size NativeImage::GetSize() { | ||||
|   return image_.Size(); | ||||
| } | ||||
| 
 | ||||
| // static
 | ||||
| mate::Handle<NativeImage> NativeImage::CreateEmpty(v8::Isolate* isolate) { | ||||
|   return mate::CreateHandle(isolate, new NativeImage); | ||||
| } | ||||
| 
 | ||||
| // static
 | ||||
| mate::Handle<NativeImage> NativeImage::Create( | ||||
|     v8::Isolate* isolate, const gfx::Image& image) { | ||||
|   return mate::CreateHandle(isolate, new NativeImage(image)); | ||||
| } | ||||
| 
 | ||||
| // static
 | ||||
| mate::Handle<NativeImage> NativeImage::CreateFromPNG( | ||||
|     v8::Isolate* isolate, const char* buffer, size_t length) { | ||||
|   gfx::Image image = gfx::Image::CreateFrom1xPNGBytes( | ||||
|       reinterpret_cast<const unsigned char*>(buffer), length); | ||||
|   return Create(isolate, image); | ||||
| } | ||||
| 
 | ||||
| // static
 | ||||
| mate::Handle<NativeImage> NativeImage::CreateFromJPEG( | ||||
|     v8::Isolate* isolate, const char* buffer, size_t length) { | ||||
|   gfx::Image image = gfx::ImageFrom1xJPEGEncodedData( | ||||
|       reinterpret_cast<const unsigned char*>(buffer), length); | ||||
|   return Create(isolate, image); | ||||
| } | ||||
| 
 | ||||
| // static
 | ||||
| mate::Handle<NativeImage> NativeImage::CreateFromPath( | ||||
|     v8::Isolate* isolate, const base::FilePath& path) { | ||||
|   gfx::ImageSkia image_skia; | ||||
|   PopulateImageSkiaRepsFromPath(&image_skia, path); | ||||
|   gfx::Image image(image_skia); | ||||
| #if defined(OS_MACOSX) | ||||
|   if (IsTemplateImage(path)) | ||||
|     MakeTemplateImage(&image); | ||||
| #endif | ||||
|   return Create(isolate, image); | ||||
| } | ||||
| 
 | ||||
| // static
 | ||||
| mate::Handle<NativeImage> NativeImage::CreateFromBuffer( | ||||
|     mate::Arguments* args, v8::Handle<v8::Value> buffer) { | ||||
|   double scale_factor = 1.; | ||||
|   args->GetNext(&scale_factor); | ||||
| 
 | ||||
|   gfx::ImageSkia image_skia; | ||||
|   AddImageSkiaRep(&image_skia, | ||||
|                   reinterpret_cast<unsigned char*>(node::Buffer::Data(buffer)), | ||||
|                   node::Buffer::Length(buffer), | ||||
|                   scale_factor); | ||||
|   return Create(args->isolate(), gfx::Image(image_skia)); | ||||
| } | ||||
| 
 | ||||
| // static
 | ||||
| mate::Handle<NativeImage> NativeImage::CreateFromDataURL( | ||||
|     v8::Isolate* isolate, const GURL& url) { | ||||
|   std::string mime_type, charset, data; | ||||
|   if (net::DataURL::Parse(url, &mime_type, &charset, &data)) { | ||||
|     if (mime_type == "image/png") | ||||
|       return CreateFromPNG(isolate, data.c_str(), data.size()); | ||||
|     else if (mime_type == "image/jpeg") | ||||
|       return CreateFromJPEG(isolate, data.c_str(), data.size()); | ||||
|   } | ||||
| 
 | ||||
|   return CreateEmpty(isolate); | ||||
| } | ||||
| 
 | ||||
| }  // namespace api
 | ||||
| 
 | ||||
| }  // namespace atom
 | ||||
| 
 | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused, | ||||
|                 v8::Handle<v8::Context> context, void* priv) { | ||||
|   mate::Dictionary dict(context->GetIsolate(), exports); | ||||
|   dict.SetMethod("createEmpty", &atom::api::NativeImage::CreateEmpty); | ||||
|   dict.SetMethod("createFromPath", &atom::api::NativeImage::CreateFromPath); | ||||
|   dict.SetMethod("createFromBuffer", &atom::api::NativeImage::CreateFromBuffer); | ||||
|   dict.SetMethod("createFromDataUrl", | ||||
|                  &atom::api::NativeImage::CreateFromDataURL); | ||||
| } | ||||
| 
 | ||||
| }  // namespace
 | ||||
| 
 | ||||
| NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_native_image, Initialize) | ||||
							
								
								
									
										82
									
								
								atom/common/api/atom_api_native_image.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								atom/common/api/atom_api_native_image.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,82 @@ | |||
| // Copyright (c) 2015 GitHub, Inc.
 | ||||
| // Use of this source code is governed by the MIT license that can be
 | ||||
| // found in the LICENSE file.
 | ||||
| 
 | ||||
| #ifndef ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_ | ||||
| #define ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_ | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| #include "native_mate/handle.h" | ||||
| #include "native_mate/wrappable.h" | ||||
| #include "ui/gfx/image/image.h" | ||||
| 
 | ||||
| class GURL; | ||||
| 
 | ||||
| namespace base { | ||||
| class FilePath; | ||||
| } | ||||
| 
 | ||||
| namespace gfx { | ||||
| class Size; | ||||
| } | ||||
| 
 | ||||
| namespace mate { | ||||
| class Arguments; | ||||
| } | ||||
| 
 | ||||
| namespace atom { | ||||
| 
 | ||||
| namespace api { | ||||
| 
 | ||||
| class NativeImage : public mate::Wrappable { | ||||
|  public: | ||||
|   static mate::Handle<NativeImage> CreateEmpty(v8::Isolate* isolate); | ||||
|   static mate::Handle<NativeImage> Create( | ||||
|       v8::Isolate* isolate, const gfx::Image& image); | ||||
|   static mate::Handle<NativeImage> CreateFromPNG( | ||||
|       v8::Isolate* isolate, const char* buffer, size_t length); | ||||
|   static mate::Handle<NativeImage> CreateFromJPEG( | ||||
|       v8::Isolate* isolate, const char* buffer, size_t length); | ||||
|   static mate::Handle<NativeImage> CreateFromPath( | ||||
|       v8::Isolate* isolate, const base::FilePath& path); | ||||
|   static mate::Handle<NativeImage> CreateFromBuffer( | ||||
|       mate::Arguments* args, v8::Handle<v8::Value> buffer); | ||||
|   static mate::Handle<NativeImage> CreateFromDataURL( | ||||
|       v8::Isolate* isolate, const GURL& url); | ||||
| 
 | ||||
|   // The default constructor should only be used by image_converter.cc.
 | ||||
|   NativeImage(); | ||||
| 
 | ||||
|   const gfx::Image& image() const { return image_; } | ||||
| 
 | ||||
|  protected: | ||||
|   explicit NativeImage(const gfx::Image& image); | ||||
|   virtual ~NativeImage(); | ||||
| 
 | ||||
|   // mate::Wrappable:
 | ||||
|   mate::ObjectTemplateBuilder GetObjectTemplateBuilder( | ||||
|       v8::Isolate* isolate) override; | ||||
| 
 | ||||
|  private: | ||||
| #if defined(OS_MACOSX) | ||||
|   // Mark the image as template image if possible.
 | ||||
|   static void MakeTemplateImage(gfx::Image* image); | ||||
| #endif | ||||
| 
 | ||||
|   v8::Handle<v8::Value> ToPNG(v8::Isolate* isolate); | ||||
|   v8::Handle<v8::Value> ToJPEG(v8::Isolate* isolate, int quality); | ||||
|   std::string ToDataURL(); | ||||
|   bool IsEmpty(); | ||||
|   gfx::Size GetSize(); | ||||
| 
 | ||||
|   gfx::Image image_; | ||||
| 
 | ||||
|   DISALLOW_COPY_AND_ASSIGN(NativeImage); | ||||
| }; | ||||
| 
 | ||||
| }  // namespace api
 | ||||
| 
 | ||||
| }  // namespace atom
 | ||||
| 
 | ||||
| #endif  // ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_
 | ||||
							
								
								
									
										20
									
								
								atom/common/api/atom_api_native_image_mac.mm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								atom/common/api/atom_api_native_image_mac.mm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| // Copyright (c) 2015 GitHub, Inc. | ||||
| // Use of this source code is governed by the MIT license that can be | ||||
| // found in the LICENSE file. | ||||
| 
 | ||||
| #include "atom/common/api/atom_api_native_image.h" | ||||
| 
 | ||||
| #import <Cocoa/Cocoa.h> | ||||
| 
 | ||||
| namespace atom { | ||||
| 
 | ||||
| namespace api { | ||||
| 
 | ||||
| // static | ||||
| void NativeImage::MakeTemplateImage(gfx::Image* image) { | ||||
|   [image->AsNSImage() setTemplate:YES]; | ||||
| } | ||||
| 
 | ||||
| }  // namespace api | ||||
| 
 | ||||
| }  // namespace atom | ||||
|  | @ -9,4 +9,5 @@ else | |||
|     read: (format, type='standard') -> binding._read format, type | ||||
|     readText: (type='standard') -> binding._readText type | ||||
|     writeText: (text, type='standard') -> binding._writeText text, type | ||||
|     readImage: (type='standard') -> binding._readImage type | ||||
|     clear: (type='standard') -> binding._clear type | ||||
|  |  | |||
							
								
								
									
										1
									
								
								atom/common/api/lib/native-image.coffee
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								atom/common/api/lib/native-image.coffee
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| module.exports = process.atomBinding 'native_image' | ||||
|  | @ -4,124 +4,48 @@ | |||
| 
 | ||||
| #include "atom/common/native_mate_converters/image_converter.h" | ||||
| 
 | ||||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "atom/common/api/atom_api_native_image.h" | ||||
| #include "atom/common/native_mate_converters/file_path_converter.h" | ||||
| #include "base/files/file_util.h" | ||||
| #include "base/strings/string_util.h" | ||||
| #include "ui/gfx/codec/jpeg_codec.h" | ||||
| #include "ui/gfx/codec/png_codec.h" | ||||
| #include "ui/gfx/image/image.h" | ||||
| #include "ui/gfx/image/image_skia.h" | ||||
| #include "ui/base/layout.h" | ||||
| 
 | ||||
| #if !defined(OS_MACOSX) | ||||
| 
 | ||||
| namespace mate { | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| struct ScaleFactorPair { | ||||
|   const char* name; | ||||
|   float scale; | ||||
| }; | ||||
| 
 | ||||
| ScaleFactorPair kScaleFactorPairs[] = { | ||||
|   // The "@2x" is put as first one to make scale matching faster.
 | ||||
|   { "@2x"    , 2.0f }, | ||||
|   { "@3x"    , 3.0f }, | ||||
|   { "@1x"    , 1.0f }, | ||||
|   { "@4x"    , 4.0f }, | ||||
|   { "@5x"    , 5.0f }, | ||||
|   { "@1.25x" , 1.25f }, | ||||
|   { "@1.33x" , 1.33f }, | ||||
|   { "@1.4x"  , 1.4f }, | ||||
|   { "@1.5x"  , 1.5f }, | ||||
|   { "@1.8x"  , 1.8f }, | ||||
|   { "@2.5x"  , 2.5f }, | ||||
| }; | ||||
| 
 | ||||
| float GetScaleFactorFromPath(const base::FilePath& path) { | ||||
|   std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe()); | ||||
| 
 | ||||
|   // We don't try to convert string to float here because it is very very
 | ||||
|   // expensive.
 | ||||
|   for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i) { | ||||
|     if (EndsWith(filename, kScaleFactorPairs[i].name, true)) | ||||
|       return kScaleFactorPairs[i].scale; | ||||
|   } | ||||
| 
 | ||||
|   return 1.0f; | ||||
| } | ||||
| 
 | ||||
| bool AddImageSkiaRep(gfx::ImageSkia* image, | ||||
|                      const base::FilePath& path, | ||||
|                      double scale_factor) { | ||||
|   std::string file_contents; | ||||
|   if (!base::ReadFileToString(path, &file_contents)) | ||||
|     return false; | ||||
| 
 | ||||
|   const unsigned char* data = | ||||
|       reinterpret_cast<const unsigned char*>(file_contents.data()); | ||||
|   size_t size = file_contents.size(); | ||||
|   scoped_ptr<SkBitmap> decoded(new SkBitmap()); | ||||
| 
 | ||||
|   // Try PNG first.
 | ||||
|   if (!gfx::PNGCodec::Decode(data, size, decoded.get())) | ||||
|     // Try JPEG.
 | ||||
|     decoded.reset(gfx::JPEGCodec::Decode(data, size)); | ||||
| 
 | ||||
|   if (!decoded) | ||||
|     return false; | ||||
| 
 | ||||
|   image->AddRepresentation(gfx::ImageSkiaRep(*decoded.release(), scale_factor)); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image, | ||||
|                                    const base::FilePath& path) { | ||||
|   bool succeed = false; | ||||
|   std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe()); | ||||
|   if (MatchPattern(filename, "*@*x")) | ||||
|     // Don't search for other representations if the DPI has been specified.
 | ||||
|     return AddImageSkiaRep(image, path, GetScaleFactorFromPath(path)); | ||||
|   else | ||||
|     succeed |= AddImageSkiaRep(image, path, 1.0f); | ||||
| 
 | ||||
|   for (const ScaleFactorPair& pair : kScaleFactorPairs) | ||||
|     succeed |= AddImageSkiaRep(image, | ||||
|                                path.InsertBeforeExtensionASCII(pair.name), | ||||
|                                pair.scale); | ||||
|   return succeed; | ||||
| } | ||||
| 
 | ||||
| }  // namespace
 | ||||
| 
 | ||||
| bool Converter<gfx::ImageSkia>::FromV8(v8::Isolate* isolate, | ||||
|                                        v8::Handle<v8::Value> val, | ||||
|                                        gfx::ImageSkia* out) { | ||||
|   if (val->IsNull()) | ||||
|     return true; | ||||
| 
 | ||||
|   base::FilePath path; | ||||
|   if (!Converter<base::FilePath>::FromV8(isolate, val, &path)) | ||||
|   gfx::Image image; | ||||
|   if (!ConvertFromV8(isolate, val, &image)) | ||||
|     return false; | ||||
| 
 | ||||
|   return PopulateImageSkiaRepsFromPath(out, path); | ||||
|   *out = image.AsImageSkia(); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool Converter<gfx::Image>::FromV8(v8::Isolate* isolate, | ||||
|                                    v8::Handle<v8::Value> val, | ||||
|                                    gfx::Image* out) { | ||||
|   gfx::ImageSkia image; | ||||
|   if (!ConvertFromV8(isolate, val, &image)) | ||||
|   if (val->IsNull()) | ||||
|     return true; | ||||
| 
 | ||||
|   Handle<atom::api::NativeImage> native_image; | ||||
|   if (!ConvertFromV8(isolate, val, &native_image)) { | ||||
|     // Try converting from file path.
 | ||||
|     base::FilePath path; | ||||
|     if (!Converter<base::FilePath>::FromV8(isolate, val, &path)) | ||||
|       return false; | ||||
| 
 | ||||
|   *out = gfx::Image(image); | ||||
|     native_image = atom::api::NativeImage::CreateFromPath(isolate, path); | ||||
|     if (native_image->image().IsEmpty()) | ||||
|       return false; | ||||
|   } | ||||
| 
 | ||||
|   *out = native_image->image(); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| }  // namespace mate
 | ||||
| v8::Handle<v8::Value> Converter<gfx::Image>::ToV8(v8::Isolate* isolate, | ||||
|                                                   const gfx::Image& val) { | ||||
|   return ConvertToV8(isolate, atom::api::NativeImage::Create(isolate, val)); | ||||
| } | ||||
| 
 | ||||
| #endif  // !defined(OS_MACOSX)
 | ||||
| }  // namespace mate
 | ||||
|  |  | |||
|  | @ -26,6 +26,8 @@ struct Converter<gfx::Image> { | |||
|   static bool FromV8(v8::Isolate* isolate, | ||||
|                      v8::Handle<v8::Value> val, | ||||
|                      gfx::Image* out); | ||||
|   static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, | ||||
|                                     const gfx::Image& val); | ||||
| }; | ||||
| 
 | ||||
| }  // namespace mate
 | ||||
|  |  | |||
|  | @ -1,60 +0,0 @@ | |||
| // Copyright (c) 2015 GitHub, Inc. | ||||
| // Use of this source code is governed by the MIT license that can be | ||||
| // found in the LICENSE file. | ||||
| 
 | ||||
| #include "atom/common/native_mate_converters/image_converter.h" | ||||
| 
 | ||||
| #import <Cocoa/Cocoa.h> | ||||
| 
 | ||||
| #include "base/mac/foundation_util.h" | ||||
| #include "base/mac/scoped_nsobject.h" | ||||
| #include "base/strings/string_util.h" | ||||
| #include "base/strings/sys_string_conversions.h" | ||||
| #include "ui/gfx/image/image.h" | ||||
| #include "ui/gfx/image/image_skia.h" | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| bool IsTemplateImage(const std::string& path) { | ||||
|   return (MatchPattern(path, "*Template.*") || | ||||
|           MatchPattern(path, "*Template@*x.*")); | ||||
| } | ||||
| 
 | ||||
| }  // namespace | ||||
| 
 | ||||
| namespace mate { | ||||
| 
 | ||||
| bool Converter<gfx::ImageSkia>::FromV8(v8::Isolate* isolate, | ||||
|                                        v8::Handle<v8::Value> val, | ||||
|                                        gfx::ImageSkia* out) { | ||||
|   gfx::Image image; | ||||
|   if (!ConvertFromV8(isolate, val, &image)) | ||||
|     return false; | ||||
| 
 | ||||
|   *out = image.AsImageSkia(); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool Converter<gfx::Image>::FromV8(v8::Isolate* isolate, | ||||
|                                    v8::Handle<v8::Value> val, | ||||
|                                    gfx::Image* out) { | ||||
|   if (val->IsNull()) | ||||
|     return true; | ||||
| 
 | ||||
|   std::string path; | ||||
|   if (!ConvertFromV8(isolate, val, &path)) | ||||
|     return false; | ||||
| 
 | ||||
|   base::scoped_nsobject<NSImage> image([[NSImage alloc] | ||||
|       initByReferencingFile:base::SysUTF8ToNSString(path)]); | ||||
|   if (![image isValid]) | ||||
|     return false; | ||||
| 
 | ||||
|   if (IsTemplateImage(path)) | ||||
|     [image setTemplate:YES]; | ||||
| 
 | ||||
|   *out = gfx::Image(image.release()); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| }  // namespace mate | ||||
|  | @ -72,6 +72,7 @@ REFERENCE_MODULE(atom_common_asar); | |||
| REFERENCE_MODULE(atom_common_clipboard); | ||||
| REFERENCE_MODULE(atom_common_crash_reporter); | ||||
| REFERENCE_MODULE(atom_common_id_weak_map); | ||||
| REFERENCE_MODULE(atom_common_native_image); | ||||
| REFERENCE_MODULE(atom_common_screen); | ||||
| REFERENCE_MODULE(atom_common_shell); | ||||
| REFERENCE_MODULE(atom_common_v8_util); | ||||
|  |  | |||
|  | @ -46,6 +46,7 @@ Modules for both sides: | |||
| 
 | ||||
| * [clipboard](api/clipboard.md) | ||||
| * [crash-reporter](api/crash-reporter.md) | ||||
| * [native-image](api/native-image.md) | ||||
| * [screen](api/screen.md) | ||||
| * [shell](api/shell.md) | ||||
| 
 | ||||
|  |  | |||
|  | @ -43,13 +43,13 @@ You can also create a window without chrome by using | |||
|      other windows | ||||
|   * `fullscreen` Boolean - Whether the window should show in fullscreen, when | ||||
|     set to `false` the fullscreen button would also be hidden on OS X | ||||
|   * `skip-taskbar` Boolean - Do not show window in taskbar | ||||
|   * `skip-taskbar` Boolean - Do not show window in Taskbar | ||||
|   * `zoom-factor` Number - The default zoom factor of the page, zoom factor is | ||||
|     zoom percent / 100, so `3.0` represents `300%` | ||||
|   * `kiosk` Boolean - The kiosk mode | ||||
|   * `title` String - Default window title | ||||
|   * `icon` [Image](image.md) - The window icon, when omitted on Windows the | ||||
|     executable's icon would be used as window icon | ||||
|   * `icon` [NativeImage](native-image.md) - The window icon, when omitted on | ||||
|     Windows the executable's icon would be used as window icon | ||||
|   * `show` Boolean - Whether window should be shown when created | ||||
|   * `frame` Boolean - Specify `false` to create a | ||||
|     [Frameless Window](frameless-window.md) | ||||
|  | @ -415,7 +415,7 @@ Starts or stops flashing the window to attract user's attention. | |||
| 
 | ||||
| * `skip` Boolean | ||||
| 
 | ||||
| Makes the window do not show in taskbar. | ||||
| Makes the window do not show in Taskbar. | ||||
| 
 | ||||
| ### BrowserWindow.setKiosk(flag) | ||||
| 
 | ||||
|  | @ -545,8 +545,11 @@ it will assume `app.getName().desktop`. | |||
| 
 | ||||
| ### BrowserWindow.setOverlayIcon(overlay, description) | ||||
| 
 | ||||
| * `overlay` [Image](image.md) - the icon to display on the bottom right corner of the Taskbar icon. If this parameter is `null`, the overlay is cleared. | ||||
| * `description` String - a description that will be provided to Accessibility screenreaders | ||||
| * `overlay` [NativeImage](native-image.md) - the icon to display on the bottom | ||||
| right corner of the Taskbar icon. If this parameter is `null`, the overlay is | ||||
| cleared | ||||
| * `description` String - a description that will be provided to Accessibility | ||||
| screen readers | ||||
| 
 | ||||
| Sets a 16px overlay onto the current Taskbar icon, usually used to convey some sort of application status or to passively notify the user. | ||||
| 
 | ||||
|  |  | |||
|  | @ -76,7 +76,7 @@ would be passed via `callback(filename)` | |||
|   * `title` String - Title of the message box, some platforms will not show it | ||||
|   * `message` String - Content of the message box | ||||
|   * `detail` String - Extra information of the message | ||||
|   * `icon` [Image](image.md) | ||||
|   * `icon` [NativeImage](native-image.md) | ||||
| * `callback` Function | ||||
| 
 | ||||
| Shows a message box, it will block until the message box is closed. It returns | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| # Image | ||||
| # NativeImage | ||||
| 
 | ||||
| In atom-shell images are represented by their file paths, we currently do not | ||||
| support in-memory images or remote images. | ||||
| In atom-shell for the APIs that take images, you can pass either file paths or | ||||
| `NativeImage` instances. When passing `null`, an empty image will be used. | ||||
| 
 | ||||
| For example when creating tray or setting window's icon, you can pass image's | ||||
| file path as `String` to represent an image: | ||||
|  | @ -11,12 +11,18 @@ var appIcon = new Tray('/Users/somebody/images/icon.png'); | |||
| var window = new BrowserWindow({icon: '/Users/somebody/images/window.png'}); | ||||
| ``` | ||||
| 
 | ||||
| Or read the image from clipboard: | ||||
| 
 | ||||
| ```javascript | ||||
| var clipboard = require('clipboard'); | ||||
| var image = clipboard.readImage(); | ||||
| var appIcon = new Tray(image); | ||||
| ``` | ||||
| 
 | ||||
| ## Supported formats | ||||
| 
 | ||||
| On Mac all formats supported by the system can be used, while on Linux and | ||||
| Windows only `PNG` and `JPG` formats are supported. | ||||
| 
 | ||||
| So it is recommended to use `PNG` images for all cases. | ||||
| Currently `PNG` and `JPEG` are supported, and it is recommended to use `PNG` | ||||
| because it supports alpha channel and image is usually not compressed. | ||||
| 
 | ||||
| ## High resolution image | ||||
| 
 | ||||
|  | @ -73,3 +79,55 @@ To mark an image as template image, its filename should end with the word | |||
| 
 | ||||
| * `xxxTemplate.png` | ||||
| * `xxxTemplate@2x.png` | ||||
| 
 | ||||
| ## nativeImage.createEmpty() | ||||
| 
 | ||||
| Creates an empty `NativeImage` instance. | ||||
| 
 | ||||
| ## nativeImage.createFromPath(path) | ||||
| 
 | ||||
| * `path` String | ||||
| 
 | ||||
| Creates a new `NativeImage` instance from file located at `path`. | ||||
| 
 | ||||
| ## nativeImage.createFromBuffer(buffer[, scaleFactor]) | ||||
| 
 | ||||
| * `buffer` [Buffer][buffer] | ||||
| * `scaleFactor` Double | ||||
| 
 | ||||
| Creates a new `NativeImage` instance from `buffer`. The `scaleFactor` is 1.0 by | ||||
| default. | ||||
| 
 | ||||
| ## nativeImage.createFromDataUrl(dataUrl) | ||||
| 
 | ||||
| * `dataUrl` String | ||||
| 
 | ||||
| Creates a new `NativeImage` instance from `dataUrl`. | ||||
| 
 | ||||
| ## Class: NativeImage | ||||
| 
 | ||||
| This class is used to represent an image. | ||||
| 
 | ||||
| ### NativeImage.toPng() | ||||
| 
 | ||||
| Returns a [Buffer][buffer] that contains image's `PNG` encoded data. | ||||
| 
 | ||||
| ### NativeImage.toJpeg(quality) | ||||
| 
 | ||||
| * `quality` Integer | ||||
| 
 | ||||
| Returns a [Buffer][buffer] that contains image's `JPEG` encoded data. | ||||
| 
 | ||||
| ### NativeImage.toDataUrl() | ||||
| 
 | ||||
| Returns the data URL of image. | ||||
| 
 | ||||
| ### NativeImage.isEmpty() | ||||
| 
 | ||||
| Returns whether the image is empty. | ||||
| 
 | ||||
| ### NativeImage.getSize() | ||||
| 
 | ||||
| Returns the size of the image. | ||||
| 
 | ||||
| [buffer]: https://iojs.org/api/buffer.html#buffer_class_buffer | ||||
|  | @ -40,7 +40,7 @@ rely on `clicked` event and always attach a context menu to the tray icon. | |||
| 
 | ||||
| ### new Tray(image) | ||||
| 
 | ||||
| * `image` [Image](image.md) | ||||
| * `image` [NativeImage](native-image.md) | ||||
| 
 | ||||
| Creates a new tray icon associated with the `image`. | ||||
| 
 | ||||
|  | @ -79,13 +79,13 @@ Destroys the tray icon immediately. | |||
| 
 | ||||
| ### Tray.setImage(image) | ||||
| 
 | ||||
| * `image` [Image](image.md) | ||||
| * `image` [NativeImage](native-image.md) | ||||
| 
 | ||||
| Sets the `image` associated with this tray icon. | ||||
| 
 | ||||
| ### Tray.setPressedImage(image) | ||||
| 
 | ||||
| * `image` [Image](image.md) | ||||
| * `image` [NativeImage](native-image.md) | ||||
| 
 | ||||
| Sets the `image` associated with this tray icon when pressed. | ||||
| 
 | ||||
|  | @ -114,7 +114,7 @@ This is only implmented on OS X. | |||
| ### Tray.displayBalloon(options) | ||||
| 
 | ||||
| * `options` Object | ||||
|   * `icon` [Image](image.md) | ||||
|   * `icon` [NativeImage](native-image.md) | ||||
|   * `title` String | ||||
|   * `content` String | ||||
| 
 | ||||
|  |  | |||
|  | @ -78,7 +78,7 @@ describe 'browser-window module', -> | |||
|   describe 'BrowserWindow.capturePage(rect, callback)', -> | ||||
|     it 'calls the callback with a Buffer', (done) -> | ||||
|       w.capturePage {x: 0, y: 0, width: 100, height: 100}, (image) -> | ||||
|         assert.equal image.constructor.name, 'Buffer' | ||||
|         assert.equal image.isEmpty(), true | ||||
|         done() | ||||
| 
 | ||||
|   describe 'BrowserWindow.setSize(width, height)', -> | ||||
|  |  | |||
							
								
								
									
										2
									
								
								vendor/native_mate
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/native_mate
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +1 @@ | |||
| Subproject commit 1116a36c15ac3e65720cf12d38a3308f40f7ea58 | ||||
| Subproject commit 8d537ee2b6da29c1aa38928590d4c56700e1c69b | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Cheng Zhao
				Cheng Zhao