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 "SkBmpRLECodec.h" | 8 #include "SkBmpRLECodec.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 SkBmpRLECodec::SkBmpRLECodec(const SkImageInfo& info, SkStream* stream, | 17 SkBmpRLECodec::SkBmpRLECodec(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, | 20 SkCodec::SkScanlineOrder rowOrder, |
21 size_t RLEBytes) | 21 size_t RLEBytes) |
22 : INHERITED(info, stream, bitsPerPixel, rowOrder) | 22 : INHERITED(info, stream, bitsPerPixel, rowOrder) |
23 , fColorTable(nullptr) | 23 , fColorTable(nullptr) |
24 , fNumColors(numColors) | 24 , fNumColors(numColors) |
25 , fBytesPerColor(bytesPerColor) | 25 , fBytesPerColor(bytesPerColor) |
26 , fOffset(offset) | 26 , fOffset(offset) |
27 , fStreamBuffer(new uint8_t[RLEBytes]) | 27 , fStreamBuffer(new uint8_t[RLEBytes]) |
28 , fRLEBytes(RLEBytes) | 28 , fRLEBytes(RLEBytes) |
29 , fOrigRLEBytes(RLEBytes) | |
29 , fCurrRLEByte(0) | 30 , fCurrRLEByte(0) |
30 , fSampleX(1) | 31 , fSampleX(1) |
31 {} | 32 {} |
32 | 33 |
33 /* | 34 /* |
34 * Initiates the bitmap decode | 35 * Initiates the bitmap decode |
35 */ | 36 */ |
36 SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, | 37 SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, |
37 void* dst, size_t dstRowBytes, | 38 void* dst, size_t dstRowBytes, |
38 const Options& opts, | 39 const Options& opts, |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
263 const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputCo lorCount) { | 264 const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputCo lorCount) { |
264 // FIXME: Support subsets for scanline decodes. | 265 // FIXME: Support subsets for scanline decodes. |
265 if (options.fSubset) { | 266 if (options.fSubset) { |
266 // Subsets are not supported. | 267 // Subsets are not supported. |
267 return kUnimplemented; | 268 return kUnimplemented; |
268 } | 269 } |
269 | 270 |
270 // Reset fSampleX. If it needs to be a value other than 1, it will get modif ied by | 271 // Reset fSampleX. If it needs to be a value other than 1, it will get modif ied by |
271 // the sampler. | 272 // the sampler. |
272 fSampleX = 1; | 273 fSampleX = 1; |
274 | |
275 // Scanline decodes allow the client to ask for a single scanline at a time. | |
scroggo
2016/02/11 15:56:52
Maybe this comment should go in the header?
msarett
2016/02/11 16:03:51
Done.
| |
276 // This can be tricky when the RLE encoding instructs the decoder to jump do wn | |
277 // multiple lines. This field keeps track of lines that need to be skipped | |
278 // on subsequent calls to getScanlines(). | |
279 fLinesToSkip = 0; | |
280 | |
273 // Create the color table if necessary and prepare the stream for decode | 281 // Create the color table if necessary and prepare the stream for decode |
274 // Note that if it is non-NULL, inputColorCount will be modified | 282 // Note that if it is non-NULL, inputColorCount will be modified |
275 if (!this->createColorTable(inputColorCount)) { | 283 if (!this->createColorTable(inputColorCount)) { |
276 SkCodecPrintf("Error: could not create color table.\n"); | 284 SkCodecPrintf("Error: could not create color table.\n"); |
277 return SkCodec::kInvalidInput; | 285 return SkCodec::kInvalidInput; |
278 } | 286 } |
279 | 287 |
280 // Copy the color table to the client if necessary | 288 // Copy the color table to the client if necessary |
281 copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount) ; | 289 copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount) ; |
282 | 290 |
283 // Initialize a buffer for encoded RLE data | 291 // Initialize a buffer for encoded RLE data |
292 fRLEBytes = fOrigRLEBytes; | |
msarett
2016/02/11 15:23:10
On bmps where we need to "check for more data", we
| |
284 if (!this->initializeStreamBuffer()) { | 293 if (!this->initializeStreamBuffer()) { |
285 SkCodecPrintf("Error: cannot initialize stream buffer.\n"); | 294 SkCodecPrintf("Error: cannot initialize stream buffer.\n"); |
286 return SkCodec::kInvalidConversion; | 295 return SkCodec::kInvalidConversion; |
287 } | 296 } |
288 | 297 |
289 return SkCodec::kSuccess; | 298 return SkCodec::kSuccess; |
290 } | 299 } |
291 | 300 |
292 /* | 301 /* |
293 * Performs the bitmap decoding for RLE input format | 302 * Performs the bitmap decoding for RLE input format |
294 * RLE decoding is performed all at once, rather than a one row at a time | 303 * RLE decoding is performed all at once, rather than a one row at a time |
295 */ | 304 */ |
296 int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB ytes, | 305 int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB ytes, |
297 const Options& opts) { | 306 const Options& opts) { |
298 // Set RLE flags | 307 // Set RLE flags |
299 static const uint8_t RLE_ESCAPE = 0; | 308 static const uint8_t RLE_ESCAPE = 0; |
300 static const uint8_t RLE_EOL = 0; | 309 static const uint8_t RLE_EOL = 0; |
301 static const uint8_t RLE_EOF = 1; | 310 static const uint8_t RLE_EOF = 1; |
302 static const uint8_t RLE_DELTA = 2; | 311 static const uint8_t RLE_DELTA = 2; |
303 | 312 |
304 // Set constant values | |
305 const int width = this->getInfo().width(); | 313 const int width = this->getInfo().width(); |
306 const int height = info.height(); | 314 int height = info.height(); |
307 | 315 |
308 // Account for sampling. | 316 // Account for sampling. |
309 SkImageInfo dstInfo = info.makeWH(get_scaled_dimension(width, fSampleX), hei ght); | 317 SkImageInfo dstInfo = info.makeWH(get_scaled_dimension(width, fSampleX), hei ght); |
310 | 318 |
311 // Destination parameters | |
312 int x = 0; | |
313 int y = 0; | |
314 | |
315 // Set the background as transparent. Then, if the RLE code skips pixels, | 319 // Set the background as transparent. Then, if the RLE code skips pixels, |
316 // the skipped pixels will be transparent. | 320 // the skipped pixels will be transparent. |
317 // Because of the need for transparent pixels, kN32 is the only color | 321 // Because of the need for transparent pixels, kN32 is the only color |
318 // type that makes sense for the destination format. | 322 // type that makes sense for the destination format. |
319 SkASSERT(kN32_SkColorType == dstInfo.colorType()); | 323 SkASSERT(kN32_SkColorType == dstInfo.colorType()); |
320 SkSampler::Fill(dstInfo, dst, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroIn itialized); | 324 SkSampler::Fill(dstInfo, dst, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroIn itialized); |
321 | 325 |
326 // Adjust the height and the dst if the previous call to decodeRows() left u s | |
327 // with lines that need to be skipped. | |
328 if (height > fLinesToSkip) { | |
329 height -= fLinesToSkip; | |
330 dst = SkTAddOffset<void>(dst, fLinesToSkip * dstRowBytes); | |
331 fLinesToSkip = 0; | |
332 } else { | |
333 fLinesToSkip -= height; | |
334 return height; | |
335 } | |
336 | |
337 // Destination parameters | |
338 int x = 0; | |
339 int y = 0; | |
340 | |
322 while (true) { | 341 while (true) { |
323 // If we have reached a row that is beyond the requested height, we have | 342 // If we have reached a row that is beyond the requested height, we have |
324 // succeeded. | 343 // succeeded. |
325 if (y >= height) { | 344 if (y >= height) { |
326 // It would be better to check for the EOF marker before indicating | 345 // It would be better to check for the EOF marker before indicating |
327 // success, but we may be performing a scanline decode, which | 346 // success, but we may be performing a scanline decode, which |
328 // would require us to stop before decoding the full height. | 347 // would require us to stop before decoding the full height. |
329 return height; | 348 return height; |
330 } | 349 } |
331 | 350 |
(...skipping 27 matching lines...) Expand all Loading... | |
359 SkCodecPrintf("Warning: might be incomplete RLE input.\n "); | 378 SkCodecPrintf("Warning: might be incomplete RLE input.\n "); |
360 if (this->checkForMoreData() < 2) { | 379 if (this->checkForMoreData() < 2) { |
361 return y; | 380 return y; |
362 } | 381 } |
363 } | 382 } |
364 // Modify x and y | 383 // Modify x and y |
365 const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++]; | 384 const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++]; |
366 const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++]; | 385 const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++]; |
367 x += dx; | 386 x += dx; |
368 y += dy; | 387 y += dy; |
369 if (x > width || y > height) { | 388 if (x > width) { |
370 SkCodecPrintf("Warning: invalid RLE input.\n"); | 389 SkCodecPrintf("Warning: invalid RLE input.\n"); |
scroggo
2016/02/11 15:56:52
Is this still correct if we consider a subset (in
msarett
2016/02/11 16:03:51
If width == originalWidth, this is fine. But if w
scroggo
2016/02/11 16:08:47
Ah, of course. Doesn't matter yet.
| |
371 return y - dy; | 390 return y - dy; |
391 } else if (y > height) { | |
392 fLinesToSkip = y - height; | |
393 return height; | |
372 } | 394 } |
373 break; | 395 break; |
374 } | 396 } |
375 default: { | 397 default: { |
376 // If task does not match any of the above signals, it | 398 // If task does not match any of the above signals, it |
377 // indicates that we have a sequence of non-RLE pixels. | 399 // indicates that we have a sequence of non-RLE pixels. |
378 // Furthermore, the value of task is equal to the number | 400 // Furthermore, the value of task is equal to the number |
379 // of pixels to interpret. | 401 // of pixels to interpret. |
380 uint8_t numPixels = task; | 402 uint8_t numPixels = task; |
381 const size_t rowBytes = compute_row_bytes(numPixels, | 403 const size_t rowBytes = compute_row_bytes(numPixels, |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
508 fSampler.reset(new SkBmpRLESampler(this)); | 530 fSampler.reset(new SkBmpRLESampler(this)); |
509 } | 531 } |
510 | 532 |
511 return fSampler; | 533 return fSampler; |
512 } | 534 } |
513 | 535 |
514 int SkBmpRLECodec::setSampleX(int sampleX){ | 536 int SkBmpRLECodec::setSampleX(int sampleX){ |
515 fSampleX = sampleX; | 537 fSampleX = sampleX; |
516 return get_scaled_dimension(this->getInfo().width(), sampleX); | 538 return get_scaled_dimension(this->getInfo().width(), sampleX); |
517 } | 539 } |
OLD | NEW |