SkImageDecoder_ktx.cpp revision c250d2e4abdbe8193357696518592af8a0b4555a
199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski/* 299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski * Copyright 2014 Google Inc. 399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski * 499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski * Use of this source code is governed by a BSD-style license that can be 599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski * found in the LICENSE file. 699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski */ 799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkColorPriv.h" 999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkImageDecoder.h" 10c250d2e4abdbe8193357696518592af8a0b4555akrajcevski#include "SkPixelRef.h" 1199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkScaledBitmapSampler.h" 1299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkStream.h" 1399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkStreamHelpers.h" 1499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "SkTypes.h" 1599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 1699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "ktx.h" 1799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski#include "etc1.h" 1899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 1999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski///////////////////////////////////////////////////////////////////////////////////////// 2099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 2199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 2299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski///////////////////////////////////////////////////////////////////////////////////////// 2399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 2499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// KTX Image decoder 2599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// --- 2699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// KTX is a general texture data storage file format ratified by the Khronos Group. As an 2799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// overview, a KTX file contains all of the appropriate values needed to fully specify a 2899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// texture in an OpenGL application, including the use of compressed data. 2999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// 3099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// This decoder is meant to be used with an SkDiscardablePixelRef so that GPU backends 3199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// can sniff the data before creating a texture. If they encounter a compressed format 3299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// that they understand, they can then upload the data directly to the GPU. Otherwise, 3399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski// they will decode the data into a format that Skia supports. 3499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 3599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskiclass SkKTXImageDecoder : public SkImageDecoder { 3699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskipublic: 3799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkKTXImageDecoder() { } 3899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 3999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski virtual Format getFormat() const SK_OVERRIDE { 4099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return kKTX_Format; 4199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 4299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 4399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskiprotected: 4499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; 4599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 4699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskiprivate: 4799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski typedef SkImageDecoder INHERITED; 4899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski}; 4999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 5099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskibool SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 5199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // TODO: Implement SkStream::copyToData() that's cheap for memory and file streams 5299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkAutoDataUnref data(CopyStreamToData(stream)); 5399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (NULL == data) { 5499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 5599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 5699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 5799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkKTXFile ktxFile(data); 5899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!ktxFile.valid()) { 5999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 6099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 6199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 6299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const unsigned short width = ktxFile.width(); 6399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const unsigned short height = ktxFile.height(); 6499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 6599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // should we allow the Chooser (if present) to pick a config for us??? 6699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!this->chooseFromOneChoice(SkBitmap::kARGB_8888_Config, width, height)) { 6799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 6899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 6999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 7099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Setup the sampler... 7199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); 7299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 7399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Set the config... 7499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski bm->setConfig(SkBitmap::kARGB_8888_Config, 7599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski sampler.scaledWidth(), sampler.scaledHeight(), 7699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 0, 77c250d2e4abdbe8193357696518592af8a0b4555akrajcevski ktxFile.isRGBA8()? kPremul_SkAlphaType : kOpaque_SkAlphaType); 7899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (SkImageDecoder::kDecodeBounds_Mode == mode) { 7999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return true; 8099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 8199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 8299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // If we've made it this far, then we know how to grok the data. 8399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!this->allocPixelRef(bm, NULL)) { 8499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 8599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 8699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 8799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Lock the pixels, since we're about to write to them... 8899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkAutoLockPixels alp(*bm); 8999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 9099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (ktxFile.isETC1()) { 9199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { 9299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 9399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 9499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 9599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // ETC1 Data is encoded as RGB pixels, so we should extract it as such 9699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski int nPixels = width * height; 9799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkAutoMalloc outRGBData(nPixels * 3); 9899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski etc1_byte *outRGBDataPtr = reinterpret_cast<etc1_byte *>(outRGBData.get()); 9999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 10099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Decode ETC1 10199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const etc1_byte *buf = reinterpret_cast<const etc1_byte *>(ktxFile.pixelData()); 10299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (etc1_decode_image(buf, outRGBDataPtr, width, height, 3, width*3)) { 10399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 10499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 10599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 10699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Set each of the pixels... 10799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int srcRowBytes = width * 3; 10899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int dstHeight = sampler.scaledHeight(); 10999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr); 11099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcY0() * srcRowBytes; 11199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski for (int y = 0; y < dstHeight; ++y) { 11299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski sampler.next(srcRow); 11399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcDY() * srcRowBytes; 11499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 11599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 11699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return true; 11799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 11899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } else if (ktxFile.isRGB8()) { 11999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 12099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Uncompressed RGB data (without alpha) 12199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { 12299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 12399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 12499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 12599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Just need to read RGB pixels 12699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int srcRowBytes = width * 3; 12799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int dstHeight = sampler.scaledHeight(); 12899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData()); 12999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcY0() * srcRowBytes; 13099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski for (int y = 0; y < dstHeight; ++y) { 13199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski sampler.next(srcRow); 13299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcDY() * srcRowBytes; 13399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 13499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 13599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return true; 13699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 13799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } else if (ktxFile.isRGBA8()) { 13899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 139c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // If we know that the image contains premultiplied alpha, then 140c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // don't premultiply it upon decoding. 141c250d2e4abdbe8193357696518592af8a0b4555akrajcevski bool setRequireUnpremul = false; 142c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const SkString premulKey("KTXPremultipliedAlpha"); 143c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (ktxFile.getValueForKey(premulKey) == SkString("True")) { 144c250d2e4abdbe8193357696518592af8a0b4555akrajcevski this->setRequireUnpremultipliedColors(true); 145c250d2e4abdbe8193357696518592af8a0b4555akrajcevski setRequireUnpremul = true; 146c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 147c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 14899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Uncompressed RGBA data 14999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, *this)) { 15099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 15199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 15299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 15399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Just need to read RGBA pixels 15499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int srcRowBytes = width * 4; 15599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int dstHeight = sampler.scaledHeight(); 15699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData()); 15799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcY0() * srcRowBytes; 15899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski for (int y = 0; y < dstHeight; ++y) { 15999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski sampler.next(srcRow); 16099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcDY() * srcRowBytes; 16199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 16299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 163c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Reset this in case the decoder needs to be used again. 164c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (setRequireUnpremul) { 165c250d2e4abdbe8193357696518592af8a0b4555akrajcevski this->setRequireUnpremultipliedColors(false); 166c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 167c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 16899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return true; 16999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 17099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 17199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return false; 17299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 17399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 174c250d2e4abdbe8193357696518592af8a0b4555akrajcevski/////////////////////////////////////////////////////////////////////////////// 175c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 176c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// KTX Image Encoder 177c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// 178c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// This encoder takes a best guess at how to encode the bitmap passed to it. If 179c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// there is an installed discardable pixel ref with existing PKM data, then we 180c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// will repurpose the existing ETC1 data into a KTX file. If the data contains 181c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// KTX data, then we simply return a copy of the same data. For all other files, 182c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// the underlying KTX library tries to do its best to encode the appropriate 183c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// data specified by the bitmap based on the config. (i.e. kAlpha8_Config will 184c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// be represented as a full resolution 8-bit image dump with the appropriate 185c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// OpenGL defines in the header). 186c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 187c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiclass SkKTXImageEncoder : public SkImageEncoder { 188c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiprotected: 189c250d2e4abdbe8193357696518592af8a0b4555akrajcevski virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE; 190c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 191c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiprivate: 192c250d2e4abdbe8193357696518592af8a0b4555akrajcevski virtual bool encodePKM(SkWStream* stream, const SkData *data); 193c250d2e4abdbe8193357696518592af8a0b4555akrajcevski typedef SkImageEncoder INHERITED; 194c250d2e4abdbe8193357696518592af8a0b4555akrajcevski}; 195c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 196c250d2e4abdbe8193357696518592af8a0b4555akrajcevskibool SkKTXImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int) { 197c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkAutoDataUnref data(bitmap.pixelRef()->refEncodedData()); 198c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 199c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Is this even encoded data? 200c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (NULL != data) { 201c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const uint8_t *bytes = data->bytes(); 202c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (etc1_pkm_is_valid(bytes)) { 203c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return this->encodePKM(stream, data); 204c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 205c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 206c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Is it a KTX file?? 207c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (SkKTXFile::is_ktx(bytes)) { 208c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return stream->write(bytes, data->size()); 209c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 210c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 211c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // If it's neither a KTX nor a PKM, then we need to 212c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // get at the actual pixels, so fall through and decompress... 213c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 214c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 215c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return SkKTXFile::WriteBitmapToKTX(stream, bitmap); 216c250d2e4abdbe8193357696518592af8a0b4555akrajcevski} 217c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 218c250d2e4abdbe8193357696518592af8a0b4555akrajcevskibool SkKTXImageEncoder::encodePKM(SkWStream* stream, const SkData *data) { 219c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const uint8_t* bytes = data->bytes(); 220c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkASSERT(etc1_pkm_is_valid(bytes)); 221c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 222c250d2e4abdbe8193357696518592af8a0b4555akrajcevski etc1_uint32 width = etc1_pkm_get_width(bytes); 223c250d2e4abdbe8193357696518592af8a0b4555akrajcevski etc1_uint32 height = etc1_pkm_get_height(bytes); 224c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 225c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // ETC1 Data is stored as compressed 4x4 pixel blocks, so we must make sure 226c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // that our dimensions are valid. 227c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (width == 0 || (width & 3) != 0 || height == 0 || (height & 3) != 0) { 228c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 229c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 230c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 231c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Advance pointer to etc1 data. 232c250d2e4abdbe8193357696518592af8a0b4555akrajcevski bytes += ETC_PKM_HEADER_SIZE; 233c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 234c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return SkKTXFile::WriteETC1ToKTX(stream, bytes, width, height); 235c250d2e4abdbe8193357696518592af8a0b4555akrajcevski} 236c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 23799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski///////////////////////////////////////////////////////////////////////////////////////// 23899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskiDEFINE_DECODER_CREATOR(KTXImageDecoder); 239c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiDEFINE_ENCODER_CREATOR(KTXImageEncoder); 24099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski///////////////////////////////////////////////////////////////////////////////////////// 24199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 24299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskistatic SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) { 24399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (SkKTXFile::is_ktx(stream)) { 24499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return SkNEW(SkKTXImageDecoder); 24599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 24699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return NULL; 24799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 24899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 24999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskistatic SkImageDecoder::Format get_format_ktx(SkStreamRewindable* stream) { 25099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (SkKTXFile::is_ktx(stream)) { 25199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return SkImageDecoder::kKTX_Format; 25299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 25399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return SkImageDecoder::kUnknown_Format; 25499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 25599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 256c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiSkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) { 257c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return (SkImageEncoder::kKTX_Type == t) ? SkNEW(SkKTXImageEncoder) : NULL; 258c250d2e4abdbe8193357696518592af8a0b4555akrajcevski} 259c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 260c250d2e4abdbe8193357696518592af8a0b4555akrajcevskistatic SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory); 26199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskistatic SkImageDecoder_FormatReg gFormatReg(get_format_ktx); 262c250d2e4abdbe8193357696518592af8a0b4555akrajcevskistatic SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory); 263