Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: src/codec/SkBmpRLECodec.cpp

Issue 1332053002: Fill incomplete images in SkCodec parent class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Response to comments Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 21 matching lines...) Expand all
32 , fSampleX(1) 32 , fSampleX(1)
33 {} 33 {}
34 34
35 /* 35 /*
36 * Initiates the bitmap decode 36 * Initiates the bitmap decode
37 */ 37 */
38 SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, 38 SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo,
39 void* dst, size_t dstRowBytes, 39 void* dst, size_t dstRowBytes,
40 const Options& opts, 40 const Options& opts,
41 SkPMColor* inputColorPtr, 41 SkPMColor* inputColorPtr,
42 int* inputColorCount) { 42 int* inputColorCount,
43 int* incompleteScanlines) {
43 if (!this->rewindIfNeeded()) { 44 if (!this->rewindIfNeeded()) {
44 return kCouldNotRewind; 45 return kCouldNotRewind;
45 } 46 }
46 if (opts.fSubset) { 47 if (opts.fSubset) {
47 // Subsets are not supported. 48 // Subsets are not supported.
48 return kUnimplemented; 49 return kUnimplemented;
49 } 50 }
50 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 51 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
51 SkCodecPrintf("Error: scaling not supported.\n"); 52 SkCodecPrintf("Error: scaling not supported.\n");
52 return kInvalidScale; 53 return kInvalidScale;
53 } 54 }
54 if (!conversion_possible(dstInfo, this->getInfo())) { 55 if (!conversion_possible(dstInfo, this->getInfo())) {
55 SkCodecPrintf("Error: cannot convert input type to output type.\n"); 56 SkCodecPrintf("Error: cannot convert input type to output type.\n");
56 return kInvalidConversion; 57 return kInvalidConversion;
57 } 58 }
58 59
59 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol orCount); 60 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol orCount);
60 if (kSuccess != result) { 61 if (kSuccess != result) {
61 return result; 62 return result;
62 } 63 }
63 64
64 // Perform the decode 65 // Perform the decode
65 return this->decodeRows(dstInfo, dst, dstRowBytes, opts); 66 uint32_t rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts);
67 if (rows != dstInfo.height()) {
68 // We do not need to set incompleteScanlines because decodeRows() will h andle
scroggo 2015/09/25 15:55:05 How? It does not look like you do anything with th
msarett 2015/10/01 12:44:52 We always fill the background on RLE decodes, beca
69 // filling the background.
70 return kIncompleteInput;
71 }
66 } 72 }
67 73
68 /* 74 /*
69 * Process the color table for the bmp input 75 * Process the color table for the bmp input
70 */ 76 */
71 bool SkBmpRLECodec::createColorTable(int* numColors) { 77 bool SkBmpRLECodec::createColorTable(int* numColors) {
72 // Allocate memory for color table 78 // Allocate memory for color table
73 uint32_t colorBytes = 0; 79 uint32_t colorBytes = 0;
74 SkPMColor colorTable[256]; 80 SkPMColor colorTable[256];
75 if (this->bitsPerPixel() <= 8) { 81 if (this->bitsPerPixel() <= 8) {
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 281
276 SkScaledCodec::ComputeSampleSize(dstInfo, this->getInfo(), &fSampleX, NULL); 282 SkScaledCodec::ComputeSampleSize(dstInfo, this->getInfo(), &fSampleX, NULL);
277 283
278 return SkCodec::kSuccess; 284 return SkCodec::kSuccess;
279 } 285 }
280 286
281 /* 287 /*
282 * Performs the bitmap decoding for RLE input format 288 * Performs the bitmap decoding for RLE input format
283 * RLE decoding is performed all at once, rather than a one row at a time 289 * RLE decoding is performed all at once, rather than a one row at a time
284 */ 290 */
285 SkCodec::Result SkBmpRLECodec::decodeRows(const SkImageInfo& dstInfo, 291 uint32_t SkBmpRLECodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
286 void* dst, size_t dstRowBytes, 292 const Options& opts) {
287 const Options& opts) {
288 // Set RLE flags 293 // Set RLE flags
289 static const uint8_t RLE_ESCAPE = 0; 294 static const uint8_t RLE_ESCAPE = 0;
290 static const uint8_t RLE_EOL = 0; 295 static const uint8_t RLE_EOL = 0;
291 static const uint8_t RLE_EOF = 1; 296 static const uint8_t RLE_EOF = 1;
292 static const uint8_t RLE_DELTA = 2; 297 static const uint8_t RLE_DELTA = 2;
293 298
294 // Set constant values 299 // Set constant values
295 const int width = this->getInfo().width(); 300 const int width = this->getInfo().width();
296 const int height = dstInfo.height(); 301 const int height = dstInfo.height();
297 302
298 // Destination parameters 303 // Destination parameters
299 int x = 0; 304 int x = 0;
300 int y = 0; 305 int y = 0;
301 306
302 // 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,
303 // the skipped pixels will be transparent. 308 // the skipped pixels will be transparent.
304 // 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
305 // type that makes sense for the destination format. 310 // type that makes sense for the destination format.
306 SkASSERT(kN32_SkColorType == dstInfo.colorType()); 311 SkASSERT(kN32_SkColorType == dstInfo.colorType());
307 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, height, SK_ColorTRANSPARENT, 312 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroI nitialized);
308 NULL, opts.fZeroInitialized);
309 313
310 while (true) { 314 while (true) {
311 // 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
312 // succeeded. 316 // succeeded.
313 if (y >= height) { 317 if (y >= height) {
314 // 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
315 // success, but we may be performing a scanline decode, which 319 // success, but we may be performing a scanline decode, which
316 // may require us to stop before decoding the full height. 320 // would require us to stop before decoding the full height.
317 return kSuccess; 321 return height;
318 } 322 }
319 323
320 // Every entry takes at least two bytes 324 // Every entry takes at least two bytes
321 if ((int) fRLEBytes - fCurrRLEByte < 2) { 325 if ((int) fRLEBytes - fCurrRLEByte < 2) {
322 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); 326 SkCodecPrintf("Warning: might be incomplete RLE input.\n");
323 if (this->checkForMoreData() < 2) { 327 if (this->checkForMoreData() < 2) {
324 return kIncompleteInput; 328 return y;
325 } 329 }
326 } 330 }
327 331
328 // Read the next two bytes. These bytes have different meanings 332 // Read the next two bytes. These bytes have different meanings
329 // depending on their values. In the first interpretation, the first 333 // depending on their values. In the first interpretation, the first
330 // 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
331 // task to perform. 335 // task to perform.
332 const uint8_t flag = fStreamBuffer.get()[fCurrRLEByte++]; 336 const uint8_t flag = fStreamBuffer.get()[fCurrRLEByte++];
333 const uint8_t task = fStreamBuffer.get()[fCurrRLEByte++]; 337 const uint8_t task = fStreamBuffer.get()[fCurrRLEByte++];
334 338
335 // Perform decoding 339 // Perform decoding
336 if (RLE_ESCAPE == flag) { 340 if (RLE_ESCAPE == flag) {
337 switch (task) { 341 switch (task) {
338 case RLE_EOL: 342 case RLE_EOL:
339 x = 0; 343 x = 0;
340 y++; 344 y++;
341 break; 345 break;
342 case RLE_EOF: 346 case RLE_EOF:
343 return kSuccess; 347 return kSuccess;
344 case RLE_DELTA: { 348 case RLE_DELTA: {
345 // Two bytes are needed to specify delta 349 // Two bytes are needed to specify delta
346 if ((int) fRLEBytes - fCurrRLEByte < 2) { 350 if ((int) fRLEBytes - fCurrRLEByte < 2) {
347 SkCodecPrintf("Warning: might be incomplete RLE input.\n "); 351 SkCodecPrintf("Warning: might be incomplete RLE input.\n ");
348 if (this->checkForMoreData() < 2) { 352 if (this->checkForMoreData() < 2) {
349 return kIncompleteInput; 353 return y;
350 } 354 }
351 } 355 }
352 // Modify x and y 356 // Modify x and y
353 const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++]; 357 const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++];
354 const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++]; 358 const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++];
355 x += dx; 359 x += dx;
356 y += dy; 360 y += dy;
357 if (x > width || y > height) { 361 if (x > width || y > height) {
358 SkCodecPrintf("Warning: invalid RLE input.\n"); 362 SkCodecPrintf("Warning: invalid RLE input.\n");
359 return kInvalidInput; 363 return y - dy;
360 } 364 }
361 break; 365 break;
362 } 366 }
363 default: { 367 default: {
364 // If task does not match any of the above signals, it 368 // If task does not match any of the above signals, it
365 // indicates that we have a sequence of non-RLE pixels. 369 // indicates that we have a sequence of non-RLE pixels.
366 // Furthermore, the value of task is equal to the number 370 // Furthermore, the value of task is equal to the number
367 // of pixels to interpret. 371 // of pixels to interpret.
368 uint8_t numPixels = task; 372 uint8_t numPixels = task;
369 const size_t rowBytes = compute_row_bytes(numPixels, 373 const size_t rowBytes = compute_row_bytes(numPixels,
370 this->bitsPerPixel()); 374 this->bitsPerPixel());
371 // Abort if setting numPixels moves us off the edge of the 375 // Abort if setting numPixels moves us off the edge of the
372 // image. 376 // image.
373 if (x + numPixels > width) { 377 if (x + numPixels > width) {
374 SkCodecPrintf("Warning: invalid RLE input.\n"); 378 SkCodecPrintf("Warning: invalid RLE input.\n");
375 return kInvalidInput; 379 return y;
376 } 380 }
377 // Also abort if there are not enough bytes 381 // Also abort if there are not enough bytes
378 // remaining in the stream to set numPixels. 382 // remaining in the stream to set numPixels.
379 if ((int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) { 383 if ((int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) {
380 SkCodecPrintf("Warning: might be incomplete RLE input.\n "); 384 SkCodecPrintf("Warning: might be incomplete RLE input.\n ");
381 if (this->checkForMoreData() < SkAlign2(rowBytes)) { 385 if (this->checkForMoreData() < SkAlign2(rowBytes)) {
382 return kIncompleteInput; 386 return y;
383 } 387 }
384 } 388 }
385 // Set numPixels number of pixels 389 // Set numPixels number of pixels
386 while (numPixels > 0) { 390 while (numPixels > 0) {
387 switch(this->bitsPerPixel()) { 391 switch(this->bitsPerPixel()) {
388 case 4: { 392 case 4: {
389 SkASSERT(fCurrRLEByte < fRLEBytes); 393 SkASSERT(fCurrRLEByte < fRLEBytes);
390 uint8_t val = fStreamBuffer.get()[fCurrRLEByte++ ]; 394 uint8_t val = fStreamBuffer.get()[fCurrRLEByte++ ];
391 setPixel(dst, dstRowBytes, dstInfo, x++, 395 setPixel(dst, dstRowBytes, dstInfo, x++,
392 y, val >> 4); 396 y, val >> 4);
(...skipping 15 matching lines...) Expand all
408 SkASSERT(fCurrRLEByte + 2 < fRLEBytes); 412 SkASSERT(fCurrRLEByte + 2 < fRLEBytes);
409 uint8_t blue = fStreamBuffer.get()[fCurrRLEByte+ +]; 413 uint8_t blue = fStreamBuffer.get()[fCurrRLEByte+ +];
410 uint8_t green = fStreamBuffer.get()[fCurrRLEByte ++]; 414 uint8_t green = fStreamBuffer.get()[fCurrRLEByte ++];
411 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++ ]; 415 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++ ];
412 setRGBPixel(dst, dstRowBytes, dstInfo, 416 setRGBPixel(dst, dstRowBytes, dstInfo,
413 x++, y, red, green, blue); 417 x++, y, red, green, blue);
414 numPixels--; 418 numPixels--;
415 } 419 }
416 default: 420 default:
417 SkASSERT(false); 421 SkASSERT(false);
418 return kInvalidInput; 422 return y;
419 } 423 }
420 } 424 }
421 // Skip a byte if necessary to maintain alignment 425 // Skip a byte if necessary to maintain alignment
422 if (!SkIsAlign2(rowBytes)) { 426 if (!SkIsAlign2(rowBytes)) {
423 fCurrRLEByte++; 427 fCurrRLEByte++;
424 } 428 }
425 break; 429 break;
426 } 430 }
427 } 431 }
428 } else { 432 } else {
429 // 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
430 // pixels to set in RLE mode. 434 // pixels to set in RLE mode.
431 const uint8_t numPixels = flag; 435 const uint8_t numPixels = flag;
432 const int endX = SkTMin<int>(x + numPixels, width); 436 const int endX = SkTMin<int>(x + numPixels, width);
433 437
434 if (24 == this->bitsPerPixel()) { 438 if (24 == this->bitsPerPixel()) {
435 // 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.
436 // There are two more required bytes to finish encoding the 440 // There are two more required bytes to finish encoding the
437 // color. 441 // color.
438 if ((int) fRLEBytes - fCurrRLEByte < 2) { 442 if ((int) fRLEBytes - fCurrRLEByte < 2) {
439 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); 443 SkCodecPrintf("Warning: might be incomplete RLE input.\n");
440 if (this->checkForMoreData() < 2) { 444 if (this->checkForMoreData() < 2) {
441 return kIncompleteInput; 445 return y;
442 } 446 }
443 } 447 }
444 448
445 // Fill the pixels up to endX with the specified color 449 // Fill the pixels up to endX with the specified color
446 uint8_t blue = task; 450 uint8_t blue = task;
447 uint8_t green = fStreamBuffer.get()[fCurrRLEByte++]; 451 uint8_t green = fStreamBuffer.get()[fCurrRLEByte++];
448 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++]; 452 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++];
449 while (x < endX) { 453 while (x < endX) {
450 setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, b lue); 454 setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, b lue);
451 } 455 }
(...skipping 11 matching lines...) Expand all
463 467
464 // Set the indicated number of pixels 468 // Set the indicated number of pixels
465 for (int which = 0; x < endX; x++) { 469 for (int which = 0; x < endX; x++) {
466 setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]); 470 setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]);
467 which = !which; 471 which = !which;
468 } 472 }
469 } 473 }
470 } 474 }
471 } 475 }
472 } 476 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698