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