1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/login/users/avatar/user_image_loader.h"
8 #include "base/bind_helpers.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "chrome/browser/chromeos/login/helper.h"
16 #include "components/user_manager/user_image/user_image.h"
17 #include "skia/ext/image_operations.h"
18 #include "third_party/skia/include/core/SkBitmap.h"
19 #include "ui/gfx/codec/png_codec.h"
20 #include "ui/gfx/skbitmap_operations.h"
24 UserImageLoader::ImageInfo::ImageInfo(const std::string
& file_path
,
26 const LoadedCallback
& loaded_cb
)
27 : file_path(file_path
),
28 pixels_per_side(pixels_per_side
),
29 loaded_cb(loaded_cb
) {
32 UserImageLoader::ImageInfo::~ImageInfo() {
35 UserImageLoader::UserImageRequest::UserImageRequest(
36 const ImageInfo
& image_info
,
37 const std::string
& image_data
,
38 const scoped_refptr
<UserImageLoader
>& user_image_loader
)
39 : ImageRequest(user_image_loader
->background_task_runner_
),
40 image_info_(image_info
),
41 image_data_(image_data
.begin(), image_data
.end()),
42 user_image_loader_(user_image_loader
) {
45 UserImageLoader::UserImageRequest::~UserImageRequest() {
48 UserImageLoader::UserImageLoader(
49 ImageDecoder::ImageCodec image_codec
,
50 scoped_refptr
<base::SequencedTaskRunner
> background_task_runner
)
51 : foreground_task_runner_(base::ThreadTaskRunnerHandle::Get()),
52 background_task_runner_(background_task_runner
),
53 image_codec_(image_codec
) {
56 UserImageLoader::~UserImageLoader() {
59 void UserImageLoader::Start(const std::string
& filepath
,
61 const LoadedCallback
& loaded_cb
) {
62 background_task_runner_
->PostTask(
64 base::Bind(&UserImageLoader::ReadAndDecodeImage
,
66 ImageInfo(filepath
, pixels_per_side
, loaded_cb
)));
69 void UserImageLoader::Start(scoped_ptr
<std::string
> data
,
71 const LoadedCallback
& loaded_cb
) {
72 background_task_runner_
->PostTask(
74 base::Bind(&UserImageLoader::DecodeImage
,
77 ImageInfo(std::string(), pixels_per_side
, loaded_cb
)));
80 void UserImageLoader::ReadAndDecodeImage(const ImageInfo
& image_info
) {
81 DCHECK(background_task_runner_
->RunsTasksOnCurrentThread());
83 scoped_ptr
<std::string
> data(new std::string
);
84 if (!base::ReadFileToString(base::FilePath(image_info
.file_path
), data
.get()))
85 LOG(ERROR
) << "Failed to read image " << image_info
.file_path
;
87 // In case ReadFileToString() fails, |data| is empty and DecodeImage() calls
88 // back to OnDecodeImageFailed().
89 DecodeImage(data
.Pass(), image_info
);
92 void UserImageLoader::DecodeImage(const scoped_ptr
<std::string
> data
,
93 const ImageInfo
& image_info
) {
94 DCHECK(background_task_runner_
->RunsTasksOnCurrentThread());
96 UserImageRequest
* image_request
=
97 new UserImageRequest(image_info
, *data
, this);
98 ImageDecoder::StartWithOptions(image_request
, *data
, image_codec_
, false);
101 void UserImageLoader::UserImageRequest::OnImageDecoded(
102 const SkBitmap
& decoded_image
) {
103 DCHECK(task_runner()->RunsTasksOnCurrentThread());
105 const int target_size
= image_info_
.pixels_per_side
;
106 SkBitmap final_image
= decoded_image
;
108 if (target_size
> 0) {
109 // Auto crop the image, taking the largest square in the center.
110 int pixels_per_side
=
111 std::min(decoded_image
.width(), decoded_image
.height());
112 int x
= (decoded_image
.width() - pixels_per_side
) / 2;
113 int y
= (decoded_image
.height() - pixels_per_side
) / 2;
114 SkBitmap cropped_image
= SkBitmapOperations::CreateTiledBitmap(
115 decoded_image
, x
, y
, pixels_per_side
, pixels_per_side
);
116 if (pixels_per_side
> target_size
) {
117 // Also downsize the image to save space and memory.
119 skia::ImageOperations::Resize(cropped_image
,
120 skia::ImageOperations::RESIZE_LANCZOS3
,
124 final_image
= cropped_image
;
127 // Make the SkBitmap immutable as we won't modify it. This is important
128 // because otherwise it gets duplicated during painting, wasting memory.
129 final_image
.setImmutable();
130 gfx::ImageSkia final_image_skia
=
131 gfx::ImageSkia::CreateFrom1xBitmap(final_image
);
132 final_image_skia
.MakeThreadSafe();
133 user_manager::UserImage
user_image(final_image_skia
, image_data_
);
134 user_image
.set_file_path(image_info_
.file_path
);
135 if (user_image_loader_
->image_codec_
== ImageDecoder::ROBUST_JPEG_CODEC
)
136 user_image
.MarkAsSafe();
137 user_image_loader_
->foreground_task_runner_
->PostTask(
138 FROM_HERE
, base::Bind(image_info_
.loaded_cb
, user_image
));
142 void UserImageLoader::UserImageRequest::OnDecodeImageFailed() {
143 DCHECK(task_runner()->RunsTasksOnCurrentThread());
144 user_image_loader_
->foreground_task_runner_
->PostTask(
145 FROM_HERE
, base::Bind(image_info_
.loaded_cb
, user_manager::UserImage()));
149 } // namespace chromeos