desktop: TaskEdit: make recur end date "recent" too, when activated
[barry/progweb.git] / src / bmp.cc
blobbc6725441370c9cd3efdafb133567c9069881168
1 ///
2 /// \file bmp.cc
3 /// BMP conversion routines
4 ///
6 /*
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.
23 #include "bmp.h"
24 #include "bmp-internal.h"
25 #include "error.h"
26 #include "endian.h"
27 #include "data.h"
28 #include "m_javaloader.h"
30 namespace Barry {
33 // GetBitmapHeadersSize
35 /// Returns the size of the bitmap headers (both file and info headers).
36 /// You can use this as an offset into the bitmap produced by
37 /// ScreenshotToBitmap to get just the 4-byte RGB data.
38 ///
39 size_t GetBitmapHeadersSize()
41 return sizeof(bmp_file_header_t) +
42 sizeof(bmp_info_header_t);
46 // GetTotalBitmapSize
48 /// Returns the total number of bytes needed to convert a
49 /// screenshot of the given dimensions into a bitmap,
50 /// using the ScreenshotToBitmap() function.
51 ///
52 size_t GetTotalBitmapSize(const JLScreenInfo &info)
54 return sizeof(bmp_file_header_t) +
55 sizeof(bmp_info_header_t) +
56 (info.width * info.height * 4); // 4 byte RGB per pixel
61 // ScreenshotToRGB
63 /// Converts screenshot data obtained via JavaLoader::GetScreenshot()
64 /// into uncompressed RGB bitmap format. The results will not have
65 /// a bitmap BMP header. Data will be written to buffer, starting
66 /// at offset. The depth variable can be 24 or 32. If invert is
67 /// true, the result will be inverted, just like a BMP file; otherwise not.
68 ///
69 void ScreenshotToRGB(const JLScreenInfo &info,
70 const Data &screenshot,
71 Data &buffer,
72 size_t offset,
73 int depth,
74 bool invert,
75 bool overwrite_alpha,
76 uint8_t alpha)
78 if( depth != 24 && depth != 32 )
79 throw Barry::Error("ScreenshotToRGB: depth must be 24 or 32");
81 // if user doesn't want to overwrite alpha channel, then use
82 // the value for our own default
83 if( !overwrite_alpha )
84 alpha = 0xFF;
86 size_t width = info.width;
87 size_t height = info.height;
88 size_t bytes_per_pixel = (depth == 24) ? 3 : 4;
89 size_t pixel_count = width * height;
90 size_t total_bitmap_size = pixel_count * bytes_per_pixel;
91 size_t total_buffer_size = total_bitmap_size + offset;
93 // using pixel_count (width*height), determine the size used
94 // per pixel
95 size_t data_size;
96 for( data_size = 2; screenshot.GetSize() > (data_size * pixel_count); data_size++ )
98 if( screenshot.GetSize() < (pixel_count * data_size) )
99 throw Error("ScreenshotToRGB: Screenshot data size is too small for given width+height");
100 if( data_size != 2 && data_size != 4 )
101 throw Error("ScreenshotToRGB: Screenshot depth is not supported (Barry supports 2 byte or 4 byte pixels in device screenshots)");
103 // setup write pointer
104 unsigned char *write = buffer.GetBuffer(total_buffer_size) + offset;
106 // pointer into screenshot data (grabbing pixel bytes per data_size)
107 const uint8_t *data = (const uint8_t*) screenshot.GetData();
109 // For each pixel... (note BMP format is up and backwards, hence
110 // offset calculation for each pixel in for loop)
111 for( size_t j = 0; j < height; j++ ) {
112 for( size_t i = 0; i < width; i++ ) {
113 // Read one pixel in the picture
115 // offset is in pixels... so multiply it by data_size
116 // to read out of data
117 int get_offset = 0;
118 if( invert )
119 get_offset = (pixel_count - 1) - ((width-1 - i) + (width * j));
120 else
121 get_offset = (j * width) + i;
123 // extract the pixel data, using data_size bytes
124 uint32_t value;
125 switch( data_size )
127 case 2:
128 value = ((const uint16_t *)data)[get_offset];
130 // 16bit pixel format used by the handheld is:
131 // MSB < .... .... .... .... > LSB
132 // ^^^^^^ : Blue (between 0x00 and 0x1F)
133 // ^^^^^^^ : Green (between 0x00 and 0x3F)
134 // ^^^^^^ : Red (between 0x00 and 0x1F)
136 if( bytes_per_pixel == 4 )
137 write[3] = alpha;
139 write[2] = (((value >> 11) & 0x1F) * 0xFF) / 0x1F; // red
140 write[1] = (((value >> 5) & 0x3F) * 0xFF) / 0x3F; // green
141 write[0] = ((value & 0x1F) * 0xFF) / 0x1F; // blue
142 break;
143 case 4:
144 value = ((const uint32_t *)data)[get_offset];
146 // 32bit pixel format used by the handheld is
147 // assumed to be RGBA
149 if( bytes_per_pixel == 4 ) {
150 if( overwrite_alpha )
151 write[3] = alpha;
152 else
153 write[3] = (value >> 24) & 0xFF;// alpha
156 write[2] = (value >> 16) & 0xFF; // red
157 write[1] = (value >> 8) & 0xFF; // green
158 write[0] = value & 0xFF; // blue
159 break;
160 default:
161 throw Error("ScreenshotToRGB: bad switch value, should never happen. Double check the data_size check.");
164 write += bytes_per_pixel;
168 buffer.ReleaseBuffer(total_buffer_size);
172 // ScreenshotToBitmap
174 /// Converts screenshot data obtained via JavaLoader::GetScreenshot()
175 /// into uncompressed bitmap format, suitable for writing BMP files.
176 /// Arguments info and screenshot come from GetScreenshot() and the
177 /// converted data is stored in bitmap.
180 // This function assumes that the btoh() converter functions match
181 // the needs of the bitmap file format. Namely: little endian.
183 void ScreenshotToBitmap(const JLScreenInfo &info,
184 const Data &screenshot,
185 Data &bitmap)
187 // Read screen info
188 size_t width = info.width;
189 size_t height = info.height;
190 size_t total_bitmap_size = GetTotalBitmapSize(info);
192 // make sure there is enough screeshot pixel data for the
193 // given width and height
194 if( screenshot.GetSize() < (width * height * 2) ) // 2 byte screenshot pixel data
195 throw Error("Screenshot data size is too small for given width+height");
198 // setup write pointer
199 unsigned char *bitbuf = bitmap.GetBuffer(total_bitmap_size);
200 unsigned char *write = bitbuf;
203 // Build header BMP file
205 bmp_file_header_t *fileheader = (bmp_file_header_t*) write;
206 write += sizeof(bmp_file_header_t);
208 // BMP
209 fileheader->bfType[0] = 'B';
210 fileheader->bfType[1] = 'M';
212 // Size of file
213 fileheader->bfSize = btohl(total_bitmap_size);
215 // Always 0x00
216 fileheader->bfReserved1 = 0;
217 fileheader->bfReserved2 = 0;
219 // Offset to find the data
220 fileheader->bfOffBits = btohl(sizeof(bmp_file_header_t) + sizeof(bmp_info_header_t));
224 // Build info BMP file
226 bmp_info_header_t *infoheader = (bmp_info_header_t*) write;
227 write += sizeof(bmp_info_header_t);
229 // Size of info section
230 infoheader->biSize = btohl(sizeof(bmp_info_header_t));
232 // Width x Height
233 infoheader->biWidth = btohl(width);
234 infoheader->biHeight = btohl(height);
236 // Planes number
237 infoheader->biPlanes = btohs(0x01);
239 // Bit count
240 infoheader->biBitCount = btohs(0x20);
242 // Compression : No
243 infoheader->biCompression = 0;
245 // Size of image
246 infoheader->biSizeImage = btohl(4 * width * height);
248 // Pels Per Meter
249 infoheader->biXPelsPerMeter = 0;
250 infoheader->biYPelsPerMeter = 0;
252 // Color palette used : None
253 infoheader->biClrUsed = 0;
255 // Color palette important : None
256 infoheader->biClrImportant = 0;
258 // Fill in the RGB data
259 ScreenshotToRGB(info, screenshot, bitmap, write - bitbuf, 32, true);
261 bitmap.ReleaseBuffer(total_bitmap_size);
264 } // namespace Barry