1
2/*
3 * Copyright 2014 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "ktx.h"
10#include "SkBitmap.h"
11#include "SkStream.h"
12#include "SkEndian.h"
13
14#include "gl/GrGLDefines.h"
15
16#include "etc1.h"
17
18#define KTX_FILE_IDENTIFIER_SIZE 12
19static const uint8_t KTX_FILE_IDENTIFIER[KTX_FILE_IDENTIFIER_SIZE] = {
20    0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
21};
22
23static const uint32_t kKTX_ENDIANNESS_CODE = 0x04030201;
24
25bool SkKTXFile::KeyValue::readKeyAndValue(const uint8_t* data) {
26    const char *key = reinterpret_cast<const char *>(data);
27    const char *value = key;
28
29    size_t bytesRead = 0;
30    while (*value != '\0' && bytesRead < this->fDataSz) {
31        ++bytesRead;
32        ++value;
33    }
34
35    // Error of some sort..
36    if (bytesRead >= this->fDataSz) {
37        return false;
38    }
39
40    // Read the zero terminator
41    ++bytesRead;
42    ++value;
43
44    size_t bytesLeft = this->fDataSz - bytesRead;
45
46    // We ignore the null terminator when setting the string value.
47    this->fKey.set(key, bytesRead - 1);
48    if (bytesLeft > 0) {
49        this->fValue.set(value, bytesLeft - 1);
50    } else {
51        return false;
52    }
53
54    return true;
55}
56
57bool SkKTXFile::KeyValue::writeKeyAndValueForKTX(SkWStream* strm) {
58    size_t bytesWritten = 0;
59    if (!strm->write(&(this->fDataSz), 4)) {
60        return false;
61    }
62
63    bytesWritten += 4;
64
65    // Here we know that C-strings must end with a null terminating
66    // character, so when we get a c_str(), it will have as many
67    // bytes of data as size() returns plus a zero, so we just
68    // write size() + 1 bytes into the stream.
69
70    size_t keySize = this->fKey.size() + 1;
71    if (!strm->write(this->fKey.c_str(), keySize)) {
72        return false;
73    }
74
75    bytesWritten += keySize;
76
77    size_t valueSize = this->fValue.size() + 1;
78    if (!strm->write(this->fValue.c_str(), valueSize)) {
79        return false;
80    }
81
82    bytesWritten += valueSize;
83
84    size_t bytesWrittenPadFour = (bytesWritten + 3) & ~3;
85    uint8_t nullBuf[4] = { 0, 0, 0, 0 };
86
87    size_t padding = bytesWrittenPadFour - bytesWritten;
88    SkASSERT(padding < 4);
89
90    return strm->write(nullBuf, padding);
91}
92
93uint32_t SkKTXFile::readInt(const uint8_t** buf, size_t* bytesLeft) const {
94    SkASSERT(NULL != buf && NULL != bytesLeft);
95
96    uint32_t result;
97
98    if (*bytesLeft < 4) {
99        SkASSERT(false);
100        return 0;
101    }
102
103    memcpy(&result, *buf, 4);
104    *buf += 4;
105
106    if (fSwapBytes) {
107        SkEndianSwap32(result);
108    }
109
110    *bytesLeft -= 4;
111
112    return result;
113}
114
115SkString SkKTXFile::getValueForKey(const SkString& key) const {
116    const KeyValue *begin = this->fKeyValuePairs.begin();
117    const KeyValue *end = this->fKeyValuePairs.end();
118    for (const KeyValue *kv = begin; kv != end; ++kv) {
119        if (kv->key() == key) {
120            return kv->value();
121        }
122    }
123    return SkString();
124}
125
126bool SkKTXFile::isETC1() const {
127    return this->valid() && GR_GL_COMPRESSED_RGB8_ETC1 == fHeader.fGLInternalFormat;
128}
129
130bool SkKTXFile::isRGBA8() const {
131    return this->valid() && GR_GL_RGBA8 == fHeader.fGLInternalFormat;
132}
133
134bool SkKTXFile::isRGB8() const {
135    return this->valid() && GR_GL_RGB8 == fHeader.fGLInternalFormat;
136}
137
138bool SkKTXFile::readKTXFile(const uint8_t* data, size_t dataLen) {
139    const uint8_t *buf = data;
140    size_t bytesLeft = dataLen;
141
142    // Make sure original KTX header is there... this should have been checked
143    // already by a call to is_ktx()
144    SkASSERT(bytesLeft > KTX_FILE_IDENTIFIER_SIZE);
145    SkASSERT(0 == memcmp(KTX_FILE_IDENTIFIER, buf, KTX_FILE_IDENTIFIER_SIZE));
146    buf += KTX_FILE_IDENTIFIER_SIZE;
147    bytesLeft -= KTX_FILE_IDENTIFIER_SIZE;
148
149    // Read header, but first make sure that we have the proper space: we need
150    // two 32-bit ints: 1 for endianness, and another for the mandatory image
151    // size after the header.
152    if (bytesLeft < 8 + sizeof(Header)) {
153        return false;
154    }
155
156    uint32_t endianness = this->readInt(&buf, &bytesLeft);
157    fSwapBytes = kKTX_ENDIANNESS_CODE != endianness;
158
159    // Read header values
160    fHeader.fGLType                = this->readInt(&buf, &bytesLeft);
161    fHeader.fGLTypeSize            = this->readInt(&buf, &bytesLeft);
162    fHeader.fGLFormat              = this->readInt(&buf, &bytesLeft);
163    fHeader.fGLInternalFormat      = this->readInt(&buf, &bytesLeft);
164    fHeader.fGLBaseInternalFormat  = this->readInt(&buf, &bytesLeft);
165    fHeader.fPixelWidth            = this->readInt(&buf, &bytesLeft);
166    fHeader.fPixelHeight           = this->readInt(&buf, &bytesLeft);
167    fHeader.fPixelDepth            = this->readInt(&buf, &bytesLeft);
168    fHeader.fNumberOfArrayElements = this->readInt(&buf, &bytesLeft);
169    fHeader.fNumberOfFaces         = this->readInt(&buf, &bytesLeft);
170    fHeader.fNumberOfMipmapLevels  = this->readInt(&buf, &bytesLeft);
171    fHeader.fBytesOfKeyValueData   = this->readInt(&buf, &bytesLeft);
172
173    // Check for things that we understand...
174    {
175        // First, we only support compressed formats and single byte
176        // representations at the moment. If the internal format is
177        // compressed, the the GLType field in the header must be zero.
178        // In the future, we may support additional data types (such
179        // as GL_UNSIGNED_SHORT_5_6_5)
180        if (fHeader.fGLType != 0 && fHeader.fGLType != GR_GL_UNSIGNED_BYTE) {
181            return false;
182        }
183
184        // This means that for well-formatted KTX files, the glTypeSize
185        // field must be one...
186        if (fHeader.fGLTypeSize != 1) {
187            return false;
188        }
189
190        // We don't support 3D textures.
191        if (fHeader.fPixelDepth > 1) {
192            return false;
193        }
194
195        // We don't support texture arrays
196        if (fHeader.fNumberOfArrayElements > 1) {
197            return false;
198        }
199
200        // We don't support cube maps
201        if (fHeader.fNumberOfFaces > 1) {
202            return false;
203        }
204    }
205
206    // Make sure that we have enough bytes left for the key/value
207    // data according to what was said in the header.
208    if (bytesLeft < fHeader.fBytesOfKeyValueData) {
209        return false;
210    }
211
212    // Next read the key value pairs
213    size_t keyValueBytesRead = 0;
214    while (keyValueBytesRead < fHeader.fBytesOfKeyValueData) {
215        uint32_t keyValueBytes = this->readInt(&buf, &bytesLeft);
216        keyValueBytesRead += 4;
217
218        if (keyValueBytes > bytesLeft) {
219            return false;
220        }
221
222        KeyValue kv(keyValueBytes);
223        if (!kv.readKeyAndValue(buf)) {
224            return false;
225        }
226
227        fKeyValuePairs.push_back(kv);
228
229        uint32_t keyValueBytesPadded = (keyValueBytes + 3) & ~3;
230        buf += keyValueBytesPadded;
231        keyValueBytesRead += keyValueBytesPadded;
232        bytesLeft -= keyValueBytesPadded;
233    }
234
235    // Read the pixel data...
236    int mipmaps = SkMax32(fHeader.fNumberOfMipmapLevels, 1);
237    SkASSERT(mipmaps == 1);
238
239    int arrayElements = SkMax32(fHeader.fNumberOfArrayElements, 1);
240    SkASSERT(arrayElements == 1);
241
242    int faces = SkMax32(fHeader.fNumberOfFaces, 1);
243    SkASSERT(faces == 1);
244
245    int depth = SkMax32(fHeader.fPixelDepth, 1);
246    SkASSERT(depth == 1);
247
248    for (int mipmap = 0; mipmap < mipmaps; ++mipmap) {
249        // Make sure that we have at least 4 more bytes for the first image size
250        if (bytesLeft < 4) {
251            return false;
252        }
253
254        uint32_t imgSize = this->readInt(&buf, &bytesLeft);
255
256        // Truncated file.
257        if (bytesLeft < imgSize) {
258            return false;
259        }
260
261        // !FIXME! If support is ever added for cube maps then the padding
262        // needs to be taken into account here.
263        for (int arrayElement = 0; arrayElement < arrayElements; ++arrayElement) {
264            for (int face = 0; face < faces; ++face) {
265                for (int z = 0; z < depth; ++z) {
266                    PixelData pd(buf, imgSize);
267                    fPixelData.append(1, &pd);
268                }
269            }
270        }
271
272        uint32_t imgSizePadded = (imgSize + 3) & ~3;
273        buf += imgSizePadded;
274        bytesLeft -= imgSizePadded;
275    }
276
277    return bytesLeft == 0;
278}
279
280bool SkKTXFile::is_ktx(const uint8_t *data) {
281    return 0 == memcmp(KTX_FILE_IDENTIFIER, data, KTX_FILE_IDENTIFIER_SIZE);
282}
283
284bool SkKTXFile::is_ktx(SkStreamRewindable* stream) {
285    // Read the KTX header and make sure it's valid.
286    unsigned char buf[KTX_FILE_IDENTIFIER_SIZE];
287    bool largeEnough =
288        stream->read((void*)buf, KTX_FILE_IDENTIFIER_SIZE) == KTX_FILE_IDENTIFIER_SIZE;
289    stream->rewind();
290    if (!largeEnough) {
291        return false;
292    }
293    return is_ktx(buf);
294}
295
296SkKTXFile::KeyValue SkKTXFile::CreateKeyValue(const char *cstrKey, const char *cstrValue) {
297    SkString key(cstrKey);
298    SkString value(cstrValue);
299
300    // Size of buffer is length of string plus the null terminators...
301    size_t size = key.size() + 1 + value.size() + 1;
302
303    SkAutoSMalloc<256> buf(size);
304    uint8_t* kvBuf = reinterpret_cast<uint8_t*>(buf.get());
305    memcpy(kvBuf, key.c_str(), key.size() + 1);
306    memcpy(kvBuf + key.size() + 1, value.c_str(), value.size() + 1);
307
308    KeyValue kv(size);
309    SkAssertResult(kv.readKeyAndValue(kvBuf));
310    return kv;
311}
312
313bool SkKTXFile::WriteETC1ToKTX(SkWStream* stream, const uint8_t *etc1Data,
314                               uint32_t width, uint32_t height) {
315    // First thing's first, write out the magic identifier and endianness...
316    if (!stream->write(KTX_FILE_IDENTIFIER, KTX_FILE_IDENTIFIER_SIZE)) {
317        return false;
318    }
319
320    if (!stream->write(&kKTX_ENDIANNESS_CODE, 4)) {
321        return false;
322    }
323
324    Header hdr;
325    hdr.fGLType = 0;
326    hdr.fGLTypeSize = 1;
327    hdr.fGLFormat = 0;
328    hdr.fGLInternalFormat = GR_GL_COMPRESSED_RGB8_ETC1;
329    hdr.fGLBaseInternalFormat = GR_GL_RGB;
330    hdr.fPixelWidth = width;
331    hdr.fPixelHeight = height;
332    hdr.fNumberOfArrayElements = 0;
333    hdr.fNumberOfFaces = 1;
334    hdr.fNumberOfMipmapLevels = 1;
335
336    // !FIXME! The spec suggests that we put KTXOrientation as a
337    // key value pair in the header, but that means that we'd have to
338    // pipe through the bitmap's orientation to properly do that.
339    hdr.fBytesOfKeyValueData = 0;
340
341    // Write the header
342    if (!stream->write(&hdr, sizeof(hdr))) {
343        return false;
344    }
345
346    // Write the size of the image data
347    etc1_uint32 dataSize = etc1_get_encoded_data_size(width, height);
348    if (!stream->write(&dataSize, 4)) {
349        return false;
350    }
351
352    // Write the actual image data
353    if (!stream->write(etc1Data, dataSize)) {
354        return false;
355    }
356
357    return true;
358}
359
360bool SkKTXFile::WriteBitmapToKTX(SkWStream* stream, const SkBitmap& bitmap) {
361    const SkColorType ct = bitmap.colorType();
362    SkAutoLockPixels alp(bitmap);
363
364    const int width = bitmap.width();
365    const int height = bitmap.width();
366    const uint8_t* src = reinterpret_cast<uint8_t*>(bitmap.getPixels());
367    if (NULL == bitmap.getPixels()) {
368        return false;
369    }
370
371    // First thing's first, write out the magic identifier and endianness...
372    if (!stream->write(KTX_FILE_IDENTIFIER, KTX_FILE_IDENTIFIER_SIZE) ||
373        !stream->write(&kKTX_ENDIANNESS_CODE, 4)) {
374        return false;
375    }
376
377    // Collect our key/value pairs...
378    SkTArray<KeyValue> kvPairs;
379
380    // Next, write the header based on the bitmap's config.
381    Header hdr;
382    switch (ct) {
383        case kIndex_8_SkColorType:
384            // There is a compressed format for this, but we don't support it yet.
385            SkDebugf("Writing indexed bitmap to KTX unsupported.\n");
386            // VVV fall through VVV
387        default:
388        case kUnknown_SkColorType:
389            // Bitmap hasn't been configured.
390            return false;
391
392        case kAlpha_8_SkColorType:
393            hdr.fGLType = GR_GL_UNSIGNED_BYTE;
394            hdr.fGLTypeSize = 1;
395            hdr.fGLFormat = GR_GL_RED;
396            hdr.fGLInternalFormat = GR_GL_R8;
397            hdr.fGLBaseInternalFormat = GR_GL_RED;
398            break;
399
400        case kRGB_565_SkColorType:
401            hdr.fGLType = GR_GL_UNSIGNED_SHORT_5_6_5;
402            hdr.fGLTypeSize = 2;
403            hdr.fGLFormat = GR_GL_RGB;
404            hdr.fGLInternalFormat = GR_GL_RGB;
405            hdr.fGLBaseInternalFormat = GR_GL_RGB;
406            break;
407
408        case kARGB_4444_SkColorType:
409            hdr.fGLType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
410            hdr.fGLTypeSize = 2;
411            hdr.fGLFormat = GR_GL_RGBA;
412            hdr.fGLInternalFormat = GR_GL_RGBA4;
413            hdr.fGLBaseInternalFormat = GR_GL_RGBA;
414            kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True"));
415            break;
416
417        case kN32_SkColorType:
418            hdr.fGLType = GR_GL_UNSIGNED_BYTE;
419            hdr.fGLTypeSize = 1;
420            hdr.fGLFormat = GR_GL_RGBA;
421            hdr.fGLInternalFormat = GR_GL_RGBA8;
422            hdr.fGLBaseInternalFormat = GR_GL_RGBA;
423            kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True"));
424            break;
425    }
426
427    // Everything else in the header is shared.
428    hdr.fPixelWidth = width;
429    hdr.fPixelHeight = height;
430    hdr.fNumberOfArrayElements = 0;
431    hdr.fNumberOfFaces = 1;
432    hdr.fNumberOfMipmapLevels = 1;
433
434    // Calculate the key value data size
435    hdr.fBytesOfKeyValueData = 0;
436    for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) {
437        // Key value size is the size of the key value data,
438        // four bytes for saying how big the key value size is
439        // and then additional bytes for padding to four byte boundary
440        size_t kvsize = kv->size();
441        kvsize += 4;
442        kvsize = (kvsize + 3) & ~3;
443        hdr.fBytesOfKeyValueData += kvsize;
444    }
445
446    // Write the header
447    if (!stream->write(&hdr, sizeof(hdr))) {
448        return false;
449    }
450
451    // Write out each key value pair
452    for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) {
453        if (!kv->writeKeyAndValueForKTX(stream)) {
454            return false;
455        }
456    }
457
458    // Calculate the size of the data
459    int bpp = bitmap.bytesPerPixel();
460    uint32_t dataSz = bpp * width * height;
461
462    if (0 >= bpp) {
463        return false;
464    }
465
466    // Write it into the buffer
467    if (!stream->write(&dataSz, 4)) {
468        return false;
469    }
470
471    // Write the pixel data...
472    const uint8_t* rowPtr = src;
473    if (kN32_SkColorType == ct) {
474        for (int j = 0; j < height; ++j) {
475            const uint32_t* pixelsPtr = reinterpret_cast<const uint32_t*>(rowPtr);
476            for (int i = 0; i < width; ++i) {
477                uint32_t pixel = pixelsPtr[i];
478                uint8_t dstPixel[4];
479                dstPixel[0] = pixel >> SK_R32_SHIFT;
480                dstPixel[1] = pixel >> SK_G32_SHIFT;
481                dstPixel[2] = pixel >> SK_B32_SHIFT;
482                dstPixel[3] = pixel >> SK_A32_SHIFT;
483                if (!stream->write(dstPixel, 4)) {
484                    return false;
485                }
486            }
487            rowPtr += bitmap.rowBytes();
488        }
489    } else {
490        for (int i = 0; i < height; ++i) {
491            if (!stream->write(rowPtr, bpp*width)) {
492                return false;
493            }
494            rowPtr += bitmap.rowBytes();
495        }
496    }
497
498    return true;
499}
500