blob: 32f1d152770c81318568c0ce88b177cf29f407a6 [file] [log] [blame]
msarett74114382015-03-16 11:55:18 -07001/*
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
msarettb46e5e22015-07-30 11:36:40 -07008#include "SkBmpCodec.h"
msarett4ab9d5f2015-08-06 15:34:42 -07009#include "SkBmpMaskCodec.h"
10#include "SkBmpRLECodec.h"
11#include "SkBmpStandardCodec.h"
msarett74114382015-03-16 11:55:18 -070012#include "SkCodecPriv.h"
13#include "SkColorPriv.h"
14#include "SkStream.h"
15
16/*
msarett74114382015-03-16 11:55:18 -070017 * Defines the version and type of the second bitmap header
msarett74114382015-03-16 11:55:18 -070018 */
msarett4ab9d5f2015-08-06 15:34:42 -070019enum 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
msarett74114382015-03-16 11:55:18 -070028};
29
30/*
msarett74114382015-03-16 11:55:18 -070031 * Possible bitmap compression types
msarett74114382015-03-16 11:55:18 -070032 */
msarett4ab9d5f2015-08-06 15:34:42 -070033enum 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
msarett74114382015-03-16 11:55:18 -070044};
45
46/*
msarett4ab9d5f2015-08-06 15:34:42 -070047 * Used to define the input format of the bmp
48 */
49enum BmpInputFormat {
50 kStandard_BmpInputFormat,
51 kRLE_BmpInputFormat,
52 kBitMask_BmpInputFormat,
53 kUnknown_BmpInputFormat
54};
55
56/*
msarett74114382015-03-16 11:55:18 -070057 * Checks the start of the stream to see if the image is a bitmap
msarett74114382015-03-16 11:55:18 -070058 */
scroggodb30be22015-12-08 18:54:13 -080059bool SkBmpCodec::IsBmp(const void* buffer, size_t bytesRead) {
msarett74114382015-03-16 11:55:18 -070060 // TODO: Support "IC", "PT", "CI", "CP", "BA"
msarett74114382015-03-16 11:55:18 -070061 const char bmpSig[] = { 'B', 'M' };
scroggodb30be22015-12-08 18:54:13 -080062 return bytesRead >= sizeof(bmpSig) && !memcmp(buffer, bmpSig, sizeof(bmpSig));
msarett74114382015-03-16 11:55:18 -070063}
64
65/*
msarett74114382015-03-16 11:55:18 -070066 * Assumes IsBmp was called and returned true
msarett9bde9182015-03-25 05:27:48 -070067 * Creates a bmp decoder
msarett74114382015-03-16 11:55:18 -070068 * Reads enough of the stream to determine the image format
msarett74114382015-03-16 11:55:18 -070069 */
70SkCodec* SkBmpCodec::NewFromStream(SkStream* stream) {
msarett9bde9182015-03-25 05:27:48 -070071 return SkBmpCodec::NewFromStream(stream, false);
72}
73
74/*
msarett9bde9182015-03-25 05:27:48 -070075 * Creates a bmp decoder for a bmp embedded in ico
76 * Reads enough of the stream to determine the image format
msarett9bde9182015-03-25 05:27:48 -070077 */
78SkCodec* SkBmpCodec::NewFromIco(SkStream* stream) {
79 return SkBmpCodec::NewFromStream(stream, true);
80}
81
82/*
scroggo79e378d2015-04-01 07:39:40 -070083 * Read enough of the stream to initialize the SkBmpCodec. Returns a bool
84 * representing success or failure. If it returned true, and codecOut was
halcanary96fcdcc2015-08-27 07:41:13 -070085 * not nullptr, it will be set to a new SkBmpCodec.
scroggo0a7e69c2015-04-03 07:22:22 -070086 * Does *not* take ownership of the passed in SkStream.
msarett9bde9182015-03-25 05:27:48 -070087 */
msarett4ab9d5f2015-08-06 15:34:42 -070088bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) {
msarett74114382015-03-16 11:55:18 -070089 // Header size constants
90 static const uint32_t kBmpHeaderBytes = 14;
91 static const uint32_t kBmpHeaderBytesPlusFour = kBmpHeaderBytes + 4;
92 static const uint32_t kBmpOS2V1Bytes = 12;
93 static const uint32_t kBmpOS2V2Bytes = 64;
94 static const uint32_t kBmpInfoBaseBytes = 16;
95 static const uint32_t kBmpInfoV1Bytes = 40;
96 static const uint32_t kBmpInfoV2Bytes = 52;
97 static const uint32_t kBmpInfoV3Bytes = 56;
98 static const uint32_t kBmpInfoV4Bytes = 108;
99 static const uint32_t kBmpInfoV5Bytes = 124;
100 static const uint32_t kBmpMaskBytes = 12;
101
tomhudson7aa846c2015-03-24 13:47:41 -0700102 // The total bytes in the bmp file
msarett9bde9182015-03-25 05:27:48 -0700103 // We only need to use this value for RLE decoding, so we will only
104 // check that it is valid in the RLE case.
105 uint32_t totalBytes;
tomhudson7aa846c2015-03-24 13:47:41 -0700106 // The offset from the start of the file where the pixel data begins
msarett9bde9182015-03-25 05:27:48 -0700107 uint32_t offset;
108 // The size of the second (info) header in bytes
109 uint32_t infoBytes;
110
111 // Bmps embedded in Icos skip the first Bmp header
msarett4ab9d5f2015-08-06 15:34:42 -0700112 if (!inIco) {
msarett9bde9182015-03-25 05:27:48 -0700113 // Read the first header and the size of the second header
halcanary385fe4d2015-08-26 13:07:48 -0700114 SkAutoTDeleteArray<uint8_t> hBuffer(new uint8_t[kBmpHeaderBytesPlusFour]);
msarett9bde9182015-03-25 05:27:48 -0700115 if (stream->read(hBuffer.get(), kBmpHeaderBytesPlusFour) !=
116 kBmpHeaderBytesPlusFour) {
scroggo230d4ac2015-03-26 07:15:55 -0700117 SkCodecPrintf("Error: unable to read first bitmap header.\n");
scroggo79e378d2015-04-01 07:39:40 -0700118 return false;
msarett9bde9182015-03-25 05:27:48 -0700119 }
120
121 totalBytes = get_int(hBuffer.get(), 2);
122 offset = get_int(hBuffer.get(), 10);
123 if (offset < kBmpHeaderBytes + kBmpOS2V1Bytes) {
scroggo230d4ac2015-03-26 07:15:55 -0700124 SkCodecPrintf("Error: invalid starting location for pixel data\n");
scroggo79e378d2015-04-01 07:39:40 -0700125 return false;
msarett9bde9182015-03-25 05:27:48 -0700126 }
127
128 // The size of the second (info) header in bytes
129 // The size is the first field of the second header, so we have already
130 // read the first four infoBytes.
131 infoBytes = get_int(hBuffer.get(), 14);
132 if (infoBytes < kBmpOS2V1Bytes) {
scroggo230d4ac2015-03-26 07:15:55 -0700133 SkCodecPrintf("Error: invalid second header size.\n");
scroggo79e378d2015-04-01 07:39:40 -0700134 return false;
msarett9bde9182015-03-25 05:27:48 -0700135 }
136 } else {
137 // This value is only used by RLE compression. Bmp in Ico files do not
138 // use RLE. If the compression field is incorrectly signaled as RLE,
139 // we will catch this and signal an error below.
140 totalBytes = 0;
141
142 // Bmps in Ico cannot specify an offset. We will always assume that
143 // pixel data begins immediately after the color table. This value
144 // will be corrected below.
145 offset = 0;
146
147 // Read the size of the second header
halcanary385fe4d2015-08-26 13:07:48 -0700148 SkAutoTDeleteArray<uint8_t> hBuffer(new uint8_t[4]);
msarett9bde9182015-03-25 05:27:48 -0700149 if (stream->read(hBuffer.get(), 4) != 4) {
scroggo230d4ac2015-03-26 07:15:55 -0700150 SkCodecPrintf("Error: unable to read size of second bitmap header.\n");
scroggo79e378d2015-04-01 07:39:40 -0700151 return false;
msarett9bde9182015-03-25 05:27:48 -0700152 }
153 infoBytes = get_int(hBuffer.get(), 0);
154 if (infoBytes < kBmpOS2V1Bytes) {
scroggo230d4ac2015-03-26 07:15:55 -0700155 SkCodecPrintf("Error: invalid second header size.\n");
scroggo79e378d2015-04-01 07:39:40 -0700156 return false;
msarett9bde9182015-03-25 05:27:48 -0700157 }
tomhudson7aa846c2015-03-24 13:47:41 -0700158 }
159
msarett9bde9182015-03-25 05:27:48 -0700160 // We already read the first four bytes of the info header to get the size
msarett74114382015-03-16 11:55:18 -0700161 const uint32_t infoBytesRemaining = infoBytes - 4;
msarett74114382015-03-16 11:55:18 -0700162
163 // Read the second header
halcanary385fe4d2015-08-26 13:07:48 -0700164 SkAutoTDeleteArray<uint8_t> iBuffer(new uint8_t[infoBytesRemaining]);
msarett74114382015-03-16 11:55:18 -0700165 if (stream->read(iBuffer.get(), infoBytesRemaining) != infoBytesRemaining) {
scroggo230d4ac2015-03-26 07:15:55 -0700166 SkCodecPrintf("Error: unable to read second bitmap header.\n");
scroggo79e378d2015-04-01 07:39:40 -0700167 return false;
msarett74114382015-03-16 11:55:18 -0700168 }
169
170 // The number of bits used per pixel in the pixel data
171 uint16_t bitsPerPixel;
172
173 // The compression method for the pixel data
msarett4ab9d5f2015-08-06 15:34:42 -0700174 uint32_t compression = kNone_BmpCompressionMethod;
msarett74114382015-03-16 11:55:18 -0700175
176 // Number of colors in the color table, defaults to 0 or max (see below)
177 uint32_t numColors = 0;
178
179 // Bytes per color in the color table, early versions use 3, most use 4
180 uint32_t bytesPerColor;
181
182 // The image width and height
183 int width, height;
184
185 // Determine image information depending on second header format
msarett4ab9d5f2015-08-06 15:34:42 -0700186 BmpHeaderType headerType;
msarett74114382015-03-16 11:55:18 -0700187 if (infoBytes >= kBmpInfoBaseBytes) {
188 // Check the version of the header
189 switch (infoBytes) {
190 case kBmpInfoV1Bytes:
msarett4ab9d5f2015-08-06 15:34:42 -0700191 headerType = kInfoV1_BmpHeaderType;
msarett74114382015-03-16 11:55:18 -0700192 break;
193 case kBmpInfoV2Bytes:
msarett4ab9d5f2015-08-06 15:34:42 -0700194 headerType = kInfoV2_BmpHeaderType;
msarett74114382015-03-16 11:55:18 -0700195 break;
196 case kBmpInfoV3Bytes:
msarett4ab9d5f2015-08-06 15:34:42 -0700197 headerType = kInfoV3_BmpHeaderType;
msarett74114382015-03-16 11:55:18 -0700198 break;
199 case kBmpInfoV4Bytes:
msarett4ab9d5f2015-08-06 15:34:42 -0700200 headerType = kInfoV4_BmpHeaderType;
msarett74114382015-03-16 11:55:18 -0700201 break;
202 case kBmpInfoV5Bytes:
msarett4ab9d5f2015-08-06 15:34:42 -0700203 headerType = kInfoV5_BmpHeaderType;
msarett74114382015-03-16 11:55:18 -0700204 break;
205 case 16:
206 case 20:
207 case 24:
208 case 28:
209 case 32:
210 case 36:
211 case 42:
212 case 46:
213 case 48:
214 case 60:
215 case kBmpOS2V2Bytes:
msarett4ab9d5f2015-08-06 15:34:42 -0700216 headerType = kOS2VX_BmpHeaderType;
msarett74114382015-03-16 11:55:18 -0700217 break;
218 default:
219 // We do not signal an error here because there is the
220 // possibility of new or undocumented bmp header types. Most
221 // of the newer versions of bmp headers are similar to and
222 // build off of the older versions, so we may still be able to
223 // decode the bmp.
scroggo230d4ac2015-03-26 07:15:55 -0700224 SkCodecPrintf("Warning: unknown bmp header format.\n");
msarett4ab9d5f2015-08-06 15:34:42 -0700225 headerType = kUnknown_BmpHeaderType;
msarett74114382015-03-16 11:55:18 -0700226 break;
227 }
228 // We check the size of the header before entering the if statement.
229 // We should not reach this point unless the size is large enough for
230 // these required fields.
231 SkASSERT(infoBytesRemaining >= 12);
232 width = get_int(iBuffer.get(), 0);
233 height = get_int(iBuffer.get(), 4);
234 bitsPerPixel = get_short(iBuffer.get(), 10);
235
236 // Some versions do not have these fields, so we check before
237 // overwriting the default value.
238 if (infoBytesRemaining >= 16) {
239 compression = get_int(iBuffer.get(), 12);
240 if (infoBytesRemaining >= 32) {
241 numColors = get_int(iBuffer.get(), 28);
242 }
243 }
244
245 // All of the headers that reach this point, store color table entries
246 // using 4 bytes per pixel.
247 bytesPerColor = 4;
248 } else if (infoBytes >= kBmpOS2V1Bytes) {
249 // The OS2V1 is treated separately because it has a unique format
msarett4ab9d5f2015-08-06 15:34:42 -0700250 headerType = kOS2V1_BmpHeaderType;
msarett74114382015-03-16 11:55:18 -0700251 width = (int) get_short(iBuffer.get(), 0);
252 height = (int) get_short(iBuffer.get(), 2);
253 bitsPerPixel = get_short(iBuffer.get(), 6);
254 bytesPerColor = 3;
255 } else {
256 // There are no valid bmp headers
scroggo230d4ac2015-03-26 07:15:55 -0700257 SkCodecPrintf("Error: second bitmap header size is invalid.\n");
scroggo79e378d2015-04-01 07:39:40 -0700258 return false;
msarett74114382015-03-16 11:55:18 -0700259 }
260
261 // Check for valid dimensions from header
scroggo46c57472015-09-30 08:57:13 -0700262 SkCodec::SkScanlineOrder rowOrder = SkCodec::kBottomUp_SkScanlineOrder;
msarett74114382015-03-16 11:55:18 -0700263 if (height < 0) {
264 height = -height;
scroggo46c57472015-09-30 08:57:13 -0700265 rowOrder = SkCodec::kTopDown_SkScanlineOrder;
msarett74114382015-03-16 11:55:18 -0700266 }
msarett9bde9182015-03-25 05:27:48 -0700267 // The height field for bmp in ico is double the actual height because they
268 // contain an XOR mask followed by an AND mask
msarett4ab9d5f2015-08-06 15:34:42 -0700269 if (inIco) {
msarett9bde9182015-03-25 05:27:48 -0700270 height /= 2;
271 }
msarett4b17fa32015-04-23 08:53:39 -0700272 if (width <= 0 || height <= 0) {
273 // TODO: Decide if we want to disable really large bmps as well.
274 // https://code.google.com/p/skia/issues/detail?id=3617
scroggo230d4ac2015-03-26 07:15:55 -0700275 SkCodecPrintf("Error: invalid bitmap dimensions.\n");
scroggo79e378d2015-04-01 07:39:40 -0700276 return false;
msarett74114382015-03-16 11:55:18 -0700277 }
278
279 // Create mask struct
280 SkMasks::InputMasks inputMasks;
msaretteed039b2015-03-18 11:11:19 -0700281 memset(&inputMasks, 0, sizeof(SkMasks::InputMasks));
msarett74114382015-03-16 11:55:18 -0700282
283 // Determine the input compression format and set bit masks if necessary
284 uint32_t maskBytes = 0;
msarett4ab9d5f2015-08-06 15:34:42 -0700285 BmpInputFormat inputFormat = kUnknown_BmpInputFormat;
msarett74114382015-03-16 11:55:18 -0700286 switch (compression) {
msarett4ab9d5f2015-08-06 15:34:42 -0700287 case kNone_BmpCompressionMethod:
288 inputFormat = kStandard_BmpInputFormat;
msarett74114382015-03-16 11:55:18 -0700289 break;
msarett4ab9d5f2015-08-06 15:34:42 -0700290 case k8BitRLE_BmpCompressionMethod:
msarett74114382015-03-16 11:55:18 -0700291 if (bitsPerPixel != 8) {
scroggo230d4ac2015-03-26 07:15:55 -0700292 SkCodecPrintf("Warning: correcting invalid bitmap format.\n");
msarett74114382015-03-16 11:55:18 -0700293 bitsPerPixel = 8;
294 }
msarett4ab9d5f2015-08-06 15:34:42 -0700295 inputFormat = kRLE_BmpInputFormat;
msarett74114382015-03-16 11:55:18 -0700296 break;
msarett4ab9d5f2015-08-06 15:34:42 -0700297 case k4BitRLE_BmpCompressionMethod:
msarett74114382015-03-16 11:55:18 -0700298 if (bitsPerPixel != 4) {
scroggo230d4ac2015-03-26 07:15:55 -0700299 SkCodecPrintf("Warning: correcting invalid bitmap format.\n");
msarett74114382015-03-16 11:55:18 -0700300 bitsPerPixel = 4;
301 }
msarett4ab9d5f2015-08-06 15:34:42 -0700302 inputFormat = kRLE_BmpInputFormat;
msarett74114382015-03-16 11:55:18 -0700303 break;
msarett4ab9d5f2015-08-06 15:34:42 -0700304 case kAlphaBitMasks_BmpCompressionMethod:
305 case kBitMasks_BmpCompressionMethod:
msarett74114382015-03-16 11:55:18 -0700306 // Load the masks
msarett4ab9d5f2015-08-06 15:34:42 -0700307 inputFormat = kBitMask_BmpInputFormat;
msarett74114382015-03-16 11:55:18 -0700308 switch (headerType) {
msarett4ab9d5f2015-08-06 15:34:42 -0700309 case kInfoV1_BmpHeaderType: {
msarett74114382015-03-16 11:55:18 -0700310 // The V1 header stores the bit masks after the header
halcanary385fe4d2015-08-26 13:07:48 -0700311 SkAutoTDeleteArray<uint8_t> mBuffer(new uint8_t[kBmpMaskBytes]);
msarett74114382015-03-16 11:55:18 -0700312 if (stream->read(mBuffer.get(), kBmpMaskBytes) !=
313 kBmpMaskBytes) {
scroggo230d4ac2015-03-26 07:15:55 -0700314 SkCodecPrintf("Error: unable to read bit inputMasks.\n");
scroggo79e378d2015-04-01 07:39:40 -0700315 return false;
msarett74114382015-03-16 11:55:18 -0700316 }
317 maskBytes = kBmpMaskBytes;
318 inputMasks.red = get_int(mBuffer.get(), 0);
319 inputMasks.green = get_int(mBuffer.get(), 4);
320 inputMasks.blue = get_int(mBuffer.get(), 8);
321 break;
322 }
msarett4ab9d5f2015-08-06 15:34:42 -0700323 case kInfoV2_BmpHeaderType:
324 case kInfoV3_BmpHeaderType:
325 case kInfoV4_BmpHeaderType:
326 case kInfoV5_BmpHeaderType:
msarett74114382015-03-16 11:55:18 -0700327 // Header types are matched based on size. If the header
328 // is V2+, we are guaranteed to be able to read at least
329 // this size.
330 SkASSERT(infoBytesRemaining >= 48);
331 inputMasks.red = get_int(iBuffer.get(), 36);
332 inputMasks.green = get_int(iBuffer.get(), 40);
333 inputMasks.blue = get_int(iBuffer.get(), 44);
334 break;
msarett4ab9d5f2015-08-06 15:34:42 -0700335 case kOS2VX_BmpHeaderType:
msarett74114382015-03-16 11:55:18 -0700336 // TODO: Decide if we intend to support this.
337 // It is unsupported in the previous version and
338 // in chromium. I have not come across a test case
339 // that uses this format.
scroggo230d4ac2015-03-26 07:15:55 -0700340 SkCodecPrintf("Error: huffman format unsupported.\n");
scroggo79e378d2015-04-01 07:39:40 -0700341 return false;
msarett74114382015-03-16 11:55:18 -0700342 default:
scroggo230d4ac2015-03-26 07:15:55 -0700343 SkCodecPrintf("Error: invalid bmp bit masks header.\n");
scroggo79e378d2015-04-01 07:39:40 -0700344 return false;
msarett74114382015-03-16 11:55:18 -0700345 }
346 break;
msarett4ab9d5f2015-08-06 15:34:42 -0700347 case kJpeg_BmpCompressionMethod:
msarett74114382015-03-16 11:55:18 -0700348 if (24 == bitsPerPixel) {
msarett4ab9d5f2015-08-06 15:34:42 -0700349 inputFormat = kRLE_BmpInputFormat;
msarett74114382015-03-16 11:55:18 -0700350 break;
351 }
352 // Fall through
msarett4ab9d5f2015-08-06 15:34:42 -0700353 case kPng_BmpCompressionMethod:
msarett74114382015-03-16 11:55:18 -0700354 // TODO: Decide if we intend to support this.
355 // It is unsupported in the previous version and
356 // in chromium. I think it is used mostly for printers.
scroggo230d4ac2015-03-26 07:15:55 -0700357 SkCodecPrintf("Error: compression format not supported.\n");
scroggo79e378d2015-04-01 07:39:40 -0700358 return false;
msarett4ab9d5f2015-08-06 15:34:42 -0700359 case kCMYK_BmpCompressionMethod:
360 case kCMYK8BitRLE_BmpCompressionMethod:
361 case kCMYK4BitRLE_BmpCompressionMethod:
msarett74114382015-03-16 11:55:18 -0700362 // TODO: Same as above.
scroggo230d4ac2015-03-26 07:15:55 -0700363 SkCodecPrintf("Error: CMYK not supported for bitmap decoding.\n");
scroggo79e378d2015-04-01 07:39:40 -0700364 return false;
msarett74114382015-03-16 11:55:18 -0700365 default:
scroggo230d4ac2015-03-26 07:15:55 -0700366 SkCodecPrintf("Error: invalid format for bitmap decoding.\n");
scroggo79e378d2015-04-01 07:39:40 -0700367 return false;
msarett74114382015-03-16 11:55:18 -0700368 }
369
370 // Most versions of bmps should be rendered as opaque. Either they do
371 // not have an alpha channel, or they expect the alpha channel to be
msarett9bde9182015-03-25 05:27:48 -0700372 // ignored. V3+ bmp files introduce an alpha mask and allow the creator
msarett74114382015-03-16 11:55:18 -0700373 // of the image to use the alpha channels. However, many of these images
msarett9bde9182015-03-25 05:27:48 -0700374 // leave the alpha channel blank and expect to be rendered as opaque. This
375 // is the case for almost all V3 images, so we render these as opaque. For
msarettef02b242016-02-11 08:41:53 -0800376 // V4+ images in kMask mode, we will use the alpha mask.
377 //
378 // skbug.com/4116: We should perhaps also apply the alpha mask in kStandard
379 // mode. We just haven't seen any images that expect this
380 // behavior.
381 //
382 // Additionally, V3 bmp-in-ico may use the alpha mask.
msarett74114382015-03-16 11:55:18 -0700383 SkAlphaType alphaType = kOpaque_SkAlphaType;
msarett4ab9d5f2015-08-06 15:34:42 -0700384 if ((kInfoV3_BmpHeaderType == headerType && inIco) ||
385 kInfoV4_BmpHeaderType == headerType ||
386 kInfoV5_BmpHeaderType == headerType) {
msarett74114382015-03-16 11:55:18 -0700387 // Header types are matched based on size. If the header is
msarett9bde9182015-03-25 05:27:48 -0700388 // V3+, we are guaranteed to be able to read at least this size.
msarett74114382015-03-16 11:55:18 -0700389 SkASSERT(infoBytesRemaining > 52);
390 inputMasks.alpha = get_int(iBuffer.get(), 48);
391 if (inputMasks.alpha != 0) {
392 alphaType = kUnpremul_SkAlphaType;
393 }
394 }
bungeman43812e22016-03-17 09:53:58 -0700395 iBuffer.free();
msarett74114382015-03-16 11:55:18 -0700396
msarett438b2ad2015-04-09 12:43:10 -0700397 // Additionally, 32 bit bmp-in-icos use the alpha channel.
scroggocc2feb12015-08-14 08:32:46 -0700398 // FIXME (msarett): Don't all bmp-in-icos use the alpha channel?
msarett438b2ad2015-04-09 12:43:10 -0700399 // And, RLE inputs may skip pixels, leaving them as transparent. This
400 // is uncommon, but we cannot be certain that an RLE bmp will be opaque.
msarett4ab9d5f2015-08-06 15:34:42 -0700401 if ((inIco && 32 == bitsPerPixel) || (kRLE_BmpInputFormat == inputFormat)) {
msarett9bde9182015-03-25 05:27:48 -0700402 alphaType = kUnpremul_SkAlphaType;
403 }
404
msarett438b2ad2015-04-09 12:43:10 -0700405 // Check for valid bits per pixel.
406 // At the same time, use this information to choose a suggested color type
407 // and to set default masks.
408 SkColorType colorType = kN32_SkColorType;
msarett74114382015-03-16 11:55:18 -0700409 switch (bitsPerPixel) {
410 // In addition to more standard pixel compression formats, bmp supports
411 // the use of bit masks to determine pixel components. The standard
412 // format for representing 16-bit colors is 555 (XRRRRRGGGGGBBBBB),
413 // which does not map well to any Skia color formats. For this reason,
414 // we will always enable mask mode with 16 bits per pixel.
415 case 16:
msarett4ab9d5f2015-08-06 15:34:42 -0700416 if (kBitMask_BmpInputFormat != inputFormat) {
msarett74114382015-03-16 11:55:18 -0700417 inputMasks.red = 0x7C00;
418 inputMasks.green = 0x03E0;
419 inputMasks.blue = 0x001F;
msarett4ab9d5f2015-08-06 15:34:42 -0700420 inputFormat = kBitMask_BmpInputFormat;
msarett74114382015-03-16 11:55:18 -0700421 }
422 break;
msarett438b2ad2015-04-09 12:43:10 -0700423 // We want to decode to kIndex_8 for input formats that are already
424 // designed in index format.
msarett74114382015-03-16 11:55:18 -0700425 case 1:
426 case 2:
427 case 4:
428 case 8:
msarett438b2ad2015-04-09 12:43:10 -0700429 // However, we cannot in RLE format since we may need to leave some
430 // pixels as transparent. Similarly, we also cannot for ICO images
431 // since we may need to apply a transparent mask.
msarett4ab9d5f2015-08-06 15:34:42 -0700432 if (kRLE_BmpInputFormat != inputFormat && !inIco) {
msarett438b2ad2015-04-09 12:43:10 -0700433 colorType = kIndex_8_SkColorType;
434 }
msarettd9ec3202016-02-17 11:26:55 -0800435
436 // Mask bmps must have 16, 24, or 32 bits per pixel.
437 if (kBitMask_BmpInputFormat == inputFormat) {
438 SkCodecPrintf("Error: invalid input value of bits per pixel for mask bmp.\n");
439 return false;
440 }
msarett74114382015-03-16 11:55:18 -0700441 case 24:
442 case 32:
443 break;
444 default:
scroggo230d4ac2015-03-26 07:15:55 -0700445 SkCodecPrintf("Error: invalid input value for bits per pixel.\n");
scroggo79e378d2015-04-01 07:39:40 -0700446 return false;
msarett74114382015-03-16 11:55:18 -0700447 }
448
449 // Check that input bit masks are valid and create the masks object
450 SkAutoTDelete<SkMasks>
451 masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel));
halcanary96fcdcc2015-08-27 07:41:13 -0700452 if (nullptr == masks) {
scroggo230d4ac2015-03-26 07:15:55 -0700453 SkCodecPrintf("Error: invalid input masks.\n");
scroggo79e378d2015-04-01 07:39:40 -0700454 return false;
msarett74114382015-03-16 11:55:18 -0700455 }
456
msaretteed039b2015-03-18 11:11:19 -0700457 // Check for a valid number of total bytes when in RLE mode
msarett4ab9d5f2015-08-06 15:34:42 -0700458 if (totalBytes <= offset && kRLE_BmpInputFormat == inputFormat) {
scroggo230d4ac2015-03-26 07:15:55 -0700459 SkCodecPrintf("Error: RLE requires valid input size.\n");
scroggo79e378d2015-04-01 07:39:40 -0700460 return false;
msarett74114382015-03-16 11:55:18 -0700461 }
msaretteed039b2015-03-18 11:11:19 -0700462 const size_t RLEBytes = totalBytes - offset;
463
464 // Calculate the number of bytes read so far
465 const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes;
msarett4ab9d5f2015-08-06 15:34:42 -0700466 if (!inIco && offset < bytesRead) {
msarett9aa32d12015-09-01 14:40:46 -0700467 // TODO (msarett): Do we really want to fail if the offset in the header is invalid?
468 // Seems like we can just assume that the offset is zero and try to decode?
469 // Maybe we don't want to try to decode corrupt images?
scroggo230d4ac2015-03-26 07:15:55 -0700470 SkCodecPrintf("Error: pixel data offset less than header size.\n");
scroggo79e378d2015-04-01 07:39:40 -0700471 return false;
msaretteed039b2015-03-18 11:11:19 -0700472 }
msarett74114382015-03-16 11:55:18 -0700473
msarett9aa32d12015-09-01 14:40:46 -0700474 // Skip to the start of the pixel array.
475 // We can do this here because there is no color table to read
476 // in bit mask mode.
477 if (!inIco && kBitMask_BmpInputFormat == inputFormat) {
478 if (stream->skip(offset - bytesRead) != offset - bytesRead) {
479 SkCodecPrintf("Error: unable to skip to image data.\n");
480 return false;
481 }
482 }
483
scroggo79e378d2015-04-01 07:39:40 -0700484 if (codecOut) {
msarettf4004f92016-02-11 10:49:31 -0800485 // BMPs-in-ICOs contain an alpha mask after the image which means we
486 // cannot guarantee that an image is opaque, even if the bmp thinks
487 // it is.
488 bool isOpaque = kOpaque_SkAlphaType == alphaType;
489 if (inIco) {
490 alphaType = kUnpremul_SkAlphaType;
491 }
492
msarett4ab9d5f2015-08-06 15:34:42 -0700493 // Set the image info
scroggo79e378d2015-04-01 07:39:40 -0700494 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
msarett438b2ad2015-04-09 12:43:10 -0700495 colorType, alphaType);
msarett4ab9d5f2015-08-06 15:34:42 -0700496
497 // Return the codec
498 switch (inputFormat) {
499 case kStandard_BmpInputFormat:
msarettbe8216a2015-12-04 08:00:50 -0800500 // We require streams to have a memory base for Bmp-in-Ico decodes.
501 SkASSERT(!inIco || nullptr != stream->getMemoryBase());
msarett9aa32d12015-09-01 14:40:46 -0700502 *codecOut = new SkBmpStandardCodec(imageInfo, stream, bitsPerPixel, numColors,
msarettf4004f92016-02-11 10:49:31 -0800503 bytesPerColor, offset - bytesRead, rowOrder, isOpaque, inIco);
msarett4ab9d5f2015-08-06 15:34:42 -0700504 return true;
505 case kBitMask_BmpInputFormat:
506 // Bmp-in-Ico must be standard mode
507 if (inIco) {
msarettd0375bc2015-08-12 08:08:56 -0700508 SkCodecPrintf("Error: Icos may not use bit mask format.\n");
msarett4ab9d5f2015-08-06 15:34:42 -0700509 return false;
510 }
msarett4ab9d5f2015-08-06 15:34:42 -0700511
mtklein18300a32016-03-16 13:53:35 -0700512 *codecOut = new SkBmpMaskCodec(imageInfo, stream, bitsPerPixel, masks.release(),
msarett9aa32d12015-09-01 14:40:46 -0700513 rowOrder);
msarett4ab9d5f2015-08-06 15:34:42 -0700514 return true;
515 case kRLE_BmpInputFormat:
516 // Bmp-in-Ico must be standard mode
msarettd0375bc2015-08-12 08:08:56 -0700517 // When inIco is true, this line cannot be reached, since we
518 // require that RLE Bmps have a valid number of totalBytes, and
519 // Icos skip the header that contains totalBytes.
520 SkASSERT(!inIco);
msarett9aa32d12015-09-01 14:40:46 -0700521 *codecOut = new SkBmpRLECodec(imageInfo, stream, bitsPerPixel, numColors,
522 bytesPerColor, offset - bytesRead, rowOrder, RLEBytes);
msarett4ab9d5f2015-08-06 15:34:42 -0700523 return true;
524 default:
525 SkASSERT(false);
526 return false;
527 }
scroggo79e378d2015-04-01 07:39:40 -0700528 }
msarett4ab9d5f2015-08-06 15:34:42 -0700529
scroggo79e378d2015-04-01 07:39:40 -0700530 return true;
531}
532
533/*
scroggo79e378d2015-04-01 07:39:40 -0700534 * Creates a bmp decoder
535 * Reads enough of the stream to determine the image format
scroggo79e378d2015-04-01 07:39:40 -0700536 */
msarett4ab9d5f2015-08-06 15:34:42 -0700537SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) {
scroggo0a7e69c2015-04-03 07:22:22 -0700538 SkAutoTDelete<SkStream> streamDeleter(stream);
halcanary96fcdcc2015-08-27 07:41:13 -0700539 SkCodec* codec = nullptr;
msarett4ab9d5f2015-08-06 15:34:42 -0700540 if (ReadHeader(stream, inIco, &codec)) {
scroggo0a7e69c2015-04-03 07:22:22 -0700541 // codec has taken ownership of stream, so we do not need to
542 // delete it.
543 SkASSERT(codec);
mtklein18300a32016-03-16 13:53:35 -0700544 streamDeleter.release();
scroggo79e378d2015-04-01 07:39:40 -0700545 return codec;
546 }
halcanary96fcdcc2015-08-27 07:41:13 -0700547 return nullptr;
msarett74114382015-03-16 11:55:18 -0700548}
549
msarett74114382015-03-16 11:55:18 -0700550SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream,
scroggo46c57472015-09-30 08:57:13 -0700551 uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
msarett74114382015-03-16 11:55:18 -0700552 : INHERITED(info, stream)
553 , fBitsPerPixel(bitsPerPixel)
msarett74114382015-03-16 11:55:18 -0700554 , fRowOrder(rowOrder)
msarett9b9497e2016-02-11 13:29:36 -0800555 , fSrcRowBytes(SkAlign4(compute_row_bytes(info.width(), fBitsPerPixel)))
msarett74114382015-03-16 11:55:18 -0700556{}
557
scroggob427db12015-08-12 07:24:13 -0700558bool SkBmpCodec::onRewind() {
halcanary96fcdcc2015-08-27 07:41:13 -0700559 return SkBmpCodec::ReadHeader(this->stream(), this->inIco(), nullptr);
msaretteed039b2015-03-18 11:11:19 -0700560}
561
scroggo46c57472015-09-30 08:57:13 -0700562int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) const {
563 if (SkCodec::kTopDown_SkScanlineOrder == fRowOrder) {
msarett5406d6f2015-08-31 06:55:13 -0700564 return y;
565 }
scroggo46c57472015-09-30 08:57:13 -0700566 SkASSERT(SkCodec::kBottomUp_SkScanlineOrder == fRowOrder);
msarett5406d6f2015-08-31 06:55:13 -0700567 return height - y - 1;
568}
569
scroggo46c57472015-09-30 08:57:13 -0700570SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
571 const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) {
scroggo46c57472015-09-30 08:57:13 -0700572 if (!conversion_possible(dstInfo, this->getInfo())) {
573 SkCodecPrintf("Error: cannot convert input type to output type.\n");
574 return kInvalidConversion;
msarett5406d6f2015-08-31 06:55:13 -0700575 }
576
scroggo46c57472015-09-30 08:57:13 -0700577 return prepareToDecode(dstInfo, options, inputColorPtr, inputColorCount);
578}
msarett5406d6f2015-08-31 06:55:13 -0700579
msarette6dd0042015-10-09 11:07:34 -0700580int SkBmpCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
scroggo46c57472015-09-30 08:57:13 -0700581 // Create a new image info representing the portion of the image to decode
582 SkImageInfo rowInfo = this->dstInfo().makeWH(this->dstInfo().width(), count);
msarett5406d6f2015-08-31 06:55:13 -0700583
scroggo46c57472015-09-30 08:57:13 -0700584 // Decode the requested rows
585 return this->decodeRows(rowInfo, dst, rowBytes, this->options());
586}
msarett9b9497e2016-02-11 13:29:36 -0800587
588bool SkBmpCodec::skipRows(int count) {
589 const size_t bytesToSkip = count * fSrcRowBytes;
590 return this->stream()->skip(bytesToSkip) == bytesToSkip;
591}
592
593bool SkBmpCodec::onSkipScanlines(int count) {
594 return this->skipRows(count);
595}