1/*
2 * Copyright 2014 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 "Resources.h"
9#include "SkBitmap.h"
10#include "SkData.h"
11#include "SkDecodingImageGenerator.h"
12#include "SkForceLinking.h"
13#include "SkImageDecoder.h"
14#include "SkOSFile.h"
15#include "SkRandom.h"
16#include "SkStream.h"
17#include "Test.h"
18
19__SK_FORCE_IMAGE_DECODER_LINKING;
20
21/**
22 * First, make sure that writing an 8-bit RGBA KTX file and then
23 * reading it produces the same bitmap.
24 */
25DEF_TEST(KtxReadWrite, reporter) {
26
27    // Random number generator with explicit seed for reproducibility
28    SkRandom rand(0x1005cbad);
29
30    SkBitmap bm8888;
31    bool pixelsAllocated = bm8888.allocN32Pixels(128, 128);
32    REPORTER_ASSERT(reporter, pixelsAllocated);
33
34    uint8_t *pixels = reinterpret_cast<uint8_t*>(bm8888.getPixels());
35    REPORTER_ASSERT(reporter, NULL != pixels);
36
37    if (NULL == pixels) {
38        return;
39    }
40
41    uint8_t *row = pixels;
42    for (int y = 0; y < bm8888.height(); ++y) {
43        for (int x = 0; x < bm8888.width(); ++x) {
44            uint8_t a = rand.nextRangeU(0, 255);
45            uint8_t r = rand.nextRangeU(0, 255);
46            uint8_t g = rand.nextRangeU(0, 255);
47            uint8_t b = rand.nextRangeU(0, 255);
48
49            SkPMColor &pixel = *(reinterpret_cast<SkPMColor*>(row + x*sizeof(SkPMColor)));
50            pixel = SkPreMultiplyARGB(a, r, g, b);
51        }
52        row += bm8888.rowBytes();
53    }
54    REPORTER_ASSERT(reporter, !(bm8888.empty()));
55
56    SkAutoDataUnref encodedData(SkImageEncoder::EncodeData(bm8888, SkImageEncoder::kKTX_Type, 0));
57    REPORTER_ASSERT(reporter, NULL != encodedData);
58
59    SkAutoTUnref<SkMemoryStream> stream(SkNEW_ARGS(SkMemoryStream, (encodedData)));
60    REPORTER_ASSERT(reporter, NULL != stream);
61
62    SkBitmap decodedBitmap;
63    bool imageDecodeSuccess = SkImageDecoder::DecodeStream(stream, &decodedBitmap);
64    REPORTER_ASSERT(reporter, imageDecodeSuccess);
65
66    REPORTER_ASSERT(reporter, decodedBitmap.colorType() == bm8888.colorType());
67    REPORTER_ASSERT(reporter, decodedBitmap.alphaType() == bm8888.alphaType());
68    REPORTER_ASSERT(reporter, decodedBitmap.width() == bm8888.width());
69    REPORTER_ASSERT(reporter, decodedBitmap.height() == bm8888.height());
70    REPORTER_ASSERT(reporter, !(decodedBitmap.empty()));
71
72    uint8_t *decodedPixels = reinterpret_cast<uint8_t*>(decodedBitmap.getPixels());
73    REPORTER_ASSERT(reporter, NULL != decodedPixels);
74    REPORTER_ASSERT(reporter, decodedBitmap.getSize() == bm8888.getSize());
75
76    if (NULL == decodedPixels) {
77        return;
78    }
79
80    REPORTER_ASSERT(reporter, memcmp(decodedPixels, pixels, decodedBitmap.getSize()) == 0);
81}
82
83/**
84 * Next test is to see whether or not reading an unpremultiplied KTX file accurately
85 * creates a premultiplied buffer...
86 */
87DEF_TEST(KtxReadUnpremul, reporter) {
88
89    static const uint8_t kHalfWhiteKTX[] = {
90        0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, // First twelve bytes is magic
91        0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A, // KTX identifier string
92        0x01, 0x02, 0x03, 0x04, // Then magic endian specifier
93        0x01, 0x14, 0x00, 0x00, // uint32_t fGLType;
94        0x01, 0x00, 0x00, 0x00, // uint32_t fGLTypeSize;
95        0x08, 0x19, 0x00, 0x00, // uint32_t fGLFormat;
96        0x58, 0x80, 0x00, 0x00, // uint32_t fGLInternalFormat;
97        0x08, 0x19, 0x00, 0x00, // uint32_t fGLBaseInternalFormat;
98        0x02, 0x00, 0x00, 0x00, // uint32_t fPixelWidth;
99        0x02, 0x00, 0x00, 0x00, // uint32_t fPixelHeight;
100        0x00, 0x00, 0x00, 0x00, // uint32_t fPixelDepth;
101        0x00, 0x00, 0x00, 0x00, // uint32_t fNumberOfArrayElements;
102        0x01, 0x00, 0x00, 0x00, // uint32_t fNumberOfFaces;
103        0x01, 0x00, 0x00, 0x00, // uint32_t fNumberOfMipmapLevels;
104        0x00, 0x00, 0x00, 0x00, // uint32_t fBytesOfKeyValueData;
105        0x10, 0x00, 0x00, 0x00, // image size: 2x2 image of RGBA = 4 * 4 = 16 bytes
106        0xFF, 0xFF, 0xFF, 0x80, // Pixel 1
107        0xFF, 0xFF, 0xFF, 0x80, // Pixel 2
108        0xFF, 0xFF, 0xFF, 0x80, // Pixel 3
109        0xFF, 0xFF, 0xFF, 0x80};// Pixel 4
110
111    SkAutoTUnref<SkMemoryStream> stream(
112        SkNEW_ARGS(SkMemoryStream, (kHalfWhiteKTX, sizeof(kHalfWhiteKTX))));
113    REPORTER_ASSERT(reporter, NULL != stream);
114
115    SkBitmap decodedBitmap;
116    bool imageDecodeSuccess = SkImageDecoder::DecodeStream(stream, &decodedBitmap);
117    REPORTER_ASSERT(reporter, imageDecodeSuccess);
118
119    REPORTER_ASSERT(reporter, decodedBitmap.colorType() == kN32_SkColorType);
120    REPORTER_ASSERT(reporter, decodedBitmap.alphaType() == kPremul_SkAlphaType);
121    REPORTER_ASSERT(reporter, decodedBitmap.width() == 2);
122    REPORTER_ASSERT(reporter, decodedBitmap.height() == 2);
123    REPORTER_ASSERT(reporter, !(decodedBitmap.empty()));
124
125    uint8_t *decodedPixels = reinterpret_cast<uint8_t*>(decodedBitmap.getPixels());
126    REPORTER_ASSERT(reporter, NULL != decodedPixels);
127
128    uint8_t *row = decodedPixels;
129    for (int j = 0; j < decodedBitmap.height(); ++j) {
130        for (int i = 0; i < decodedBitmap.width(); ++i) {
131            SkPMColor pixel = *(reinterpret_cast<SkPMColor*>(row + i*sizeof(SkPMColor)));
132            REPORTER_ASSERT(reporter, SkPreMultiplyARGB(0x80, 0xFF, 0xFF, 0xFF) == pixel);
133        }
134        row += decodedBitmap.rowBytes();
135    }
136}
137
138/**
139 * Finally, make sure that if we get ETC1 data from a PKM file that we can then
140 * accurately write it out into a KTX file (i.e. transferring the ETC1 data from
141 * the PKM to the KTX should produce an identical KTX to the one we have on file)
142 */
143DEF_TEST(KtxReexportPKM, reporter) {
144    SkString resourcePath = GetResourcePath();
145    SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), "mandrill_128.pkm");
146
147    // Load PKM file into a bitmap
148    SkBitmap etcBitmap;
149    SkAutoTUnref<SkData> fileData(SkData::NewFromFileName(filename.c_str()));
150    REPORTER_ASSERT(reporter, NULL != fileData);
151    if (NULL == fileData) {
152        return;
153    }
154
155    bool installDiscardablePixelRefSuccess =
156        SkInstallDiscardablePixelRef(
157            SkDecodingImageGenerator::Create(
158                fileData, SkDecodingImageGenerator::Options()), &etcBitmap);
159    REPORTER_ASSERT(reporter, installDiscardablePixelRefSuccess);
160
161    // Write the bitmap out to a KTX file.
162    SkData *ktxDataPtr = SkImageEncoder::EncodeData(etcBitmap, SkImageEncoder::kKTX_Type, 0);
163    SkAutoDataUnref newKtxData(ktxDataPtr);
164    REPORTER_ASSERT(reporter, NULL != ktxDataPtr);
165
166    // See is this data is identical to data in existing ktx file.
167    SkString ktxFilename = SkOSPath::SkPathJoin(resourcePath.c_str(), "mandrill_128.ktx");
168    SkAutoDataUnref oldKtxData(SkData::NewFromFileName(ktxFilename.c_str()));
169    REPORTER_ASSERT(reporter, oldKtxData->equals(newKtxData));
170}
171