blob: b86a210279b16fca5c20842412d932e16a508675 [file] [log] [blame]
Leon Scroggins III07a722c2018-01-16 15:01:17 -05001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkAndroidCodec.h"
9#include "SkCodec.h"
10#include "SkEncodedImageFormat.h"
11
12#include "Resources.h"
13#include "Test.h"
14
15static SkISize times(const SkISize& size, float factor) {
16 return { (int) (size.width() * factor), (int) (size.height() * factor) };
17}
18
19static SkISize plus(const SkISize& size, int term) {
20 return { size.width() + term, size.height() + term };
21}
22
23static bool invalid(const SkISize& size) {
24 return size.width() < 1 || size.height() < 1;
25}
26
27DEF_TEST(AndroidCodec_computeSampleSize, r) {
28 if (GetResourcePath().isEmpty()) {
29 return;
30 }
31 for (const char* file : { "images/color_wheel.webp",
32 "images/ship.png",
33 "images/dog.jpg",
34 "images/color_wheel.gif",
35 "images/rle.bmp",
36 "images/google_chrome.ico",
37 "images/mandrill.wbmp",
38#ifdef SK_CODEC_DECODES_RAW
39 "images/sample_1mp.dng",
40#endif
41 }) {
42 auto data = GetResourceAsData(file);
43 if (!data) {
44 ERRORF(r, "Could not get %s", file);
45 continue;
46 }
47
48 auto codec = SkAndroidCodec::MakeFromCodec(SkCodec::MakeFromData(std::move(data)));
49 if (!codec) {
50 ERRORF(r, "Could not create codec for %s", file);
51 continue;
52 }
53
54 const auto dims = codec->getInfo().dimensions();
55 const SkISize downscales[] = {
56 plus(dims, -1),
57 times(dims, .15f),
58 times(dims, .6f),
59 { (int32_t) (dims.width() * .25f), (int32_t) (dims.height() * .75f ) },
60 { 1, 1 },
61 { 1, 2 },
62 { 2, 1 },
63 { 0, -1 },
64 { dims.width(), dims.height() - 1 },
65 };
66 for (SkISize size : downscales) {
67 const auto requested = size;
68 const int computedSampleSize = codec->computeSampleSize(&size);
69 REPORTER_ASSERT(r, size.width() >= 1 && size.height() >= 1);
70 if (codec->getEncodedFormat() == SkEncodedImageFormat::kWEBP) {
71 // WebP supports arbitrary down-scaling.
72 REPORTER_ASSERT(r, size == requested || invalid(requested));
73 } else if (computedSampleSize == 1) {
74 REPORTER_ASSERT(r, size == dims);
75 } else {
76 REPORTER_ASSERT(r, computedSampleSize > 1);
77 if (size.width() >= dims.width() || size.height() >= dims.height()) {
78 ERRORF(r, "File %s's computed sample size (%i) is bigger than"
79 " original? original: %i x %i\tsampled: %i x %i",
80 file, computedSampleSize, dims.width(), dims.height(),
81 size.width(), size.height());
82 }
83 REPORTER_ASSERT(r, size.width() >= requested.width() &&
84 size.height() >= requested.height());
85 REPORTER_ASSERT(r, size.width() < dims.width() &&
86 size.height() < dims.height());
87 }
88 }
89
90 const SkISize upscales[] = {
91 dims, plus(dims, 5), times(dims, 2),
92 };
93 for (SkISize size : upscales) {
94 const int computedSampleSize = codec->computeSampleSize(&size);
95 REPORTER_ASSERT(r, computedSampleSize == 1);
96 REPORTER_ASSERT(r, dims == size);
97 }
98
99 // This mimics how Android's ImageDecoder uses SkAndroidCodec. A client
100 // can choose their dimensions based on calling getSampledDimensions,
101 // but the ImageDecoder API takes an arbitrary size. It then uses
102 // computeSampleSize to determine the best dimensions and sampleSize.
103 // It should return the same dimensions. the sampleSize may be different
104 // due to integer division.
105 for (int sampleSize : { 1, 2, 3, 4, 8, 16, 32 }) {
106 const SkISize sampledDims = codec->getSampledDimensions(sampleSize);
107 SkISize size = sampledDims;
108 const int computedSampleSize = codec->computeSampleSize(&size);
109 if (sampledDims != size) {
110 ERRORF(r, "File '%s'->getSampledDimensions(%i) yields computed"
111 " sample size of %i\n\tsampledDimensions: %i x %i\t"
112 "computed dimensions: %i x %i",
113 file, sampleSize, computedSampleSize,
114 sampledDims.width(), sampledDims.height(),
115 size.width(), size.height());
116 }
117 }
118 }
119}