1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "src/codec/SkBmpCodec.h" 9 10#include <memory> 11 12#include "include/core/SkStream.h" 13#include "include/private/SkColorData.h" 14#include "src/codec/SkBmpMaskCodec.h" 15#include "src/codec/SkBmpRLECodec.h" 16#include "src/codec/SkBmpStandardCodec.h" 17#include "src/codec/SkCodecPriv.h" 18 19/* 20 * Defines the version and type of the second bitmap header 21 */ 22enum BmpHeaderType { 23 kInfoV1_BmpHeaderType, 24 kInfoV2_BmpHeaderType, 25 kInfoV3_BmpHeaderType, 26 kInfoV4_BmpHeaderType, 27 kInfoV5_BmpHeaderType, 28 kOS2V1_BmpHeaderType, 29 kOS2VX_BmpHeaderType, 30 kUnknown_BmpHeaderType 31}; 32 33/* 34 * Possible bitmap compression types 35 */ 36enum BmpCompressionMethod { 37 kNone_BmpCompressionMethod = 0, 38 k8BitRLE_BmpCompressionMethod = 1, 39 k4BitRLE_BmpCompressionMethod = 2, 40 kBitMasks_BmpCompressionMethod = 3, 41 kJpeg_BmpCompressionMethod = 4, 42 kPng_BmpCompressionMethod = 5, 43 kAlphaBitMasks_BmpCompressionMethod = 6, 44 kCMYK_BmpCompressionMethod = 11, 45 kCMYK8BitRLE_BmpCompressionMethod = 12, 46 kCMYK4BitRLE_BmpCompressionMethod = 13 47}; 48 49/* 50 * Used to define the input format of the bmp 51 */ 52enum BmpInputFormat { 53 kStandard_BmpInputFormat, 54 kRLE_BmpInputFormat, 55 kBitMask_BmpInputFormat, 56 kUnknown_BmpInputFormat 57}; 58 59/* 60 * Checks the start of the stream to see if the image is a bitmap 61 */ 62bool SkBmpCodec::IsBmp(const void* buffer, size_t bytesRead) { 63 // TODO: Support "IC", "PT", "CI", "CP", "BA" 64 const char bmpSig[] = { 'B', 'M' }; 65 return bytesRead >= sizeof(bmpSig) && !memcmp(buffer, bmpSig, sizeof(bmpSig)); 66} 67 68/* 69 * Assumes IsBmp was called and returned true 70 * Creates a bmp decoder 71 * Reads enough of the stream to determine the image format 72 */ 73std::unique_ptr<SkCodec> SkBmpCodec::MakeFromStream(std::unique_ptr<SkStream> stream, 74 Result* result) { 75 return SkBmpCodec::MakeFromStream(std::move(stream), result, false); 76} 77 78/* 79 * Creates a bmp decoder for a bmp embedded in ico 80 * Reads enough of the stream to determine the image format 81 */ 82std::unique_ptr<SkCodec> SkBmpCodec::MakeFromIco(std::unique_ptr<SkStream> stream, Result* result) { 83 return SkBmpCodec::MakeFromStream(std::move(stream), result, true); 84} 85 86// Header size constants 87static constexpr uint32_t kBmpHeaderBytes = 14; 88static constexpr uint32_t kBmpHeaderBytesPlusFour = kBmpHeaderBytes + 4; 89static constexpr uint32_t kBmpOS2V1Bytes = 12; 90static constexpr uint32_t kBmpOS2V2Bytes = 64; 91static constexpr uint32_t kBmpInfoBaseBytes = 16; 92static constexpr uint32_t kBmpInfoV1Bytes = 40; 93static constexpr uint32_t kBmpInfoV2Bytes = 52; 94static constexpr uint32_t kBmpInfoV3Bytes = 56; 95static constexpr uint32_t kBmpInfoV4Bytes = 108; 96static constexpr uint32_t kBmpInfoV5Bytes = 124; 97static constexpr uint32_t kBmpMaskBytes = 12; 98 99static BmpHeaderType get_header_type(size_t infoBytes) { 100 if (infoBytes >= kBmpInfoBaseBytes) { 101 // Check the version of the header 102 switch (infoBytes) { 103 case kBmpInfoV1Bytes: 104 return kInfoV1_BmpHeaderType; 105 case kBmpInfoV2Bytes: 106 return kInfoV2_BmpHeaderType; 107 case kBmpInfoV3Bytes: 108 return kInfoV3_BmpHeaderType; 109 case kBmpInfoV4Bytes: 110 return kInfoV4_BmpHeaderType; 111 case kBmpInfoV5Bytes: 112 return kInfoV5_BmpHeaderType; 113 case 16: 114 case 20: 115 case 24: 116 case 28: 117 case 32: 118 case 36: 119 case 42: 120 case 46: 121 case 48: 122 case 60: 123 case kBmpOS2V2Bytes: 124 return kOS2VX_BmpHeaderType; 125 default: 126 SkCodecPrintf("Error: unknown bmp header format.\n"); 127 return kUnknown_BmpHeaderType; 128 } 129 } if (infoBytes >= kBmpOS2V1Bytes) { 130 // The OS2V1 is treated separately because it has a unique format 131 return kOS2V1_BmpHeaderType; 132 } else { 133 // There are no valid bmp headers 134 SkCodecPrintf("Error: second bitmap header size is invalid.\n"); 135 return kUnknown_BmpHeaderType; 136 } 137} 138 139SkCodec::Result SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, 140 std::unique_ptr<SkCodec>* codecOut) { 141 // The total bytes in the bmp file 142 // We only need to use this value for RLE decoding, so we will only 143 // check that it is valid in the RLE case. 144 uint32_t totalBytes; 145 // The offset from the start of the file where the pixel data begins 146 uint32_t offset; 147 // The size of the second (info) header in bytes 148 uint32_t infoBytes; 149 150 // Bmps embedded in Icos skip the first Bmp header 151 if (!inIco) { 152 // Read the first header and the size of the second header 153 uint8_t hBuffer[kBmpHeaderBytesPlusFour]; 154 if (stream->read(hBuffer, kBmpHeaderBytesPlusFour) != 155 kBmpHeaderBytesPlusFour) { 156 SkCodecPrintf("Error: unable to read first bitmap header.\n"); 157 return kIncompleteInput; 158 } 159 160 totalBytes = get_int(hBuffer, 2); 161 offset = get_int(hBuffer, 10); 162 if (offset < kBmpHeaderBytes + kBmpOS2V1Bytes) { 163 SkCodecPrintf("Error: invalid starting location for pixel data\n"); 164 return kInvalidInput; 165 } 166 167 // The size of the second (info) header in bytes 168 // The size is the first field of the second header, so we have already 169 // read the first four infoBytes. 170 infoBytes = get_int(hBuffer, 14); 171 if (infoBytes < kBmpOS2V1Bytes) { 172 SkCodecPrintf("Error: invalid second header size.\n"); 173 return kInvalidInput; 174 } 175 } else { 176 // This value is only used by RLE compression. Bmp in Ico files do not 177 // use RLE. If the compression field is incorrectly signaled as RLE, 178 // we will catch this and signal an error below. 179 totalBytes = 0; 180 181 // Bmps in Ico cannot specify an offset. We will always assume that 182 // pixel data begins immediately after the color table. This value 183 // will be corrected below. 184 offset = 0; 185 186 // Read the size of the second header 187 uint8_t hBuffer[4]; 188 if (stream->read(hBuffer, 4) != 4) { 189 SkCodecPrintf("Error: unable to read size of second bitmap header.\n"); 190 return kIncompleteInput; 191 } 192 infoBytes = get_int(hBuffer, 0); 193 if (infoBytes < kBmpOS2V1Bytes) { 194 SkCodecPrintf("Error: invalid second header size.\n"); 195 return kInvalidInput; 196 } 197 } 198 199 // Determine image information depending on second header format 200 const BmpHeaderType headerType = get_header_type(infoBytes); 201 if (kUnknown_BmpHeaderType == headerType) { 202 return kInvalidInput; 203 } 204 205 // We already read the first four bytes of the info header to get the size 206 const uint32_t infoBytesRemaining = infoBytes - 4; 207 208 // Read the second header 209 std::unique_ptr<uint8_t[]> iBuffer(new uint8_t[infoBytesRemaining]); 210 if (stream->read(iBuffer.get(), infoBytesRemaining) != infoBytesRemaining) { 211 SkCodecPrintf("Error: unable to read second bitmap header.\n"); 212 return kIncompleteInput; 213 } 214 215 // The number of bits used per pixel in the pixel data 216 uint16_t bitsPerPixel; 217 218 // The compression method for the pixel data 219 uint32_t compression = kNone_BmpCompressionMethod; 220 221 // Number of colors in the color table, defaults to 0 or max (see below) 222 uint32_t numColors = 0; 223 224 // Bytes per color in the color table, early versions use 3, most use 4 225 uint32_t bytesPerColor; 226 227 // The image width and height 228 int width, height; 229 230 switch (headerType) { 231 case kInfoV1_BmpHeaderType: 232 case kInfoV2_BmpHeaderType: 233 case kInfoV3_BmpHeaderType: 234 case kInfoV4_BmpHeaderType: 235 case kInfoV5_BmpHeaderType: 236 case kOS2VX_BmpHeaderType: 237 // We check the size of the header before entering the if statement. 238 // We should not reach this point unless the size is large enough for 239 // these required fields. 240 SkASSERT(infoBytesRemaining >= 12); 241 width = get_int(iBuffer.get(), 0); 242 height = get_int(iBuffer.get(), 4); 243 bitsPerPixel = get_short(iBuffer.get(), 10); 244 245 // Some versions do not have these fields, so we check before 246 // overwriting the default value. 247 if (infoBytesRemaining >= 16) { 248 compression = get_int(iBuffer.get(), 12); 249 if (infoBytesRemaining >= 32) { 250 numColors = get_int(iBuffer.get(), 28); 251 } 252 } 253 254 // All of the headers that reach this point, store color table entries 255 // using 4 bytes per pixel. 256 bytesPerColor = 4; 257 break; 258 case kOS2V1_BmpHeaderType: 259 // The OS2V1 is treated separately because it has a unique format 260 width = (int) get_short(iBuffer.get(), 0); 261 height = (int) get_short(iBuffer.get(), 2); 262 bitsPerPixel = get_short(iBuffer.get(), 6); 263 bytesPerColor = 3; 264 break; 265 case kUnknown_BmpHeaderType: 266 // We'll exit above in this case. 267 SkASSERT(false); 268 return kInvalidInput; 269 } 270 271 // Check for valid dimensions from header 272 SkCodec::SkScanlineOrder rowOrder = SkCodec::kBottomUp_SkScanlineOrder; 273 if (height < 0) { 274 // We can't negate INT32_MIN. 275 if (height == INT32_MIN) { 276 return kInvalidInput; 277 } 278 279 height = -height; 280 rowOrder = SkCodec::kTopDown_SkScanlineOrder; 281 } 282 // The height field for bmp in ico is double the actual height because they 283 // contain an XOR mask followed by an AND mask 284 if (inIco) { 285 height /= 2; 286 } 287 288 // Arbitrary maximum. Matches Chromium. 289 constexpr int kMaxDim = 1 << 16; 290 if (width <= 0 || height <= 0 || width >= kMaxDim || height >= kMaxDim) { 291 SkCodecPrintf("Error: invalid bitmap dimensions.\n"); 292 return kInvalidInput; 293 } 294 295 // Create mask struct 296 SkMasks::InputMasks inputMasks; 297 memset(&inputMasks, 0, sizeof(SkMasks::InputMasks)); 298 299 // Determine the input compression format and set bit masks if necessary 300 uint32_t maskBytes = 0; 301 BmpInputFormat inputFormat = kUnknown_BmpInputFormat; 302 switch (compression) { 303 case kNone_BmpCompressionMethod: 304 inputFormat = kStandard_BmpInputFormat; 305 306 // In addition to more standard pixel compression formats, bmp supports 307 // the use of bit masks to determine pixel components. The standard 308 // format for representing 16-bit colors is 555 (XRRRRRGGGGGBBBBB), 309 // which does not map well to any Skia color formats. For this reason, 310 // we will always enable mask mode with 16 bits per pixel. 311 if (16 == bitsPerPixel) { 312 inputMasks.red = 0x7C00; 313 inputMasks.green = 0x03E0; 314 inputMasks.blue = 0x001F; 315 inputFormat = kBitMask_BmpInputFormat; 316 } 317 break; 318 case k8BitRLE_BmpCompressionMethod: 319 if (bitsPerPixel != 8) { 320 SkCodecPrintf("Warning: correcting invalid bitmap format.\n"); 321 bitsPerPixel = 8; 322 } 323 inputFormat = kRLE_BmpInputFormat; 324 break; 325 case k4BitRLE_BmpCompressionMethod: 326 if (bitsPerPixel != 4) { 327 SkCodecPrintf("Warning: correcting invalid bitmap format.\n"); 328 bitsPerPixel = 4; 329 } 330 inputFormat = kRLE_BmpInputFormat; 331 break; 332 case kAlphaBitMasks_BmpCompressionMethod: 333 case kBitMasks_BmpCompressionMethod: 334 // Load the masks 335 inputFormat = kBitMask_BmpInputFormat; 336 switch (headerType) { 337 case kInfoV1_BmpHeaderType: { 338 // The V1 header stores the bit masks after the header 339 uint8_t buffer[kBmpMaskBytes]; 340 if (stream->read(buffer, kBmpMaskBytes) != kBmpMaskBytes) { 341 SkCodecPrintf("Error: unable to read bit inputMasks.\n"); 342 return kIncompleteInput; 343 } 344 maskBytes = kBmpMaskBytes; 345 inputMasks.red = get_int(buffer, 0); 346 inputMasks.green = get_int(buffer, 4); 347 inputMasks.blue = get_int(buffer, 8); 348 break; 349 } 350 case kInfoV2_BmpHeaderType: 351 case kInfoV3_BmpHeaderType: 352 case kInfoV4_BmpHeaderType: 353 case kInfoV5_BmpHeaderType: 354 // Header types are matched based on size. If the header 355 // is V2+, we are guaranteed to be able to read at least 356 // this size. 357 SkASSERT(infoBytesRemaining >= 48); 358 inputMasks.red = get_int(iBuffer.get(), 36); 359 inputMasks.green = get_int(iBuffer.get(), 40); 360 inputMasks.blue = get_int(iBuffer.get(), 44); 361 362 if (kInfoV2_BmpHeaderType == headerType || 363 (kInfoV3_BmpHeaderType == headerType && !inIco)) { 364 break; 365 } 366 367 // V3+ bmp files introduce an alpha mask and allow the creator of the image 368 // to use the alpha channels. However, many of these images leave the 369 // alpha channel blank and expect to be rendered as opaque. This is the 370 // case for almost all V3 images, so we ignore the alpha mask. For V4+ 371 // images in kMask mode, we will use the alpha mask. Additionally, V3 372 // bmp-in-ico expect us to use the alpha mask. 373 // 374 // skbug.com/4116: We should perhaps also apply the alpha mask in kStandard 375 // mode. We just haven't seen any images that expect this 376 // behavior. 377 // 378 // Header types are matched based on size. If the header is 379 // V3+, we are guaranteed to be able to read at least this size. 380 SkASSERT(infoBytesRemaining >= 52); 381 inputMasks.alpha = get_int(iBuffer.get(), 48); 382 break; 383 case kOS2VX_BmpHeaderType: 384 // TODO: Decide if we intend to support this. 385 // It is unsupported in the previous version and 386 // in chromium. I have not come across a test case 387 // that uses this format. 388 SkCodecPrintf("Error: huffman format unsupported.\n"); 389 return kUnimplemented; 390 default: 391 SkCodecPrintf("Error: invalid bmp bit masks header.\n"); 392 return kInvalidInput; 393 } 394 break; 395 case kJpeg_BmpCompressionMethod: 396 if (24 == bitsPerPixel) { 397 inputFormat = kRLE_BmpInputFormat; 398 break; 399 } 400 [[fallthrough]]; 401 case kPng_BmpCompressionMethod: 402 // TODO: Decide if we intend to support this. 403 // It is unsupported in the previous version and 404 // in chromium. I think it is used mostly for printers. 405 SkCodecPrintf("Error: compression format not supported.\n"); 406 return kUnimplemented; 407 case kCMYK_BmpCompressionMethod: 408 case kCMYK8BitRLE_BmpCompressionMethod: 409 case kCMYK4BitRLE_BmpCompressionMethod: 410 // TODO: Same as above. 411 SkCodecPrintf("Error: CMYK not supported for bitmap decoding.\n"); 412 return kUnimplemented; 413 default: 414 SkCodecPrintf("Error: invalid format for bitmap decoding.\n"); 415 return kInvalidInput; 416 } 417 iBuffer.reset(); 418 419 // Calculate the number of bytes read so far 420 const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes; 421 if (!inIco && offset < bytesRead) { 422 // TODO (msarett): Do we really want to fail if the offset in the header is invalid? 423 // Seems like we can just assume that the offset is zero and try to decode? 424 // Maybe we don't want to try to decode corrupt images? 425 SkCodecPrintf("Error: pixel data offset less than header size.\n"); 426 return kInvalidInput; 427 } 428 429 430 431 switch (inputFormat) { 432 case kStandard_BmpInputFormat: { 433 // BMPs are generally opaque, however BMPs-in-ICOs may contain 434 // a transparency mask after the image. Therefore, we mark the 435 // alpha as kBinary if the BMP is contained in an ICO. 436 // We use |isOpaque| to indicate if the BMP itself is opaque. 437 SkEncodedInfo::Alpha alpha = inIco ? SkEncodedInfo::kBinary_Alpha : 438 SkEncodedInfo::kOpaque_Alpha; 439 bool isOpaque = true; 440 441 SkEncodedInfo::Color color; 442 uint8_t bitsPerComponent; 443 switch (bitsPerPixel) { 444 // Palette formats 445 case 1: 446 case 2: 447 case 4: 448 case 8: 449 // In the case of ICO, kBGRA is actually the closest match, 450 // since we will need to apply a transparency mask. 451 if (inIco) { 452 color = SkEncodedInfo::kBGRA_Color; 453 bitsPerComponent = 8; 454 } else { 455 color = SkEncodedInfo::kPalette_Color; 456 bitsPerComponent = (uint8_t) bitsPerPixel; 457 } 458 break; 459 case 24: 460 // In the case of ICO, kBGRA is actually the closest match, 461 // since we will need to apply a transparency mask. 462 color = inIco ? SkEncodedInfo::kBGRA_Color : SkEncodedInfo::kBGR_Color; 463 bitsPerComponent = 8; 464 break; 465 case 32: 466 // 32-bit BMP-in-ICOs actually use the alpha channel in place of a 467 // transparency mask. 468 if (inIco) { 469 isOpaque = false; 470 alpha = SkEncodedInfo::kUnpremul_Alpha; 471 color = SkEncodedInfo::kBGRA_Color; 472 } else { 473 color = SkEncodedInfo::kBGRX_Color; 474 } 475 bitsPerComponent = 8; 476 break; 477 default: 478 SkCodecPrintf("Error: invalid input value for bits per pixel.\n"); 479 return kInvalidInput; 480 } 481 482 if (codecOut) { 483 // We require streams to have a memory base for Bmp-in-Ico decodes. 484 SkASSERT(!inIco || nullptr != stream->getMemoryBase()); 485 486 // Set the image info and create a codec. 487 auto info = SkEncodedInfo::Make(width, height, color, alpha, bitsPerComponent); 488 *codecOut = std::make_unique<SkBmpStandardCodec>(std::move(info), 489 std::unique_ptr<SkStream>(stream), 490 bitsPerPixel, numColors, bytesPerColor, 491 offset - bytesRead, rowOrder, isOpaque, 492 inIco); 493 return static_cast<SkBmpStandardCodec*>(codecOut->get())->didCreateSrcBuffer() 494 ? kSuccess : kInvalidInput; 495 } 496 return kSuccess; 497 } 498 499 case kBitMask_BmpInputFormat: { 500 // Bmp-in-Ico must be standard mode 501 if (inIco) { 502 SkCodecPrintf("Error: Icos may not use bit mask format.\n"); 503 return kInvalidInput; 504 } 505 506 switch (bitsPerPixel) { 507 case 16: 508 case 24: 509 case 32: 510 break; 511 default: 512 SkCodecPrintf("Error: invalid input value for bits per pixel.\n"); 513 return kInvalidInput; 514 } 515 516 // Skip to the start of the pixel array. 517 // We can do this here because there is no color table to read 518 // in bit mask mode. 519 if (stream->skip(offset - bytesRead) != offset - bytesRead) { 520 SkCodecPrintf("Error: unable to skip to image data.\n"); 521 return kIncompleteInput; 522 } 523 524 if (codecOut) { 525 // Check that input bit masks are valid and create the masks object 526 SkASSERT(bitsPerPixel % 8 == 0); 527 std::unique_ptr<SkMasks> masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel/8)); 528 if (nullptr == masks) { 529 SkCodecPrintf("Error: invalid input masks.\n"); 530 return kInvalidInput; 531 } 532 533 // Masked bmps are not a great fit for SkEncodedInfo, since they have 534 // arbitrary component orderings and bits per component. Here we choose 535 // somewhat reasonable values - it's ok that we don't match exactly 536 // because SkBmpMaskCodec has its own mask swizzler anyway. 537 SkEncodedInfo::Color color; 538 SkEncodedInfo::Alpha alpha; 539 if (masks->getAlphaMask()) { 540 color = SkEncodedInfo::kBGRA_Color; 541 alpha = SkEncodedInfo::kUnpremul_Alpha; 542 } else { 543 color = SkEncodedInfo::kBGR_Color; 544 alpha = SkEncodedInfo::kOpaque_Alpha; 545 } 546 auto info = SkEncodedInfo::Make(width, height, color, alpha, 8); 547 *codecOut = std::make_unique<SkBmpMaskCodec>(std::move(info), 548 std::unique_ptr<SkStream>(stream), bitsPerPixel, 549 masks.release(), rowOrder); 550 return static_cast<SkBmpMaskCodec*>(codecOut->get())->didCreateSrcBuffer() 551 ? kSuccess : kInvalidInput; 552 } 553 return kSuccess; 554 } 555 556 case kRLE_BmpInputFormat: { 557 // We should not reach this point without a valid value of bitsPerPixel. 558 SkASSERT(4 == bitsPerPixel || 8 == bitsPerPixel || 24 == bitsPerPixel); 559 560 // Check for a valid number of total bytes when in RLE mode 561 if (totalBytes <= offset) { 562 SkCodecPrintf("Error: RLE requires valid input size.\n"); 563 return kInvalidInput; 564 } 565 566 // Bmp-in-Ico must be standard mode 567 // When inIco is true, this line cannot be reached, since we 568 // require that RLE Bmps have a valid number of totalBytes, and 569 // Icos skip the header that contains totalBytes. 570 SkASSERT(!inIco); 571 572 if (codecOut) { 573 // RLE inputs may skip pixels, leaving them as transparent. This 574 // is uncommon, but we cannot be certain that an RLE bmp will be 575 // opaque or that we will be able to represent it with a palette. 576 // For that reason, we always indicate that we are kBGRA. 577 auto info = SkEncodedInfo::Make(width, height, SkEncodedInfo::kBGRA_Color, 578 SkEncodedInfo::kBinary_Alpha, 8); 579 *codecOut = std::make_unique<SkBmpRLECodec>(std::move(info), 580 std::unique_ptr<SkStream>(stream), bitsPerPixel, 581 numColors, bytesPerColor, offset - bytesRead, 582 rowOrder); 583 } 584 return kSuccess; 585 } 586 default: 587 SkASSERT(false); 588 return kInvalidInput; 589 } 590} 591 592/* 593 * Creates a bmp decoder 594 * Reads enough of the stream to determine the image format 595 */ 596std::unique_ptr<SkCodec> SkBmpCodec::MakeFromStream(std::unique_ptr<SkStream> stream, 597 Result* result, bool inIco) { 598 std::unique_ptr<SkCodec> codec; 599 *result = ReadHeader(stream.get(), inIco, &codec); 600 if (codec) { 601 // codec has taken ownership of stream, so we do not need to delete it. 602 stream.release(); 603 } 604 return kSuccess == *result ? std::move(codec) : nullptr; 605} 606 607SkBmpCodec::SkBmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream, 608 uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder) 609 : INHERITED(std::move(info), kXformSrcColorFormat, std::move(stream)) 610 , fBitsPerPixel(bitsPerPixel) 611 , fRowOrder(rowOrder) 612 , fSrcRowBytes(SkAlign4(compute_row_bytes(this->dimensions().width(), fBitsPerPixel))) 613 , fXformBuffer(nullptr) 614{} 615 616bool SkBmpCodec::onRewind() { 617 return SkBmpCodec::ReadHeader(this->stream(), this->inIco(), nullptr) == kSuccess; 618} 619 620int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) const { 621 if (SkCodec::kTopDown_SkScanlineOrder == fRowOrder) { 622 return y; 623 } 624 SkASSERT(SkCodec::kBottomUp_SkScanlineOrder == fRowOrder); 625 return height - y - 1; 626} 627 628SkCodec::Result SkBmpCodec::prepareToDecode(const SkImageInfo& dstInfo, 629 const SkCodec::Options& options) { 630 return this->onPrepareToDecode(dstInfo, options); 631} 632 633SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, 634 const SkCodec::Options& options) { 635 return prepareToDecode(dstInfo, options); 636} 637 638int SkBmpCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { 639 // Create a new image info representing the portion of the image to decode 640 SkImageInfo rowInfo = this->dstInfo().makeWH(this->dstInfo().width(), count); 641 642 // Decode the requested rows 643 return this->decodeRows(rowInfo, dst, rowBytes, this->options()); 644} 645 646bool SkBmpCodec::skipRows(int count) { 647 const size_t bytesToSkip = count * fSrcRowBytes; 648 return this->stream()->skip(bytesToSkip) == bytesToSkip; 649} 650 651bool SkBmpCodec::onSkipScanlines(int count) { 652 return this->skipRows(count); 653} 654