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: 44af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; 4599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 4699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskiprivate: 4799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski typedef SkImageDecoder INHERITED; 4899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski}; 4999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 50af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins IIISkImageDecoder::Result 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) { 54af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kFailure; 5599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 5699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 5799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkKTXFile ktxFile(data); 5899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!ktxFile.valid()) { 59af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kFailure; 6099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 6199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 6299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const unsigned short width = ktxFile.width(); 6399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const unsigned short height = ktxFile.height(); 6499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 655926b86b90c68bffefbdc8639e41b5bc9102cec6reed#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER 6699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // should we allow the Chooser (if present) to pick a config for us??? 676c22573edb234ad14df947278cfed010669a39a7reed if (!this->chooseFromOneChoice(kN32_SkColorType, width, height)) { 68af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kFailure; 6999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 705926b86b90c68bffefbdc8639e41b5bc9102cec6reed#endif 7199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 723b570c6b023c5556613f435400798d5df37a78e3krajcevski // Set a flag if our source is premultiplied alpha 733b570c6b023c5556613f435400798d5df37a78e3krajcevski const SkString premulKey("KTXPremultipliedAlpha"); 743b570c6b023c5556613f435400798d5df37a78e3krajcevski const bool bSrcIsPremul = ktxFile.getValueForKey(premulKey) == SkString("True"); 753b570c6b023c5556613f435400798d5df37a78e3krajcevski 7699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Setup the sampler... 7799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); 7899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 793b570c6b023c5556613f435400798d5df37a78e3krajcevski // Determine the alpha of the bitmap... 803b570c6b023c5556613f435400798d5df37a78e3krajcevski SkAlphaType alphaType = kOpaque_SkAlphaType; 813b570c6b023c5556613f435400798d5df37a78e3krajcevski if (ktxFile.isRGBA8()) { 823b570c6b023c5556613f435400798d5df37a78e3krajcevski if (this->getRequireUnpremultipliedColors()) { 833b570c6b023c5556613f435400798d5df37a78e3krajcevski alphaType = kUnpremul_SkAlphaType; 843b570c6b023c5556613f435400798d5df37a78e3krajcevski // If the client wants unpremul colors and we only have 853b570c6b023c5556613f435400798d5df37a78e3krajcevski // premul, then we cannot honor their wish. 863b570c6b023c5556613f435400798d5df37a78e3krajcevski if (bSrcIsPremul) { 87af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kFailure; 883b570c6b023c5556613f435400798d5df37a78e3krajcevski } 893b570c6b023c5556613f435400798d5df37a78e3krajcevski } else { 903b570c6b023c5556613f435400798d5df37a78e3krajcevski alphaType = kPremul_SkAlphaType; 913b570c6b023c5556613f435400798d5df37a78e3krajcevski } 923b570c6b023c5556613f435400798d5df37a78e3krajcevski } 933b570c6b023c5556613f435400798d5df37a78e3krajcevski 9499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Set the config... 953b570c6b023c5556613f435400798d5df37a78e3krajcevski bm->setInfo(SkImageInfo::MakeN32(sampler.scaledWidth(), sampler.scaledHeight(), alphaType)); 9699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (SkImageDecoder::kDecodeBounds_Mode == mode) { 97af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kSuccess; 9899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 9999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 10099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // If we've made it this far, then we know how to grok the data. 10199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!this->allocPixelRef(bm, NULL)) { 102af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kFailure; 10399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 10499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 10599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Lock the pixels, since we're about to write to them... 10699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkAutoLockPixels alp(*bm); 10799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 10899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (ktxFile.isETC1()) { 10999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { 110af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kFailure; 11199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 11299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 11399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // ETC1 Data is encoded as RGB pixels, so we should extract it as such 11499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski int nPixels = width * height; 11599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski SkAutoMalloc outRGBData(nPixels * 3); 11699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski etc1_byte *outRGBDataPtr = reinterpret_cast<etc1_byte *>(outRGBData.get()); 11799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 11899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Decode ETC1 11999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const etc1_byte *buf = reinterpret_cast<const etc1_byte *>(ktxFile.pixelData()); 12099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (etc1_decode_image(buf, outRGBDataPtr, width, height, 3, width*3)) { 121af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kFailure; 12299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 12399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 12499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Set each of the pixels... 12599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int srcRowBytes = width * 3; 12699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int dstHeight = sampler.scaledHeight(); 12799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr); 12899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcY0() * srcRowBytes; 12999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski for (int y = 0; y < dstHeight; ++y) { 13099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski sampler.next(srcRow); 13199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcDY() * srcRowBytes; 13299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 13399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 134af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kSuccess; 13599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 13699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } else if (ktxFile.isRGB8()) { 13799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 13899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Uncompressed RGB data (without alpha) 13999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { 140af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kFailure; 14199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 14299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 14399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Just need to read RGB pixels 14499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int srcRowBytes = width * 3; 14599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int dstHeight = sampler.scaledHeight(); 14699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData()); 14799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcY0() * srcRowBytes; 14899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski for (int y = 0; y < dstHeight; ++y) { 14999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski sampler.next(srcRow); 15099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcDY() * srcRowBytes; 15199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 15299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 153af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kSuccess; 15499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 15599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } else if (ktxFile.isRGBA8()) { 15699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 1573b570c6b023c5556613f435400798d5df37a78e3krajcevski // Uncompressed RGBA data 1583b570c6b023c5556613f435400798d5df37a78e3krajcevski 159c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // If we know that the image contains premultiplied alpha, then 1603b570c6b023c5556613f435400798d5df37a78e3krajcevski // we need to turn off the premultiplier 1613b570c6b023c5556613f435400798d5df37a78e3krajcevski SkScaledBitmapSampler::Options opts (*this); 1623b570c6b023c5556613f435400798d5df37a78e3krajcevski if (bSrcIsPremul) { 1633b570c6b023c5556613f435400798d5df37a78e3krajcevski SkASSERT(bm->alphaType() == kPremul_SkAlphaType); 1643b570c6b023c5556613f435400798d5df37a78e3krajcevski SkASSERT(!this->getRequireUnpremultipliedColors()); 165c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 1663b570c6b023c5556613f435400798d5df37a78e3krajcevski opts.fPremultiplyAlpha = false; 1673b570c6b023c5556613f435400798d5df37a78e3krajcevski } 1683b570c6b023c5556613f435400798d5df37a78e3krajcevski 1693b570c6b023c5556613f435400798d5df37a78e3krajcevski if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, opts)) { 170af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kFailure; 17199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 17299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 17399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski // Just need to read RGBA pixels 17499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int srcRowBytes = width * 4; 17599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const int dstHeight = sampler.scaledHeight(); 17699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData()); 17799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcY0() * srcRowBytes; 17899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski for (int y = 0; y < dstHeight; ++y) { 17999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski sampler.next(srcRow); 18099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski srcRow += sampler.srcDY() * srcRowBytes; 18199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 18299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 183af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kSuccess; 18499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 18599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 186af1d4f84b8730781cc6dca61748cae66c237ca57Leon Scroggins III return kFailure; 18799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 18899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 189c250d2e4abdbe8193357696518592af8a0b4555akrajcevski/////////////////////////////////////////////////////////////////////////////// 190c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 191c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// KTX Image Encoder 192c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// 193c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// This encoder takes a best guess at how to encode the bitmap passed to it. If 194c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// there is an installed discardable pixel ref with existing PKM data, then we 195c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// will repurpose the existing ETC1 data into a KTX file. If the data contains 196c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// KTX data, then we simply return a copy of the same data. For all other files, 197c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// the underlying KTX library tries to do its best to encode the appropriate 198c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// data specified by the bitmap based on the config. (i.e. kAlpha8_Config will 199c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// be represented as a full resolution 8-bit image dump with the appropriate 200c250d2e4abdbe8193357696518592af8a0b4555akrajcevski// OpenGL defines in the header). 201c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 202c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiclass SkKTXImageEncoder : public SkImageEncoder { 203c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiprotected: 204c250d2e4abdbe8193357696518592af8a0b4555akrajcevski virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE; 205c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 206c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiprivate: 207c250d2e4abdbe8193357696518592af8a0b4555akrajcevski virtual bool encodePKM(SkWStream* stream, const SkData *data); 208c250d2e4abdbe8193357696518592af8a0b4555akrajcevski typedef SkImageEncoder INHERITED; 209c250d2e4abdbe8193357696518592af8a0b4555akrajcevski}; 210c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 211c250d2e4abdbe8193357696518592af8a0b4555akrajcevskibool SkKTXImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int) { 212c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkAutoDataUnref data(bitmap.pixelRef()->refEncodedData()); 213c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 214c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Is this even encoded data? 215c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (NULL != data) { 216c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const uint8_t *bytes = data->bytes(); 217c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (etc1_pkm_is_valid(bytes)) { 218c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return this->encodePKM(stream, data); 219c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 220c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 221c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Is it a KTX file?? 222c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (SkKTXFile::is_ktx(bytes)) { 223c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return stream->write(bytes, data->size()); 224c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 225c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 226c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // If it's neither a KTX nor a PKM, then we need to 227c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // get at the actual pixels, so fall through and decompress... 228c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 229c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 230c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return SkKTXFile::WriteBitmapToKTX(stream, bitmap); 231c250d2e4abdbe8193357696518592af8a0b4555akrajcevski} 232c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 233c250d2e4abdbe8193357696518592af8a0b4555akrajcevskibool SkKTXImageEncoder::encodePKM(SkWStream* stream, const SkData *data) { 234c250d2e4abdbe8193357696518592af8a0b4555akrajcevski const uint8_t* bytes = data->bytes(); 235c250d2e4abdbe8193357696518592af8a0b4555akrajcevski SkASSERT(etc1_pkm_is_valid(bytes)); 236c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 237c250d2e4abdbe8193357696518592af8a0b4555akrajcevski etc1_uint32 width = etc1_pkm_get_width(bytes); 238c250d2e4abdbe8193357696518592af8a0b4555akrajcevski etc1_uint32 height = etc1_pkm_get_height(bytes); 239c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 240c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // ETC1 Data is stored as compressed 4x4 pixel blocks, so we must make sure 241c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // that our dimensions are valid. 242c250d2e4abdbe8193357696518592af8a0b4555akrajcevski if (width == 0 || (width & 3) != 0 || height == 0 || (height & 3) != 0) { 243c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return false; 244c250d2e4abdbe8193357696518592af8a0b4555akrajcevski } 245c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 246c250d2e4abdbe8193357696518592af8a0b4555akrajcevski // Advance pointer to etc1 data. 247c250d2e4abdbe8193357696518592af8a0b4555akrajcevski bytes += ETC_PKM_HEADER_SIZE; 248c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 249c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return SkKTXFile::WriteETC1ToKTX(stream, bytes, width, height); 250c250d2e4abdbe8193357696518592af8a0b4555akrajcevski} 251c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 25299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski///////////////////////////////////////////////////////////////////////////////////////// 25399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskiDEFINE_DECODER_CREATOR(KTXImageDecoder); 254c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiDEFINE_ENCODER_CREATOR(KTXImageEncoder); 25599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski///////////////////////////////////////////////////////////////////////////////////////// 25699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 25799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskistatic SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) { 25899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (SkKTXFile::is_ktx(stream)) { 25999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return SkNEW(SkKTXImageDecoder); 26099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 26199ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return NULL; 26299ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 26399ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 26499ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskistatic SkImageDecoder::Format get_format_ktx(SkStreamRewindable* stream) { 26599ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski if (SkKTXFile::is_ktx(stream)) { 26699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return SkImageDecoder::kKTX_Format; 26799ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski } 26899ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski return SkImageDecoder::kUnknown_Format; 26999ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski} 27099ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevski 271c250d2e4abdbe8193357696518592af8a0b4555akrajcevskiSkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) { 272c250d2e4abdbe8193357696518592af8a0b4555akrajcevski return (SkImageEncoder::kKTX_Type == t) ? SkNEW(SkKTXImageEncoder) : NULL; 273c250d2e4abdbe8193357696518592af8a0b4555akrajcevski} 274c250d2e4abdbe8193357696518592af8a0b4555akrajcevski 275c250d2e4abdbe8193357696518592af8a0b4555akrajcevskistatic SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory); 27699ffe24200d8940ceba20f6fbf8c460f994d3cd1krajcevskistatic SkImageDecoder_FormatReg gFormatReg(get_format_ktx); 277c250d2e4abdbe8193357696518592af8a0b4555akrajcevskistatic SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory); 278