| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkColorPriv.h" | 8 #include "SkColorPriv.h" |
| 9 #include "SkImageDecoder.h" | 9 #include "SkImageDecoder.h" |
| 10 #include "SkPixelRef.h" | 10 #include "SkPixelRef.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 | 34 |
| 35 class SkKTXImageDecoder : public SkImageDecoder { | 35 class SkKTXImageDecoder : public SkImageDecoder { |
| 36 public: | 36 public: |
| 37 SkKTXImageDecoder() { } | 37 SkKTXImageDecoder() { } |
| 38 | 38 |
| 39 virtual Format getFormat() const SK_OVERRIDE { | 39 virtual Format getFormat() const SK_OVERRIDE { |
| 40 return kKTX_Format; | 40 return kKTX_Format; |
| 41 } | 41 } |
| 42 | 42 |
| 43 protected: | 43 protected: |
| 44 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; | 44 virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; |
| 45 | 45 |
| 46 private: | 46 private: |
| 47 typedef SkImageDecoder INHERITED; | 47 typedef SkImageDecoder INHERITED; |
| 48 }; | 48 }; |
| 49 | 49 |
| 50 bool SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { | 50 SkImageDecoder::Result SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* b
m, Mode mode) { |
| 51 // TODO: Implement SkStream::copyToData() that's cheap for memory and file s
treams | 51 // TODO: Implement SkStream::copyToData() that's cheap for memory and file s
treams |
| 52 SkAutoDataUnref data(SkCopyStreamToData(stream)); | 52 SkAutoDataUnref data(SkCopyStreamToData(stream)); |
| 53 if (NULL == data) { | 53 if (NULL == data) { |
| 54 return false; | 54 return kFailure; |
| 55 } | 55 } |
| 56 | 56 |
| 57 SkKTXFile ktxFile(data); | 57 SkKTXFile ktxFile(data); |
| 58 if (!ktxFile.valid()) { | 58 if (!ktxFile.valid()) { |
| 59 return false; | 59 return kFailure; |
| 60 } | 60 } |
| 61 | 61 |
| 62 const unsigned short width = ktxFile.width(); | 62 const unsigned short width = ktxFile.width(); |
| 63 const unsigned short height = ktxFile.height(); | 63 const unsigned short height = ktxFile.height(); |
| 64 | 64 |
| 65 #ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER | 65 #ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER |
| 66 // should we allow the Chooser (if present) to pick a config for us??? | 66 // should we allow the Chooser (if present) to pick a config for us??? |
| 67 if (!this->chooseFromOneChoice(kN32_SkColorType, width, height)) { | 67 if (!this->chooseFromOneChoice(kN32_SkColorType, width, height)) { |
| 68 return false; | 68 return kFailure; |
| 69 } | 69 } |
| 70 #endif | 70 #endif |
| 71 | 71 |
| 72 // Set a flag if our source is premultiplied alpha | 72 // Set a flag if our source is premultiplied alpha |
| 73 const SkString premulKey("KTXPremultipliedAlpha"); | 73 const SkString premulKey("KTXPremultipliedAlpha"); |
| 74 const bool bSrcIsPremul = ktxFile.getValueForKey(premulKey) == SkString("Tru
e"); | 74 const bool bSrcIsPremul = ktxFile.getValueForKey(premulKey) == SkString("Tru
e"); |
| 75 | 75 |
| 76 // Setup the sampler... | 76 // Setup the sampler... |
| 77 SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); | 77 SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); |
| 78 | 78 |
| 79 // Determine the alpha of the bitmap... | 79 // Determine the alpha of the bitmap... |
| 80 SkAlphaType alphaType = kOpaque_SkAlphaType; | 80 SkAlphaType alphaType = kOpaque_SkAlphaType; |
| 81 if (ktxFile.isRGBA8()) { | 81 if (ktxFile.isRGBA8()) { |
| 82 if (this->getRequireUnpremultipliedColors()) { | 82 if (this->getRequireUnpremultipliedColors()) { |
| 83 alphaType = kUnpremul_SkAlphaType; | 83 alphaType = kUnpremul_SkAlphaType; |
| 84 // If the client wants unpremul colors and we only have | 84 // If the client wants unpremul colors and we only have |
| 85 // premul, then we cannot honor their wish. | 85 // premul, then we cannot honor their wish. |
| 86 if (bSrcIsPremul) { | 86 if (bSrcIsPremul) { |
| 87 return false; | 87 return kFailure; |
| 88 } | 88 } |
| 89 } else { | 89 } else { |
| 90 alphaType = kPremul_SkAlphaType; | 90 alphaType = kPremul_SkAlphaType; |
| 91 } | 91 } |
| 92 } | 92 } |
| 93 | 93 |
| 94 // Search through the compressed formats to see if the KTX file is holding | 94 // Search through the compressed formats to see if the KTX file is holding |
| 95 // compressed data | 95 // compressed data |
| 96 bool ktxIsCompressed = false; | 96 bool ktxIsCompressed = false; |
| 97 SkTextureCompressor::Format ktxCompressedFormat; | 97 SkTextureCompressor::Format ktxCompressedFormat; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 114 const int w = sampler.scaledWidth(); | 114 const int w = sampler.scaledWidth(); |
| 115 const int h = sampler.scaledHeight(); | 115 const int h = sampler.scaledHeight(); |
| 116 bm->setInfo(SkImageInfo::MakeA8(w, h)); | 116 bm->setInfo(SkImageInfo::MakeA8(w, h)); |
| 117 } else { | 117 } else { |
| 118 const int w = sampler.scaledWidth(); | 118 const int w = sampler.scaledWidth(); |
| 119 const int h = sampler.scaledHeight(); | 119 const int h = sampler.scaledHeight(); |
| 120 bm->setInfo(SkImageInfo::MakeN32(w, h, alphaType)); | 120 bm->setInfo(SkImageInfo::MakeN32(w, h, alphaType)); |
| 121 } | 121 } |
| 122 | 122 |
| 123 if (SkImageDecoder::kDecodeBounds_Mode == mode) { | 123 if (SkImageDecoder::kDecodeBounds_Mode == mode) { |
| 124 return true; | 124 return kSuccess; |
| 125 } | 125 } |
| 126 | 126 |
| 127 // If we've made it this far, then we know how to grok the data. | 127 // If we've made it this far, then we know how to grok the data. |
| 128 if (!this->allocPixelRef(bm, NULL)) { | 128 if (!this->allocPixelRef(bm, NULL)) { |
| 129 return false; | 129 return kFailure; |
| 130 } | 130 } |
| 131 | 131 |
| 132 // Lock the pixels, since we're about to write to them... | 132 // Lock the pixels, since we're about to write to them... |
| 133 SkAutoLockPixels alp(*bm); | 133 SkAutoLockPixels alp(*bm); |
| 134 | 134 |
| 135 if (isCompressedAlpha) { | 135 if (isCompressedAlpha) { |
| 136 if (!sampler.begin(bm, SkScaledBitmapSampler::kGray, *this)) { | 136 if (!sampler.begin(bm, SkScaledBitmapSampler::kGray, *this)) { |
| 137 return false; | 137 return kFailure; |
| 138 } | 138 } |
| 139 | 139 |
| 140 // Alpha data is only a single byte per pixel. | 140 // Alpha data is only a single byte per pixel. |
| 141 int nPixels = width * height; | 141 int nPixels = width * height; |
| 142 SkAutoMalloc outRGBData(nPixels); | 142 SkAutoMalloc outRGBData(nPixels); |
| 143 uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get()); | 143 uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get()); |
| 144 | 144 |
| 145 // Decode the compressed format | 145 // Decode the compressed format |
| 146 const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData
()); | 146 const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData
()); |
| 147 if (!SkTextureCompressor::DecompressBufferFromFormat( | 147 if (!SkTextureCompressor::DecompressBufferFromFormat( |
| 148 outRGBDataPtr, width, buf, width, height, ktxCompressedFormat))
{ | 148 outRGBDataPtr, width, buf, width, height, ktxCompressedFormat))
{ |
| 149 return false; | 149 return kFailure; |
| 150 } | 150 } |
| 151 | 151 |
| 152 // Set each of the pixels... | 152 // Set each of the pixels... |
| 153 const int srcRowBytes = width; | 153 const int srcRowBytes = width; |
| 154 const int dstHeight = sampler.scaledHeight(); | 154 const int dstHeight = sampler.scaledHeight(); |
| 155 const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr); | 155 const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr); |
| 156 srcRow += sampler.srcY0() * srcRowBytes; | 156 srcRow += sampler.srcY0() * srcRowBytes; |
| 157 for (int y = 0; y < dstHeight; ++y) { | 157 for (int y = 0; y < dstHeight; ++y) { |
| 158 sampler.next(srcRow); | 158 sampler.next(srcRow); |
| 159 srcRow += sampler.srcDY() * srcRowBytes; | 159 srcRow += sampler.srcDY() * srcRowBytes; |
| 160 } | 160 } |
| 161 | 161 |
| 162 return true; | 162 return kSuccess; |
| 163 | 163 |
| 164 } else if (ktxFile.isCompressedFormat(SkTextureCompressor::kETC1_Format)) { | 164 } else if (ktxFile.isCompressedFormat(SkTextureCompressor::kETC1_Format)) { |
| 165 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { | 165 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { |
| 166 return false; | 166 return kFailure; |
| 167 } | 167 } |
| 168 | 168 |
| 169 // ETC1 Data is encoded as RGB pixels, so we should extract it as such | 169 // ETC1 Data is encoded as RGB pixels, so we should extract it as such |
| 170 int nPixels = width * height; | 170 int nPixels = width * height; |
| 171 SkAutoMalloc outRGBData(nPixels * 3); | 171 SkAutoMalloc outRGBData(nPixels * 3); |
| 172 uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get()); | 172 uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get()); |
| 173 | 173 |
| 174 // Decode ETC1 | 174 // Decode ETC1 |
| 175 const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData
()); | 175 const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData
()); |
| 176 if (!SkTextureCompressor::DecompressBufferFromFormat( | 176 if (!SkTextureCompressor::DecompressBufferFromFormat( |
| 177 outRGBDataPtr, width*3, buf, width, height, SkTextureCompressor:
:kETC1_Format)) { | 177 outRGBDataPtr, width*3, buf, width, height, SkTextureCompressor:
:kETC1_Format)) { |
| 178 return false; | 178 return kFailure; |
| 179 } | 179 } |
| 180 | 180 |
| 181 // Set each of the pixels... | 181 // Set each of the pixels... |
| 182 const int srcRowBytes = width * 3; | 182 const int srcRowBytes = width * 3; |
| 183 const int dstHeight = sampler.scaledHeight(); | 183 const int dstHeight = sampler.scaledHeight(); |
| 184 const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr); | 184 const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr); |
| 185 srcRow += sampler.srcY0() * srcRowBytes; | 185 srcRow += sampler.srcY0() * srcRowBytes; |
| 186 for (int y = 0; y < dstHeight; ++y) { | 186 for (int y = 0; y < dstHeight; ++y) { |
| 187 sampler.next(srcRow); | 187 sampler.next(srcRow); |
| 188 srcRow += sampler.srcDY() * srcRowBytes; | 188 srcRow += sampler.srcDY() * srcRowBytes; |
| 189 } | 189 } |
| 190 | 190 |
| 191 return true; | 191 return kSuccess; |
| 192 | 192 |
| 193 } else if (ktxFile.isRGB8()) { | 193 } else if (ktxFile.isRGB8()) { |
| 194 | 194 |
| 195 // Uncompressed RGB data (without alpha) | 195 // Uncompressed RGB data (without alpha) |
| 196 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { | 196 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { |
| 197 return false; | 197 return kFailure; |
| 198 } | 198 } |
| 199 | 199 |
| 200 // Just need to read RGB pixels | 200 // Just need to read RGB pixels |
| 201 const int srcRowBytes = width * 3; | 201 const int srcRowBytes = width * 3; |
| 202 const int dstHeight = sampler.scaledHeight(); | 202 const int dstHeight = sampler.scaledHeight(); |
| 203 const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelD
ata()); | 203 const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelD
ata()); |
| 204 srcRow += sampler.srcY0() * srcRowBytes; | 204 srcRow += sampler.srcY0() * srcRowBytes; |
| 205 for (int y = 0; y < dstHeight; ++y) { | 205 for (int y = 0; y < dstHeight; ++y) { |
| 206 sampler.next(srcRow); | 206 sampler.next(srcRow); |
| 207 srcRow += sampler.srcDY() * srcRowBytes; | 207 srcRow += sampler.srcDY() * srcRowBytes; |
| 208 } | 208 } |
| 209 | 209 |
| 210 return true; | 210 return kSuccess; |
| 211 | 211 |
| 212 } else if (ktxFile.isRGBA8()) { | 212 } else if (ktxFile.isRGBA8()) { |
| 213 | 213 |
| 214 // Uncompressed RGBA data | 214 // Uncompressed RGBA data |
| 215 | 215 |
| 216 // If we know that the image contains premultiplied alpha, then | 216 // If we know that the image contains premultiplied alpha, then |
| 217 // we need to turn off the premultiplier | 217 // we need to turn off the premultiplier |
| 218 SkScaledBitmapSampler::Options opts (*this); | 218 SkScaledBitmapSampler::Options opts (*this); |
| 219 if (bSrcIsPremul) { | 219 if (bSrcIsPremul) { |
| 220 SkASSERT(bm->alphaType() == kPremul_SkAlphaType); | 220 SkASSERT(bm->alphaType() == kPremul_SkAlphaType); |
| 221 SkASSERT(!this->getRequireUnpremultipliedColors()); | 221 SkASSERT(!this->getRequireUnpremultipliedColors()); |
| 222 | 222 |
| 223 opts.fPremultiplyAlpha = false; | 223 opts.fPremultiplyAlpha = false; |
| 224 } | 224 } |
| 225 | 225 |
| 226 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, opts)) { | 226 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, opts)) { |
| 227 return false; | 227 return kFailure; |
| 228 } | 228 } |
| 229 | 229 |
| 230 // Just need to read RGBA pixels | 230 // Just need to read RGBA pixels |
| 231 const int srcRowBytes = width * 4; | 231 const int srcRowBytes = width * 4; |
| 232 const int dstHeight = sampler.scaledHeight(); | 232 const int dstHeight = sampler.scaledHeight(); |
| 233 const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelD
ata()); | 233 const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelD
ata()); |
| 234 srcRow += sampler.srcY0() * srcRowBytes; | 234 srcRow += sampler.srcY0() * srcRowBytes; |
| 235 for (int y = 0; y < dstHeight; ++y) { | 235 for (int y = 0; y < dstHeight; ++y) { |
| 236 sampler.next(srcRow); | 236 sampler.next(srcRow); |
| 237 srcRow += sampler.srcDY() * srcRowBytes; | 237 srcRow += sampler.srcDY() * srcRowBytes; |
| 238 } | 238 } |
| 239 | 239 |
| 240 return true; | 240 return kSuccess; |
| 241 } | 241 } |
| 242 | 242 |
| 243 return false; | 243 return kFailure; |
| 244 } | 244 } |
| 245 | 245 |
| 246 /////////////////////////////////////////////////////////////////////////////// | 246 /////////////////////////////////////////////////////////////////////////////// |
| 247 | 247 |
| 248 // KTX Image Encoder | 248 // KTX Image Encoder |
| 249 // | 249 // |
| 250 // This encoder takes a best guess at how to encode the bitmap passed to it. If | 250 // This encoder takes a best guess at how to encode the bitmap passed to it. If |
| 251 // there is an installed discardable pixel ref with existing PKM data, then we | 251 // there is an installed discardable pixel ref with existing PKM data, then we |
| 252 // will repurpose the existing ETC1 data into a KTX file. If the data contains | 252 // will repurpose the existing ETC1 data into a KTX file. If the data contains |
| 253 // KTX data, then we simply return a copy of the same data. For all other files, | 253 // KTX data, then we simply return a copy of the same data. For all other files, |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 return SkImageDecoder::kUnknown_Format; | 328 return SkImageDecoder::kUnknown_Format; |
| 329 } | 329 } |
| 330 | 330 |
| 331 SkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) { | 331 SkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) { |
| 332 return (SkImageEncoder::kKTX_Type == t) ? SkNEW(SkKTXImageEncoder) : NULL; | 332 return (SkImageEncoder::kKTX_Type == t) ? SkNEW(SkKTXImageEncoder) : NULL; |
| 333 } | 333 } |
| 334 | 334 |
| 335 static SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory); | 335 static SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory); |
| 336 static SkImageDecoder_FormatReg gFormatReg(get_format_ktx); | 336 static SkImageDecoder_FormatReg gFormatReg(get_format_ktx); |
| 337 static SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory); | 337 static SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory); |
| OLD | NEW |