diff --git a/atom/common/native_mate_converters/image_converter.cc b/atom/common/native_mate_converters/image_converter.cc index f3292297405d..53f65d9e030d 100644 --- a/atom/common/native_mate_converters/image_converter.cc +++ b/atom/common/native_mate_converters/image_converter.cc @@ -5,6 +5,7 @@ #include "atom/common/native_mate_converters/image_converter.h" #include +#include #include "atom/common/native_mate_converters/file_path_converter.h" #include "base/file_util.h" @@ -18,12 +19,83 @@ namespace mate { namespace { -ui::ScaleFactor GetScaleFactorFromFileName(const base::FilePath& path) { +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 }, + { "@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()); - if (EndsWith(filename, "@2x", true)) - return ui::SCALE_FACTOR_200P; - else - return ui::SCALE_FACTOR_100P; + + // There is no scale info in the file path. + if (!EndsWith(filename, "x", true)) + return 1.0f; + + // 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; +} + +void AppendIfExists(std::vector* paths, + const base::FilePath& path) { + if (base::PathExists(path)) + paths->push_back(path); +} + +void PopulatePossibleFilePaths(std::vector* paths, + const base::FilePath& path) { + AppendIfExists(paths, path); + + std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe()); + if (MatchPattern(filename, "*@*x")) + return; + + for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i) + AppendIfExists(paths, + path.InsertBeforeExtensionASCII(kScaleFactorPairs[i].name)); +} + +bool AddImageSkiaRepFromPath(gfx::ImageSkia* image, + const base::FilePath& path) { + std::string file_contents; + if (!base::ReadFileToString(path, &file_contents)) + return false; + + const unsigned char* data = + reinterpret_cast(file_contents.data()); + size_t size = file_contents.size(); + scoped_ptr 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) { + image->AddRepresentation(gfx::ImageSkiaRep( + *decoded.release(), GetScaleFactorFromPath(path))); + return true; + } + + return false; } } // namespace @@ -33,25 +105,16 @@ bool Converter::FromV8(v8::Isolate* isolate, gfx::ImageSkia* out) { base::FilePath path; if (Converter::FromV8(isolate, val, &path)) { - std::string file_contents; - if (!base::ReadFileToString(path, &file_contents)) + std::vector paths; + PopulatePossibleFilePaths(&paths, path); + if (paths.empty()) return false; - const unsigned char* data = - reinterpret_cast(file_contents.data()); - size_t size = file_contents.size(); - scoped_ptr 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) { - *out = gfx::ImageSkia(gfx::ImageSkiaRep(*decoded.release(), - GetScaleFactorFromFileName(path))); - return true; + for (size_t i = 0; i < paths.size(); ++i) { + if (!AddImageSkiaRepFromPath(out, paths[i])) + return false; } + return true; } return false; diff --git a/docs/api/image.md b/docs/api/image.md index a18e3e8ae1a5..75545e99ade1 100644 --- a/docs/api/image.md +++ b/docs/api/image.md @@ -7,7 +7,7 @@ For example when creating tray or setting window's icon, you can pass image's file path as `String` to represent an image: ```javascript -var appIcon = new Tray('/Users/somebody/images/icon@2x.png'); +var appIcon = new Tray('/Users/somebody/images/icon.png'); var window = new BrowserWindow({icon: '/Users/somebody/images/window.png'}); ``` @@ -23,3 +23,32 @@ file name's base name to mark it as a high resolution image. For example if `icon.png` is a normal image that has standard resolution, the `icon@2x.png` would be treated as a high resolution image that has double DPI dense. + +If you want to support displays with different DPI denses at the same time, you +can put images with different sizes in the same folder, and use the filename +without DPI suffixes, like this: + +```text +images/ +├── icon.png +├── icon@2x.png +└── icon@3x.png +``` + + +```javascript +var appIcon = new Tray('/Users/somebody/images/icon.png'); +``` + +Following suffixes as DPI denses are also supported: + +* `@1x` +* `@1.25x` +* `@1.33x` +* `@1.4x` +* `@1.5x` +* `@1.8x` +* `@2x` +* `@2.5x` +* `@3x` +