Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsCRT.h"
6 #include "mozilla/Endian.h"
7 #include "nsBMPEncoder.h"
8 #include "prprf.h"
9 #include "nsString.h"
10 #include "nsStreamUtils.h"
11 #include "nsTArray.h"
12 #include "nsAutoPtr.h"
14 using namespace mozilla;
16 NS_IMPL_ISUPPORTS(nsBMPEncoder, imgIEncoder, nsIInputStream, nsIAsyncInputStream)
18 nsBMPEncoder::nsBMPEncoder() : mImageBufferStart(nullptr),
19 mImageBufferCurr(0),
20 mImageBufferSize(0),
21 mImageBufferReadPoint(0),
22 mFinished(false),
23 mCallback(nullptr),
24 mCallbackTarget(nullptr),
25 mNotifyThreshold(0)
26 {
27 }
29 nsBMPEncoder::~nsBMPEncoder()
30 {
31 if (mImageBufferStart) {
32 moz_free(mImageBufferStart);
33 mImageBufferStart = nullptr;
34 mImageBufferCurr = nullptr;
35 }
36 }
38 // nsBMPEncoder::InitFromData
39 //
40 // One output option is supported: bpp=<bpp_value>
41 // bpp specifies the bits per pixel to use where bpp_value can be 24 or 32
42 NS_IMETHODIMP nsBMPEncoder::InitFromData(const uint8_t* aData,
43 uint32_t aLength, // (unused,
44 // req'd by JS)
45 uint32_t aWidth,
46 uint32_t aHeight,
47 uint32_t aStride,
48 uint32_t aInputFormat,
49 const nsAString& aOutputOptions)
50 {
51 // validate input format
52 if (aInputFormat != INPUT_FORMAT_RGB &&
53 aInputFormat != INPUT_FORMAT_RGBA &&
54 aInputFormat != INPUT_FORMAT_HOSTARGB) {
55 return NS_ERROR_INVALID_ARG;
56 }
58 // Stride is the padded width of each row, so it better be longer
59 if ((aInputFormat == INPUT_FORMAT_RGB &&
60 aStride < aWidth * 3) ||
61 ((aInputFormat == INPUT_FORMAT_RGBA || aInputFormat == INPUT_FORMAT_HOSTARGB) &&
62 aStride < aWidth * 4)) {
63 NS_WARNING("Invalid stride for InitFromData");
64 return NS_ERROR_INVALID_ARG;
65 }
67 nsresult rv;
68 rv = StartImageEncode(aWidth, aHeight, aInputFormat, aOutputOptions);
69 if (NS_FAILED(rv)) {
70 return rv;
71 }
73 rv = AddImageFrame(aData, aLength, aWidth, aHeight, aStride,
74 aInputFormat, aOutputOptions);
75 if (NS_FAILED(rv)) {
76 return rv;
77 }
79 rv = EndImageEncode();
80 return rv;
81 }
83 // Just a helper method to make it explicit in calculations that we are dealing
84 // with bytes and not bits
85 static inline uint32_t
86 BytesPerPixel(uint32_t aBPP)
87 {
88 return aBPP / 8;
89 }
91 // Calculates the number of padding bytes that are needed per row of image data
92 static inline uint32_t
93 PaddingBytes(uint32_t aBPP, uint32_t aWidth)
94 {
95 uint32_t rowSize = aWidth * BytesPerPixel(aBPP);
96 uint8_t paddingSize = 0;
97 if(rowSize % 4) {
98 paddingSize = (4 - (rowSize % 4));
99 }
100 return paddingSize;
101 }
103 // See ::InitFromData for other info.
104 NS_IMETHODIMP nsBMPEncoder::StartImageEncode(uint32_t aWidth,
105 uint32_t aHeight,
106 uint32_t aInputFormat,
107 const nsAString& aOutputOptions)
108 {
109 // can't initialize more than once
110 if (mImageBufferStart || mImageBufferCurr) {
111 return NS_ERROR_ALREADY_INITIALIZED;
112 }
114 // validate input format
115 if (aInputFormat != INPUT_FORMAT_RGB &&
116 aInputFormat != INPUT_FORMAT_RGBA &&
117 aInputFormat != INPUT_FORMAT_HOSTARGB) {
118 return NS_ERROR_INVALID_ARG;
119 }
121 // parse and check any provided output options
122 Version version;
123 uint32_t bpp;
124 nsresult rv = ParseOptions(aOutputOptions, &version, &bpp);
125 if (NS_FAILED(rv)) {
126 return rv;
127 }
129 InitFileHeader(version, bpp, aWidth, aHeight);
130 InitInfoHeader(version, bpp, aWidth, aHeight);
132 mImageBufferSize = mBMPFileHeader.filesize;
133 mImageBufferStart = static_cast<uint8_t*>(moz_malloc(mImageBufferSize));
134 if (!mImageBufferStart) {
135 return NS_ERROR_OUT_OF_MEMORY;
136 }
137 mImageBufferCurr = mImageBufferStart;
139 EncodeFileHeader();
140 EncodeInfoHeader();
142 return NS_OK;
143 }
145 // Returns the number of bytes in the image buffer used.
146 // For a BMP file, this is all bytes in the buffer.
147 NS_IMETHODIMP nsBMPEncoder::GetImageBufferUsed(uint32_t *aOutputSize)
148 {
149 NS_ENSURE_ARG_POINTER(aOutputSize);
150 *aOutputSize = mImageBufferSize;
151 return NS_OK;
152 }
154 // Returns a pointer to the start of the image buffer
155 NS_IMETHODIMP nsBMPEncoder::GetImageBuffer(char **aOutputBuffer)
156 {
157 NS_ENSURE_ARG_POINTER(aOutputBuffer);
158 *aOutputBuffer = reinterpret_cast<char*>(mImageBufferStart);
159 return NS_OK;
160 }
162 NS_IMETHODIMP nsBMPEncoder::AddImageFrame(const uint8_t* aData,
163 uint32_t aLength, // (unused,
164 // req'd by JS)
165 uint32_t aWidth,
166 uint32_t aHeight,
167 uint32_t aStride,
168 uint32_t aInputFormat,
169 const nsAString& aFrameOptions)
170 {
171 // must be initialized
172 if (!mImageBufferStart || !mImageBufferCurr) {
173 return NS_ERROR_NOT_INITIALIZED;
174 }
176 // validate input format
177 if (aInputFormat != INPUT_FORMAT_RGB &&
178 aInputFormat != INPUT_FORMAT_RGBA &&
179 aInputFormat != INPUT_FORMAT_HOSTARGB) {
180 return NS_ERROR_INVALID_ARG;
181 }
183 static fallible_t fallible = fallible_t();
184 nsAutoArrayPtr<uint8_t> row(new (fallible)
185 uint8_t[mBMPInfoHeader.width *
186 BytesPerPixel(mBMPInfoHeader.bpp)]);
187 if (!row) {
188 return NS_ERROR_OUT_OF_MEMORY;
189 }
191 // write each row: if we add more input formats, we may want to
192 // generalize the conversions
193 if (aInputFormat == INPUT_FORMAT_HOSTARGB) {
194 // BMP requires RGBA with post-multiplied alpha, so we need to convert
195 for (int32_t y = mBMPInfoHeader.height - 1; y >= 0 ; y --) {
196 ConvertHostARGBRow(&aData[y * aStride], row, mBMPInfoHeader.width);
197 if(mBMPInfoHeader.bpp == 24) {
198 EncodeImageDataRow24(row);
199 } else {
200 EncodeImageDataRow32(row);
201 }
202 }
203 } else if (aInputFormat == INPUT_FORMAT_RGBA) {
204 // simple RGBA, no conversion needed
205 for (int32_t y = 0; y < mBMPInfoHeader.height; y ++) {
206 if (mBMPInfoHeader.bpp == 24) {
207 EncodeImageDataRow24(row);
208 } else {
209 EncodeImageDataRow32(row);
210 }
211 }
212 } else if (aInputFormat == INPUT_FORMAT_RGB) {
213 // simple RGB, no conversion needed
214 for (int32_t y = 0; y < mBMPInfoHeader.height; y ++) {
215 if (mBMPInfoHeader.bpp == 24) {
216 EncodeImageDataRow24(&aData[y * aStride]);
217 } else {
218 EncodeImageDataRow32(&aData[y * aStride]);
219 }
220 }
221 } else {
222 NS_NOTREACHED("Bad format type");
223 return NS_ERROR_INVALID_ARG;
224 }
226 return NS_OK;
227 }
230 NS_IMETHODIMP nsBMPEncoder::EndImageEncode()
231 {
232 // must be initialized
233 if (!mImageBufferStart || !mImageBufferCurr) {
234 return NS_ERROR_NOT_INITIALIZED;
235 }
237 mFinished = true;
238 NotifyListener();
240 // if output callback can't get enough memory, it will free our buffer
241 if (!mImageBufferStart || !mImageBufferCurr) {
242 return NS_ERROR_OUT_OF_MEMORY;
243 }
245 return NS_OK;
246 }
249 // Parses the encoder options and sets the bits per pixel to use
250 // See InitFromData for a description of the parse options
251 nsresult
252 nsBMPEncoder::ParseOptions(const nsAString& aOptions, Version* version,
253 uint32_t* bpp)
254 {
255 if (version) {
256 *version = VERSION_3;
257 }
258 if (bpp) {
259 *bpp = 24;
260 }
262 // Parse the input string into a set of name/value pairs.
263 // From a format like: name=value;bpp=<bpp_value>;name=value
264 // to format: [0] = name=value, [1] = bpp=<bpp_value>, [2] = name=value
265 nsTArray<nsCString> nameValuePairs;
266 if (!ParseString(NS_ConvertUTF16toUTF8(aOptions), ';', nameValuePairs)) {
267 return NS_ERROR_INVALID_ARG;
268 }
270 // For each name/value pair in the set
271 for (uint32_t i = 0; i < nameValuePairs.Length(); ++i) {
273 // Split the name value pair [0] = name, [1] = value
274 nsTArray<nsCString> nameValuePair;
275 if (!ParseString(nameValuePairs[i], '=', nameValuePair)) {
276 return NS_ERROR_INVALID_ARG;
277 }
278 if (nameValuePair.Length() != 2) {
279 return NS_ERROR_INVALID_ARG;
280 }
282 // Parse the bpp portion of the string name=value;version=<version_value>;
283 // name=value
284 if (nameValuePair[0].Equals("version",
285 nsCaseInsensitiveCStringComparator())) {
286 if (nameValuePair[1].Equals("3")) {
287 *version = VERSION_3;
288 } else if (nameValuePair[1].Equals("5")) {
289 *version = VERSION_5;
290 } else {
291 return NS_ERROR_INVALID_ARG;
292 }
293 }
295 // Parse the bpp portion of the string name=value;bpp=<bpp_value>;name=value
296 if (nameValuePair[0].Equals("bpp", nsCaseInsensitiveCStringComparator())) {
297 if (nameValuePair[1].Equals("24")) {
298 *bpp = 24;
299 } else if (nameValuePair[1].Equals("32")) {
300 *bpp = 32;
301 } else {
302 return NS_ERROR_INVALID_ARG;
303 }
304 }
305 }
307 return NS_OK;
308 }
310 NS_IMETHODIMP nsBMPEncoder::Close()
311 {
312 if (mImageBufferStart) {
313 moz_free(mImageBufferStart);
314 mImageBufferStart = nullptr;
315 mImageBufferSize = 0;
316 mImageBufferReadPoint = 0;
317 mImageBufferCurr = nullptr;
318 }
320 return NS_OK;
321 }
323 // Obtains the available bytes to read
324 NS_IMETHODIMP nsBMPEncoder::Available(uint64_t *_retval)
325 {
326 if (!mImageBufferStart || !mImageBufferCurr) {
327 return NS_BASE_STREAM_CLOSED;
328 }
330 *_retval = GetCurrentImageBufferOffset() - mImageBufferReadPoint;
331 return NS_OK;
332 }
334 // [noscript] Reads bytes which are available
335 NS_IMETHODIMP nsBMPEncoder::Read(char * aBuf, uint32_t aCount,
336 uint32_t *_retval)
337 {
338 return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, _retval);
339 }
341 // [noscript] Reads segments
342 NS_IMETHODIMP nsBMPEncoder::ReadSegments(nsWriteSegmentFun aWriter,
343 void *aClosure, uint32_t aCount,
344 uint32_t *_retval)
345 {
346 uint32_t maxCount = GetCurrentImageBufferOffset() - mImageBufferReadPoint;
347 if (maxCount == 0) {
348 *_retval = 0;
349 return mFinished ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
350 }
352 if (aCount > maxCount) {
353 aCount = maxCount;
354 }
355 nsresult rv = aWriter(this, aClosure,
356 reinterpret_cast<const char*>(mImageBufferStart +
357 mImageBufferReadPoint),
358 0, aCount, _retval);
359 if (NS_SUCCEEDED(rv)) {
360 NS_ASSERTION(*_retval <= aCount, "bad write count");
361 mImageBufferReadPoint += *_retval;
362 }
363 // errors returned from the writer end here!
364 return NS_OK;
365 }
367 NS_IMETHODIMP
368 nsBMPEncoder::IsNonBlocking(bool *_retval)
369 {
370 *_retval = true;
371 return NS_OK;
372 }
374 NS_IMETHODIMP
375 nsBMPEncoder::AsyncWait(nsIInputStreamCallback *aCallback,
376 uint32_t aFlags,
377 uint32_t aRequestedCount,
378 nsIEventTarget *aTarget)
379 {
380 if (aFlags != 0) {
381 return NS_ERROR_NOT_IMPLEMENTED;
382 }
384 if (mCallback || mCallbackTarget) {
385 return NS_ERROR_UNEXPECTED;
386 }
388 mCallbackTarget = aTarget;
389 // 0 means "any number of bytes except 0"
390 mNotifyThreshold = aRequestedCount;
391 if (!aRequestedCount) {
392 mNotifyThreshold = 1024; // We don't want to notify incessantly
393 }
395 // We set the callback absolutely last, because NotifyListener uses it to
396 // determine if someone needs to be notified. If we don't set it last,
397 // NotifyListener might try to fire off a notification to a null target
398 // which will generally cause non-threadsafe objects to be used off the main thread
399 mCallback = aCallback;
401 // What we are being asked for may be present already
402 NotifyListener();
403 return NS_OK;
404 }
406 NS_IMETHODIMP nsBMPEncoder::CloseWithStatus(nsresult aStatus)
407 {
408 return Close();
409 }
411 // nsBMPEncoder::ConvertHostARGBRow
412 //
413 // Our colors are stored with premultiplied alphas, but we need
414 // an output with no alpha in machine-independent byte order.
415 //
416 void
417 nsBMPEncoder::ConvertHostARGBRow(const uint8_t* aSrc, uint8_t* aDest,
418 uint32_t aPixelWidth)
419 {
420 int bytes = BytesPerPixel(mBMPInfoHeader.bpp);
422 if (mBMPInfoHeader.bpp == 32) {
423 for (uint32_t x = 0; x < aPixelWidth; x++) {
424 const uint32_t& pixelIn = ((const uint32_t*)(aSrc))[x];
425 uint8_t *pixelOut = &aDest[x * bytes];
427 pixelOut[0] = (pixelIn & 0x00ff0000) >> 16;
428 pixelOut[1] = (pixelIn & 0x0000ff00) >> 8;
429 pixelOut[2] = (pixelIn & 0x000000ff) >> 0;
430 pixelOut[3] = (pixelIn & 0xff000000) >> 24;
431 }
432 } else {
433 for (uint32_t x = 0; x < aPixelWidth; x++) {
434 const uint32_t& pixelIn = ((const uint32_t*)(aSrc))[x];
435 uint8_t *pixelOut = &aDest[x * bytes];
437 pixelOut[0] = (pixelIn & 0xff0000) >> 16;
438 pixelOut[1] = (pixelIn & 0x00ff00) >> 8;
439 pixelOut[2] = (pixelIn & 0x0000ff) >> 0;
440 }
441 }
442 }
444 void
445 nsBMPEncoder::NotifyListener()
446 {
447 if (mCallback &&
448 (GetCurrentImageBufferOffset() - mImageBufferReadPoint >=
449 mNotifyThreshold || mFinished)) {
450 nsCOMPtr<nsIInputStreamCallback> callback;
451 if (mCallbackTarget) {
452 callback = NS_NewInputStreamReadyEvent(mCallback, mCallbackTarget);
453 } else {
454 callback = mCallback;
455 }
457 NS_ASSERTION(callback, "Shouldn't fail to make the callback");
458 // Null the callback first because OnInputStreamReady could
459 // reenter AsyncWait
460 mCallback = nullptr;
461 mCallbackTarget = nullptr;
462 mNotifyThreshold = 0;
464 callback->OnInputStreamReady(this);
465 }
466 }
468 // Initializes the BMP file header mBMPFileHeader to the passed in values
469 void
470 nsBMPEncoder::InitFileHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
471 uint32_t aHeight)
472 {
473 memset(&mBMPFileHeader, 0, sizeof(mBMPFileHeader));
474 mBMPFileHeader.signature[0] = 'B';
475 mBMPFileHeader.signature[1] = 'M';
477 if (aVersion == VERSION_3) {
478 mBMPFileHeader.dataoffset = WIN_V3_HEADER_LENGTH;
479 } else { // aVersion == 5
480 mBMPFileHeader.dataoffset = WIN_V5_HEADER_LENGTH;
481 }
483 // The color table is present only if BPP is <= 8
484 if (aBPP <= 8) {
485 uint32_t numColors = 1 << aBPP;
486 mBMPFileHeader.dataoffset += 4 * numColors;
487 mBMPFileHeader.filesize = mBMPFileHeader.dataoffset + aWidth * aHeight;
488 } else {
489 mBMPFileHeader.filesize = mBMPFileHeader.dataoffset + (aWidth *
490 BytesPerPixel(aBPP) + PaddingBytes(aBPP, aWidth)) *
491 aHeight;
492 }
494 mBMPFileHeader.reserved = 0;
496 if (aVersion == VERSION_3) {
497 mBMPFileHeader.bihsize = WIN_V3_BIH_LENGTH;
498 } else { // aVersion == VERSION_5
499 mBMPFileHeader.bihsize = WIN_V5_BIH_LENGTH;
500 }
501 }
503 #define ENCODE(pImageBufferCurr, value) \
504 memcpy(*pImageBufferCurr, &value, sizeof value); \
505 *pImageBufferCurr += sizeof value;
507 // Initializes the bitmap info header mBMPInfoHeader to the passed in values
508 void
509 nsBMPEncoder::InitInfoHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
510 uint32_t aHeight)
511 {
512 memset(&mBMPInfoHeader, 0, sizeof(mBMPInfoHeader));
513 mBMPInfoHeader.width = aWidth;
514 mBMPInfoHeader.height = aHeight;
515 mBMPInfoHeader.planes = 1;
516 mBMPInfoHeader.bpp = aBPP;
517 mBMPInfoHeader.compression = 0;
518 mBMPInfoHeader.colors = 0;
519 mBMPInfoHeader.important_colors = 0;
520 if (aBPP <= 8) {
521 mBMPInfoHeader.image_size = aWidth * aHeight;
522 } else {
523 mBMPInfoHeader.image_size = (aWidth * BytesPerPixel(aBPP) +
524 PaddingBytes(aBPP, aWidth)) * aHeight;
525 }
526 mBMPInfoHeader.xppm = 0;
527 mBMPInfoHeader.yppm = 0;
528 if (aVersion >= VERSION_5) {
529 mBMPInfoHeader.red_mask = 0x000000FF;
530 mBMPInfoHeader.green_mask = 0x0000FF00;
531 mBMPInfoHeader.blue_mask = 0x00FF0000;
532 mBMPInfoHeader.alpha_mask = 0xFF000000;
533 mBMPInfoHeader.color_space = LCS_sRGB;
534 mBMPInfoHeader.white_point.r.x = 0;
535 mBMPInfoHeader.white_point.r.y = 0;
536 mBMPInfoHeader.white_point.r.z = 0;
537 mBMPInfoHeader.white_point.g.x = 0;
538 mBMPInfoHeader.white_point.g.y = 0;
539 mBMPInfoHeader.white_point.g.z = 0;
540 mBMPInfoHeader.white_point.b.x = 0;
541 mBMPInfoHeader.white_point.b.y = 0;
542 mBMPInfoHeader.white_point.b.z = 0;
543 mBMPInfoHeader.gamma_red = 0;
544 mBMPInfoHeader.gamma_green = 0;
545 mBMPInfoHeader.gamma_blue = 0;
546 mBMPInfoHeader.intent = 0;
547 mBMPInfoHeader.profile_offset = 0;
548 mBMPInfoHeader.profile_size = 0;
549 mBMPInfoHeader.reserved = 0;
550 }
551 }
553 // Encodes the BMP file header mBMPFileHeader
554 void
555 nsBMPEncoder::EncodeFileHeader()
556 {
557 mozilla::image::BMPFILEHEADER littleEndianBFH = mBMPFileHeader;
558 NativeEndian::swapToLittleEndianInPlace(&littleEndianBFH.filesize, 1);
559 NativeEndian::swapToLittleEndianInPlace(&littleEndianBFH.reserved, 1);
560 NativeEndian::swapToLittleEndianInPlace(&littleEndianBFH.dataoffset, 1);
561 NativeEndian::swapToLittleEndianInPlace(&littleEndianBFH.bihsize, 1);
563 ENCODE(&mImageBufferCurr, littleEndianBFH.signature);
564 ENCODE(&mImageBufferCurr, littleEndianBFH.filesize);
565 ENCODE(&mImageBufferCurr, littleEndianBFH.reserved);
566 ENCODE(&mImageBufferCurr, littleEndianBFH.dataoffset);
567 ENCODE(&mImageBufferCurr, littleEndianBFH.bihsize);
568 }
570 // Encodes the BMP infor header mBMPInfoHeader
571 void
572 nsBMPEncoder::EncodeInfoHeader()
573 {
574 mozilla::image::BITMAPV5HEADER littleEndianmBIH = mBMPInfoHeader;
575 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.width, 1);
576 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.height, 1);
577 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.planes, 1);
578 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.bpp, 1);
579 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.compression, 1);
580 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.image_size, 1);
581 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.xppm, 1);
582 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.yppm, 1);
583 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.colors, 1);
584 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.important_colors, 1);
585 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.red_mask, 1);
586 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.green_mask, 1);
587 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.blue_mask, 1);
588 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.alpha_mask, 1);
589 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.color_space, 1);
590 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.white_point.r.x, 1);
591 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.white_point.r.y, 1);
592 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.white_point.r.z, 1);
593 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.white_point.g.x, 1);
594 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.white_point.g.y, 1);
595 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.white_point.g.z, 1);
596 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.white_point.b.x, 1);
597 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.white_point.b.y, 1);
598 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.white_point.b.z, 1);
599 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.gamma_red, 1);
600 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.gamma_green, 1);
601 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.gamma_blue, 1);
602 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.intent, 1);
603 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.profile_offset, 1);
604 NativeEndian::swapToLittleEndianInPlace(&littleEndianmBIH.profile_size, 1);
606 if (mBMPFileHeader.bihsize == OS2_BIH_LENGTH) {
607 uint16_t width = (uint16_t) littleEndianmBIH.width;
608 ENCODE(&mImageBufferCurr, width);
609 uint16_t height = (uint16_t) littleEndianmBIH.width;
610 ENCODE(&mImageBufferCurr, height);
611 } else {
612 ENCODE(&mImageBufferCurr, littleEndianmBIH.width);
613 ENCODE(&mImageBufferCurr, littleEndianmBIH.height);
614 }
616 ENCODE(&mImageBufferCurr, littleEndianmBIH.planes);
617 ENCODE(&mImageBufferCurr, littleEndianmBIH.bpp);
619 if (mBMPFileHeader.bihsize > OS2_BIH_LENGTH) {
620 ENCODE(&mImageBufferCurr, littleEndianmBIH.compression);
621 ENCODE(&mImageBufferCurr, littleEndianmBIH.image_size);
622 ENCODE(&mImageBufferCurr, littleEndianmBIH.xppm);
623 ENCODE(&mImageBufferCurr, littleEndianmBIH.yppm);
624 ENCODE(&mImageBufferCurr, littleEndianmBIH.colors);
625 ENCODE(&mImageBufferCurr, littleEndianmBIH.important_colors);
626 }
628 if (mBMPFileHeader.bihsize > WIN_V3_BIH_LENGTH) {
629 ENCODE(&mImageBufferCurr, littleEndianmBIH.red_mask);
630 ENCODE(&mImageBufferCurr, littleEndianmBIH.green_mask);
631 ENCODE(&mImageBufferCurr, littleEndianmBIH.blue_mask);
632 ENCODE(&mImageBufferCurr, littleEndianmBIH.alpha_mask);
633 ENCODE(&mImageBufferCurr, littleEndianmBIH.color_space);
634 ENCODE(&mImageBufferCurr, littleEndianmBIH.white_point.r.x);
635 ENCODE(&mImageBufferCurr, littleEndianmBIH.white_point.r.y);
636 ENCODE(&mImageBufferCurr, littleEndianmBIH.white_point.r.z);
637 ENCODE(&mImageBufferCurr, littleEndianmBIH.white_point.g.x);
638 ENCODE(&mImageBufferCurr, littleEndianmBIH.white_point.g.y);
639 ENCODE(&mImageBufferCurr, littleEndianmBIH.white_point.g.z);
640 ENCODE(&mImageBufferCurr, littleEndianmBIH.white_point.b.x);
641 ENCODE(&mImageBufferCurr, littleEndianmBIH.white_point.b.y);
642 ENCODE(&mImageBufferCurr, littleEndianmBIH.white_point.b.z);
643 ENCODE(&mImageBufferCurr, littleEndianmBIH.gamma_red);
644 ENCODE(&mImageBufferCurr, littleEndianmBIH.gamma_green);
645 ENCODE(&mImageBufferCurr, littleEndianmBIH.gamma_blue);
646 ENCODE(&mImageBufferCurr, littleEndianmBIH.intent);
647 ENCODE(&mImageBufferCurr, littleEndianmBIH.profile_offset);
648 ENCODE(&mImageBufferCurr, littleEndianmBIH.profile_size);
649 ENCODE(&mImageBufferCurr, littleEndianmBIH.reserved);
650 }
651 }
653 // Sets a pixel in the image buffer that doesn't have alpha data
654 static inline void
655 SetPixel24(uint8_t*& imageBufferCurr, uint8_t aRed, uint8_t aGreen,
656 uint8_t aBlue)
657 {
658 *imageBufferCurr = aBlue;
659 *(imageBufferCurr + 1) = aGreen;
660 *(imageBufferCurr + 2) = aRed;
661 }
663 // Sets a pixel in the image buffer with alpha data
664 static inline void
665 SetPixel32(uint8_t*& imageBufferCurr, uint8_t aRed, uint8_t aGreen,
666 uint8_t aBlue, uint8_t aAlpha = 0xFF)
667 {
668 *imageBufferCurr = aBlue;
669 *(imageBufferCurr + 1) = aGreen;
670 *(imageBufferCurr + 2) = aRed;
671 *(imageBufferCurr + 3) = aAlpha;
672 }
674 // Encodes a row of image data which does not have alpha data
675 void
676 nsBMPEncoder::EncodeImageDataRow24(const uint8_t* aData)
677 {
678 for (int32_t x = 0; x < mBMPInfoHeader.width; x++) {
679 uint32_t pos = x * BytesPerPixel(mBMPInfoHeader.bpp);
680 SetPixel24(mImageBufferCurr, aData[pos], aData[pos + 1], aData[pos + 2]);
681 mImageBufferCurr += BytesPerPixel(mBMPInfoHeader.bpp);
682 }
684 for (uint32_t x = 0; x < PaddingBytes(mBMPInfoHeader.bpp,
685 mBMPInfoHeader.width); x++) {
686 *mImageBufferCurr++ = 0;
687 }
688 }
690 // Encodes a row of image data which does have alpha data
691 void
692 nsBMPEncoder::EncodeImageDataRow32(const uint8_t* aData)
693 {
694 for (int32_t x = 0; x < mBMPInfoHeader.width; x ++) {
695 uint32_t pos = x * BytesPerPixel(mBMPInfoHeader.bpp);
696 SetPixel32(mImageBufferCurr, aData[pos], aData[pos + 1],
697 aData[pos + 2], aData[pos + 3]);
698 mImageBufferCurr += 4;
699 }
701 for (uint32_t x = 0; x < PaddingBytes(mBMPInfoHeader.bpp,
702 mBMPInfoHeader.width); x ++) {
703 *mImageBufferCurr++ = 0;
704 }
705 }