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
19 static 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
23 static const uint32_t kKTX_ENDIANNESS_CODE = 0x04030201;
24
readKeyAndValue(const uint8_t * data)25 bool 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
writeKeyAndValueForKTX(SkWStream * strm)57 bool 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
readInt(const uint8_t ** buf,size_t * bytesLeft) const93 uint32_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
getValueForKey(const SkString & key) const115 SkString 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
isETC1() const126 bool SkKTXFile::isETC1() const {
127 return this->valid() && GR_GL_COMPRESSED_RGB8_ETC1 == fHeader.fGLInternalFormat;
128 }
129
isRGBA8() const130 bool SkKTXFile::isRGBA8() const {
131 return this->valid() && GR_GL_RGBA8 == fHeader.fGLInternalFormat;
132 }
133
isRGB8() const134 bool SkKTXFile::isRGB8() const {
135 return this->valid() && GR_GL_RGB8 == fHeader.fGLInternalFormat;
136 }
137
readKTXFile(const uint8_t * data,size_t dataLen)138 bool 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
is_ktx(const uint8_t * data)280 bool SkKTXFile::is_ktx(const uint8_t *data) {
281 return 0 == memcmp(KTX_FILE_IDENTIFIER, data, KTX_FILE_IDENTIFIER_SIZE);
282 }
283
is_ktx(SkStreamRewindable * stream)284 bool 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
CreateKeyValue(const char * cstrKey,const char * cstrValue)296 SkKTXFile::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
WriteETC1ToKTX(SkWStream * stream,const uint8_t * etc1Data,uint32_t width,uint32_t height)313 bool 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
WriteBitmapToKTX(SkWStream * stream,const SkBitmap & bitmap)360 bool 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