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

Side by Side Diff: components/webp_transcode/webp_decoder_unittest.mm

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

Powered by Google App Engine
This is Rietveld 408576698