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