tzwrapper.cc: fixed use of iterator after erase
[barry.git] / src / bmp.cc
blob411cf3f953d0f6390b8c90f44822633042c52023
1 ///
2 /// \file bmp.cc
3 /// BMP conversion routines
4 ///
6 /*
7 Copyright (C) 2009-2013, 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.
23 #include "i18n.h"
24 #include "bmp.h"
25 #include "bmp-internal.h"
26 #include "error.h"
27 #include "endian.h"
28 #include "data.h"
29 #include "m_javaloader.h"
31 namespace Barry {
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.
39 ///
40 size_t GetBitmapHeadersSize()
42 return sizeof(bmp_file_header_t) +
43 sizeof(bmp_info_header_t);
47 // GetTotalBitmapSize
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.
52 ///
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
62 // ScreenshotToRGB
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.
69 ///
70 void ScreenshotToRGB(const JLScreenInfo &info,
71 const Data &screenshot,
72 Data &buffer,
73 size_t offset,
74 int depth,
75 bool invert,
76 bool overwrite_alpha,
77 uint8_t alpha)
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 )
85 alpha = 0xFF;
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
95 // per pixel
96 size_t data_size;
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
118 int get_offset = 0;
119 if( invert )
120 get_offset = (pixel_count - 1) - ((width-1 - i) + (width * j));
121 else
122 get_offset = (j * width) + i;
124 // extract the pixel data, using data_size bytes
125 uint32_t value;
126 switch( data_size )
128 case 2:
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 )
138 write[3] = alpha;
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
143 break;
144 case 4:
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 )
152 write[3] = alpha;
153 else
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
160 break;
161 default:
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,
186 Data &bitmap)
188 // Read screen info
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);
209 // BMP
210 fileheader->bfType[0] = 'B';
211 fileheader->bfType[1] = 'M';
213 // Size of file
214 fileheader->bfSize = btohl(total_bitmap_size);
216 // Always 0x00
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));
233 // Width x Height
234 infoheader->biWidth = btohl(width);
235 infoheader->biHeight = btohl(height);
237 // Planes number
238 infoheader->biPlanes = btohs(0x01);
240 // Bit count
241 infoheader->biBitCount = btohs(0x20);
243 // Compression : No
244 infoheader->biCompression = 0;
246 // Size of image
247 infoheader->biSizeImage = btohl(4 * width * height);
249 // Pels Per Meter
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);
265 } // namespace Barry