3 /// BMP conversion routines
7 Copyright (C) 2009-2012, Net Direct Inc. (http://www.netdirect.ca/)
8 Copyright (C) 2008-2009, Nicolas VIVIEN
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
25 #include "bmp-internal.h"
29 #include "m_javaloader.h"
34 // GetBitmapHeadersSize
36 /// Returns the size of the bitmap headers (both file and info headers).
37 /// You can use this as an offset into the bitmap produced by
38 /// ScreenshotToBitmap to get just the 4-byte RGB data.
40 size_t GetBitmapHeadersSize()
42 return sizeof(bmp_file_header_t
) +
43 sizeof(bmp_info_header_t
);
49 /// Returns the total number of bytes needed to convert a
50 /// screenshot of the given dimensions into a bitmap,
51 /// using the ScreenshotToBitmap() function.
53 size_t GetTotalBitmapSize(const JLScreenInfo
&info
)
55 return sizeof(bmp_file_header_t
) +
56 sizeof(bmp_info_header_t
) +
57 (info
.width
* info
.height
* 4); // 4 byte RGB per pixel
64 /// Converts screenshot data obtained via JavaLoader::GetScreenshot()
65 /// into uncompressed RGB bitmap format. The results will not have
66 /// a bitmap BMP header. Data will be written to buffer, starting
67 /// at offset. The depth variable can be 24 or 32. If invert is
68 /// true, the result will be inverted, just like a BMP file; otherwise not.
70 void ScreenshotToRGB(const JLScreenInfo
&info
,
71 const Data
&screenshot
,
79 if( depth
!= 24 && depth
!= 32 )
80 throw Barry::Error(_("ScreenshotToRGB: depth must be 24 or 32"));
82 // if user doesn't want to overwrite alpha channel, then use
83 // the value for our own default
84 if( !overwrite_alpha
)
87 size_t width
= info
.width
;
88 size_t height
= info
.height
;
89 size_t bytes_per_pixel
= (depth
== 24) ? 3 : 4;
90 size_t pixel_count
= width
* height
;
91 size_t total_bitmap_size
= pixel_count
* bytes_per_pixel
;
92 size_t total_buffer_size
= total_bitmap_size
+ offset
;
94 // using pixel_count (width*height), determine the size used
97 for( data_size
= 2; screenshot
.GetSize() > (data_size
* pixel_count
); data_size
++ )
99 if( screenshot
.GetSize() < (pixel_count
* data_size
) )
100 throw Error(_("ScreenshotToRGB: Screenshot data size is too small for given width+height"));
101 if( data_size
!= 2 && data_size
!= 4 )
102 throw Error(_("ScreenshotToRGB: Screenshot depth is not supported (Barry supports 2 byte or 4 byte pixels in device screenshots)"));
104 // setup write pointer
105 unsigned char *write
= buffer
.GetBuffer(total_buffer_size
) + offset
;
107 // pointer into screenshot data (grabbing pixel bytes per data_size)
108 const uint8_t *data
= (const uint8_t*) screenshot
.GetData();
110 // For each pixel... (note BMP format is up and backwards, hence
111 // offset calculation for each pixel in for loop)
112 for( size_t j
= 0; j
< height
; j
++ ) {
113 for( size_t i
= 0; i
< width
; i
++ ) {
114 // Read one pixel in the picture
116 // offset is in pixels... so multiply it by data_size
117 // to read out of data
120 get_offset
= (pixel_count
- 1) - ((width
-1 - i
) + (width
* j
));
122 get_offset
= (j
* width
) + i
;
124 // extract the pixel data, using data_size bytes
129 value
= ((const uint16_t *)data
)[get_offset
];
131 // 16bit pixel format used by the handheld is:
132 // MSB < .... .... .... .... > LSB
133 // ^^^^^^ : Blue (between 0x00 and 0x1F)
134 // ^^^^^^^ : Green (between 0x00 and 0x3F)
135 // ^^^^^^ : Red (between 0x00 and 0x1F)
137 if( bytes_per_pixel
== 4 )
140 write
[2] = (((value
>> 11) & 0x1F) * 0xFF) / 0x1F; // red
141 write
[1] = (((value
>> 5) & 0x3F) * 0xFF) / 0x3F; // green
142 write
[0] = ((value
& 0x1F) * 0xFF) / 0x1F; // blue
145 value
= ((const uint32_t *)data
)[get_offset
];
147 // 32bit pixel format used by the handheld is
148 // assumed to be RGBA
150 if( bytes_per_pixel
== 4 ) {
151 if( overwrite_alpha
)
154 write
[3] = (value
>> 24) & 0xFF;// alpha
157 write
[2] = (value
>> 16) & 0xFF; // red
158 write
[1] = (value
>> 8) & 0xFF; // green
159 write
[0] = value
& 0xFF; // blue
162 throw Error(_("ScreenshotToRGB: bad switch value, should never happen. Double check the data_size check."));
165 write
+= bytes_per_pixel
;
169 buffer
.ReleaseBuffer(total_buffer_size
);
173 // ScreenshotToBitmap
175 /// Converts screenshot data obtained via JavaLoader::GetScreenshot()
176 /// into uncompressed bitmap format, suitable for writing BMP files.
177 /// Arguments info and screenshot come from GetScreenshot() and the
178 /// converted data is stored in bitmap.
181 // This function assumes that the btoh() converter functions match
182 // the needs of the bitmap file format. Namely: little endian.
184 void ScreenshotToBitmap(const JLScreenInfo
&info
,
185 const Data
&screenshot
,
189 size_t width
= info
.width
;
190 size_t height
= info
.height
;
191 size_t total_bitmap_size
= GetTotalBitmapSize(info
);
193 // make sure there is enough screeshot pixel data for the
194 // given width and height
195 if( screenshot
.GetSize() < (width
* height
* 2) ) // 2 byte screenshot pixel data
196 throw Error(_("Screenshot data size is too small for given width+height"));
199 // setup write pointer
200 unsigned char *bitbuf
= bitmap
.GetBuffer(total_bitmap_size
);
201 unsigned char *write
= bitbuf
;
204 // Build header BMP file
206 bmp_file_header_t
*fileheader
= (bmp_file_header_t
*) write
;
207 write
+= sizeof(bmp_file_header_t
);
210 fileheader
->bfType
[0] = 'B';
211 fileheader
->bfType
[1] = 'M';
214 fileheader
->bfSize
= btohl(total_bitmap_size
);
217 fileheader
->bfReserved1
= 0;
218 fileheader
->bfReserved2
= 0;
220 // Offset to find the data
221 fileheader
->bfOffBits
= btohl(sizeof(bmp_file_header_t
) + sizeof(bmp_info_header_t
));
225 // Build info BMP file
227 bmp_info_header_t
*infoheader
= (bmp_info_header_t
*) write
;
228 write
+= sizeof(bmp_info_header_t
);
230 // Size of info section
231 infoheader
->biSize
= btohl(sizeof(bmp_info_header_t
));
234 infoheader
->biWidth
= btohl(width
);
235 infoheader
->biHeight
= btohl(height
);
238 infoheader
->biPlanes
= btohs(0x01);
241 infoheader
->biBitCount
= btohs(0x20);
244 infoheader
->biCompression
= 0;
247 infoheader
->biSizeImage
= btohl(4 * width
* height
);
250 infoheader
->biXPelsPerMeter
= 0;
251 infoheader
->biYPelsPerMeter
= 0;
253 // Color palette used : None
254 infoheader
->biClrUsed
= 0;
256 // Color palette important : None
257 infoheader
->biClrImportant
= 0;
259 // Fill in the RGB data
260 ScreenshotToRGB(info
, screenshot
, bitmap
, write
- bitbuf
, 32, true);
262 bitmap
.ReleaseBuffer(total_bitmap_size
);