| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |