bool SkKTXFile::WriteBitmapToKTX(SkWStream* stream, const SkBitmap& bitmap) { const SkColorType ct = bitmap.colorType(); SkAutoLockPixels alp(bitmap); const int width = bitmap.width(); const int height = bitmap.width(); const uint8_t* src = reinterpret_cast<uint8_t*>(bitmap.getPixels()); if (NULL == bitmap.getPixels()) { return false; } // First thing's first, write out the magic identifier and endianness... if (!stream->write(KTX_FILE_IDENTIFIER, KTX_FILE_IDENTIFIER_SIZE) || !stream->write(&kKTX_ENDIANNESS_CODE, 4)) { return false; } // Collect our key/value pairs... SkTArray<KeyValue> kvPairs; // Next, write the header based on the bitmap's config. Header hdr; switch (ct) { case kIndex_8_SkColorType: // There is a compressed format for this, but we don't support it yet. SkDebugf("Writing indexed bitmap to KTX unsupported.\n"); // VVV fall through VVV default: case kUnknown_SkColorType: // Bitmap hasn't been configured. return false; case kAlpha_8_SkColorType: hdr.fGLType = GR_GL_UNSIGNED_BYTE; hdr.fGLTypeSize = 1; hdr.fGLFormat = GR_GL_RED; hdr.fGLInternalFormat = GR_GL_R8; hdr.fGLBaseInternalFormat = GR_GL_RED; break; case kRGB_565_SkColorType: hdr.fGLType = GR_GL_UNSIGNED_SHORT_5_6_5; hdr.fGLTypeSize = 2; hdr.fGLFormat = GR_GL_RGB; hdr.fGLInternalFormat = GR_GL_RGB; hdr.fGLBaseInternalFormat = GR_GL_RGB; break; case kARGB_4444_SkColorType: hdr.fGLType = GR_GL_UNSIGNED_SHORT_4_4_4_4; hdr.fGLTypeSize = 2; hdr.fGLFormat = GR_GL_RGBA; hdr.fGLInternalFormat = GR_GL_RGBA4; hdr.fGLBaseInternalFormat = GR_GL_RGBA; kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True")); break; case kN32_SkColorType: hdr.fGLType = GR_GL_UNSIGNED_BYTE; hdr.fGLTypeSize = 1; hdr.fGLFormat = GR_GL_RGBA; hdr.fGLInternalFormat = GR_GL_RGBA8; hdr.fGLBaseInternalFormat = GR_GL_RGBA; kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True")); break; } // Everything else in the header is shared. hdr.fPixelWidth = width; hdr.fPixelHeight = height; hdr.fNumberOfArrayElements = 0; hdr.fNumberOfFaces = 1; hdr.fNumberOfMipmapLevels = 1; // Calculate the key value data size hdr.fBytesOfKeyValueData = 0; for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) { // Key value size is the size of the key value data, // four bytes for saying how big the key value size is // and then additional bytes for padding to four byte boundary size_t kvsize = kv->size(); kvsize += 4; kvsize = (kvsize + 3) & ~3; hdr.fBytesOfKeyValueData = SkToU32(hdr.fBytesOfKeyValueData + kvsize); } // Write the header if (!stream->write(&hdr, sizeof(hdr))) { return false; } // Write out each key value pair for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) { if (!kv->writeKeyAndValueForKTX(stream)) { return false; } } // Calculate the size of the data int bpp = bitmap.bytesPerPixel(); uint32_t dataSz = bpp * width * height; if (0 >= bpp) { return false; } // Write it into the buffer if (!stream->write(&dataSz, 4)) { return false; } // Write the pixel data... const uint8_t* rowPtr = src; if (kN32_SkColorType == ct) { for (int j = 0; j < height; ++j) { const uint32_t* pixelsPtr = reinterpret_cast<const uint32_t*>(rowPtr); for (int i = 0; i < width; ++i) { uint32_t pixel = pixelsPtr[i]; uint8_t dstPixel[4]; dstPixel[0] = pixel >> SK_R32_SHIFT; dstPixel[1] = pixel >> SK_G32_SHIFT; dstPixel[2] = pixel >> SK_B32_SHIFT; dstPixel[3] = pixel >> SK_A32_SHIFT; if (!stream->write(dstPixel, 4)) { return false; } } rowPtr += bitmap.rowBytes(); } } else { for (int i = 0; i < height; ++i) {