Prep for v1.1.0
[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 // Draw image.bmp (from the root folder) starting at pixel 0,0
150 bmp_error_t error = bmpDrawBitmap(0, 0, "/image.bmp");
151
152 if (error)
153 {
154 switch (error)
155 {
156 case BMP_ERROR_SDINITFAIL:
157 break;
158 case BMP_ERROR_FILENOTFOUND:
159 break;
160 case BMP_ERROR_NOTABITMAP:
161 // First two bytes of image not 'BM'
162 break;
163 case BMP_ERROR_INVALIDBITDEPTH:
164 // Image is not 24-bits
165 break;
166 case BMP_ERROR_COMPRESSEDDATA:
167 // Image contains compressed data
168 break;
169 case BMP_ERROR_INVALIDDIMENSIONS:
170 // Width or Height is > LCD size
171 break;
172 case BMP_ERROR_PREMATUREEOF:
173 // EOF unexpectedly reached in pixel data
174 break;
175 }
176 }
177
178 @endcode
179 */
180 /**************************************************************************/
181 bmp_error_t bmpDrawBitmap(uint16_t x, uint16_t y, const char* filename)
182 {
183 bmp_error_t error = BMP_ERROR_NONE;
184 DSTATUS stat;
185 BYTE res;
186
187 stat = disk_initialize(0);
188
189 if ((stat & STA_NOINIT) || (stat & STA_NODISK))
190 {
191 // Card not initialised or no disk present
192 return BMP_ERROR_SDINITFAIL;
193 }
194
195 if (stat == 0)
196 {
197 // Try to mount drive
198 res = f_mount(0, &Fatfs[0]);
199 if (res != FR_OK)
200 {
201 // Failed to mount 0:
202 return BMP_ERROR_SDINITFAIL;
203 }
204 if (res == FR_OK)
205 {
206 // Try to open the requested file
207 FIL imgfile;
208 if(f_open(&imgfile, filename, FA_READ | FA_OPEN_EXISTING) != FR_OK)
209 {
210 // Unable to open the requested file
211 return BMP_ERROR_FILENOTFOUND;
212 }
213 // Try to render the specified image
214 error = bmpParseBitmap(x, y, imgfile);
215 // Close file
216 f_close(&imgfile);
217 // Unmount drive
218 f_mount(0,0);
219 // Return results
220 return error;
221 }
222 }
223
224 // Return OK signal
225 return BMP_ERROR_NONE;
226 }
227
228 #if defined CFG_SDCARD_READONLY && CFG_SDCARD_READONLY == 0
229 /**************************************************************************/
230 /*!
231 @brief Writes the contents of the LCD screen to a 24-bit bitmap
232 images. CFG_SDCARD_READONLY must be set to '0' to be able
233 to use this function.
234
235 @section Example
236
237 @code
238
239 #include "drivers/displays/tft/bmp.h"
240
241 bmp_error_t error;
242
243 // Note: The LED stays on while the image is being written since
244 // it can take quite a while to read the entire screen
245 // pixel by pixel and write the data to the SD card
246
247 // Turn the LED on to signal busy state
248 gpioSetValue (CFG_LED_PORT, CFG_LED_PIN, CFG_LED_ON);
249 // Write the screen contents to a bitmap image
250 error = bmpSaveScreenshot("capture.bmp");
251 // Turn the LED off to indicate that the capture is complete
252 gpioSetValue (CFG_LED_PORT, CFG_LED_PIN, CFG_LED_OFF);
253
254 // Check 'error' for problems
255
256 @endcode
257 */
258 /**************************************************************************/
259 bmp_error_t bmpSaveScreenshot(const char* filename)
260 {
261 DSTATUS stat;
262 bmp_error_t error = BMP_ERROR_NONE;
263 bmp_header_t header;
264 bmp_infoheader_t infoHeader;
265 uint32_t lcdWidth, lcdHeight, x, y, bgra32;
266 UINT bytesWritten;
267 uint16_t rgb565, eof;
268 uint8_t r, g, b;
269
270 // Create a new file (Crossworks only)
271 stat = disk_initialize(0);
272 if (stat & STA_NOINIT)
273 {
274 return BMP_ERROR_SDINITFAIL;
275 }
276 if (stat & STA_NODISK)
277 {
278 return BMP_ERROR_SDINITFAIL;
279 }
280 if (stat == 0)
281 {
282 // SD card sucessfully initialised
283 DSTATUS stat;
284 DWORD p2;
285 WORD w1;
286 BYTE res, b1;
287 DIR dir;
288 // Try to mount drive
289 res = f_mount(0, &Fatfs[0]);
290 if (res != FR_OK)
291 {
292 return BMP_ERROR_SDINITFAIL;
293 }
294 if (res == FR_OK)
295 {
296 // Create a file (overwriting any existing file!)
297 if(f_open(&bmpSDFile, filename, FA_READ | FA_WRITE | FA_CREATE_ALWAYS)!=FR_OK)
298 {
299 return BMP_ERROR_UNABLETOCREATEFILE;
300 }
301 }
302 }
303
304 lcdWidth = lcdGetWidth();
305 lcdHeight = lcdGetHeight();
306
307 // Create header
308 header.type = 0x4d42; // 'BM'
309 header.size = (lcdWidth * lcdHeight * 3) + sizeof(header) + sizeof(infoHeader); // File size in bytes
310 header.reserved1 = 0;
311 header.reserved2 = 0;
312 header.offset = 0x36; // Offset in bytes to the image data
313
314 // Create infoheader
315 infoHeader.size = sizeof(infoHeader);
316 infoHeader.width = lcdWidth;
317 infoHeader.height = lcdHeight;
318 infoHeader.planes = 1;
319 infoHeader.bits = 24;
320 infoHeader.compression = BMP_COMPRESSION_NONE;
321 infoHeader.imagesize = (lcdWidth * lcdHeight * 3) + 2; // 3 bytes per pixel + 2 bytes for EOF
322 infoHeader.xresolution = 0x0B12;
323 infoHeader.yresolution = 0x0B12;
324 infoHeader.ncolours = 0;
325 infoHeader.importantcolours = 0;
326
327 // Write header to disk
328 f_write(&bmpSDFile, &header.type, sizeof(header.type), &bytesWritten);
329 f_write(&bmpSDFile, &header.size, sizeof(header.size), &bytesWritten);
330 f_write(&bmpSDFile, &header.reserved1, sizeof(header.reserved1), &bytesWritten);
331 f_write(&bmpSDFile, &header.reserved2, sizeof(header.reserved2), &bytesWritten);
332 f_write(&bmpSDFile, &header.offset, sizeof(header.offset), &bytesWritten);
333 f_write(&bmpSDFile, &infoHeader.size, sizeof(infoHeader.size), &bytesWritten);
334 f_write(&bmpSDFile, &infoHeader.width, sizeof(infoHeader.width), &bytesWritten);
335 f_write(&bmpSDFile, &infoHeader.height, sizeof(infoHeader.height), &bytesWritten);
336 f_write(&bmpSDFile, &infoHeader.planes, sizeof(infoHeader.planes), &bytesWritten);
337 f_write(&bmpSDFile, &infoHeader.bits, sizeof(infoHeader.bits), &bytesWritten);
338 f_write(&bmpSDFile, &infoHeader.compression, sizeof(infoHeader.compression), &bytesWritten);
339 f_write(&bmpSDFile, &infoHeader.imagesize, sizeof(infoHeader.imagesize), &bytesWritten);
340 f_write(&bmpSDFile, &infoHeader.xresolution, sizeof(infoHeader.xresolution), &bytesWritten);
341 f_write(&bmpSDFile, &infoHeader.yresolution, sizeof(infoHeader.yresolution), &bytesWritten);
342 f_write(&bmpSDFile, &infoHeader.ncolours, sizeof(infoHeader.ncolours), &bytesWritten);
343 f_write(&bmpSDFile, &infoHeader.importantcolours, sizeof(infoHeader.importantcolours), &bytesWritten);
344
345 // Write image data to disk (starting from bottom row)
346 for (y = lcdHeight; y != 0; y--)
347 {
348 for (x = 0; x < lcdWidth; x++)
349 {
350 rgb565 = lcdGetPixel(x, y - 1); // Get RGB565 pixel
351 bgra32 = colorsRGB565toBGRA32(rgb565); // Convert RGB565 to 24-bit color
352 r = (bgra32 & 0x00FF0000) >> 16;
353 g = (bgra32 & 0x0000FF00) >> 8;
354 b = (bgra32 & 0x000000FF);
355 f_write(&bmpSDFile, &b, 1, &bytesWritten); // Write RGB data
356 f_write(&bmpSDFile, &g, 1, &bytesWritten);
357 f_write(&bmpSDFile, &r, 1, &bytesWritten);
358 }
359 }
360
361 // Write EOF (2 bytes)
362 eof = 0x0000;
363 f_write(&bmpSDFile, &eof, 2, &bytesWritten);
364
365 // Close the file
366 f_close(&bmpSDFile);
367
368 // Return OK signal
369 return BMP_ERROR_NONE;
370 }
371 #endif // End of read-only check to write bitmaps
372
373 #endif // End of CFG_SDCARD check
This page took 0.068263 seconds and 5 git commands to generate.