Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(803)

Side by Side Diff: chrome/browser/chromeos/login/users/avatar/user_image_loader.cc

Issue 2537713002: Add support for transparent/translucent pixels in the user image (Closed)
Patch Set: Add support for transparent/translucent pixels in the user image Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/login/users/avatar/user_image_loader.h" 5 #include "chrome/browser/chromeos/login/users/avatar/user_image_loader.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 29 matching lines...) Expand all
40 ~ImageInfo() {} 40 ~ImageInfo() {}
41 41
42 const base::FilePath file_path; 42 const base::FilePath file_path;
43 const int pixels_per_side; 43 const int pixels_per_side;
44 const ImageDecoder::ImageCodec image_codec; 44 const ImageDecoder::ImageCodec image_codec;
45 const LoadedCallback loaded_cb; 45 const LoadedCallback loaded_cb;
46 }; 46 };
47 47
48 // Crops |image| to the square format and downsizes the image to 48 // Crops |image| to the square format and downsizes the image to
49 // |target_size| in pixels. On success, returns the bytes representation and 49 // |target_size| in pixels. On success, returns the bytes representation and
50 // stores the cropped image in |bitmap|. On failure, returns nullptr. 50 // stores the cropped image in |bitmap|, and the format of the bytes
51 scoped_refptr<base::RefCountedBytes> CropImage(const SkBitmap& image, 51 // representation in |image_format|. On failure, returns nullptr.
52 int target_size, 52 scoped_refptr<base::RefCountedBytes> CropImage(
53 SkBitmap* bitmap) { 53 const SkBitmap& image,
54 int target_size,
55 SkBitmap* bitmap,
56 user_manager::UserImage::ImageFormat* image_format) {
54 DCHECK_GT(target_size, 0); 57 DCHECK_GT(target_size, 0);
58 DCHECK(image_format);
55 59
56 SkBitmap final_image; 60 SkBitmap final_image;
57 // Auto crop the image, taking the largest square in the center. 61 // Auto crop the image, taking the largest square in the center.
58 int pixels_per_side = std::min(image.width(), image.height()); 62 int pixels_per_side = std::min(image.width(), image.height());
59 int x = (image.width() - pixels_per_side) / 2; 63 int x = (image.width() - pixels_per_side) / 2;
60 int y = (image.height() - pixels_per_side) / 2; 64 int y = (image.height() - pixels_per_side) / 2;
61 SkBitmap cropped_image = SkBitmapOperations::CreateTiledBitmap( 65 SkBitmap cropped_image = SkBitmapOperations::CreateTiledBitmap(
62 image, x, y, pixels_per_side, pixels_per_side); 66 image, x, y, pixels_per_side, pixels_per_side);
63 if (pixels_per_side > target_size) { 67 if (pixels_per_side > target_size) {
64 // Also downsize the image to save space and memory. 68 // Also downsize the image to save space and memory.
65 final_image = skia::ImageOperations::Resize( 69 final_image = skia::ImageOperations::Resize(
66 cropped_image, skia::ImageOperations::RESIZE_LANCZOS3, target_size, 70 cropped_image, skia::ImageOperations::RESIZE_LANCZOS3, target_size,
67 target_size); 71 target_size);
68 } else { 72 } else {
69 final_image = cropped_image; 73 final_image = cropped_image;
70 } 74 }
71 75
72 // Encode the cropped image to web-compatible bytes representation 76 // Encode the cropped image to web-compatible bytes representation
77 *image_format = user_manager::UserImage::ChooseImageFormat(final_image);
73 scoped_refptr<base::RefCountedBytes> encoded = 78 scoped_refptr<base::RefCountedBytes> encoded =
74 user_manager::UserImage::Encode(final_image); 79 user_manager::UserImage::Encode(final_image, *image_format);
75 if (encoded) 80 if (encoded)
achuithb 2016/11/30 00:26:48 Does it make sense to reset image_format to FORMAT
satorux1 2016/12/01 07:43:36 No, I think. The function returns nullptr on error
76 bitmap->swap(final_image); 81 bitmap->swap(final_image);
77 return encoded; 82 return encoded;
78 } 83 }
79 84
85 // Returns the image format for the bytes representation of the user image
86 // from the image codec used for loading the image.
87 user_manager::UserImage::ImageFormat ChooseImageFormatFromCodec(
88 ImageDecoder::ImageCodec image_codec) {
89 switch (image_codec) {
90 case ImageDecoder::ROBUST_JPEG_CODEC:
91 return user_manager::UserImage::FORMAT_JPEG;
92 case ImageDecoder::ROBUST_PNG_CODEC:
93 return user_manager::UserImage::FORMAT_PNG;
94 case ImageDecoder::DEFAULT_CODEC:
95 // The default codec can accept many kinds of image formats, hence the
96 // image format of the bytes representation is unknown.
97 return user_manager::UserImage::FORMAT_UNKNOWN;
98 }
99 NOTREACHED();
100 return user_manager::UserImage::FORMAT_UNKNOWN;
101 }
102
80 // Handles the decoded image returned from ImageDecoder through the 103 // Handles the decoded image returned from ImageDecoder through the
81 // ImageRequest interface. 104 // ImageRequest interface.
82 class UserImageRequest : public ImageDecoder::ImageRequest { 105 class UserImageRequest : public ImageDecoder::ImageRequest {
83 public: 106 public:
84 UserImageRequest( 107 UserImageRequest(
85 const ImageInfo& image_info, 108 const ImageInfo& image_info,
86 const std::string& image_data, 109 const std::string& image_data,
87 scoped_refptr<base::SequencedTaskRunner> background_task_runner) 110 scoped_refptr<base::SequencedTaskRunner> background_task_runner)
88 : image_info_(image_info), 111 : image_info_(image_info),
89 // TODO(crbug.com/593251): Remove the data copy here. 112 // TODO(crbug.com/593251): Remove the data copy here.
90 image_data_(new base::RefCountedBytes( 113 image_data_(new base::RefCountedBytes(
91 reinterpret_cast<const unsigned char*>(image_data.data()), 114 reinterpret_cast<const unsigned char*>(image_data.data()),
92 image_data.size())), 115 image_data.size())),
93 background_task_runner_(background_task_runner), 116 background_task_runner_(background_task_runner),
94 weak_ptr_factory_(this) {} 117 weak_ptr_factory_(this) {}
95 ~UserImageRequest() override {} 118 ~UserImageRequest() override {}
96 119
97 // ImageDecoder::ImageRequest implementation. 120 // ImageDecoder::ImageRequest implementation.
98 void OnImageDecoded(const SkBitmap& decoded_image) override; 121 void OnImageDecoded(const SkBitmap& decoded_image) override;
99 void OnDecodeImageFailed() override; 122 void OnDecodeImageFailed() override;
100 123
101 // Called after the image is cropped (and downsized) as needed. 124 // Called after the image is cropped (and downsized) as needed.
102 void OnImageCropped(SkBitmap* bitmap, 125 void OnImageCropped(SkBitmap* bitmap,
126 user_manager::UserImage::ImageFormat* image_format,
103 scoped_refptr<base::RefCountedBytes> bytes); 127 scoped_refptr<base::RefCountedBytes> bytes);
104 128
105 // Called after the image is finalized. |image_bytes_regenerated| is true 129 // Called after the image is finalized. |image_bytes_regenerated| is true
106 // if |image_bytes| is regenerated from the cropped image. 130 // if |image_bytes| is regenerated from the cropped image.
107 void OnImageFinalized(const SkBitmap& image, 131 void OnImageFinalized(const SkBitmap& image,
132 user_manager::UserImage::ImageFormat image_format,
108 scoped_refptr<base::RefCountedBytes> image_bytes, 133 scoped_refptr<base::RefCountedBytes> image_bytes,
109 bool image_bytes_regenerated); 134 bool image_bytes_regenerated);
110 135
111 private: 136 private:
112 const ImageInfo image_info_; 137 const ImageInfo image_info_;
113 scoped_refptr<base::RefCountedBytes> image_data_; 138 scoped_refptr<base::RefCountedBytes> image_data_;
114 scoped_refptr<base::SequencedTaskRunner> background_task_runner_; 139 scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
115 140
116 // This should be the last member. 141 // This should be the last member.
117 base::WeakPtrFactory<UserImageRequest> weak_ptr_factory_; 142 base::WeakPtrFactory<UserImageRequest> weak_ptr_factory_;
118 }; 143 };
119 144
120 void UserImageRequest::OnImageDecoded(const SkBitmap& decoded_image) { 145 void UserImageRequest::OnImageDecoded(const SkBitmap& decoded_image) {
121 int target_size = image_info_.pixels_per_side; 146 int target_size = image_info_.pixels_per_side;
122 if (target_size > 0) { 147 if (target_size > 0) {
123 // Cropping an image could be expensive, hence posting to the background 148 // Cropping an image could be expensive, hence posting to the background
124 // thread. 149 // thread.
125 SkBitmap* bitmap = new SkBitmap; 150 SkBitmap* bitmap = new SkBitmap;
151 user_manager::UserImage::ImageFormat* image_format =
achuithb 2016/11/30 00:26:48 auto* is appropriate here
satorux1 2016/12/01 07:43:36 Done.
152 new user_manager::UserImage::ImageFormat(
153 user_manager::UserImage::FORMAT_UNKNOWN);
126 base::PostTaskAndReplyWithResult( 154 base::PostTaskAndReplyWithResult(
127 background_task_runner_.get(), FROM_HERE, 155 background_task_runner_.get(), FROM_HERE,
128 base::Bind(&CropImage, decoded_image, target_size, bitmap), 156 base::Bind(&CropImage, decoded_image, target_size, bitmap,
157 image_format),
129 base::Bind(&UserImageRequest::OnImageCropped, 158 base::Bind(&UserImageRequest::OnImageCropped,
130 weak_ptr_factory_.GetWeakPtr(), base::Owned(bitmap))); 159 weak_ptr_factory_.GetWeakPtr(), base::Owned(bitmap),
160 base::Owned(image_format)));
131 } else { 161 } else {
132 OnImageFinalized(decoded_image, image_data_, 162 const user_manager::UserImage::ImageFormat image_format =
163 ChooseImageFormatFromCodec(image_info_.image_codec);
164 OnImageFinalized(decoded_image, image_format, image_data_,
133 false /* image_bytes_regenerated */); 165 false /* image_bytes_regenerated */);
134 } 166 }
135 } 167 }
136 168
137 void UserImageRequest::OnImageCropped( 169 void UserImageRequest::OnImageCropped(
138 SkBitmap* bitmap, 170 SkBitmap* bitmap,
171 user_manager::UserImage::ImageFormat* image_format,
139 scoped_refptr<base::RefCountedBytes> bytes) { 172 scoped_refptr<base::RefCountedBytes> bytes) {
140 DCHECK_GT(image_info_.pixels_per_side, 0); 173 DCHECK_GT(image_info_.pixels_per_side, 0);
141 174
142 if (!bytes) { 175 if (!bytes) {
143 OnDecodeImageFailed(); 176 OnDecodeImageFailed();
144 return; 177 return;
145 } 178 }
146 OnImageFinalized(*bitmap, bytes, true /* image_bytes_regenerated */); 179 OnImageFinalized(*bitmap, *image_format, bytes,
180 true /* image_bytes_regenerated */);
147 } 181 }
148 182
149 void UserImageRequest::OnImageFinalized( 183 void UserImageRequest::OnImageFinalized(
150 const SkBitmap& image, 184 const SkBitmap& image,
185 user_manager::UserImage::ImageFormat image_format,
151 scoped_refptr<base::RefCountedBytes> image_bytes, 186 scoped_refptr<base::RefCountedBytes> image_bytes,
152 bool image_bytes_regenerated) { 187 bool image_bytes_regenerated) {
153 SkBitmap final_image = image; 188 SkBitmap final_image = image;
154 // Make the SkBitmap immutable as we won't modify it. This is important 189 // Make the SkBitmap immutable as we won't modify it. This is important
155 // because otherwise it gets duplicated during painting, wasting memory. 190 // because otherwise it gets duplicated during painting, wasting memory.
156 final_image.setImmutable(); 191 final_image.setImmutable();
157 gfx::ImageSkia final_image_skia = 192 gfx::ImageSkia final_image_skia =
158 gfx::ImageSkia::CreateFrom1xBitmap(final_image); 193 gfx::ImageSkia::CreateFrom1xBitmap(final_image);
159 final_image_skia.MakeThreadSafe(); 194 final_image_skia.MakeThreadSafe();
160 std::unique_ptr<user_manager::UserImage> user_image( 195 std::unique_ptr<user_manager::UserImage> user_image(
161 new user_manager::UserImage(final_image_skia, image_bytes)); 196 new user_manager::UserImage(final_image_skia, image_bytes, image_format));
162 user_image->set_file_path(image_info_.file_path); 197 user_image->set_file_path(image_info_.file_path);
163 if (image_info_.image_codec == ImageDecoder::ROBUST_JPEG_CODEC || 198 if (image_info_.image_codec == ImageDecoder::ROBUST_JPEG_CODEC ||
199 image_info_.image_codec == ImageDecoder::ROBUST_PNG_CODEC ||
achuithb 2016/11/30 00:26:48 This is a change in behavior right?
satorux1 2016/12/01 07:43:36 Yes. Added some comment to clarify the intention h
164 image_bytes_regenerated) 200 image_bytes_regenerated)
165 user_image->MarkAsSafe(); 201 user_image->MarkAsSafe();
166 image_info_.loaded_cb.Run(std::move(user_image)); 202 image_info_.loaded_cb.Run(std::move(user_image));
167 delete this; 203 delete this;
168 } 204 }
169 205
170 void UserImageRequest::OnDecodeImageFailed() { 206 void UserImageRequest::OnDecodeImageFailed() {
171 image_info_.loaded_cb.Run(base::WrapUnique(new user_manager::UserImage)); 207 image_info_.loaded_cb.Run(base::WrapUnique(new user_manager::UserImage));
172 delete this; 208 delete this;
173 } 209 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 ImageDecoder::ImageCodec image_codec, 252 ImageDecoder::ImageCodec image_codec,
217 int pixels_per_side, 253 int pixels_per_side,
218 const LoadedCallback& loaded_cb) { 254 const LoadedCallback& loaded_cb) {
219 DecodeImage( 255 DecodeImage(
220 ImageInfo(base::FilePath(), pixels_per_side, image_codec, loaded_cb), 256 ImageInfo(base::FilePath(), pixels_per_side, image_codec, loaded_cb),
221 background_task_runner, data.get(), true /* data_is_ready */); 257 background_task_runner, data.get(), true /* data_is_ready */);
222 } 258 }
223 259
224 } // namespace user_image_loader 260 } // namespace user_image_loader
225 } // namespace chromeos 261 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698