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