summaryrefslogtreecommitdiff
path: root/image/decoders/nsBMPDecoder.h
blob: 793ebd1558e0a1022c1bb3d46c572c7ecfbbc649 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_image_decoders_nsBMPDecoder_h
#define mozilla_image_decoders_nsBMPDecoder_h

#include "BMPHeaders.h"
#include "Decoder.h"
#include "gfxColor.h"
#include "StreamingLexer.h"
#include "mozilla/UniquePtr.h"

namespace mozilla {
namespace image {

namespace bmp {

/// This struct contains the fields from the file header and info header that
/// we use during decoding. (Excluding bitfields fields, which are kept in
/// BitFields.)
struct Header {
  uint32_t mDataOffset;     // Offset to raster data.
  uint32_t mBIHSize;        // Header size.
  int32_t  mWidth;          // Image width.
  int32_t  mHeight;         // Image height.
  uint16_t mBpp;            // Bits per pixel.
  uint32_t mCompression;    // See struct Compression for valid values.
  uint32_t mImageSize;      // (compressed) image size. Can be 0 if
                            // mCompression==0.
  uint32_t mNumColors;      // Used colors.

  Header()
   : mDataOffset(0)
   , mBIHSize(0)
   , mWidth(0)
   , mHeight(0)
   , mBpp(0)
   , mCompression(0)
   , mImageSize(0)
   , mNumColors(0)
  {}
};

/// An entry in the color table.
struct ColorTableEntry {
  uint8_t mRed;
  uint8_t mGreen;
  uint8_t mBlue;
};

/// All the color-related bitfields for 16bpp and 32bpp images. We use this
/// even for older format BMPs that don't have explicit bitfields.
class BitFields {
  class Value {
    friend class BitFields;

    uint32_t mMask;       // The mask for the value.
    uint8_t mRightShift;  // The amount to right-shift after masking.
    uint8_t mBitWidth;    // The width (in bits) of the value.

    /// Sets the mask (and thus the right-shift and bit-width as well).
    void Set(uint32_t aMask);

  public:
    Value()
    {
      mMask = 0;
      mRightShift = 0;
      mBitWidth = 0;
    }

    /// Returns true if this channel is used. Only used for alpha.
    bool IsPresent() const { return mMask != 0x0; }

    /// Extracts the single color value from the multi-color value.
    uint8_t Get(uint32_t aVal) const;

    /// Like Get(), but specially for alpha.
    uint8_t GetAlpha(uint32_t aVal, bool& aHasAlphaOut) const;

    /// Specialized versions of Get() for when the bit-width is 5 or 8.
    /// (They will assert if called and the bit-width is not 5 or 8.)
    uint8_t Get5(uint32_t aVal) const;
    uint8_t Get8(uint32_t aVal) const;
  };

public:
  /// The individual color channels.
  Value mRed;
  Value mGreen;
  Value mBlue;
  Value mAlpha;

  /// Set bitfields to the standard 5-5-5 16bpp values.
  void SetR5G5B5();

  /// Set bitfields to the standard 8-8-8 32bpp values.
  void SetR8G8B8();

  /// Test if bitfields have the standard 5-5-5 16bpp values.
  bool IsR5G5B5() const;

  /// Test if bitfields have the standard 8-8-8 32bpp values.
  bool IsR8G8B8() const;

  /// Read the bitfields from a header. The reading of the alpha mask is
  /// optional.
  void ReadFromHeader(const char* aData, bool aReadAlpha);

  /// Length of the bitfields structure in the BMP file.
  static const size_t LENGTH = 12;
};

} // namespace bmp

class RasterImage;

/// Decoder for BMP-Files, as used by Windows and OS/2.

class nsBMPDecoder : public Decoder
{
public:
  ~nsBMPDecoder();

  DecoderType GetType() const override { return DecoderType::BMP; }

  /// Obtains the internal output image buffer.
  uint32_t* GetImageData() { return reinterpret_cast<uint32_t*>(mImageData); }

  /// Obtains the length of the internal output image buffer.
  size_t GetImageDataLength() const { return mImageDataLength; }

  /// Obtains the size of the compressed image resource.
  int32_t GetCompressedImageSize() const;

  /// Mark this BMP as being within an ICO file. Only used for testing purposes
  /// because the ICO-specific constructor does this marking automatically.
  void SetIsWithinICO() { mIsWithinICO = true; }

  /// Did the BMP file have alpha data of any kind? (Only use this after the
  /// bitmap has been fully decoded.)
  bool HasTransparency() const { return mDoesHaveTransparency; }

  LexerResult DoDecode(SourceBufferIterator& aIterator,
                       IResumable* aOnResume) override;
  nsresult BeforeFinishInternal() override;
  nsresult FinishInternal() override;

private:
  friend class DecoderFactory;

  enum class State {
    FILE_HEADER,
    INFO_HEADER_SIZE,
    INFO_HEADER_REST,
    BITFIELDS,
    COLOR_TABLE,
    GAP,
    AFTER_GAP,
    PIXEL_ROW,
    RLE_SEGMENT,
    RLE_DELTA,
    RLE_ABSOLUTE
  };

  // This is the constructor used for normal and clipboard BMP images.
  explicit nsBMPDecoder(RasterImage* aImage, bool aForClipboard = false);

  // This is the constructor used for BMP resources in ICO images.
  nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset);

  // Helper constructor called by the other two.
  nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength, bool aForClipboard);

  int32_t AbsoluteHeight() const { return abs(mH.mHeight); }

  uint32_t* RowBuffer();

  void FinishRow();

  LexerTransition<State> ReadFileHeader(const char* aData, size_t aLength);
  LexerTransition<State> ReadInfoHeaderSize(const char* aData, size_t aLength);
  LexerTransition<State> ReadInfoHeaderRest(const char* aData, size_t aLength);
  LexerTransition<State> ReadBitfields(const char* aData, size_t aLength);
  LexerTransition<State> ReadColorTable(const char* aData, size_t aLength);
  LexerTransition<State> SkipGap();
  LexerTransition<State> AfterGap();
  LexerTransition<State> ReadPixelRow(const char* aData);
  LexerTransition<State> ReadRLESegment(const char* aData);
  LexerTransition<State> ReadRLEDelta(const char* aData);
  LexerTransition<State> ReadRLEAbsolute(const char* aData, size_t aLength);

  StreamingLexer<State> mLexer;

  bmp::Header mH;

  // If the BMP is within an ICO file our treatment of it differs slightly.
  bool mIsWithinICO;

  // If the BMP is decoded from the clipboard, we start with a data offset.
  bool mIsForClipboard;

  bmp::BitFields mBitFields;

  // Might the image have transparency? Determined from the headers during
  // metadata decode. (Does not guarantee the image actually has transparency.)
  bool mMayHaveTransparency;

  // Does the image have transparency? Determined during full decoding, so only
  // use this after that has been completed.
  bool mDoesHaveTransparency;

  uint32_t mNumColors;      // The number of used colors, i.e. the number of
                            // entries in mColors, if it's present.
  UniquePtr<bmp::ColorTableEntry[]> mColors; // The color table, if it's present.
  uint32_t mBytesPerColor;  // 3 or 4, depending on the format

  // The number of bytes prior to the optional gap that have been read. This
  // is used to find the start of the pixel data.
  uint32_t mPreGapLength;

  uint32_t mPixelRowSize;   // The number of bytes per pixel row.

  int32_t mCurrentRow;      // Index of the row of the image that's currently
                            // being decoded: [height,1].
  int32_t mCurrentPos;      // Index into the current line. Used when
                            // doing RLE decoding and when filling in pixels
                            // for truncated files.

  // Only used in RLE_ABSOLUTE state: the number of pixels to read.
  uint32_t mAbsoluteModeNumPixels;
};

} // namespace image
} // namespace mozilla

#endif // mozilla_image_decoders_nsBMPDecoder_h