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

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, 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/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 };
sdefresne 2016/10/05 09:15:28 DISALLOW_COPY_AND_ASSIGN(WebpDecoderDelegate);
vitaliii 2016/10/06 06:35:08 Done.
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(scoped_refptr<base::TaskRunner> task_runner);
sdefresne 2016/10/05 09:15:28 const scoped_refptr<base::TaskRunner>& task_runner
vitaliii 2016/10/06 06:35:09 Done. However, I was advised against |const &| an
sdefresne 2016/10/06 15:53:06 Since the implementation does not use std::move()
vitaliii 2016/10/07 09:50:31 No worries :) That is a very good point about std:
85 ~IOSImageDecoderImpl() override;
86
87 void DecodeImage(
88 const std::string& image_data,
89 const image_fetcher::ImageDecodedCallback& callback) override;
90
91 private:
92 void CreateUIImageAndRunCallback(
93 const image_fetcher::ImageDecodedCallback& callback,
94 base::scoped_nsobject<NSData> image_data);
95
96 // The task runner used to decode images if necessary.
97 const scoped_refptr<base::TaskRunner> task_runner_;
98
99 // The WeakPtrFactory is used to cancel callbacks if ImageFetcher is
100 // destroyed during WebP decoding.
101 base::WeakPtrFactory<IOSImageDecoderImpl> weak_factory_;
102
103 DISALLOW_COPY_AND_ASSIGN(IOSImageDecoderImpl);
104 };
105
106 IOSImageDecoderImpl::IOSImageDecoderImpl(
107 scoped_refptr<base::TaskRunner> task_runner)
108 : task_runner_(task_runner), weak_factory_(this) {
109 DCHECK(task_runner_.get());
110 }
15 111
16 IOSImageDecoderImpl::~IOSImageDecoderImpl() {} 112 IOSImageDecoderImpl::~IOSImageDecoderImpl() {}
17 113
18 void IOSImageDecoderImpl::DecodeImage( 114 void IOSImageDecoderImpl::DecodeImage(
19 const std::string& image_data, 115 const std::string& image_data,
20 const image_fetcher::ImageDecodedCallback& callback) { 116 const image_fetcher::ImageDecodedCallback& callback) {
21 // Convert the |image_data| std::string to a NSData buffer. 117 // Convert the |image_data| std::string to an NSData buffer.
22 NSData* data = 118 base::scoped_nsobject<NSData> data(
23 [NSData dataWithBytesNoCopy:const_cast<char*>(image_data.c_str()) 119 [[NSData dataWithBytesNoCopy:const_cast<char*>(image_data.c_str())
24 length:image_data.length() 120 length:image_data.length()
25 freeWhenDone:NO]; 121 freeWhenDone:NO] retain]);
26 122
27 // Decode the Image using UIImage. 123 // The WebP image format is not supported by iOS natively. Therefore WebP
28 if (data) { 124 // images need to be decoded explicitly,
29 // Most likely always returns 1x images. 125 if (IsWebpImage(image_data)) {
30 UIImage* ui_image = [UIImage imageWithData:data scale:1]; 126 base::PostTaskAndReplyWithResult(
127 task_runner_.get(), FROM_HERE, base::Bind(&DecodeWebpImage, data),
128 base::Bind(&IOSImageDecoderImpl::CreateUIImageAndRunCallback,
129 weak_factory_.GetWeakPtr(), callback));
130 } else {
131 CreateUIImageAndRunCallback(callback, data);
132 }
133 }
134
135 void IOSImageDecoderImpl::CreateUIImageAndRunCallback(
136 const image_fetcher::ImageDecodedCallback& callback,
137 base::scoped_nsobject<NSData> image_data) {
sdefresne 2016/10/05 09:15:28 const base::scoped_nsobject<NSData>& image_data
vitaliii 2016/10/06 06:35:09 Done.
138 // Decode the image data using UIImage.
139 if (image_data) {
140 // "Most likely" always returns 1x images.
141 UIImage* ui_image = [UIImage imageWithData:image_data scale:1];
31 if (ui_image) { 142 if (ui_image) {
32 gfx::Image gfx_image(ui_image); 143 // This constructor does not retain the image, but expects to take the
144 // ownership, therefore, |ui_image| is retained here, but not released
145 // afterwards.
146 gfx::Image gfx_image([ui_image retain]);
33 callback.Run(gfx_image); 147 callback.Run(gfx_image);
34 return; 148 return;
35 } 149 }
36 } 150 }
37 gfx::Image empty_image; 151 gfx::Image empty_image;
38 callback.Run(empty_image); 152 callback.Run(empty_image);
39 } 153 }
40 154
155 std::unique_ptr<image_fetcher::ImageDecoder> createIOSImageDecoder(
156 scoped_refptr<base::TaskRunner> task_runner) {
157 return std::unique_ptr<image_fetcher::ImageDecoder>(
sdefresne 2016/10/05 09:15:28 Please use base::MakeUnique<T>(...) instead of std
vitaliii 2016/10/06 06:35:08 Done.
158 new IOSImageDecoderImpl(std::move(task_runner)));
159 }
160
41 } // namespace suggestions 161 } // namespace suggestions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698