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

Side by Side Diff: tests/ImageDecodingTest.cpp

Issue 93703004: Change SkDecodingImageGenerator API (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: rebase Created 7 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 | Annotate | Revision Log
« no previous file with comments | « tests/CachedDecodingPixelRefTest.cpp ('k') | tests/PictureTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "Test.h" 8 #include "Test.h"
9 #include "TestClassDef.h" 9 #include "TestClassDef.h"
10 #include "SkBitmap.h" 10 #include "SkBitmap.h"
11 #include "SkCanvas.h" 11 #include "SkCanvas.h"
12 #include "SkColor.h" 12 #include "SkColor.h"
13 #include "SkColorPriv.h" 13 #include "SkColorPriv.h"
14 #include "SkData.h" 14 #include "SkData.h"
15 #include "SkDecodingImageGenerator.h"
16 #include "SkDiscardableMemoryPool.h"
15 #include "SkForceLinking.h" 17 #include "SkForceLinking.h"
16 #include "SkGradientShader.h" 18 #include "SkGradientShader.h"
17 #include "SkImageDecoder.h" 19 #include "SkImageDecoder.h"
18 #include "SkImageEncoder.h" 20 #include "SkImageEncoder.h"
21 #include "SkImageGenerator.h"
19 #include "SkOSFile.h" 22 #include "SkOSFile.h"
20 #include "SkPoint.h" 23 #include "SkPoint.h"
21 #include "SkShader.h" 24 #include "SkShader.h"
22 #include "SkStream.h" 25 #include "SkStream.h"
23 #include "SkString.h" 26 #include "SkString.h"
24 27
25 __SK_FORCE_IMAGE_DECODER_LINKING; 28 __SK_FORCE_IMAGE_DECODER_LINKING;
26 29
27 /** 30 /**
28 * Interprets c as an unpremultiplied color, and returns the 31 * Interprets c as an unpremultiplied color, and returns the
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 SkString resourcePath = skiatest::Test::GetResourcePath(); 148 SkString resourcePath = skiatest::Test::GetResourcePath();
146 if (resourcePath.isEmpty()) { 149 if (resourcePath.isEmpty()) {
147 SkDebugf("Could not run unpremul test because resourcePath not specified ."); 150 SkDebugf("Could not run unpremul test because resourcePath not specified .");
148 return; 151 return;
149 } 152 }
150 SkOSFile::Iter iter(resourcePath.c_str()); 153 SkOSFile::Iter iter(resourcePath.c_str());
151 SkString basename; 154 SkString basename;
152 if (iter.next(&basename)) { 155 if (iter.next(&basename)) {
153 do { 156 do {
154 SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), basen ame.c_str()); 157 SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), basen ame.c_str());
155 //SkDebugf("about to decode \"%s\"\n", filename.c_str()); 158 // SkDebugf("about to decode \"%s\"\n", filename.c_str());
156 compare_unpremul(reporter, filename); 159 compare_unpremul(reporter, filename);
157 } while (iter.next(&basename)); 160 } while (iter.next(&basename));
158 } else { 161 } else {
159 SkDebugf("Failed to find any files :(\n"); 162 SkDebugf("Failed to find any files :(\n");
160 } 163 }
161 } 164 }
162 165
163 #ifdef SK_DEBUG 166 #ifdef SK_DEBUG
164 // Create a stream containing a bitmap encoded to Type type. 167 // Create a stream containing a bitmap encoded to Type type.
165 static SkMemoryStream* create_image_stream(SkImageEncoder::Type type) { 168 static SkMemoryStream* create_image_stream(SkImageEncoder::Type type) {
(...skipping 27 matching lines...) Expand all
193 // Only runs in debug mode since we are testing for a crash. 196 // Only runs in debug mode since we are testing for a crash.
194 static void test_stream_life() { 197 static void test_stream_life() {
195 const SkImageEncoder::Type gTypes[] = { 198 const SkImageEncoder::Type gTypes[] = {
196 #ifdef SK_BUILD_FOR_ANDROID 199 #ifdef SK_BUILD_FOR_ANDROID
197 SkImageEncoder::kJPEG_Type, 200 SkImageEncoder::kJPEG_Type,
198 SkImageEncoder::kPNG_Type, 201 SkImageEncoder::kPNG_Type,
199 #endif 202 #endif
200 SkImageEncoder::kWEBP_Type, 203 SkImageEncoder::kWEBP_Type,
201 }; 204 };
202 for (size_t i = 0; i < SK_ARRAY_COUNT(gTypes); ++i) { 205 for (size_t i = 0; i < SK_ARRAY_COUNT(gTypes); ++i) {
203 //SkDebugf("encoding to %i\n", i); 206 // SkDebugf("encoding to %i\n", i);
204 SkAutoTUnref<SkMemoryStream> stream(create_image_stream(gTypes[i])); 207 SkAutoTUnref<SkMemoryStream> stream(create_image_stream(gTypes[i]));
205 if (NULL == stream.get()) { 208 if (NULL == stream.get()) {
206 SkDebugf("no stream\n"); 209 SkDebugf("no stream\n");
207 continue; 210 continue;
208 } 211 }
209 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream)); 212 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
210 if (NULL == decoder.get()) { 213 if (NULL == decoder.get()) {
211 SkDebugf("no decoder\n"); 214 SkDebugf("no decoder\n");
212 continue; 215 continue;
213 } 216 }
214 int width, height; 217 int width, height;
215 if (!decoder->buildTileIndex(stream.get(), &width, &height)) { 218 if (!decoder->buildTileIndex(stream.get(), &width, &height)) {
216 SkDebugf("could not build a tile index\n"); 219 SkDebugf("could not build a tile index\n");
217 continue; 220 continue;
218 } 221 }
219 // Now unref the stream to make sure it survives 222 // Now unref the stream to make sure it survives
220 stream.reset(NULL); 223 stream.reset(NULL);
221 SkBitmap bm; 224 SkBitmap bm;
222 decoder->decodeSubset(&bm, SkIRect::MakeWH(width, height), 225 decoder->decodeSubset(&bm, SkIRect::MakeWH(width, height),
223 SkBitmap::kARGB_8888_Config); 226 SkBitmap::kARGB_8888_Config);
224 } 227 }
225 } 228 }
226 229
227 // Test inside SkScaledBitmapSampler.cpp 230 // Test inside SkScaledBitmapSampler.cpp
228 extern void test_row_proc_choice(); 231 extern void test_row_proc_choice();
229 232
230 #endif // SK_DEBUG 233 #endif // SK_DEBUG
231 234
232 DEF_TEST(ImageDecoding, reporter) { 235 DEF_TEST(ImageDecoding, reporter) {
233 test_unpremul(reporter); 236 test_unpremul(reporter);
234 #ifdef SK_DEBUG 237 #ifdef SK_DEBUG
235 test_stream_life(); 238 test_stream_life();
236 test_row_proc_choice(); 239 test_row_proc_choice();
237 #endif 240 #endif
238 } 241 }
242
243 ////////////////////////////////////////////////////////////////////////////////
244
245 // example of how Android will do this inside their BitmapFactory
246 static SkPixelRef* install_pixel_ref(SkBitmap* bitmap,
247 SkStreamRewindable* stream,
248 int sampleSize, bool ditherImage) {
249 SkASSERT(bitmap != NULL);
250 SkASSERT(stream != NULL);
251 SkASSERT(stream->rewind());
252 SkASSERT(stream->unique());
253 SkDecoderOptions opts(sampleSize, ditherImage, bitmap->config());
254 SkAutoTDelete<SkImageGenerator> gen(
255 SkNewDecodingImageGenerator(stream, opts));
256 SkImageInfo info;
257 if ((NULL == gen.get()) || !gen->getInfo(&info)) {
258 return NULL;
259 }
260 SkDiscardableMemory::Factory* factory = NULL;
261 if (SkBitmap::ComputeSize(info) < (32 * 1024)) {
262 // only use ashmem for large images, since mmaps come at a price
263 factory = SkGetGlobalDiscardableMemoryPool();
264 }
265 if (SkInstallDiscardablePixelRef(gen.detach(), bitmap, factory)) {
266 return bitmap->pixelRef();
267 }
268 return NULL;
269 }
270 /**
271 * A test for the SkNewDecodingImageGenerator and
272 * SkInstallDiscardablePixelRef functions.
273 */
274 DEF_TEST(ImprovedBitmapFactory, reporter) {
275 SkString resourcePath = skiatest::Test::GetResourcePath();
276 SkString directory = SkOSPath::SkPathJoin(resourcePath.c_str(), "encoding");
277 SkString path = SkOSPath::SkPathJoin(directory.c_str(), "randPixels.png");
278 SkAutoTUnref<SkStreamRewindable> stream(
279 SkStream::NewFromFile(path.c_str()));
280 if (sk_exists(path.c_str())) {
281 SkBitmap bm;
282 SkAssertResult(bm.setConfig(SkBitmap::kARGB_8888_Config, 1, 1));
283 REPORTER_ASSERT(reporter,
284 NULL != install_pixel_ref(&bm, stream.detach(), 1, true));
285 SkAutoLockPixels alp(bm);
286 REPORTER_ASSERT(reporter, NULL != bm.getPixels());
287 }
288 }
289
290
291 ////////////////////////////////////////////////////////////////////////////////
292
293
294 static inline bool check_rounding(int value, int dividend, int divisor) {
295 // returns true if (dividend/divisor) rounds up OR down to value
296 return (((divisor * value) > (dividend - divisor))
297 && ((divisor * value) < (dividend + divisor)));
298 }
299 namespace {
300 // expected output for 8x8 bitmap
301 const int kExpectedWidth = 8;
302 const int kExpectedHeight = 8;
303 const SkColor kExpectedPixels[] = {
304 0xffbba570, 0xff395f5d, 0xffe25c39, 0xff197666,
305 0xff3cba27, 0xffdefcb0, 0xffc13874, 0xfffa0093,
306 0xffbda60e, 0xffc01db6, 0xff2bd688, 0xff9362d4,
307 0xffc641b2, 0xffa5cede, 0xff606eba, 0xff8f4bf3,
308 0xff3bf742, 0xff8f02a8, 0xff5509df, 0xffc7027e,
309 0xff24aa8a, 0xff886c96, 0xff625481, 0xff403689,
310 0xffc52152, 0xff78ccd6, 0xffdcb4ab, 0xff09d27d,
311 0xffca00f3, 0xff605d47, 0xff446fb2, 0xff576e46,
312 0xff273df9, 0xffb41a83, 0xfff812c3, 0xffccab67,
313 0xff034218, 0xff7db9a7, 0xff821048, 0xfffe4ab4,
314 0xff6fac98, 0xff941d27, 0xff5fe411, 0xfffbb283,
315 0xffd86e99, 0xff169162, 0xff71128c, 0xff39cab4,
316 0xffa7fe63, 0xff4c956b, 0xffbc22e0, 0xffb272e4,
317 0xff129f4a, 0xffe34513, 0xff3d3742, 0xffbd190a,
318 0xffb07222, 0xff2e23f8, 0xfff089d9, 0xffb35738,
319 0xffa86022, 0xff3340fe, 0xff95fe71, 0xff6a71df
320 };
321 SK_COMPILE_ASSERT((kExpectedWidth * kExpectedHeight)
322 == SK_ARRAY_COUNT(kExpectedPixels), array_size_mismatch);
323 } // namespace
324
325 /**
326 * Given either a SkStream or a SkData, try to decode the endoded
scroggo 2013/12/16 15:38:36 encoded*
hal.canary 2013/12/17 17:08:11 Done.
327 * image using the specified options and report errors.
328 */
329 static void test_options(skiatest::Reporter* reporter,
330 const SkDecoderOptions& opts,
331 SkStreamRewindable* encodedStream,
332 SkData* encodedData,
333 bool useData,
334 const SkString& path) {
335 SkBitmap bm;
336 bool success = false;
337 if (useData) {
338 if (NULL == encodedData) {
339 return;
340 }
341 success = SkInstallDiscardablePixelRef(
342 SkNewDecodingImageGenerator(encodedData, opts), &bm, NULL);
343 } else {
344 if (NULL == encodedStream) {
345 return;
346 }
347 success = SkInstallDiscardablePixelRef(
348 SkNewDecodingImageGenerator(encodedStream->duplicate(), opts),
349 &bm, NULL);
350 }
351
352 REPORTER_ASSERT(reporter, success
353 || (SkBitmap::kARGB_4444_Config == opts.fRequestedConfig));
354 if (!success) {
355 return;
356 }
357 REPORTER_ASSERT(reporter, check_rounding(bm.height(), kExpectedHeight,
358 opts.fSampleSize));
359 REPORTER_ASSERT(reporter, check_rounding(bm.width(), kExpectedWidth,
360 opts.fSampleSize));
361
362 SkAutoLockPixels alp(bm);
363 REPORTER_ASSERT(reporter, bm.getPixels() != NULL);
364
365 REPORTER_ASSERT(reporter,
366 (SkBitmap::kNo_Config == opts.fRequestedConfig)
367 || (bm.config() == opts.fRequestedConfig));
368
369 // Condition under which we should check the decoding results:
370 if ((SkBitmap::kARGB_8888_Config == bm.config())
371 && (NULL != bm.getPixels())
372 && (!path.endsWith(".jpg")) // lossy
373 && (!path.endsWith(".webp")) // decoder error
374 && (opts.fSampleSize == 1)) { // scaled
375 bool pixelError = false;
376 const SkColor* correctPixels = kExpectedPixels;
377 SkASSERT(bm.height() == kExpectedHeight);
378 SkASSERT(bm.width() == kExpectedWidth);
379 for (int y = 0; y < bm.height(); ++y) {
380 for (int x = 0; x < bm.width(); ++x) {
381 pixelError |= (*correctPixels != bm.getColor(x, y));
382 ++correctPixels;
383 }
384 }
385 REPORTER_ASSERT(reporter, !pixelError);
386 }
387 }
388
389 /**
390 * SkDecodingImageGenerator has an Options struct which lets the
391 * client of the generator set sample size, dithering, and bitmap
392 * config. This test loops through many possible options and tries
393 * them on a set of 5 small encoded images (each in a different
394 * format). We test both SkData and SkStreamRewindable decoding.
395 */
396 DEF_TEST(ImageDecoderOptions, reporter) {
397 const char* files[] = {
398 "randPixels.bmp",
399 "randPixels.jpg",
400 "randPixels.png",
401 "randPixels.webp",
402 "randPixels.gif"
403 };
404
405 SkString resourceDir = skiatest::Test::GetResourcePath();
406 SkString directory = SkOSPath::SkPathJoin(resourceDir.c_str(), "encoding");
407 if (!sk_exists(directory.c_str())) {
408 return;
409 }
410
411 int scaleList[] = {1, 2, 3, 4};
412 bool ditherList[] = {true, false};
413 SkBitmap::Config configList[] = {
414 SkBitmap::kNo_Config, // Use whatever the decoder prefers.
415 SkBitmap::kARGB_8888_Config,
416 SkBitmap::kRGB_565_Config,
417 SkBitmap::kA8_Config,
418 SkBitmap::kARGB_4444_Config, // Most decoders will fail on 4444.
419 // Note that indexed color is left out of the list. Lazy
420 // decoding doesn't do indexed color.
421 };
422 const bool useDataList[] = {true, false};
423
424 for (size_t fidx = 0; fidx < SK_ARRAY_COUNT(files); ++fidx) {
425 SkString path = SkOSPath::SkPathJoin(directory.c_str(), files[fidx]);
426 if (!sk_exists(path.c_str())) {
427 continue;
428 }
429
430 SkAutoDataUnref encodedData(SkData::NewFromFileName(path.c_str()));
431 REPORTER_ASSERT(reporter, encodedData.get() != NULL);
432 SkAutoTUnref<SkStreamRewindable> encodedStream(
433 SkStream::NewFromFile(path.c_str()));
434 REPORTER_ASSERT(reporter, encodedStream.get() != NULL);
435
436 for (size_t i = 0; i < SK_ARRAY_COUNT(scaleList); ++i) {
437 for (size_t j = 0; j < SK_ARRAY_COUNT(ditherList); ++j) {
438 for (size_t k = 0; k < SK_ARRAY_COUNT(configList); ++k) {
439 SkDecoderOptions opts(scaleList[i], ditherList[j],
440 configList[k]);
441 for (size_t m = 0; m < SK_ARRAY_COUNT(useDataList); ++m) {
442 test_options(reporter, opts, encodedStream, encodedData,
443 useDataList[m], path);
444 }
445 }
446 }
447 }
448 }
449 }
450
OLDNEW
« no previous file with comments | « tests/CachedDecodingPixelRefTest.cpp ('k') | tests/PictureTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698