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 */ 25 DEF_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 */ 87 DEF_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 */ 143 DEF_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