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 |