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 "SkBmpCodec.h" | 8 #include "SkBmpCodec.h" |
9 #include "SkBmpMaskCodec.h" | 9 #include "SkBmpMaskCodec.h" |
10 #include "SkBmpRLECodec.h" | 10 #include "SkBmpRLECodec.h" |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 // Create mask struct | 279 // Create mask struct |
280 SkMasks::InputMasks inputMasks; | 280 SkMasks::InputMasks inputMasks; |
281 memset(&inputMasks, 0, sizeof(SkMasks::InputMasks)); | 281 memset(&inputMasks, 0, sizeof(SkMasks::InputMasks)); |
282 | 282 |
283 // Determine the input compression format and set bit masks if necessary | 283 // Determine the input compression format and set bit masks if necessary |
284 uint32_t maskBytes = 0; | 284 uint32_t maskBytes = 0; |
285 BmpInputFormat inputFormat = kUnknown_BmpInputFormat; | 285 BmpInputFormat inputFormat = kUnknown_BmpInputFormat; |
286 switch (compression) { | 286 switch (compression) { |
287 case kNone_BmpCompressionMethod: | 287 case kNone_BmpCompressionMethod: |
288 inputFormat = kStandard_BmpInputFormat; | 288 inputFormat = kStandard_BmpInputFormat; |
| 289 |
| 290 // In addition to more standard pixel compression formats, bmp suppo
rts |
| 291 // the use of bit masks to determine pixel components. The standard |
| 292 // format for representing 16-bit colors is 555 (XRRRRRGGGGGBBBBB), |
| 293 // which does not map well to any Skia color formats. For this reas
on, |
| 294 // we will always enable mask mode with 16 bits per pixel. |
| 295 if (16 == bitsPerPixel) { |
| 296 inputMasks.red = 0x7C00; |
| 297 inputMasks.green = 0x03E0; |
| 298 inputMasks.blue = 0x001F; |
| 299 inputFormat = kBitMask_BmpInputFormat; |
| 300 } |
289 break; | 301 break; |
290 case k8BitRLE_BmpCompressionMethod: | 302 case k8BitRLE_BmpCompressionMethod: |
291 if (bitsPerPixel != 8) { | 303 if (bitsPerPixel != 8) { |
292 SkCodecPrintf("Warning: correcting invalid bitmap format.\n"); | 304 SkCodecPrintf("Warning: correcting invalid bitmap format.\n"); |
293 bitsPerPixel = 8; | 305 bitsPerPixel = 8; |
294 } | 306 } |
295 inputFormat = kRLE_BmpInputFormat; | 307 inputFormat = kRLE_BmpInputFormat; |
296 break; | 308 break; |
297 case k4BitRLE_BmpCompressionMethod: | 309 case k4BitRLE_BmpCompressionMethod: |
298 if (bitsPerPixel != 4) { | 310 if (bitsPerPixel != 4) { |
(...skipping 25 matching lines...) Expand all Loading... |
324 case kInfoV3_BmpHeaderType: | 336 case kInfoV3_BmpHeaderType: |
325 case kInfoV4_BmpHeaderType: | 337 case kInfoV4_BmpHeaderType: |
326 case kInfoV5_BmpHeaderType: | 338 case kInfoV5_BmpHeaderType: |
327 // Header types are matched based on size. If the header | 339 // Header types are matched based on size. If the header |
328 // is V2+, we are guaranteed to be able to read at least | 340 // is V2+, we are guaranteed to be able to read at least |
329 // this size. | 341 // this size. |
330 SkASSERT(infoBytesRemaining >= 48); | 342 SkASSERT(infoBytesRemaining >= 48); |
331 inputMasks.red = get_int(iBuffer.get(), 36); | 343 inputMasks.red = get_int(iBuffer.get(), 36); |
332 inputMasks.green = get_int(iBuffer.get(), 40); | 344 inputMasks.green = get_int(iBuffer.get(), 40); |
333 inputMasks.blue = get_int(iBuffer.get(), 44); | 345 inputMasks.blue = get_int(iBuffer.get(), 44); |
| 346 |
| 347 if (kInfoV2_BmpHeaderType == headerType || |
| 348 (kInfoV3_BmpHeaderType == headerType && !inIco)) { |
| 349 break; |
| 350 } |
| 351 |
| 352 // V3+ bmp files introduce an alpha mask and allow the creat
or of the image |
| 353 // to use the alpha channels. However, many of these images
leave the |
| 354 // alpha channel blank and expect to be rendered as opaque.
This is the |
| 355 // case for almost all V3 images, so we ignore the alpha mas
k. For V4+ |
| 356 // images in kMask mode, we will use the alpha mask. Additi
onally, V3 |
| 357 // bmp-in-ico expect us to use the alpha mask. |
| 358 // |
| 359 // skbug.com/4116: We should perhaps also apply the alpha ma
sk in kStandard |
| 360 // mode. We just haven't seen any images th
at expect this |
| 361 // behavior. |
| 362 // |
| 363 // Header types are matched based on size. If the header is |
| 364 // V3+, we are guaranteed to be able to read at least this s
ize. |
| 365 SkASSERT(infoBytesRemaining > 52); |
| 366 inputMasks.alpha = get_int(iBuffer.get(), 48); |
334 break; | 367 break; |
335 case kOS2VX_BmpHeaderType: | 368 case kOS2VX_BmpHeaderType: |
336 // TODO: Decide if we intend to support this. | 369 // TODO: Decide if we intend to support this. |
337 // It is unsupported in the previous version and | 370 // It is unsupported in the previous version and |
338 // in chromium. I have not come across a test case | 371 // in chromium. I have not come across a test case |
339 // that uses this format. | 372 // that uses this format. |
340 SkCodecPrintf("Error: huffman format unsupported.\n"); | 373 SkCodecPrintf("Error: huffman format unsupported.\n"); |
341 return false; | 374 return false; |
342 default: | 375 default: |
343 SkCodecPrintf("Error: invalid bmp bit masks header.\n"); | 376 SkCodecPrintf("Error: invalid bmp bit masks header.\n"); |
(...skipping 15 matching lines...) Expand all Loading... |
359 case kCMYK_BmpCompressionMethod: | 392 case kCMYK_BmpCompressionMethod: |
360 case kCMYK8BitRLE_BmpCompressionMethod: | 393 case kCMYK8BitRLE_BmpCompressionMethod: |
361 case kCMYK4BitRLE_BmpCompressionMethod: | 394 case kCMYK4BitRLE_BmpCompressionMethod: |
362 // TODO: Same as above. | 395 // TODO: Same as above. |
363 SkCodecPrintf("Error: CMYK not supported for bitmap decoding.\n"); | 396 SkCodecPrintf("Error: CMYK not supported for bitmap decoding.\n"); |
364 return false; | 397 return false; |
365 default: | 398 default: |
366 SkCodecPrintf("Error: invalid format for bitmap decoding.\n"); | 399 SkCodecPrintf("Error: invalid format for bitmap decoding.\n"); |
367 return false; | 400 return false; |
368 } | 401 } |
369 | |
370 // Most versions of bmps should be rendered as opaque. Either they do | |
371 // not have an alpha channel, or they expect the alpha channel to be | |
372 // ignored. V3+ bmp files introduce an alpha mask and allow the creator | |
373 // of the image to use the alpha channels. However, many of these images | |
374 // leave the alpha channel blank and expect to be rendered as opaque. This | |
375 // is the case for almost all V3 images, so we render these as opaque. For | |
376 // V4+ images in kMask mode, we will use the alpha mask. | |
377 // | |
378 // skbug.com/4116: We should perhaps also apply the alpha mask in kStandard | |
379 // mode. We just haven't seen any images that expect this | |
380 // behavior. | |
381 // | |
382 // Additionally, V3 bmp-in-ico may use the alpha mask. | |
383 SkAlphaType alphaType = kOpaque_SkAlphaType; | |
384 if ((kInfoV3_BmpHeaderType == headerType && inIco) || | |
385 kInfoV4_BmpHeaderType == headerType || | |
386 kInfoV5_BmpHeaderType == headerType) { | |
387 // Header types are matched based on size. If the header is | |
388 // V3+, we are guaranteed to be able to read at least this size. | |
389 SkASSERT(infoBytesRemaining > 52); | |
390 inputMasks.alpha = get_int(iBuffer.get(), 48); | |
391 if (inputMasks.alpha != 0) { | |
392 alphaType = kUnpremul_SkAlphaType; | |
393 } | |
394 } | |
395 iBuffer.reset(); | 402 iBuffer.reset(); |
396 | 403 |
397 // Additionally, 32 bit bmp-in-icos use the alpha channel. | |
398 // FIXME (msarett): Don't all bmp-in-icos use the alpha channel? | |
399 // And, RLE inputs may skip pixels, leaving them as transparent. This | |
400 // is uncommon, but we cannot be certain that an RLE bmp will be opaque. | |
401 if ((inIco && 32 == bitsPerPixel) || (kRLE_BmpInputFormat == inputFormat)) { | |
402 alphaType = kUnpremul_SkAlphaType; | |
403 } | |
404 | |
405 // Check for valid bits per pixel. | |
406 // At the same time, use this information to choose a suggested color type | |
407 // and to set default masks. | |
408 SkColorType colorType = kN32_SkColorType; | |
409 switch (bitsPerPixel) { | |
410 // In addition to more standard pixel compression formats, bmp supports | |
411 // the use of bit masks to determine pixel components. The standard | |
412 // format for representing 16-bit colors is 555 (XRRRRRGGGGGBBBBB), | |
413 // which does not map well to any Skia color formats. For this reason, | |
414 // we will always enable mask mode with 16 bits per pixel. | |
415 case 16: | |
416 if (kBitMask_BmpInputFormat != inputFormat) { | |
417 inputMasks.red = 0x7C00; | |
418 inputMasks.green = 0x03E0; | |
419 inputMasks.blue = 0x001F; | |
420 inputFormat = kBitMask_BmpInputFormat; | |
421 } | |
422 break; | |
423 // We want to decode to kIndex_8 for input formats that are already | |
424 // designed in index format. | |
425 case 1: | |
426 case 2: | |
427 case 4: | |
428 case 8: | |
429 // However, we cannot in RLE format since we may need to leave some | |
430 // pixels as transparent. Similarly, we also cannot for ICO images | |
431 // since we may need to apply a transparent mask. | |
432 if (kRLE_BmpInputFormat != inputFormat && !inIco) { | |
433 colorType = kIndex_8_SkColorType; | |
434 } | |
435 | |
436 // Mask bmps must have 16, 24, or 32 bits per pixel. | |
437 if (kBitMask_BmpInputFormat == inputFormat) { | |
438 SkCodecPrintf("Error: invalid input value of bits per pixel for
mask bmp.\n"); | |
439 return false; | |
440 } | |
441 case 24: | |
442 case 32: | |
443 break; | |
444 default: | |
445 SkCodecPrintf("Error: invalid input value for bits per pixel.\n"); | |
446 return false; | |
447 } | |
448 | |
449 // Check that input bit masks are valid and create the masks object | |
450 SkAutoTDelete<SkMasks> | |
451 masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel)); | |
452 if (nullptr == masks) { | |
453 SkCodecPrintf("Error: invalid input masks.\n"); | |
454 return false; | |
455 } | |
456 | |
457 // Check for a valid number of total bytes when in RLE mode | |
458 if (totalBytes <= offset && kRLE_BmpInputFormat == inputFormat) { | |
459 SkCodecPrintf("Error: RLE requires valid input size.\n"); | |
460 return false; | |
461 } | |
462 const size_t RLEBytes = totalBytes - offset; | |
463 | |
464 // Calculate the number of bytes read so far | 404 // Calculate the number of bytes read so far |
465 const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes; | 405 const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes; |
466 if (!inIco && offset < bytesRead) { | 406 if (!inIco && offset < bytesRead) { |
467 // TODO (msarett): Do we really want to fail if the offset in the header
is invalid? | 407 // TODO (msarett): Do we really want to fail if the offset in the header
is invalid? |
468 // Seems like we can just assume that the offset is zero
and try to decode? | 408 // Seems like we can just assume that the offset is zero
and try to decode? |
469 // Maybe we don't want to try to decode corrupt images? | 409 // Maybe we don't want to try to decode corrupt images? |
470 SkCodecPrintf("Error: pixel data offset less than header size.\n"); | 410 SkCodecPrintf("Error: pixel data offset less than header size.\n"); |
471 return false; | 411 return false; |
472 } | 412 } |
473 | 413 |
474 // Skip to the start of the pixel array. | |
475 // We can do this here because there is no color table to read | |
476 // in bit mask mode. | |
477 if (!inIco && kBitMask_BmpInputFormat == inputFormat) { | |
478 if (stream->skip(offset - bytesRead) != offset - bytesRead) { | |
479 SkCodecPrintf("Error: unable to skip to image data.\n"); | |
480 return false; | |
481 } | |
482 } | |
483 | 414 |
484 if (codecOut) { | 415 |
485 // BMPs-in-ICOs contain an alpha mask after the image which means we | 416 switch (inputFormat) { |
486 // cannot guarantee that an image is opaque, even if the bmp thinks | 417 case kStandard_BmpInputFormat: { |
487 // it is. | 418 // BMPs-in-ICOs often contain an alpha mask after the image, which |
488 bool isOpaque = kOpaque_SkAlphaType == alphaType; | 419 // means we cannot guarantee that an image is opaque, even if the |
489 if (inIco) { | 420 // embedded bmp is opaque. |
490 alphaType = kUnpremul_SkAlphaType; | 421 // We use |isOpaque| to indicate if the BMP itself is opaque, but |
| 422 // still need to recommend kUnpremul when it is contained in an ICO. |
| 423 SkColorType colorType = kN32_SkColorType; |
| 424 SkAlphaType alphaType = inIco ? kUnpremul_SkAlphaType : kOpaque_SkAl
phaType; |
| 425 bool isOpaque = true; |
| 426 switch (bitsPerPixel) { |
| 427 // Palette formats |
| 428 case 1: |
| 429 case 2: |
| 430 case 4: |
| 431 case 8: |
| 432 // We cannot recommend a palette color type for ICOs because
they |
| 433 // may contain a transparency mask. |
| 434 if (!inIco) { |
| 435 colorType = kIndex_8_SkColorType; |
| 436 } |
| 437 break; |
| 438 case 24: |
| 439 case 32: |
| 440 // 32-bit BMP-in-ICOs actually use the alpha channel in plac
e of a |
| 441 // transparency mask. |
| 442 if (inIco) { |
| 443 isOpaque = false; |
| 444 } |
| 445 break; |
| 446 default: |
| 447 SkCodecPrintf("Error: invalid input value for bits per pixel
.\n"); |
| 448 return false; |
| 449 } |
| 450 |
| 451 if (codecOut) { |
| 452 // We require streams to have a memory base for Bmp-in-Ico decod
es. |
| 453 SkASSERT(!inIco || nullptr != stream->getMemoryBase()); |
| 454 |
| 455 // Set the image info and create a codec. |
| 456 const SkImageInfo imageInfo = SkImageInfo::Make(width, height, c
olorType, |
| 457 alphaType); |
| 458 *codecOut = new SkBmpStandardCodec(imageInfo, stream, bitsPerPix
el, numColors, |
| 459 bytesPerColor, offset - bytesRead, rowOrder, isOpaque, i
nIco); |
| 460 |
| 461 } |
| 462 return true; |
491 } | 463 } |
492 | 464 |
493 // Set the image info | 465 case kBitMask_BmpInputFormat: { |
494 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, | 466 // Bmp-in-Ico must be standard mode |
495 colorType, alphaType); | 467 if (inIco) { |
| 468 SkCodecPrintf("Error: Icos may not use bit mask format.\n"); |
| 469 return false; |
| 470 } |
496 | 471 |
497 // Return the codec | 472 switch (bitsPerPixel) { |
498 switch (inputFormat) { | 473 case 16: |
499 case kStandard_BmpInputFormat: | 474 case 24: |
500 // We require streams to have a memory base for Bmp-in-Ico decod
es. | 475 case 32: |
501 SkASSERT(!inIco || nullptr != stream->getMemoryBase()); | 476 break; |
502 *codecOut = new SkBmpStandardCodec(imageInfo, stream, bitsPerPix
el, numColors, | 477 default: |
503 bytesPerColor, offset - bytesRead, rowOrder, isOpaque, i
nIco); | 478 SkCodecPrintf("Error: invalid input value for bits per pixel
.\n"); |
504 return true; | 479 return false; |
505 case kBitMask_BmpInputFormat: | 480 } |
506 // Bmp-in-Ico must be standard mode | 481 |
507 if (inIco) { | 482 // Skip to the start of the pixel array. |
508 SkCodecPrintf("Error: Icos may not use bit mask format.\n"); | 483 // We can do this here because there is no color table to read |
| 484 // in bit mask mode. |
| 485 if (stream->skip(offset - bytesRead) != offset - bytesRead) { |
| 486 SkCodecPrintf("Error: unable to skip to image data.\n"); |
| 487 return false; |
| 488 } |
| 489 |
| 490 if (codecOut) { |
| 491 // Check that input bit masks are valid and create the masks obj
ect |
| 492 SkAutoTDelete<SkMasks> masks(SkMasks::CreateMasks(inputMasks, bi
tsPerPixel)); |
| 493 if (nullptr == masks) { |
| 494 SkCodecPrintf("Error: invalid input masks.\n"); |
509 return false; | 495 return false; |
510 } | 496 } |
511 | 497 |
| 498 // Set the image info |
| 499 SkAlphaType alphaType = masks->getAlphaMask() ? kUnpremul_SkAlph
aType : |
| 500 kOpaque_SkAlphaType; |
| 501 const SkImageInfo imageInfo = SkImageInfo::Make(width, height, k
N32_SkColorType, |
| 502 alphaType); |
512 *codecOut = new SkBmpMaskCodec(imageInfo, stream, bitsPerPixel,
masks.release(), | 503 *codecOut = new SkBmpMaskCodec(imageInfo, stream, bitsPerPixel,
masks.release(), |
513 rowOrder); | 504 rowOrder); |
514 return true; | 505 } |
515 case kRLE_BmpInputFormat: | 506 return true; |
516 // Bmp-in-Ico must be standard mode | 507 } |
517 // When inIco is true, this line cannot be reached, since we | 508 |
518 // require that RLE Bmps have a valid number of totalBytes, and | 509 case kRLE_BmpInputFormat: { |
519 // Icos skip the header that contains totalBytes. | 510 // We should not reach this point without a valid value of bitsPerPi
xel. |
520 SkASSERT(!inIco); | 511 SkASSERT(4 == bitsPerPixel || 8 == bitsPerPixel || 24 == bitsPerPixe
l); |
| 512 |
| 513 // Check for a valid number of total bytes when in RLE mode |
| 514 if (totalBytes <= offset) { |
| 515 SkCodecPrintf("Error: RLE requires valid input size.\n"); |
| 516 return false; |
| 517 } |
| 518 const size_t RLEBytes = totalBytes - offset; |
| 519 |
| 520 // Bmp-in-Ico must be standard mode |
| 521 // When inIco is true, this line cannot be reached, since we |
| 522 // require that RLE Bmps have a valid number of totalBytes, and |
| 523 // Icos skip the header that contains totalBytes. |
| 524 SkASSERT(!inIco); |
| 525 |
| 526 if (codecOut) { |
| 527 // RLE inputs may skip pixels, leaving them as transparent. Thi
s |
| 528 // is uncommon, but we cannot be certain that an RLE bmp will be |
| 529 // opaque. |
| 530 const SkImageInfo imageInfo = SkImageInfo::Make(width, height, k
N32_SkColorType, |
| 531 kUnpremul_SkAlphaType); |
521 *codecOut = new SkBmpRLECodec(imageInfo, stream, bitsPerPixel, n
umColors, | 532 *codecOut = new SkBmpRLECodec(imageInfo, stream, bitsPerPixel, n
umColors, |
522 bytesPerColor, offset - bytesRead, rowOrder, RLEBytes); | 533 bytesPerColor, offset - bytesRead, rowOrder, RLEBytes); |
523 return true; | 534 } |
524 default: | 535 return true; |
525 SkASSERT(false); | |
526 return false; | |
527 } | 536 } |
| 537 default: |
| 538 SkASSERT(false); |
| 539 return false; |
528 } | 540 } |
529 | |
530 return true; | |
531 } | 541 } |
532 | 542 |
533 /* | 543 /* |
534 * Creates a bmp decoder | 544 * Creates a bmp decoder |
535 * Reads enough of the stream to determine the image format | 545 * Reads enough of the stream to determine the image format |
536 */ | 546 */ |
537 SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) { | 547 SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) { |
538 SkAutoTDelete<SkStream> streamDeleter(stream); | 548 SkAutoTDelete<SkStream> streamDeleter(stream); |
539 SkCodec* codec = nullptr; | 549 SkCodec* codec = nullptr; |
540 if (ReadHeader(stream, inIco, &codec)) { | 550 if (ReadHeader(stream, inIco, &codec)) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
586 } | 596 } |
587 | 597 |
588 bool SkBmpCodec::skipRows(int count) { | 598 bool SkBmpCodec::skipRows(int count) { |
589 const size_t bytesToSkip = count * fSrcRowBytes; | 599 const size_t bytesToSkip = count * fSrcRowBytes; |
590 return this->stream()->skip(bytesToSkip) == bytesToSkip; | 600 return this->stream()->skip(bytesToSkip) == bytesToSkip; |
591 } | 601 } |
592 | 602 |
593 bool SkBmpCodec::onSkipScanlines(int count) { | 603 bool SkBmpCodec::onSkipScanlines(int count) { |
594 return this->skipRows(count); | 604 return this->skipRows(count); |
595 } | 605 } |
OLD | NEW |