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

Side by Side Diff: ios/chrome/browser/webp_transcode/webp_decoder_unittest.mm

Issue 2526773002: Move iOS ImageFetcher to ios/web/public (Closed)
Patch Set: Rename headers 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
(Empty)
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ios/chrome/browser/webp_transcode/webp_decoder.h"
6
7 #import <CoreGraphics/CoreGraphics.h>
8 #import <Foundation/Foundation.h>
9 #include <stddef.h>
10 #include <stdint.h>
11
12 #include <memory>
13
14 #include "base/base_paths.h"
15 #include "base/files/file_path.h"
16 #include "base/ios/ios_util.h"
17 #include "base/logging.h"
18 #include "base/mac/scoped_cftyperef.h"
19 #include "base/mac/scoped_nsobject.h"
20 #include "base/macros.h"
21 #include "base/memory/ref_counted.h"
22 #include "base/path_service.h"
23 #include "base/strings/sys_string_conversions.h"
24 #include "build/build_config.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27
28 #if !defined(__has_feature) || !__has_feature(objc_arc)
29 #error "This file requires ARC support."
30 #endif
31
32 namespace webp_transcode {
33 namespace {
34
35 class WebpDecoderDelegate : public WebpDecoder::Delegate {
36 public:
37 WebpDecoderDelegate() : image_([[NSMutableData alloc] init]) {}
38
39 NSData* GetImage() const { return image_; }
40
41 // WebpDecoder::Delegate methods.
42 MOCK_METHOD1(OnFinishedDecoding, void(bool success));
43 MOCK_METHOD2(SetImageFeatures,
44 void(size_t total_size, WebpDecoder::DecodedImageFormat format));
45 void OnDataDecoded(NSData* data) override { [image_ appendData:data]; }
46
47 private:
48 virtual ~WebpDecoderDelegate() {}
49
50 base::scoped_nsobject<NSMutableData> image_;
51 };
52
53 class WebpDecoderTest : public testing::Test {
54 public:
55 WebpDecoderTest()
56 : delegate_(new WebpDecoderDelegate),
57 decoder_(new WebpDecoder(delegate_.get())) {}
58
59 NSData* LoadImage(const base::FilePath& filename) {
60 base::FilePath path;
61 PathService::Get(base::DIR_SOURCE_ROOT, &path);
62 path = path.AppendASCII("ios/chrome/test/data/webp_transcode")
63 .Append(filename);
64 return
65 [NSData dataWithContentsOfFile:base::SysUTF8ToNSString(path.value())];
66 }
67
68 std::vector<uint8_t>* DecompressData(NSData* data,
69 WebpDecoder::DecodedImageFormat format) {
70 base::ScopedCFTypeRef<CGDataProviderRef> provider(
71 CGDataProviderCreateWithCFData((CFDataRef)data));
72 base::ScopedCFTypeRef<CGImageRef> image;
73 switch (format) {
74 case WebpDecoder::JPEG:
75 image.reset(CGImageCreateWithJPEGDataProvider(
76 provider, nullptr, false, kCGRenderingIntentDefault));
77 break;
78 case WebpDecoder::PNG:
79 image.reset(CGImageCreateWithPNGDataProvider(
80 provider, nullptr, false, kCGRenderingIntentDefault));
81 break;
82 case WebpDecoder::TIFF:
83 ADD_FAILURE() << "Data already decompressed";
84 return nil;
85 case WebpDecoder::DECODED_FORMAT_COUNT:
86 ADD_FAILURE() << "Unknown format";
87 return nil;
88 }
89 size_t width = CGImageGetWidth(image);
90 size_t height = CGImageGetHeight(image);
91 base::ScopedCFTypeRef<CGColorSpaceRef> color_space(
92 CGColorSpaceCreateDeviceRGB());
93 size_t bytes_per_pixel = 4;
94 size_t bytes_per_row = bytes_per_pixel * width;
95 size_t bits_per_component = 8;
96 std::vector<uint8_t>* result =
97 new std::vector<uint8_t>(width * height * bytes_per_pixel, 0);
98 base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate(
99 &result->front(), width, height, bits_per_component, bytes_per_row,
100 color_space, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big));
101 CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
102 // Check that someting has been written in |result|.
103 std::vector<uint8_t> zeroes(width * height * bytes_per_pixel, 0);
104 EXPECT_NE(0, memcmp(&result->front(), &zeroes.front(), zeroes.size()))
105 << "Decompression failed.";
106 return result;
107 }
108
109 // Compares data, allowing an averaged absolute difference of 1.
110 bool CompareUncompressedData(const uint8_t* ptr_1,
111 const uint8_t* ptr_2,
112 size_t size) {
113 uint64_t difference = 0;
114 for (size_t i = 0; i < size; ++i) {
115 // Casting to int to avoid overflow.
116 int error = abs(int(ptr_1[i]) - int(ptr_2[i]));
117 EXPECT_GE(difference + error, difference)
118 << "Image difference too big (overflow).";
119 difference += error;
120 }
121 double average_difference = double(difference) / double(size);
122 DLOG(INFO) << "Average image difference: " << average_difference;
123 return average_difference < 1.5;
124 }
125
126 bool CheckCompressedImagesEqual(NSData* data_1,
127 NSData* data_2,
128 WebpDecoder::DecodedImageFormat format) {
129 std::unique_ptr<std::vector<uint8_t>> uncompressed_1(
130 DecompressData(data_1, format));
131 std::unique_ptr<std::vector<uint8_t>> uncompressed_2(
132 DecompressData(data_2, format));
133 if (uncompressed_1->size() != uncompressed_2->size()) {
134 DLOG(ERROR) << "Image sizes don't match";
135 return false;
136 }
137 return CompareUncompressedData(&uncompressed_1->front(),
138 &uncompressed_2->front(),
139 uncompressed_1->size());
140 }
141
142 bool CheckTiffImagesEqual(NSData* image_1, NSData* image_2) {
143 if ([image_1 length] != [image_2 length]) {
144 DLOG(ERROR) << "Image lengths don't match";
145 return false;
146 }
147 // Compare headers.
148 const size_t kHeaderSize = WebpDecoder::GetHeaderSize();
149 NSData* header_1 = [image_1 subdataWithRange:NSMakeRange(0, kHeaderSize)];
150 NSData* header_2 = [image_2 subdataWithRange:NSMakeRange(0, kHeaderSize)];
151 if (!header_1 || !header_2)
152 return false;
153 if (![header_1 isEqualToData:header_2]) {
154 DLOG(ERROR) << "Headers don't match.";
155 return false;
156 }
157 return CompareUncompressedData(
158 static_cast<const uint8_t*>([image_1 bytes]) + kHeaderSize,
159 static_cast<const uint8_t*>([image_2 bytes]) + kHeaderSize,
160 [image_1 length] - kHeaderSize);
161 }
162
163 protected:
164 scoped_refptr<WebpDecoderDelegate> delegate_;
165 scoped_refptr<WebpDecoder> decoder_;
166 };
167
168 } // namespace
169
170 TEST_F(WebpDecoderTest, DecodeToJpeg) {
171 // TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
172 #if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
173 if (base::ios::IsRunningOnIOS9OrLater())
174 return;
175 #endif
176 // Load a WebP image from disk.
177 base::scoped_nsobject<NSData> webp_image(
178 LoadImage(base::FilePath("test.webp")));
179 ASSERT_TRUE(webp_image != nil);
180 // Load reference image.
181 base::scoped_nsobject<NSData> jpg_image(
182 LoadImage(base::FilePath("test.jpg")));
183 ASSERT_TRUE(jpg_image != nil);
184 // Convert to JPEG.
185 EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
186 EXPECT_CALL(*delegate_, SetImageFeatures(testing::_, WebpDecoder::JPEG))
187 .Times(1);
188 decoder_->OnDataReceived(webp_image);
189 // Compare to reference image.
190 EXPECT_TRUE(CheckCompressedImagesEqual(jpg_image, delegate_->GetImage(),
191 WebpDecoder::JPEG));
192 }
193
194 TEST_F(WebpDecoderTest, DecodeToPng) {
195 // TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
196 #if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
197 if (base::ios::IsRunningOnIOS9OrLater())
198 return;
199 #endif
200 // Load a WebP image from disk.
201 base::scoped_nsobject<NSData> webp_image(
202 LoadImage(base::FilePath("test_alpha.webp")));
203 ASSERT_TRUE(webp_image != nil);
204 // Load reference image.
205 base::scoped_nsobject<NSData> png_image(
206 LoadImage(base::FilePath("test_alpha.png")));
207 ASSERT_TRUE(png_image != nil);
208 // Convert to PNG.
209 EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
210 EXPECT_CALL(*delegate_, SetImageFeatures(testing::_, WebpDecoder::PNG))
211 .Times(1);
212 decoder_->OnDataReceived(webp_image);
213 // Compare to reference image.
214 EXPECT_TRUE(CheckCompressedImagesEqual(png_image, delegate_->GetImage(),
215 WebpDecoder::PNG));
216 }
217
218 TEST_F(WebpDecoderTest, DecodeToTiff) {
219 // TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
220 #if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
221 if (base::ios::IsRunningOnIOS9OrLater())
222 return;
223 #endif
224 // Load a WebP image from disk.
225 base::scoped_nsobject<NSData> webp_image(
226 LoadImage(base::FilePath("test_small.webp")));
227 ASSERT_TRUE(webp_image != nil);
228 // Load reference image.
229 base::scoped_nsobject<NSData> tiff_image(
230 LoadImage(base::FilePath("test_small.tiff")));
231 ASSERT_TRUE(tiff_image != nil);
232 // Convert to TIFF.
233 EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
234 EXPECT_CALL(*delegate_,
235 SetImageFeatures([tiff_image length], WebpDecoder::TIFF))
236 .Times(1);
237 decoder_->OnDataReceived(webp_image);
238 // Compare to reference image.
239 EXPECT_TRUE(CheckTiffImagesEqual(tiff_image, delegate_->GetImage()));
240 }
241
242 TEST_F(WebpDecoderTest, StreamedDecode) {
243 // TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
244 #if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
245 if (base::ios::IsRunningOnIOS9OrLater())
246 return;
247 #endif
248 // Load a WebP image from disk.
249 base::scoped_nsobject<NSData> webp_image(
250 LoadImage(base::FilePath("test.webp")));
251 ASSERT_TRUE(webp_image != nil);
252 // Load reference image.
253 base::scoped_nsobject<NSData> jpg_image(
254 LoadImage(base::FilePath("test.jpg")));
255 ASSERT_TRUE(jpg_image != nil);
256 // Convert to JPEG in chunks.
257 EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
258 EXPECT_CALL(*delegate_, SetImageFeatures(testing::_, WebpDecoder::JPEG))
259 .Times(1);
260 const size_t kChunkSize = 10;
261 unsigned int num_chunks = 0;
262 while ([webp_image length] > kChunkSize) {
263 base::scoped_nsobject<NSData> chunk(
264 [webp_image subdataWithRange:NSMakeRange(0, kChunkSize)]);
265 decoder_->OnDataReceived(chunk);
266 webp_image.reset([webp_image
267 subdataWithRange:NSMakeRange(kChunkSize,
268 [webp_image length] - kChunkSize)]);
269 ++num_chunks;
270 }
271 if ([webp_image length] > 0u) {
272 decoder_->OnDataReceived(webp_image);
273 ++num_chunks;
274 }
275 ASSERT_GT(num_chunks, 3u) << "Not enough chunks";
276 // Compare to reference image.
277 EXPECT_TRUE(CheckCompressedImagesEqual(jpg_image, delegate_->GetImage(),
278 WebpDecoder::JPEG));
279 }
280
281 TEST_F(WebpDecoderTest, InvalidFormat) {
282 EXPECT_CALL(*delegate_, OnFinishedDecoding(false)).Times(1);
283 const char dummy_image[] = "(>'-')> <('-'<) ^('-')^ <('-'<) (>'-')>";
284 base::scoped_nsobject<NSData> data(
285 [[NSData alloc] initWithBytes:dummy_image length:arraysize(dummy_image)]);
286 decoder_->OnDataReceived(data);
287 EXPECT_EQ(0u, [delegate_->GetImage() length]);
288 }
289
290 TEST_F(WebpDecoderTest, DecodeAborted) {
291 EXPECT_CALL(*delegate_, OnFinishedDecoding(false)).Times(1);
292 decoder_->Stop();
293 EXPECT_EQ(0u, [delegate_->GetImage() length]);
294 }
295
296 } // namespace webp_transcode
OLDNEW
« no previous file with comments | « ios/chrome/browser/webp_transcode/webp_decoder.mm ('k') | ios/chrome/test/data/webp_transcode/OWNERS » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698