1/*
2 * Copyright 2013 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 "SkCodec.h"
9#include "Resources.h"
10#include "SkStream.h"
11#include "SkTemplates.h"
12#include "Test.h"
13
14static SkStreamAsset* resource(const char path[]) {
15    SkString fullPath = GetResourcePath(path);
16    return SkStream::NewFromFile(fullPath.c_str());
17}
18
19static void codec_yuv(skiatest::Reporter* reporter,
20                  const char path[],
21                  SkISize expectedSizes[3]) {
22    SkAutoTDelete<SkStream> stream(resource(path));
23    if (!stream) {
24        INFOF(reporter, "Missing resource '%s'\n", path);
25        return;
26    }
27    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.detach()));
28    REPORTER_ASSERT(reporter, codec);
29    if (!codec) {
30        return;
31    }
32
33    // Test queryYUV8()
34    SkCodec::YUVSizeInfo info;
35    bool success = codec->queryYUV8(nullptr, nullptr);
36    REPORTER_ASSERT(reporter, !success);
37    success = codec->queryYUV8(&info, nullptr);
38    REPORTER_ASSERT(reporter, (expectedSizes == nullptr) == !success);
39    if (!success) {
40        return;
41    }
42    REPORTER_ASSERT(reporter,
43            0 == memcmp((const void*) &info, (const void*) expectedSizes, 3 * sizeof(SkISize)));
44    REPORTER_ASSERT(reporter, info.fYWidthBytes == (uint32_t) SkAlign8(info.fYSize.width()));
45    REPORTER_ASSERT(reporter, info.fUWidthBytes == (uint32_t) SkAlign8(info.fUSize.width()));
46    REPORTER_ASSERT(reporter, info.fVWidthBytes == (uint32_t) SkAlign8(info.fVSize.width()));
47    SkYUVColorSpace colorSpace;
48    success = codec->queryYUV8(&info, &colorSpace);
49    REPORTER_ASSERT(reporter,
50            0 == memcmp((const void*) &info, (const void*) expectedSizes, 3 * sizeof(SkISize)));
51    REPORTER_ASSERT(reporter, info.fYWidthBytes == (uint32_t) SkAlign8(info.fYSize.width()));
52    REPORTER_ASSERT(reporter, info.fUWidthBytes == (uint32_t) SkAlign8(info.fUSize.width()));
53    REPORTER_ASSERT(reporter, info.fVWidthBytes == (uint32_t) SkAlign8(info.fVSize.width()));
54    REPORTER_ASSERT(reporter, kJPEG_SkYUVColorSpace == colorSpace);
55
56    // Allocate the memory for the YUV decode
57    size_t totalBytes = info.fYWidthBytes * info.fYSize.height() +
58            info.fUWidthBytes * info.fUSize.height() +
59            info.fVWidthBytes * info.fVSize.height();
60    SkAutoMalloc storage(totalBytes);
61    void* planes[3];
62    planes[0] = storage.get();
63    planes[1] = SkTAddOffset<void>(planes[0], info.fYWidthBytes * info.fYSize.height());
64    planes[2] = SkTAddOffset<void>(planes[1], info.fUWidthBytes * info.fUSize.height());
65
66    // Test getYUV8Planes()
67    REPORTER_ASSERT(reporter, SkCodec::kInvalidInput ==
68            codec->getYUV8Planes(info, nullptr));
69    REPORTER_ASSERT(reporter, SkCodec::kSuccess ==
70            codec->getYUV8Planes(info, planes));
71}
72
73DEF_TEST(Jpeg_YUV_Codec, r) {
74    SkISize sizes[3];
75
76    sizes[0].set(128, 128);
77    sizes[1].set(64, 64);
78    sizes[2].set(64, 64);
79    codec_yuv(r, "color_wheel.jpg", sizes);
80
81    // H2V2
82    sizes[0].set(512, 512);
83    sizes[1].set(256, 256);
84    sizes[2].set(256, 256);
85    codec_yuv(r, "mandrill_512_q075.jpg", sizes);
86
87    // H1V1
88    sizes[1].set(512, 512);
89    sizes[2].set(512, 512);
90    codec_yuv(r, "mandrill_h1v1.jpg", sizes);
91
92    // H2V1
93    sizes[1].set(256, 512);
94    sizes[2].set(256, 512);
95    codec_yuv(r, "mandrill_h2v1.jpg", sizes);
96
97    // Non-power of two dimensions
98    sizes[0].set(439, 154);
99    sizes[1].set(220, 77);
100    sizes[2].set(220, 77);
101    codec_yuv(r, "cropped_mandrill.jpg", sizes);
102
103    sizes[0].set(8, 8);
104    sizes[1].set(4, 4);
105    sizes[2].set(4, 4);
106    codec_yuv(r, "randPixels.jpg", sizes);
107
108    // Progressive images
109    sizes[0].set(512, 512);
110    sizes[1].set(512, 512);
111    sizes[2].set(512, 512);
112    codec_yuv(r, "brickwork-texture.jpg", sizes);
113    codec_yuv(r, "brickwork_normal-map.jpg", sizes);
114
115    // A CMYK encoded image should fail.
116    codec_yuv(r, "CMYK.jpg", nullptr);
117    // A grayscale encoded image should fail.
118    codec_yuv(r, "grayscale.jpg", nullptr);
119    // A PNG should fail.
120    codec_yuv(r, "arrow.png", nullptr);
121}
122