Chromium Code Reviews| 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 "SkScaledBitmapSampler.h" | 11 #include "SkScaledBitmapSampler.h" |
| 11 #include "SkStream.h" | 12 #include "SkStream.h" |
| 12 #include "SkStreamHelpers.h" | 13 #include "SkStreamHelpers.h" |
| 13 #include "SkTypes.h" | 14 #include "SkTypes.h" |
| 14 | 15 |
| 15 #include "ktx.h" | 16 #include "ktx.h" |
| 16 #include "etc1.h" | 17 #include "etc1.h" |
| 17 | 18 |
| 18 //////////////////////////////////////////////////////////////////////////////// ///////// | 19 //////////////////////////////////////////////////////////////////////////////// ///////// |
| 19 | 20 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 66 return false; | 67 return false; |
| 67 } | 68 } |
| 68 | 69 |
| 69 // Setup the sampler... | 70 // Setup the sampler... |
| 70 SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); | 71 SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); |
| 71 | 72 |
| 72 // Set the config... | 73 // Set the config... |
| 73 bm->setConfig(SkBitmap::kARGB_8888_Config, | 74 bm->setConfig(SkBitmap::kARGB_8888_Config, |
| 74 sampler.scaledWidth(), sampler.scaledHeight(), | 75 sampler.scaledWidth(), sampler.scaledHeight(), |
| 75 0, | 76 0, |
| 76 ktxFile.isRGBA8()? kUnpremul_SkAlphaType : kOpaque_SkAlphaType ); | 77 ktxFile.isRGBA8()? kPremul_SkAlphaType : kOpaque_SkAlphaType); |
| 77 if (SkImageDecoder::kDecodeBounds_Mode == mode) { | 78 if (SkImageDecoder::kDecodeBounds_Mode == mode) { |
| 78 return true; | 79 return true; |
| 79 } | 80 } |
| 80 | 81 |
| 81 // If we've made it this far, then we know how to grok the data. | 82 // If we've made it this far, then we know how to grok the data. |
| 82 if (!this->allocPixelRef(bm, NULL)) { | 83 if (!this->allocPixelRef(bm, NULL)) { |
| 83 return false; | 84 return false; |
| 84 } | 85 } |
| 85 | 86 |
| 86 // Lock the pixels, since we're about to write to them... | 87 // Lock the pixels, since we're about to write to them... |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 128 srcRow += sampler.srcY0() * srcRowBytes; | 129 srcRow += sampler.srcY0() * srcRowBytes; |
| 129 for (int y = 0; y < dstHeight; ++y) { | 130 for (int y = 0; y < dstHeight; ++y) { |
| 130 sampler.next(srcRow); | 131 sampler.next(srcRow); |
| 131 srcRow += sampler.srcDY() * srcRowBytes; | 132 srcRow += sampler.srcDY() * srcRowBytes; |
| 132 } | 133 } |
| 133 | 134 |
| 134 return true; | 135 return true; |
| 135 | 136 |
| 136 } else if (ktxFile.isRGBA8()) { | 137 } else if (ktxFile.isRGBA8()) { |
| 137 | 138 |
| 139 // If we know that the image contains premultiplied alpha, then | |
| 140 // don't premultiply it upon decoding. | |
| 141 bool setRequireUnpremul = false; | |
| 142 const SkString premulKey("KTXPremultipliedAlpha"); | |
| 143 if (ktxFile.getValueForKey(premulKey) == SkString("True")) { | |
| 144 this->setRequireUnpremultipliedColors(true); | |
|
scroggo
2014/06/09 14:49:45
This is intended as a setting for the client. If t
| |
| 145 setRequireUnpremul = true; | |
| 146 } | |
| 147 | |
| 138 // Uncompressed RGBA data | 148 // Uncompressed RGBA data |
| 139 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, *this)) { | 149 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, *this)) { |
| 140 return false; | 150 return false; |
| 141 } | 151 } |
| 142 | 152 |
| 143 // Just need to read RGBA pixels | 153 // Just need to read RGBA pixels |
| 144 const int srcRowBytes = width * 4; | 154 const int srcRowBytes = width * 4; |
| 145 const int dstHeight = sampler.scaledHeight(); | 155 const int dstHeight = sampler.scaledHeight(); |
| 146 const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelD ata()); | 156 const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelD ata()); |
| 147 srcRow += sampler.srcY0() * srcRowBytes; | 157 srcRow += sampler.srcY0() * srcRowBytes; |
| 148 for (int y = 0; y < dstHeight; ++y) { | 158 for (int y = 0; y < dstHeight; ++y) { |
| 149 sampler.next(srcRow); | 159 sampler.next(srcRow); |
| 150 srcRow += sampler.srcDY() * srcRowBytes; | 160 srcRow += sampler.srcDY() * srcRowBytes; |
| 151 } | 161 } |
| 152 | 162 |
| 163 // Reset this in case the decoder needs to be used again. | |
| 164 if (setRequireUnpremul) { | |
| 165 this->setRequireUnpremultipliedColors(false); | |
|
scroggo
2014/06/09 14:49:45
Again, if the client wanted unpremultiplied colors
| |
| 166 } | |
| 167 | |
| 153 return true; | 168 return true; |
| 154 } | 169 } |
| 155 | 170 |
| 156 return false; | 171 return false; |
| 157 } | 172 } |
| 158 | 173 |
| 174 /////////////////////////////////////////////////////////////////////////////// | |
| 175 | |
| 176 // KTX Image Encoder | |
| 177 // | |
| 178 // This encoder takes a best guess at how to encode the bitmap passed to it. If | |
| 179 // there is an installed discardable pixel ref with existing PKM data, then we | |
| 180 // will repurpose the existing ETC1 data into a KTX file. If the data contains | |
| 181 // KTX data, then we simply return a copy of the same data. For all other files, | |
| 182 // the underlying KTX library tries to do its best to encode the appropriate | |
| 183 // data specified by the bitmap based on the config. (i.e. kAlpha8_Config will | |
| 184 // be represented as a full resolution 8-bit image dump with the appropriate | |
| 185 // OpenGL defines in the header). | |
| 186 | |
| 187 class SkKTXImageEncoder : public SkImageEncoder { | |
| 188 protected: | |
| 189 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK _OVERRIDE; | |
| 190 | |
| 191 private: | |
| 192 virtual bool encodePKM(SkWStream* stream, const SkData *data); | |
| 193 typedef SkImageEncoder INHERITED; | |
| 194 }; | |
| 195 | |
| 196 bool SkKTXImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int) { | |
| 197 SkAutoDataUnref data(bitmap.pixelRef()->refEncodedData()); | |
| 198 | |
| 199 // Is this even encoded data? | |
| 200 if (NULL != data) { | |
| 201 const uint8_t *bytes = data->bytes(); | |
| 202 if (etc1_pkm_is_valid(bytes)) { | |
| 203 return this->encodePKM(stream, data); | |
| 204 } | |
| 205 | |
| 206 // Is it a KTX file?? | |
| 207 if (SkKTXFile::is_ktx(bytes)) { | |
| 208 return stream->write(bytes, data->size()); | |
| 209 } | |
| 210 | |
| 211 // If it's neither a KTX nor a PKM, then we need to | |
| 212 // get at the actual pixels, so fall through and decompress... | |
| 213 } | |
| 214 | |
| 215 return SkKTXFile::WriteBitmapToKTX(stream, bitmap); | |
| 216 } | |
| 217 | |
| 218 bool SkKTXImageEncoder::encodePKM(SkWStream* stream, const SkData *data) { | |
| 219 const uint8_t* bytes = data->bytes(); | |
| 220 SkASSERT(etc1_pkm_is_valid(bytes)); | |
| 221 | |
| 222 etc1_uint32 width = etc1_pkm_get_width(bytes); | |
| 223 etc1_uint32 height = etc1_pkm_get_height(bytes); | |
| 224 | |
| 225 // ETC1 Data is stored as compressed 4x4 pixel blocks, so we must make sure | |
| 226 // that our dimensions are valid. | |
| 227 if (width == 0 || (width & 3) != 0 || height == 0 || (height & 3) != 0) { | |
| 228 return false; | |
| 229 } | |
| 230 | |
| 231 // Advance pointer to etc1 data. | |
| 232 bytes += ETC_PKM_HEADER_SIZE; | |
| 233 | |
| 234 return SkKTXFile::WriteETC1ToKTX(stream, bytes, width, height); | |
| 235 } | |
| 236 | |
| 159 //////////////////////////////////////////////////////////////////////////////// ///////// | 237 //////////////////////////////////////////////////////////////////////////////// ///////// |
| 160 DEFINE_DECODER_CREATOR(KTXImageDecoder); | 238 DEFINE_DECODER_CREATOR(KTXImageDecoder); |
| 239 DEFINE_ENCODER_CREATOR(KTXImageEncoder); | |
| 161 //////////////////////////////////////////////////////////////////////////////// ///////// | 240 //////////////////////////////////////////////////////////////////////////////// ///////// |
| 162 | 241 |
| 163 static SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) { | 242 static SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) { |
| 164 if (SkKTXFile::is_ktx(stream)) { | 243 if (SkKTXFile::is_ktx(stream)) { |
| 165 return SkNEW(SkKTXImageDecoder); | 244 return SkNEW(SkKTXImageDecoder); |
| 166 } | 245 } |
| 167 return NULL; | 246 return NULL; |
| 168 } | 247 } |
| 169 | 248 |
| 170 static SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory); | |
| 171 | |
| 172 static SkImageDecoder::Format get_format_ktx(SkStreamRewindable* stream) { | 249 static SkImageDecoder::Format get_format_ktx(SkStreamRewindable* stream) { |
| 173 if (SkKTXFile::is_ktx(stream)) { | 250 if (SkKTXFile::is_ktx(stream)) { |
| 174 return SkImageDecoder::kKTX_Format; | 251 return SkImageDecoder::kKTX_Format; |
| 175 } | 252 } |
| 176 return SkImageDecoder::kUnknown_Format; | 253 return SkImageDecoder::kUnknown_Format; |
| 177 } | 254 } |
| 178 | 255 |
| 256 SkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) { | |
| 257 return (SkImageEncoder::kKTX_Type == t) ? SkNEW(SkKTXImageEncoder) : NULL; | |
| 258 } | |
| 259 | |
| 260 static SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory); | |
| 179 static SkImageDecoder_FormatReg gFormatReg(get_format_ktx); | 261 static SkImageDecoder_FormatReg gFormatReg(get_format_ktx); |
| 262 static SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory); | |
| OLD | NEW |