1 /**************************************************************************/
4 @author K. Townsend (microBuilder.eu)
6 @brief Loads uncomprssed 24-bit windows bitmaps images
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
14 Software License Agreement (BSD License)
16 Copyright (c) 2010, microBuilder SARL
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.
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.
41 /**************************************************************************/
46 #include "drivers/displays/tft/drawing.h"
47 #include "drivers/displays/tft/lcd.h"
49 // Only include read support if CFG_SDCARD is defined
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
59 /**************************************************************************/
61 /* ----------------------- Private Methods ------------------------------ */
63 /**************************************************************************/
64 bmp_error_t
bmpParseBitmap(uint16_t x
, uint16_t y
, FIL file
)
68 bmp_infoheader_t infoHeader
;
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
);
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
;
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
);
95 // Make sure that this is a 24-bit image
96 if (infoHeader
.bits
!= 24)
97 return BMP_ERROR_INVALIDBITDEPTH
;
99 // Check image dimensions
100 if ((infoHeader
.width
> lcdGetWidth()) | (infoHeader
.height
> lcdGetHeight()))
101 return BMP_ERROR_INVALIDDIMENSIONS
;
103 // Make sure image is not compressed
104 if (infoHeader
.compression
!= BMP_COMPRESSION_NONE
)
105 return BMP_ERROR_COMPRESSEDDATA
;
107 // Read 24-bit image data
110 uint8_t buffer
[infoHeader
.width
* 3];
111 for (py
= infoHeader
.height
; py
> 0; py
--)
113 // Read one row at a time
114 res
= f_read(&file
, &buffer
, infoHeader
.width
* 3, &bytesRead
);
115 if (res
|| bytesRead
== 0)
118 return BMP_ERROR_PREMATUREEOF
;
120 for (px
= 0; px
< infoHeader
.width
; px
++)
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)]));
129 return BMP_ERROR_NONE
;
132 /**************************************************************************/
134 /* ----------------------- Public Methods ------------------------------- */
136 /**************************************************************************/
138 /**************************************************************************/
140 @brief Loads a 24-bit Windows bitmap image from an SD card and
147 #include "drivers/displays/tft/bmp.h"
149 // Draw image.bmp (from the root folder) starting at pixel 0,0
150 bmp_error_t error = bmpDrawBitmap(0, 0, "/image.bmp");
156 case BMP_ERROR_SDINITFAIL:
158 case BMP_ERROR_FILENOTFOUND:
160 case BMP_ERROR_NOTABITMAP:
161 // First two bytes of image not 'BM'
163 case BMP_ERROR_INVALIDBITDEPTH:
164 // Image is not 24-bits
166 case BMP_ERROR_COMPRESSEDDATA:
167 // Image contains compressed data
169 case BMP_ERROR_INVALIDDIMENSIONS:
170 // Width or Height is > LCD size
172 case BMP_ERROR_PREMATUREEOF:
173 // EOF unexpectedly reached in pixel data
180 /**************************************************************************/
181 bmp_error_t
bmpDrawBitmap(uint16_t x
, uint16_t y
, const char* filename
)
183 bmp_error_t error
= BMP_ERROR_NONE
;
187 stat
= disk_initialize(0);
189 if ((stat
& STA_NOINIT
) || (stat
& STA_NODISK
))
191 // Card not initialised or no disk present
192 return BMP_ERROR_SDINITFAIL
;
197 // Try to mount drive
198 res
= f_mount(0, &Fatfs
[0]);
201 // Failed to mount 0:
202 return BMP_ERROR_SDINITFAIL
;
206 // Try to open the requested file
208 if(f_open(&imgfile
, filename
, FA_READ
| FA_OPEN_EXISTING
) != FR_OK
)
210 // Unable to open the requested file
211 return BMP_ERROR_FILENOTFOUND
;
213 // Try to render the specified image
214 error
= bmpParseBitmap(x
, y
, imgfile
);
225 return BMP_ERROR_NONE
;
228 #if defined CFG_SDCARD_READONLY && CFG_SDCARD_READONLY == 0
229 /**************************************************************************/
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.
239 #include "drivers/displays/tft/bmp.h"
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
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);
254 // Check 'error' for problems
258 /**************************************************************************/
259 bmp_error_t
bmpSaveScreenshot(const char* filename
)
262 bmp_error_t error
= BMP_ERROR_NONE
;
264 bmp_infoheader_t infoHeader
;
265 uint32_t lcdWidth
, lcdHeight
, x
, y
, bgra32
;
267 uint16_t rgb565
, eof
;
270 // Create a new file (Crossworks only)
271 stat
= disk_initialize(0);
272 if (stat
& STA_NOINIT
)
274 return BMP_ERROR_SDINITFAIL
;
276 if (stat
& STA_NODISK
)
278 return BMP_ERROR_SDINITFAIL
;
282 // SD card sucessfully initialised
288 // Try to mount drive
289 res
= f_mount(0, &Fatfs
[0]);
292 return BMP_ERROR_SDINITFAIL
;
296 // Create a file (overwriting any existing file!)
297 if(f_open(&bmpSDFile
, filename
, FA_READ
| FA_WRITE
| FA_CREATE_ALWAYS
)!=FR_OK
)
299 return BMP_ERROR_UNABLETOCREATEFILE
;
304 lcdWidth
= lcdGetWidth();
305 lcdHeight
= lcdGetHeight();
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
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;
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
);
345 // Write image data to disk (starting from bottom row)
346 for (y
= lcdHeight
; y
!= 0; y
--)
348 for (x
= 0; x
< lcdWidth
; x
++)
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
);
361 // Write EOF (2 bytes)
363 f_write(&bmpSDFile
, &eof
, 2, &bytesWritten
);
369 return BMP_ERROR_NONE
;
371 #endif // End of read-only check to write bitmaps
373 #endif // End of CFG_SDCARD check