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

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

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

Powered by Google App Engine
This is Rietveld 408576698