| 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" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 , fSampleX(1) | 31 , fSampleX(1) |
| 32 {} | 32 {} |
| 33 | 33 |
| 34 /* | 34 /* |
| 35 * Initiates the bitmap decode | 35 * Initiates the bitmap decode |
| 36 */ | 36 */ |
| 37 SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, | 37 SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, |
| 38 void* dst, size_t dstRowBytes, | 38 void* dst, size_t dstRowBytes, |
| 39 const Options& opts, | 39 const Options& opts, |
| 40 SkPMColor* inputColorPtr, | 40 SkPMColor* inputColorPtr, |
| 41 int* inputColorCount) { | 41 int* inputColorCount, |
| 42 int* rowsDecoded) { |
| 42 if (opts.fSubset) { | 43 if (opts.fSubset) { |
| 43 // Subsets are not supported. | 44 // Subsets are not supported. |
| 44 return kUnimplemented; | 45 return kUnimplemented; |
| 45 } | 46 } |
| 46 if (!conversion_possible(dstInfo, this->getInfo())) { | 47 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 47 SkCodecPrintf("Error: cannot convert input type to output type.\n"); | 48 SkCodecPrintf("Error: cannot convert input type to output type.\n"); |
| 48 return kInvalidConversion; | 49 return kInvalidConversion; |
| 49 } | 50 } |
| 50 | 51 |
| 51 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol
orCount); | 52 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol
orCount); |
| 52 if (kSuccess != result) { | 53 if (kSuccess != result) { |
| 53 return result; | 54 return result; |
| 54 } | 55 } |
| 55 | 56 |
| 56 // Perform the decode | 57 // Perform the decode |
| 57 return this->decodeRows(dstInfo, dst, dstRowBytes, opts); | 58 uint32_t rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); |
| 59 if (rows != dstInfo.height()) { |
| 60 // We set rowsDecoded equal to the height because the background has alr
eady |
| 61 // been filled. RLE encodings sometimes skip pixels, so we always start
by |
| 62 // filling the background. |
| 63 *rowsDecoded = dstInfo.height(); |
| 64 return kIncompleteInput; |
| 65 } |
| 66 |
| 67 return kSuccess; |
| 58 } | 68 } |
| 59 | 69 |
| 60 /* | 70 /* |
| 61 * Process the color table for the bmp input | 71 * Process the color table for the bmp input |
| 62 */ | 72 */ |
| 63 bool SkBmpRLECodec::createColorTable(int* numColors) { | 73 bool SkBmpRLECodec::createColorTable(int* numColors) { |
| 64 // Allocate memory for color table | 74 // Allocate memory for color table |
| 65 uint32_t colorBytes = 0; | 75 uint32_t colorBytes = 0; |
| 66 SkPMColor colorTable[256]; | 76 SkPMColor colorTable[256]; |
| 67 if (this->bitsPerPixel() <= 8) { | 77 if (this->bitsPerPixel() <= 8) { |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 return SkCodec::kInvalidConversion; | 278 return SkCodec::kInvalidConversion; |
| 269 } | 279 } |
| 270 | 280 |
| 271 return SkCodec::kSuccess; | 281 return SkCodec::kSuccess; |
| 272 } | 282 } |
| 273 | 283 |
| 274 /* | 284 /* |
| 275 * Performs the bitmap decoding for RLE input format | 285 * Performs the bitmap decoding for RLE input format |
| 276 * RLE decoding is performed all at once, rather than a one row at a time | 286 * RLE decoding is performed all at once, rather than a one row at a time |
| 277 */ | 287 */ |
| 278 SkCodec::Result SkBmpRLECodec::decodeRows(const SkImageInfo& info, | 288 int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB
ytes, |
| 279 void* dst, size_t dstRowBytes, | 289 const Options& opts) { |
| 280 const Options& opts) { | |
| 281 // Set RLE flags | 290 // Set RLE flags |
| 282 static const uint8_t RLE_ESCAPE = 0; | 291 static const uint8_t RLE_ESCAPE = 0; |
| 283 static const uint8_t RLE_EOL = 0; | 292 static const uint8_t RLE_EOL = 0; |
| 284 static const uint8_t RLE_EOF = 1; | 293 static const uint8_t RLE_EOF = 1; |
| 285 static const uint8_t RLE_DELTA = 2; | 294 static const uint8_t RLE_DELTA = 2; |
| 286 | 295 |
| 287 // Set constant values | 296 // Set constant values |
| 288 const int width = this->getInfo().width(); | 297 const int width = this->getInfo().width(); |
| 289 const int height = info.height(); | 298 const int height = info.height(); |
| 290 | 299 |
| 291 // Account for sampling. | 300 // Account for sampling. |
| 292 SkImageInfo dstInfo = info.makeWH(get_scaled_dimension(width, fSampleX), hei
ght); | 301 SkImageInfo dstInfo = info.makeWH(get_scaled_dimension(width, fSampleX), hei
ght); |
| 293 | 302 |
| 294 // Destination parameters | 303 // Destination parameters |
| 295 int x = 0; | 304 int x = 0; |
| 296 int y = 0; | 305 int y = 0; |
| 297 | 306 |
| 298 // Set the background as transparent. Then, if the RLE code skips pixels, | 307 // Set the background as transparent. Then, if the RLE code skips pixels, |
| 299 // the skipped pixels will be transparent. | 308 // the skipped pixels will be transparent. |
| 300 // Because of the need for transparent pixels, kN32 is the only color | 309 // Because of the need for transparent pixels, kN32 is the only color |
| 301 // type that makes sense for the destination format. | 310 // type that makes sense for the destination format. |
| 302 SkASSERT(kN32_SkColorType == dstInfo.colorType()); | 311 SkASSERT(kN32_SkColorType == dstInfo.colorType()); |
| 303 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, height, SK_ColorTRANSPARENT, | 312 SkSampler::Fill(dstInfo, dst, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroIn
itialized); |
| 304 NULL, opts.fZeroInitialized); | |
| 305 | 313 |
| 306 while (true) { | 314 while (true) { |
| 307 // If we have reached a row that is beyond the requested height, we have | 315 // If we have reached a row that is beyond the requested height, we have |
| 308 // succeeded. | 316 // succeeded. |
| 309 if (y >= height) { | 317 if (y >= height) { |
| 310 // It would be better to check for the EOF marker before returning | 318 // It would be better to check for the EOF marker before indicating |
| 311 // success, but we may be performing a scanline decode, which | 319 // success, but we may be performing a scanline decode, which |
| 312 // may require us to stop before decoding the full height. | 320 // would require us to stop before decoding the full height. |
| 313 return kSuccess; | 321 return height; |
| 314 } | 322 } |
| 315 | 323 |
| 316 // Every entry takes at least two bytes | 324 // Every entry takes at least two bytes |
| 317 if ((int) fRLEBytes - fCurrRLEByte < 2) { | 325 if ((int) fRLEBytes - fCurrRLEByte < 2) { |
| 318 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); | 326 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); |
| 319 if (this->checkForMoreData() < 2) { | 327 if (this->checkForMoreData() < 2) { |
| 320 return kIncompleteInput; | 328 return y; |
| 321 } | 329 } |
| 322 } | 330 } |
| 323 | 331 |
| 324 // Read the next two bytes. These bytes have different meanings | 332 // Read the next two bytes. These bytes have different meanings |
| 325 // depending on their values. In the first interpretation, the first | 333 // depending on their values. In the first interpretation, the first |
| 326 // byte is an escape flag and the second byte indicates what special | 334 // byte is an escape flag and the second byte indicates what special |
| 327 // task to perform. | 335 // task to perform. |
| 328 const uint8_t flag = fStreamBuffer.get()[fCurrRLEByte++]; | 336 const uint8_t flag = fStreamBuffer.get()[fCurrRLEByte++]; |
| 329 const uint8_t task = fStreamBuffer.get()[fCurrRLEByte++]; | 337 const uint8_t task = fStreamBuffer.get()[fCurrRLEByte++]; |
| 330 | 338 |
| 331 // Perform decoding | 339 // Perform decoding |
| 332 if (RLE_ESCAPE == flag) { | 340 if (RLE_ESCAPE == flag) { |
| 333 switch (task) { | 341 switch (task) { |
| 334 case RLE_EOL: | 342 case RLE_EOL: |
| 335 x = 0; | 343 x = 0; |
| 336 y++; | 344 y++; |
| 337 break; | 345 break; |
| 338 case RLE_EOF: | 346 case RLE_EOF: |
| 339 return kSuccess; | 347 return kSuccess; |
| 340 case RLE_DELTA: { | 348 case RLE_DELTA: { |
| 341 // Two bytes are needed to specify delta | 349 // Two bytes are needed to specify delta |
| 342 if ((int) fRLEBytes - fCurrRLEByte < 2) { | 350 if ((int) fRLEBytes - fCurrRLEByte < 2) { |
| 343 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); | 351 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); |
| 344 if (this->checkForMoreData() < 2) { | 352 if (this->checkForMoreData() < 2) { |
| 345 return kIncompleteInput; | 353 return y; |
| 346 } | 354 } |
| 347 } | 355 } |
| 348 // Modify x and y | 356 // Modify x and y |
| 349 const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++]; | 357 const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++]; |
| 350 const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++]; | 358 const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++]; |
| 351 x += dx; | 359 x += dx; |
| 352 y += dy; | 360 y += dy; |
| 353 if (x > width || y > height) { | 361 if (x > width || y > height) { |
| 354 SkCodecPrintf("Warning: invalid RLE input.\n"); | 362 SkCodecPrintf("Warning: invalid RLE input.\n"); |
| 355 return kInvalidInput; | 363 return y - dy; |
| 356 } | 364 } |
| 357 break; | 365 break; |
| 358 } | 366 } |
| 359 default: { | 367 default: { |
| 360 // If task does not match any of the above signals, it | 368 // If task does not match any of the above signals, it |
| 361 // indicates that we have a sequence of non-RLE pixels. | 369 // indicates that we have a sequence of non-RLE pixels. |
| 362 // Furthermore, the value of task is equal to the number | 370 // Furthermore, the value of task is equal to the number |
| 363 // of pixels to interpret. | 371 // of pixels to interpret. |
| 364 uint8_t numPixels = task; | 372 uint8_t numPixels = task; |
| 365 const size_t rowBytes = compute_row_bytes(numPixels, | 373 const size_t rowBytes = compute_row_bytes(numPixels, |
| 366 this->bitsPerPixel()); | 374 this->bitsPerPixel()); |
| 367 // Abort if setting numPixels moves us off the edge of the | 375 // Abort if setting numPixels moves us off the edge of the |
| 368 // image. | 376 // image. |
| 369 if (x + numPixels > width) { | 377 if (x + numPixels > width) { |
| 370 SkCodecPrintf("Warning: invalid RLE input.\n"); | 378 SkCodecPrintf("Warning: invalid RLE input.\n"); |
| 371 return kInvalidInput; | 379 return y; |
| 372 } | 380 } |
| 373 // Also abort if there are not enough bytes | 381 // Also abort if there are not enough bytes |
| 374 // remaining in the stream to set numPixels. | 382 // remaining in the stream to set numPixels. |
| 375 if ((int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) { | 383 if ((int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) { |
| 376 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); | 384 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); |
| 377 if (this->checkForMoreData() < SkAlign2(rowBytes)) { | 385 if (this->checkForMoreData() < SkAlign2(rowBytes)) { |
| 378 return kIncompleteInput; | 386 return y; |
| 379 } | 387 } |
| 380 } | 388 } |
| 381 // Set numPixels number of pixels | 389 // Set numPixels number of pixels |
| 382 while (numPixels > 0) { | 390 while (numPixels > 0) { |
| 383 switch(this->bitsPerPixel()) { | 391 switch(this->bitsPerPixel()) { |
| 384 case 4: { | 392 case 4: { |
| 385 SkASSERT(fCurrRLEByte < fRLEBytes); | 393 SkASSERT(fCurrRLEByte < fRLEBytes); |
| 386 uint8_t val = fStreamBuffer.get()[fCurrRLEByte++
]; | 394 uint8_t val = fStreamBuffer.get()[fCurrRLEByte++
]; |
| 387 setPixel(dst, dstRowBytes, dstInfo, x++, | 395 setPixel(dst, dstRowBytes, dstInfo, x++, |
| 388 y, val >> 4); | 396 y, val >> 4); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 404 SkASSERT(fCurrRLEByte + 2 < fRLEBytes); | 412 SkASSERT(fCurrRLEByte + 2 < fRLEBytes); |
| 405 uint8_t blue = fStreamBuffer.get()[fCurrRLEByte+
+]; | 413 uint8_t blue = fStreamBuffer.get()[fCurrRLEByte+
+]; |
| 406 uint8_t green = fStreamBuffer.get()[fCurrRLEByte
++]; | 414 uint8_t green = fStreamBuffer.get()[fCurrRLEByte
++]; |
| 407 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++
]; | 415 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++
]; |
| 408 setRGBPixel(dst, dstRowBytes, dstInfo, | 416 setRGBPixel(dst, dstRowBytes, dstInfo, |
| 409 x++, y, red, green, blue); | 417 x++, y, red, green, blue); |
| 410 numPixels--; | 418 numPixels--; |
| 411 } | 419 } |
| 412 default: | 420 default: |
| 413 SkASSERT(false); | 421 SkASSERT(false); |
| 414 return kInvalidInput; | 422 return y; |
| 415 } | 423 } |
| 416 } | 424 } |
| 417 // Skip a byte if necessary to maintain alignment | 425 // Skip a byte if necessary to maintain alignment |
| 418 if (!SkIsAlign2(rowBytes)) { | 426 if (!SkIsAlign2(rowBytes)) { |
| 419 fCurrRLEByte++; | 427 fCurrRLEByte++; |
| 420 } | 428 } |
| 421 break; | 429 break; |
| 422 } | 430 } |
| 423 } | 431 } |
| 424 } else { | 432 } else { |
| 425 // If the first byte read is not a flag, it indicates the number of | 433 // If the first byte read is not a flag, it indicates the number of |
| 426 // pixels to set in RLE mode. | 434 // pixels to set in RLE mode. |
| 427 const uint8_t numPixels = flag; | 435 const uint8_t numPixels = flag; |
| 428 const int endX = SkTMin<int>(x + numPixels, width); | 436 const int endX = SkTMin<int>(x + numPixels, width); |
| 429 | 437 |
| 430 if (24 == this->bitsPerPixel()) { | 438 if (24 == this->bitsPerPixel()) { |
| 431 // In RLE24, the second byte read is part of the pixel color. | 439 // In RLE24, the second byte read is part of the pixel color. |
| 432 // There are two more required bytes to finish encoding the | 440 // There are two more required bytes to finish encoding the |
| 433 // color. | 441 // color. |
| 434 if ((int) fRLEBytes - fCurrRLEByte < 2) { | 442 if ((int) fRLEBytes - fCurrRLEByte < 2) { |
| 435 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); | 443 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); |
| 436 if (this->checkForMoreData() < 2) { | 444 if (this->checkForMoreData() < 2) { |
| 437 return kIncompleteInput; | 445 return y; |
| 438 } | 446 } |
| 439 } | 447 } |
| 440 | 448 |
| 441 // Fill the pixels up to endX with the specified color | 449 // Fill the pixels up to endX with the specified color |
| 442 uint8_t blue = task; | 450 uint8_t blue = task; |
| 443 uint8_t green = fStreamBuffer.get()[fCurrRLEByte++]; | 451 uint8_t green = fStreamBuffer.get()[fCurrRLEByte++]; |
| 444 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++]; | 452 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++]; |
| 445 while (x < endX) { | 453 while (x < endX) { |
| 446 setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, b
lue); | 454 setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, b
lue); |
| 447 } | 455 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 460 // Set the indicated number of pixels | 468 // Set the indicated number of pixels |
| 461 for (int which = 0; x < endX; x++) { | 469 for (int which = 0; x < endX; x++) { |
| 462 setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]); | 470 setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]); |
| 463 which = !which; | 471 which = !which; |
| 464 } | 472 } |
| 465 } | 473 } |
| 466 } | 474 } |
| 467 } | 475 } |
| 468 } | 476 } |
| 469 | 477 |
| 478 // FIXME: Make SkBmpRLECodec have no knowledge of sampling. |
| 479 // Or it should do all sampling natively. |
| 480 // It currently is a hybrid that needs to know what SkScaledCodec is doin
g. |
| 470 class SkBmpRLESampler : public SkSampler { | 481 class SkBmpRLESampler : public SkSampler { |
| 471 public: | 482 public: |
| 472 SkBmpRLESampler(SkBmpRLECodec* codec) | 483 SkBmpRLESampler(SkBmpRLECodec* codec) |
| 473 : fCodec(codec) | 484 : fCodec(codec) |
| 474 { | 485 { |
| 475 SkASSERT(fCodec); | 486 SkASSERT(fCodec); |
| 476 } | 487 } |
| 477 | 488 |
| 478 private: | 489 private: |
| 479 int onSetSampleX(int sampleX) { | 490 int onSetSampleX(int sampleX) override { |
| 480 return fCodec->setSampleX(sampleX); | 491 return fCodec->setSampleX(sampleX); |
| 481 } | 492 } |
| 482 | 493 |
| 483 // Unowned pointer. fCodec will delete this class in its destructor. | 494 // Unowned pointer. fCodec will delete this class in its destructor. |
| 484 SkBmpRLECodec* fCodec; | 495 SkBmpRLECodec* fCodec; |
| 485 }; | 496 }; |
| 486 | 497 |
| 487 SkSampler* SkBmpRLECodec::getSampler() { | 498 SkSampler* SkBmpRLECodec::getSampler(bool createIfNecessary) { |
| 488 if (!fSampler) { | 499 if (!fSampler && createIfNecessary) { |
| 489 fSampler.reset(new SkBmpRLESampler(this)); | 500 fSampler.reset(new SkBmpRLESampler(this)); |
| 490 } | 501 } |
| 491 | 502 |
| 492 return fSampler; | 503 return fSampler; |
| 493 } | 504 } |
| 494 | 505 |
| 495 int SkBmpRLECodec::setSampleX(int sampleX) { | 506 int SkBmpRLECodec::setSampleX(int sampleX){ |
| 496 fSampleX = sampleX; | 507 fSampleX = sampleX; |
| 497 return get_scaled_dimension(this->getInfo().width(), sampleX); | 508 return get_scaled_dimension(this->getInfo().width(), sampleX); |
| 498 } | 509 } |
| OLD | NEW |