Basic alpha-blending
[hackover2013-badge-firmware.git] / drivers / displays / tft / bmp.c
1 /**************************************************************************/
2 /*!
3 @file bmp.c
4 @author K. Townsend (microBuilder.eu)
5
6 @brief Loads uncomprssed 24-bit windows bitmaps images
7
8 Based on the information available at:
9 http://local.wasp.uwa.edu.au/~pbourke/dataformats/bmp/
10 and some sample code written by Michael Sweet
11
12 @section LICENSE
13
14 Software License Agreement (BSD License)
15
16 Copyright (c) 2010, microBuilder SARL
17 All rights reserved.
18
19 Redistribution and use in source and binary forms, with or without
20 modification, are permitted provided that the following conditions are met:
21 1. Redistributions of source code must retain the above copyright
22 notice, this list of conditions and the following disclaimer.
23 2. Redistributions in binary form must reproduce the above copyright
24 notice, this list of conditions and the following disclaimer in the
25 documentation and/or other materials provided with the distribution.
26 3. Neither the name of the copyright holders nor the
27 names of its contributors may be used to endorse or promote products
28 derived from this software without specific prior written permission.
29
30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
31 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
37 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41 /**************************************************************************/
42 #include <string.h>
43
44 #include "bmp.h"
45
46 #include "drivers/displays/tft/drawing.h"
47 #include "drivers/displays/tft/lcd.h"
48
49 // Only include read support if CFG_SDCARD is defined
50 #ifdef CFG_SDCARD
51 #include "drivers/fatfs/diskio.h"
52 #include "drivers/fatfs/ff.h"
53 static FATFS Fatfs[1];
54 #if defined CFG_SDCARD_READONLY && CFG_SDCARD_READONLY == 0
55 static FILINFO Finfo;
56 static FIL bmpSDFile;
57 #endif
58
59 /**************************************************************************/
60 /* */
61 /* ----------------------- Private Methods ------------------------------ */
62 /* */
63 /**************************************************************************/
64 bmp_error_t bmpParseBitmap(uint16_t x, uint16_t y, FIL file)
65 {
66 UINT bytesRead;
67 bmp_header_t header;
68 bmp_infoheader_t infoHeader;
69
70 // Read the file header
71 // ToDo: Optimise this to read buffer once and parse it
72 f_read(&file, &header.type, sizeof(header.type), &bytesRead);
73 f_read(&file, &header.size, sizeof(header.size), &bytesRead);
74 f_read(&file, &header.reserved1, sizeof(header.reserved1), &bytesRead);
75 f_read(&file, &header.reserved2, sizeof(header.reserved2), &bytesRead);
76 f_read(&file, &header.offset, sizeof(header.offset), &bytesRead);
77
78 // Make sure this is a bitmap (first two bytes = 'BM' or 0x4D42 on little-endian systems)
79 if (header.type != 0x4D42) return BMP_ERROR_NOTABITMAP;
80
81 // Read the info header
82 // ToDo: Optimise this to read buffer once and parse it
83 f_read(&file, &infoHeader.size, sizeof(infoHeader.size), &bytesRead);
84 f_read(&file, &infoHeader.width, sizeof(infoHeader.width), &bytesRead);
85 f_read(&file, &infoHeader.height, sizeof(infoHeader.height), &bytesRead);
86 f_read(&file, &infoHeader.planes, sizeof(infoHeader.planes), &bytesRead);
87 f_read(&file, &infoHeader.bits, sizeof(infoHeader.bits), &bytesRead);
88 f_read(&file, &infoHeader.compression, sizeof(infoHeader.compression), &bytesRead);
89 f_read(&file, &infoHeader.imagesize, sizeof(infoHeader.imagesize), &bytesRead);
90 f_read(&file, &infoHeader.xresolution, sizeof(infoHeader.xresolution), &bytesRead);
91 f_read(&file, &infoHeader.yresolution, sizeof(infoHeader.yresolution), &bytesRead);
92 f_read(&file, &infoHeader.ncolours, sizeof(infoHeader.ncolours), &bytesRead);
93 f_read(&file, &infoHeader.importantcolours, sizeof(infoHeader.importantcolours), &bytesRead);
94
95 // Make sure that this is a 24-bit image
96 if (infoHeader.bits != 24)
97 return BMP_ERROR_INVALIDBITDEPTH;
98
99 // Check image dimensions
100 if ((infoHeader.width > lcdGetWidth()) | (infoHeader.height > lcdGetHeight()))
101 return BMP_ERROR_INVALIDDIMENSIONS;
102
103 // Make sure image is not compressed
104 if (infoHeader.compression != BMP_COMPRESSION_NONE)
105 return BMP_ERROR_COMPRESSEDDATA;
106
107 // Read 24-bit image data
108 uint32_t px, py;
109 FRESULT res;
110 uint8_t buffer[infoHeader.width * 3];
111 for (py = infoHeader.height; py > 0; py--)
112 {
113 // Read one row at a time
114 res = f_read(&file, &buffer, infoHeader.width * 3, &bytesRead);
115 if (res || bytesRead == 0)
116 {
117 // Error or EOF
118 return BMP_ERROR_PREMATUREEOF;
119 }
120 for (px = 0; px < infoHeader.width; px++)
121 {
122 // Render pixel
123 // ToDo: This is a brutally slow way of rendering bitmaps ...
124 // update to pass one row of data at a time
125 drawPixel(x + px, y + py - 1, colorsRGB24toRGB565(buffer[(px * 3) + 2], buffer[(px * 3) + 1], buffer[(px * 3)]));
126 }
127 }
128
129 return BMP_ERROR_NONE;
130 }
131
132 /**************************************************************************/
133 /* */
134 /* ----------------------- Public Methods ------------------------------- */
135 /* */
136 /**************************************************************************/
137
138 /**************************************************************************/
139 /*!
140 @brief Loads a 24-bit Windows bitmap image from an SD card and
141 renders it
142
143 @section Example
144
145 @code
146
147 #include "drivers/displays/tft/bmp.h"
148
149 bmp_error_t error;
150
151 // Draw image.bmp (from the root folder) starting at pixel 0,0
152 error = bmpDrawBitmap(0, 0, "/image.bmp");
153
154 // Check 'error' for problems such as BMP_ERROR_FILENOTFOUND
155
156 @endcode
157 */
158 /**************************************************************************/
159 bmp_error_t bmpDrawBitmap(uint16_t x, uint16_t y, const char* filename)
160 {
161 bmp_error_t error = BMP_ERROR_NONE;
162 DSTATUS stat;
163 BYTE res;
164
165 stat = disk_initialize(0);
166
167 if ((stat & STA_NOINIT) || (stat & STA_NODISK))
168 {
169 // Card not initialised or no disk present
170 return BMP_ERROR_SDINITFAIL;
171 }
172
173 if (stat == 0)
174 {
175 // Try to mount drive
176 res = f_mount(0, &Fatfs[0]);
177 if (res != FR_OK)
178 {
179 // Failed to mount 0:
180 return BMP_ERROR_SDINITFAIL;
181 }
182 if (res == FR_OK)
183 {
184 // Try to open the requested file
185 FIL imgfile;
186 if(f_open(&imgfile, filename, FA_READ | FA_OPEN_EXISTING) != FR_OK)
187 {
188 // Unable to open the requested file
189 return BMP_ERROR_FILENOTFOUND;
190 }
191 // Try to render the specified image
192 error = bmpParseBitmap(x, y, imgfile);
193 // Close file
194 f_close(&imgfile);
195 // Unmount drive
196 f_mount(0,0);
197 // Return results
198 return error;
199 }
200 }
201
202 // Return OK signal
203 return BMP_ERROR_NONE;
204 }
205
206 #if defined CFG_SDCARD_READONLY && CFG_SDCARD_READONLY == 0
207 /**************************************************************************/
208 /*!
209 @brief Writes the contents of the LCD screen to a 24-bit bitmap
210 images. CFG_SDCARD_READONLY must be set to '0' to be able
211 to use this function.
212
213 @section Example
214
215 @code
216
217 #include "drivers/displays/tft/bmp.h"
218
219 bmp_error_t error;
220
221 // Note: The LED stays on while the image is being written since
222 // it can take quite a while to read the entire screen
223 // pixel by pixel and write the data to the SD card
224
225 // Turn the LED on to signal busy state
226 gpioSetValue (CFG_LED_PORT, CFG_LED_PIN, CFG_LED_ON);
227 // Write the screen contents to a bitmap image
228 error = bmpSaveScreenshot("capture.bmp");
229 // Turn the LED off to indicate that the capture is complete
230 gpioSetValue (CFG_LED_PORT, CFG_LED_PIN, CFG_LED_OFF);
231
232 // Check 'error' for problems
233
234 @endcode
235 */
236 /**************************************************************************/
237 bmp_error_t bmpSaveScreenshot(const char* filename)
238 {
239 DSTATUS stat;
240 bmp_error_t error = BMP_ERROR_NONE;
241 bmp_header_t header;
242 bmp_infoheader_t infoHeader;
243 uint32_t lcdWidth, lcdHeight, x, y, bgra32;
244 UINT bytesWritten;
245 uint16_t rgb565, eof;
246 uint8_t r, g, b;
247
248 // Create a new file (Crossworks only)
249 stat = disk_initialize(0);
250 if (stat & STA_NOINIT)
251 {
252 return BMP_ERROR_SDINITFAIL;
253 }
254 if (stat & STA_NODISK)
255 {
256 return BMP_ERROR_SDINITFAIL;
257 }
258 if (stat == 0)
259 {
260 // SD card sucessfully initialised
261 DSTATUS stat;
262 DWORD p2;
263 WORD w1;
264 BYTE res, b1;
265 DIR dir;
266 // Try to mount drive
267 res = f_mount(0, &Fatfs[0]);
268 if (res != FR_OK)
269 {
270 return BMP_ERROR_SDINITFAIL;
271 }
272 if (res == FR_OK)
273 {
274 // Create a file (overwriting any existing file!)
275 if(f_open(&bmpSDFile, filename, FA_READ | FA_WRITE | FA_CREATE_ALWAYS)!=FR_OK)
276 {
277 return BMP_ERROR_UNABLETOCREATEFILE;
278 }
279 }
280 }
281
282 lcdWidth = lcdGetWidth();
283 lcdHeight = lcdGetHeight();
284
285 // Create header
286 header.type = 0x4d42; // 'BM'
287 header.size = (lcdWidth * lcdHeight * 3) + sizeof(header) + sizeof(infoHeader); // File size in bytes
288 header.reserved1 = 0;
289 header.reserved2 = 0;
290 header.offset = 0x36; // Offset in bytes to the image data
291
292 // Create infoheader
293 infoHeader.size = sizeof(infoHeader);
294 infoHeader.width = lcdWidth;
295 infoHeader.height = lcdHeight;
296 infoHeader.planes = 1;
297 infoHeader.bits = 24;
298 infoHeader.compression = BMP_COMPRESSION_NONE;
299 infoHeader.imagesize = (lcdWidth * lcdHeight * 3) + 2; // 3 bytes per pixel + 2 bytes for EOF
300 infoHeader.xresolution = 0x0B12;
301 infoHeader.yresolution = 0x0B12;
302 infoHeader.ncolours = 0;
303 infoHeader.importantcolours = 0;
304
305 // Write header to disk
306 f_write(&bmpSDFile, &header.type, sizeof(header.type), &bytesWritten);
307 f_write(&bmpSDFile, &header.size, sizeof(header.size), &bytesWritten);
308 f_write(&bmpSDFile, &header.reserved1, sizeof(header.reserved1), &bytesWritten);
309 f_write(&bmpSDFile, &header.reserved2, sizeof(header.reserved2), &bytesWritten);
310 f_write(&bmpSDFile, &header.offset, sizeof(header.offset), &bytesWritten);
311 f_write(&bmpSDFile, &infoHeader.size, sizeof(infoHeader.size), &bytesWritten);
312 f_write(&bmpSDFile, &infoHeader.width, sizeof(infoHeader.width), &bytesWritten);
313 f_write(&bmpSDFile, &infoHeader.height, sizeof(infoHeader.height), &bytesWritten);
314 f_write(&bmpSDFile, &infoHeader.planes, sizeof(infoHeader.planes), &bytesWritten);
315 f_write(&bmpSDFile, &infoHeader.bits, sizeof(infoHeader.bits), &bytesWritten);
316 f_write(&bmpSDFile, &infoHeader.compression, sizeof(infoHeader.compression), &bytesWritten);
317 f_write(&bmpSDFile, &infoHeader.imagesize, sizeof(infoHeader.imagesize), &bytesWritten);
318 f_write(&bmpSDFile, &infoHeader.xresolution, sizeof(infoHeader.xresolution), &bytesWritten);
319 f_write(&bmpSDFile, &infoHeader.yresolution, sizeof(infoHeader.yresolution), &bytesWritten);
320 f_write(&bmpSDFile, &infoHeader.ncolours, sizeof(infoHeader.ncolours), &bytesWritten);
321 f_write(&bmpSDFile, &infoHeader.importantcolours, sizeof(infoHeader.importantcolours), &bytesWritten);
322
323 // Write image data to disk (starting from bottom row)
324 for (y = lcdHeight; y != 0; y--)
325 {
326 for (x = 0; x < lcdWidth; x++)
327 {
328 rgb565 = lcdGetPixel(x, y - 1); // Get RGB565 pixel
329 bgra32 = colorsRGB565toBGRA32(rgb565); // Convert RGB565 to 24-bit color
330 r = (bgra32 & 0x00FF0000) >> 16;
331 g = (bgra32 & 0x0000FF00) >> 8;
332 b = (bgra32 & 0x000000FF);
333 f_write(&bmpSDFile, &b, 1, &bytesWritten); // Write RGB data
334 f_write(&bmpSDFile, &g, 1, &bytesWritten);
335 f_write(&bmpSDFile, &r, 1, &bytesWritten);
336 }
337 }
338
339 // Write EOF (2 bytes)
340 eof = 0x0000;
341 f_write(&bmpSDFile, &eof, 2, &bytesWritten);
342
343 // Close the file
344 f_close(&bmpSDFile);
345
346 // Return OK signal
347 return BMP_ERROR_NONE;
348 }
349 #endif // End of read-only check to write bitmaps
350
351 #endif // End of CFG_SDCARD check
This page took 0.063249 seconds and 5 git commands to generate.