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