OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 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 "SkBmpStandardCodec.h" | 8 #include "SkBmpStandardCodec.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
11 #include "SkStream.h" | 11 #include "SkStream.h" |
12 | 12 |
13 /* | 13 /* |
14 * Creates an instance of the decoder | 14 * Creates an instance of the decoder |
15 * Called only by NewFromStream | 15 * Called only by NewFromStream |
16 */ | 16 */ |
17 SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream
, | 17 SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream
, |
18 uint16_t bitsPerPixel, uint32_t numColors
, | 18 uint16_t bitsPerPixel, uint32_t numColors
, |
19 uint32_t bytesPerColor, uint32_t offset, | 19 uint32_t bytesPerColor, uint32_t offset, |
20 SkCodec::SkScanlineOrder rowOrder, bool i
nIco) | 20 SkCodec::SkScanlineOrder rowOrder, bool i
nIco) |
21 : INHERITED(info, stream, bitsPerPixel, rowOrder) | 21 : INHERITED(info, stream, bitsPerPixel, rowOrder) |
22 , fColorTable(nullptr) | 22 , fColorTable(nullptr) |
23 , fNumColors(this->computeNumColors(numColors)) | 23 , fNumColors(this->computeNumColors(numColors)) |
24 , fBytesPerColor(bytesPerColor) | 24 , fBytesPerColor(bytesPerColor) |
25 , fOffset(offset) | 25 , fOffset(offset) |
26 , fSwizzler(nullptr) | 26 , fSwizzler(nullptr) |
27 , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getInfo().width(), this->bit
sPerPixel()))) | 27 , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getInfo().width(), this->bit
sPerPixel()))) |
28 , fSrcBuffer(new uint8_t [fSrcRowBytes]) | 28 , fSrcBuffer(new uint8_t [fSrcRowBytes]) |
29 , fInIco(inIco) | 29 , fInIco(inIco) |
| 30 , fAndMaskRowBytes(fInIco ? SkAlign4(compute_row_bytes(this->getInfo().width
(), 1)) : 0) |
30 {} | 31 {} |
31 | 32 |
32 /* | 33 /* |
33 * Initiates the bitmap decode | 34 * Initiates the bitmap decode |
34 */ | 35 */ |
35 SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, | 36 SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, |
36 void* dst, size_t dstRowBytes, | 37 void* dst, size_t dstRowBytes, |
37 const Options& opts, | 38 const Options& opts, |
38 SkPMColor* inputColorPtr, | 39 SkPMColor* inputColorPtr, |
39 int* inputColorCount, | 40 int* inputColorCount, |
(...skipping 13 matching lines...) Expand all Loading... |
53 | 54 |
54 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol
orCount); | 55 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol
orCount); |
55 if (kSuccess != result) { | 56 if (kSuccess != result) { |
56 return result; | 57 return result; |
57 } | 58 } |
58 int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); | 59 int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); |
59 if (rows != dstInfo.height()) { | 60 if (rows != dstInfo.height()) { |
60 *rowsDecoded = rows; | 61 *rowsDecoded = rows; |
61 return kIncompleteInput; | 62 return kIncompleteInput; |
62 } | 63 } |
63 if (fInIco) { | |
64 return this->decodeIcoMask(dstInfo, dst, dstRowBytes); | |
65 } | |
66 return kSuccess; | 64 return kSuccess; |
67 } | 65 } |
68 | 66 |
69 /* | 67 /* |
70 * Process the color table for the bmp input | 68 * Process the color table for the bmp input |
71 */ | 69 */ |
72 bool SkBmpStandardCodec::createColorTable(SkAlphaType alphaType, int* numColors
) { | 70 bool SkBmpStandardCodec::createColorTable(SkAlphaType alphaType, int* numColors
) { |
73 // Allocate memory for color table | 71 // Allocate memory for color table |
74 uint32_t colorBytes = 0; | 72 uint32_t colorBytes = 0; |
75 SkPMColor colorTable[256]; | 73 SkPMColor colorTable[256]; |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 if (!this->initializeSwizzler(dstInfo, options)) { | 218 if (!this->initializeSwizzler(dstInfo, options)) { |
221 SkCodecPrintf("Error: cannot initialize swizzler.\n"); | 219 SkCodecPrintf("Error: cannot initialize swizzler.\n"); |
222 return SkCodec::kInvalidConversion; | 220 return SkCodec::kInvalidConversion; |
223 } | 221 } |
224 return SkCodec::kSuccess; | 222 return SkCodec::kSuccess; |
225 } | 223 } |
226 | 224 |
227 /* | 225 /* |
228 * Performs the bitmap decoding for standard input format | 226 * Performs the bitmap decoding for standard input format |
229 */ | 227 */ |
230 int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, | 228 int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t
dstRowBytes, |
231 void* dst, size_t dstRowBytes, | 229 const Options& opts) { |
232 const Options& opts) { | |
233 // Iterate over rows of the image | 230 // Iterate over rows of the image |
234 const int height = dstInfo.height(); | 231 const int height = dstInfo.height(); |
235 for (int y = 0; y < height; y++) { | 232 for (int y = 0; y < height; y++) { |
236 // Read a row of the input | 233 // Read a row of the input |
237 if (this->stream()->read(fSrcBuffer.get(), fSrcRowBytes) != fSrcRowBytes
) { | 234 if (this->stream()->read(fSrcBuffer.get(), fSrcRowBytes) != fSrcRowBytes
) { |
238 SkCodecPrintf("Warning: incomplete input stream.\n"); | 235 SkCodecPrintf("Warning: incomplete input stream.\n"); |
239 return y; | 236 return y; |
240 } | 237 } |
241 | 238 |
242 // Decode the row in destination format | 239 // Decode the row in destination format |
243 uint32_t row = this->getDstRow(y, dstInfo.height()); | 240 uint32_t row = this->getDstRow(y, dstInfo.height()); |
244 | 241 |
245 void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); | 242 void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); |
246 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 243 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); |
247 } | 244 } |
248 | 245 |
249 // Finished decoding the entire image | 246 if (fInIco) { |
| 247 const int startScanline = this->currScanline(); |
| 248 if (startScanline < 0) { |
| 249 // We are not performing a scanline decode. |
| 250 // Just decode the entire ICO mask and return. |
| 251 decodeIcoMask(this->stream(), dstInfo, dst, dstRowBytes); |
| 252 return height; |
| 253 } |
| 254 |
| 255 // In order to perform a scanline ICO decode, we must be able |
| 256 // to skip ahead in the stream in order to apply the AND mask |
| 257 // to the requested scanlines. |
| 258 // We will do this by taking advantage of the fact that |
| 259 // SkIcoCodec always uses a SkMemoryStream as its underlying |
| 260 // representation of the stream. |
| 261 const void* memoryBase = this->stream()->getMemoryBase(); |
| 262 SkASSERT(nullptr != memoryBase); |
| 263 SkASSERT(this->stream()->hasLength()); |
| 264 SkASSERT(this->stream()->hasPosition()); |
| 265 |
| 266 const size_t length = this->stream()->getLength(); |
| 267 const size_t currPosition = this->stream()->getPosition(); |
| 268 |
| 269 // Calculate how many bytes we must skip to reach the AND mask. |
| 270 const int remainingScanlines = this->getInfo().height() - startScanline
- height; |
| 271 const size_t bytesToSkip = remainingScanlines * fSrcRowBytes + |
| 272 startScanline * fAndMaskRowBytes; |
| 273 const size_t subStreamStartPosition = currPosition + bytesToSkip; |
| 274 if (subStreamStartPosition >= length) { |
| 275 // FIXME: How can we indicate that this decode was actually incomple
te? |
| 276 return height; |
| 277 } |
| 278 |
| 279 // Create a subStream to pass to decodeIcoMask(). It is useful to encap
sulate |
| 280 // the memory base into a stream in order to safely handle incomplete im
ages |
| 281 // without reading out of bounds memory. |
| 282 const void* subStreamMemoryBase = SkTAddOffset<const void>(memoryBase, |
| 283 subStreamStartPosition); |
| 284 const size_t subStreamLength = length - subStreamStartPosition; |
| 285 // This call does not transfer ownership of the subStreamMemoryBase. |
| 286 SkMemoryStream subStream(subStreamMemoryBase, subStreamLength, false); |
| 287 |
| 288 // FIXME: If decodeIcoMask does not succeed, is there a way that we can |
| 289 // indicate the decode was incomplete? |
| 290 decodeIcoMask(&subStream, dstInfo, dst, dstRowBytes); |
| 291 } |
| 292 |
250 return height; | 293 return height; |
251 } | 294 } |
252 | 295 |
253 // TODO (msarett): This function will need to be modified in order to perform ro
w by row decodes | 296 void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstI
nfo, |
254 // when the Ico scanline decoder is implemented. | |
255 SkCodec::Result SkBmpStandardCodec::decodeIcoMask(const SkImageInfo& dstInfo, | |
256 void* dst, size_t dstRowBytes) { | 297 void* dst, size_t dstRowBytes) { |
257 // BMP in ICO have transparency, so this cannot be 565, and this mask | 298 // BMP in ICO have transparency, so this cannot be 565, and this mask |
258 // prevents us from using kIndex8. The below code depends on the output | 299 // prevents us from using kIndex8. The below code depends on the output |
259 // being an SkPMColor. | 300 // being an SkPMColor. |
260 SkASSERT(dstInfo.colorType() == kN32_SkColorType); | 301 SkASSERT(dstInfo.colorType() == kN32_SkColorType); |
261 | 302 |
262 // The AND mask is always 1 bit per pixel | 303 // If we are sampling, make sure that we only mask the sampled pixels. |
263 const int width = this->getInfo().width(); | 304 // We do not need to worry about sampling in the y-dimension because that |
264 const size_t rowBytes = SkAlign4(compute_row_bytes(width, 1)); | 305 // should be handled by SkSampledCodec. |
| 306 const int sampleX = fSwizzler->sampleX(); |
| 307 const int sampledWidth = get_scaled_dimension(this->getInfo().width(), sampl
eX); |
| 308 const int srcStartX = get_start_coord(sampleX); |
| 309 |
265 | 310 |
266 SkPMColor* dstPtr = (SkPMColor*) dst; | 311 SkPMColor* dstPtr = (SkPMColor*) dst; |
267 for (int y = 0; y < dstInfo.height(); y++) { | 312 for (int y = 0; y < dstInfo.height(); y++) { |
268 // The srcBuffer will at least be large enough | 313 // The srcBuffer will at least be large enough |
269 if (stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) { | 314 if (stream->read(fSrcBuffer.get(), fAndMaskRowBytes) != fAndMaskRowBytes
) { |
270 SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); | 315 SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); |
271 return kIncompleteInput; | 316 return; |
272 } | 317 } |
273 | 318 |
274 int row = this->getDstRow(y, dstInfo.height()); | 319 int row = this->getDstRow(y, dstInfo.height()); |
275 | 320 |
276 SkPMColor* dstRow = | 321 SkPMColor* dstRow = |
277 SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes); | 322 SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes); |
278 | 323 |
279 for (int x = 0; x < width; x++) { | 324 int srcX = srcStartX; |
| 325 for (int dstX = 0; dstX < sampledWidth; dstX++) { |
280 int quotient; | 326 int quotient; |
281 int modulus; | 327 int modulus; |
282 SkTDivMod(x, 8, "ient, &modulus); | 328 SkTDivMod(srcX, 8, "ient, &modulus); |
283 uint32_t shift = 7 - modulus; | 329 uint32_t shift = 7 - modulus; |
284 uint32_t alphaBit = | 330 uint32_t alphaBit = (fSrcBuffer.get()[quotient] >> shift) & 0x1; |
285 (fSrcBuffer.get()[quotient] >> shift) & 0x1; | 331 dstRow[dstX] &= alphaBit - 1; |
286 dstRow[x] &= alphaBit - 1; | 332 srcX += sampleX; |
287 } | 333 } |
288 } | 334 } |
289 return kSuccess; | |
290 } | 335 } |
291 | 336 |
292 uint32_t SkBmpStandardCodec::onGetFillValue(SkColorType colorType, SkAlphaType a
lphaType) const { | 337 uint32_t SkBmpStandardCodec::onGetFillValue(SkColorType colorType, SkAlphaType a
lphaType) const { |
293 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 338 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
294 if (colorPtr) { | 339 if (colorPtr) { |
295 return get_color_table_fill_value(colorType, colorPtr, 0); | 340 return get_color_table_fill_value(colorType, colorPtr, 0); |
296 } | 341 } |
297 return INHERITED::onGetFillValue(colorType, alphaType); | 342 return INHERITED::onGetFillValue(colorType, alphaType); |
298 } | 343 } |
OLD | NEW |