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

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: rebased 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, and
52 int target_size, 52 // the contents of |bitmap| and |image_format| are undefined.
53 SkBitmap* bitmap) { 53 scoped_refptr<base::RefCountedBytes> CropImage(
54 const SkBitmap& image,
55 int target_size,
56 SkBitmap* bitmap,
57 user_manager::UserImage::ImageFormat* image_format) {
54 DCHECK_GT(target_size, 0); 58 DCHECK_GT(target_size, 0);
59 DCHECK(image_format);
55 60
56 SkBitmap final_image; 61 SkBitmap final_image;
57 // Auto crop the image, taking the largest square in the center. 62 // Auto crop the image, taking the largest square in the center.
58 int pixels_per_side = std::min(image.width(), image.height()); 63 int pixels_per_side = std::min(image.width(), image.height());
59 int x = (image.width() - pixels_per_side) / 2; 64 int x = (image.width() - pixels_per_side) / 2;
60 int y = (image.height() - pixels_per_side) / 2; 65 int y = (image.height() - pixels_per_side) / 2;
61 SkBitmap cropped_image = SkBitmapOperations::CreateTiledBitmap( 66 SkBitmap cropped_image = SkBitmapOperations::CreateTiledBitmap(
62 image, x, y, pixels_per_side, pixels_per_side); 67 image, x, y, pixels_per_side, pixels_per_side);
63 if (pixels_per_side > target_size) { 68 if (pixels_per_side > target_size) {
64 // Also downsize the image to save space and memory. 69 // Also downsize the image to save space and memory.
65 final_image = skia::ImageOperations::Resize( 70 final_image = skia::ImageOperations::Resize(
66 cropped_image, skia::ImageOperations::RESIZE_LANCZOS3, target_size, 71 cropped_image, skia::ImageOperations::RESIZE_LANCZOS3, target_size,
67 target_size); 72 target_size);
68 } else { 73 } else {
69 final_image = cropped_image; 74 final_image = cropped_image;
70 } 75 }
71 76
72 // Encode the cropped image to web-compatible bytes representation 77 // Encode the cropped image to web-compatible bytes representation
78 *image_format = user_manager::UserImage::ChooseImageFormat(final_image);
73 scoped_refptr<base::RefCountedBytes> encoded = 79 scoped_refptr<base::RefCountedBytes> encoded =
74 user_manager::UserImage::Encode(final_image); 80 user_manager::UserImage::Encode(final_image, *image_format);
75 if (encoded) 81 if (encoded)
76 bitmap->swap(final_image); 82 bitmap->swap(final_image);
77 return encoded; 83 return encoded;
78 } 84 }
79 85
86 // Returns the image format for the bytes representation of the user image
87 // from the image codec used for loading the image.
88 user_manager::UserImage::ImageFormat ChooseImageFormatFromCodec(
89 ImageDecoder::ImageCodec image_codec) {
90 switch (image_codec) {
91 case ImageDecoder::ROBUST_JPEG_CODEC:
92 return user_manager::UserImage::FORMAT_JPEG;
93 case ImageDecoder::ROBUST_PNG_CODEC:
94 return user_manager::UserImage::FORMAT_PNG;
95 case ImageDecoder::DEFAULT_CODEC:
96 // The default codec can accept many kinds of image formats, hence the
97 // image format of the bytes representation is unknown.
98 return user_manager::UserImage::FORMAT_UNKNOWN;
99 }
100 NOTREACHED();
101 return user_manager::UserImage::FORMAT_UNKNOWN;
102 }
103
80 // Handles the decoded image returned from ImageDecoder through the 104 // Handles the decoded image returned from ImageDecoder through the
81 // ImageRequest interface. 105 // ImageRequest interface.
82 class UserImageRequest : public ImageDecoder::ImageRequest { 106 class UserImageRequest : public ImageDecoder::ImageRequest {
83 public: 107 public:
84 UserImageRequest( 108 UserImageRequest(
85 const ImageInfo& image_info, 109 const ImageInfo& image_info,
86 const std::string& image_data, 110 const std::string& image_data,
87 scoped_refptr<base::SequencedTaskRunner> background_task_runner) 111 scoped_refptr<base::SequencedTaskRunner> background_task_runner)
88 : image_info_(image_info), 112 : image_info_(image_info),
89 // TODO(crbug.com/593251): Remove the data copy here. 113 // TODO(crbug.com/593251): Remove the data copy here.
90 image_data_(new base::RefCountedBytes( 114 image_data_(new base::RefCountedBytes(
91 reinterpret_cast<const unsigned char*>(image_data.data()), 115 reinterpret_cast<const unsigned char*>(image_data.data()),
92 image_data.size())), 116 image_data.size())),
93 background_task_runner_(background_task_runner), 117 background_task_runner_(background_task_runner),
94 weak_ptr_factory_(this) {} 118 weak_ptr_factory_(this) {}
95 ~UserImageRequest() override {} 119 ~UserImageRequest() override {}
96 120
97 // ImageDecoder::ImageRequest implementation. 121 // ImageDecoder::ImageRequest implementation.
98 void OnImageDecoded(const SkBitmap& decoded_image) override; 122 void OnImageDecoded(const SkBitmap& decoded_image) override;
99 void OnDecodeImageFailed() override; 123 void OnDecodeImageFailed() override;
100 124
101 // Called after the image is cropped (and downsized) as needed. 125 // Called after the image is cropped (and downsized) as needed.
102 void OnImageCropped(SkBitmap* bitmap, 126 void OnImageCropped(SkBitmap* bitmap,
127 user_manager::UserImage::ImageFormat* image_format,
103 scoped_refptr<base::RefCountedBytes> bytes); 128 scoped_refptr<base::RefCountedBytes> bytes);
104 129
105 // Called after the image is finalized. |image_bytes_regenerated| is true 130 // Called after the image is finalized. |image_bytes_regenerated| is true
106 // if |image_bytes| is regenerated from the cropped image. 131 // if |image_bytes| is regenerated from the cropped image.
107 void OnImageFinalized(const SkBitmap& image, 132 void OnImageFinalized(const SkBitmap& image,
133 user_manager::UserImage::ImageFormat image_format,
108 scoped_refptr<base::RefCountedBytes> image_bytes, 134 scoped_refptr<base::RefCountedBytes> image_bytes,
109 bool image_bytes_regenerated); 135 bool image_bytes_regenerated);
110 136
111 private: 137 private:
112 const ImageInfo image_info_; 138 const ImageInfo image_info_;
113 scoped_refptr<base::RefCountedBytes> image_data_; 139 scoped_refptr<base::RefCountedBytes> image_data_;
114 scoped_refptr<base::SequencedTaskRunner> background_task_runner_; 140 scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
115 141
116 // This should be the last member. 142 // This should be the last member.
117 base::WeakPtrFactory<UserImageRequest> weak_ptr_factory_; 143 base::WeakPtrFactory<UserImageRequest> weak_ptr_factory_;
118 }; 144 };
119 145
120 void UserImageRequest::OnImageDecoded(const SkBitmap& decoded_image) { 146 void UserImageRequest::OnImageDecoded(const SkBitmap& decoded_image) {
121 int target_size = image_info_.pixels_per_side; 147 int target_size = image_info_.pixels_per_side;
122 if (target_size > 0) { 148 if (target_size > 0) {
123 // Cropping an image could be expensive, hence posting to the background 149 // Cropping an image could be expensive, hence posting to the background
124 // thread. 150 // thread.
125 SkBitmap* bitmap = new SkBitmap; 151 SkBitmap* bitmap = new SkBitmap;
152 auto* image_format = 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);
198 // The user image is safe if it is decoded using one of the robust image
199 // decoders, or regenerated by Chrome's image encoder.
163 if (image_info_.image_codec == ImageDecoder::ROBUST_JPEG_CODEC || 200 if (image_info_.image_codec == ImageDecoder::ROBUST_JPEG_CODEC ||
201 image_info_.image_codec == ImageDecoder::ROBUST_PNG_CODEC ||
164 image_bytes_regenerated) 202 image_bytes_regenerated)
165 user_image->MarkAsSafe(); 203 user_image->MarkAsSafe();
166 image_info_.loaded_cb.Run(std::move(user_image)); 204 image_info_.loaded_cb.Run(std::move(user_image));
167 delete this; 205 delete this;
168 } 206 }
169 207
170 void UserImageRequest::OnDecodeImageFailed() { 208 void UserImageRequest::OnDecodeImageFailed() {
171 image_info_.loaded_cb.Run(base::WrapUnique(new user_manager::UserImage)); 209 image_info_.loaded_cb.Run(base::WrapUnique(new user_manager::UserImage));
172 delete this; 210 delete this;
173 } 211 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 ImageDecoder::ImageCodec image_codec, 254 ImageDecoder::ImageCodec image_codec,
217 int pixels_per_side, 255 int pixels_per_side,
218 const LoadedCallback& loaded_cb) { 256 const LoadedCallback& loaded_cb) {
219 DecodeImage( 257 DecodeImage(
220 ImageInfo(base::FilePath(), pixels_per_side, image_codec, loaded_cb), 258 ImageInfo(base::FilePath(), pixels_per_side, image_codec, loaded_cb),
221 background_task_runner, data.get(), true /* data_is_ready */); 259 background_task_runner, data.get(), true /* data_is_ready */);
222 } 260 }
223 261
224 } // namespace user_image_loader 262 } // namespace user_image_loader
225 } // namespace chromeos 263 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698