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

Side by Side Diff: ios/chrome/browser/suggestions/ios_image_decoder_impl.mm

Issue 2324793002: Support WebP images in the IOSImageDecoderImpl (Closed)
Patch Set: rebase + sdefresne@ comments. Created 4 years, 2 months 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "ios/chrome/browser/suggestions/ios_image_decoder_impl.h" 5 #include "ios/chrome/browser/suggestions/ios_image_decoder_impl.h"
6 6
7 #include <UIKit/UIKit.h> 7 #include <UIKit/UIKit.h>
8 8
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/mac/scoped_nsobject.h"
11 #include "base/macros.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/memory/weak_ptr.h"
14 #include "ios/chrome/browser/webp_transcode/webp_decoder.h"
15 #include "ios/web/public/web_thread.h"
10 #include "ui/gfx/image/image.h" 16 #include "ui/gfx/image/image.h"
11 17
18 namespace {
19
20 class WebpDecoderDelegate : public webp_transcode::WebpDecoder::Delegate {
21 public:
22 WebpDecoderDelegate() = default;
23
24 NSData* data() const { return decoded_image_; }
25
26 // WebpDecoder::Delegate methods
27 void OnFinishedDecoding(bool success) override {
28 if (!success)
29 decoded_image_.reset();
30 }
31
32 void SetImageFeatures(
33 size_t total_size,
34 webp_transcode::WebpDecoder::DecodedImageFormat format) override {
35 decoded_image_.reset([[NSMutableData alloc] initWithCapacity:total_size]);
36 }
37
38 void OnDataDecoded(NSData* data) override {
39 DCHECK(decoded_image_);
40 [decoded_image_ appendData:data];
41 }
42
43 private:
44 ~WebpDecoderDelegate() override {}
45 base::scoped_nsobject<NSMutableData> decoded_image_;
46
47 DISALLOW_COPY_AND_ASSIGN(WebpDecoderDelegate);
48 };
49
50 // Returns an NSData object containing the decoded image data of the given
51 // webp_image. Returns nil in case of failure.
52 base::scoped_nsobject<NSData> DecodeWebpImage(
53 const base::scoped_nsobject<NSData>& webp_image) {
54 scoped_refptr<WebpDecoderDelegate> delegate(new WebpDecoderDelegate);
55 scoped_refptr<webp_transcode::WebpDecoder> decoder(
56 new webp_transcode::WebpDecoder(delegate.get()));
57 decoder->OnDataReceived(webp_image);
58 DLOG_IF(ERROR, !delegate->data()) << "WebP image decoding failed.";
59 return base::scoped_nsobject<NSData>([delegate->data() retain]);
60 }
61
62 // Returns true if the given image_data is a WebP image.
63 //
64 // Every WebP file contains a 12 byte file header in the beginning of the file.
65 // A WebP file header starts with the four ASCII characters "RIFF". The next
66 // four bytes contain the image size and the last four header bytes contain the
67 // four ASCII characters "WEBP".
68 //
69 // WebP file header:
70 // 1 1
71 // Byte Nr. 0 1 2 3 4 5 6 7 8 9 0 1
72 // Byte value [ R I F F ? ? ? ? W E B P ]
73 //
74 // For more information see:
75 // https://developers.google.com/speed/webp/docs/riff_container#webp_file_header
76 bool IsWebpImage(const std::string& image_data) {
77 if (image_data.length() < 12)
78 return false;
79 return image_data.compare(0, 4, "RIFF") == 0 &&
80 image_data.compare(8, 4, "WEBP") == 0;
81 }
82
83 } // namespace
84
12 namespace suggestions { 85 namespace suggestions {
13 86
14 IOSImageDecoderImpl::IOSImageDecoderImpl() {} 87 class IOSImageDecoderImpl : public image_fetcher::ImageDecoder {
88 public:
89 explicit IOSImageDecoderImpl(scoped_refptr<base::TaskRunner> task_runner);
90 ~IOSImageDecoderImpl() override;
91
92 void DecodeImage(
93 const std::string& image_data,
94 const image_fetcher::ImageDecodedCallback& callback) override;
95
96 private:
97 void CreateUIImageAndRunCallback(
98 const image_fetcher::ImageDecodedCallback& callback,
99 const base::scoped_nsobject<NSData>& image_data);
100
101 // The task runner used to decode images if necessary.
102 const scoped_refptr<base::TaskRunner> task_runner_;
103
104 // The WeakPtrFactory is used to cancel callbacks if ImageFetcher is
105 // destroyed during WebP decoding.
106 base::WeakPtrFactory<IOSImageDecoderImpl> weak_factory_;
107
108 DISALLOW_COPY_AND_ASSIGN(IOSImageDecoderImpl);
109 };
110
111 IOSImageDecoderImpl::IOSImageDecoderImpl(
112 scoped_refptr<base::TaskRunner> task_runner)
113 : task_runner_(std::move(task_runner)), weak_factory_(this) {
114 DCHECK(task_runner_.get());
115 }
15 116
16 IOSImageDecoderImpl::~IOSImageDecoderImpl() {} 117 IOSImageDecoderImpl::~IOSImageDecoderImpl() {}
17 118
18 void IOSImageDecoderImpl::DecodeImage( 119 void IOSImageDecoderImpl::DecodeImage(
19 const std::string& image_data, 120 const std::string& image_data,
20 const image_fetcher::ImageDecodedCallback& callback) { 121 const image_fetcher::ImageDecodedCallback& callback) {
21 // Convert the |image_data| std::string to a NSData buffer. 122 // Convert the |image_data| std::string to an NSData buffer.
22 NSData* data = 123 base::scoped_nsobject<NSData> data(
23 [NSData dataWithBytesNoCopy:const_cast<char*>(image_data.c_str()) 124 [[NSData dataWithBytesNoCopy:const_cast<char*>(image_data.c_str())
24 length:image_data.length() 125 length:image_data.length()
25 freeWhenDone:NO]; 126 freeWhenDone:NO] retain]);
26 127
27 // Decode the Image using UIImage. 128 // The WebP image format is not supported by iOS natively. Therefore WebP
28 if (data) { 129 // images need to be decoded explicitly,
29 // Most likely always returns 1x images. 130 if (IsWebpImage(image_data)) {
30 UIImage* ui_image = [UIImage imageWithData:data scale:1]; 131 base::PostTaskAndReplyWithResult(
132 task_runner_.get(), FROM_HERE, base::Bind(&DecodeWebpImage, data),
133 base::Bind(&IOSImageDecoderImpl::CreateUIImageAndRunCallback,
134 weak_factory_.GetWeakPtr(), callback));
135 } else {
136 CreateUIImageAndRunCallback(callback, data);
137 }
138 }
139
140 void IOSImageDecoderImpl::CreateUIImageAndRunCallback(
141 const image_fetcher::ImageDecodedCallback& callback,
142 const base::scoped_nsobject<NSData>& image_data) {
143 // Decode the image data using UIImage.
144 if (image_data) {
145 // "Most likely" always returns 1x images.
146 UIImage* ui_image = [UIImage imageWithData:image_data scale:1];
31 if (ui_image) { 147 if (ui_image) {
32 gfx::Image gfx_image(ui_image); 148 // This constructor does not retain the image, but expects to take the
149 // ownership, therefore, |ui_image| is retained here, but not released
150 // afterwards.
151 gfx::Image gfx_image([ui_image retain]);
33 callback.Run(gfx_image); 152 callback.Run(gfx_image);
34 return; 153 return;
35 } 154 }
36 } 155 }
37 gfx::Image empty_image; 156 gfx::Image empty_image;
38 callback.Run(empty_image); 157 callback.Run(empty_image);
39 } 158 }
40 159
160 std::unique_ptr<image_fetcher::ImageDecoder> CreateIOSImageDecoder(
161 scoped_refptr<base::TaskRunner> task_runner) {
162 return base::MakeUnique<IOSImageDecoderImpl>(std::move(task_runner));
163 }
164
41 } // namespace suggestions 165 } // namespace suggestions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698