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"
151 // Draw image.bmp (from the root folder) starting at pixel 0,0
152 error = bmpDrawBitmap(0, 0, "/image.bmp");
154 // Check 'error' for problems such as BMP_ERROR_FILENOTFOUND
158 /**************************************************************************/
159 bmp_error_t
bmpDrawBitmap(uint16_t x
, uint16_t y
, const char* filename
)
161 bmp_error_t error
= BMP_ERROR_NONE
;
165 stat
= disk_initialize(0);
167 if ((stat
& STA_NOINIT
) || (stat
& STA_NODISK
))
169 // Card not initialised or no disk present
170 return BMP_ERROR_SDINITFAIL
;
175 // Try to mount drive
176 res
= f_mount(0, &Fatfs
[0]);
179 // Failed to mount 0:
180 return BMP_ERROR_SDINITFAIL
;
184 // Try to open the requested file
186 if(f_open(&imgfile
, filename
, FA_READ
| FA_OPEN_EXISTING
) != FR_OK
)
188 // Unable to open the requested file
189 return BMP_ERROR_FILENOTFOUND
;
191 // Try to render the specified image
192 error
= bmpParseBitmap(x
, y
, imgfile
);
203 return BMP_ERROR_NONE
;
206 #if defined CFG_SDCARD_READONLY && CFG_SDCARD_READONLY == 0
207 /**************************************************************************/
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.
217 #include "drivers/displays/tft/bmp.h"
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
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);
232 // Check 'error' for problems
236 /**************************************************************************/
237 bmp_error_t
bmpSaveScreenshot(const char* filename
)
240 bmp_error_t error
= BMP_ERROR_NONE
;
242 bmp_infoheader_t infoHeader
;
243 uint32_t lcdWidth
, lcdHeight
, x
, y
, bgra32
;
245 uint16_t rgb565
, eof
;
248 // Create a new file (Crossworks only)
249 stat
= disk_initialize(0);
250 if (stat
& STA_NOINIT
)
252 return BMP_ERROR_SDINITFAIL
;
254 if (stat
& STA_NODISK
)
256 return BMP_ERROR_SDINITFAIL
;
260 // SD card sucessfully initialised
266 // Try to mount drive
267 res
= f_mount(0, &Fatfs
[0]);
270 return BMP_ERROR_SDINITFAIL
;
274 // Create a file (overwriting any existing file!)
275 if(f_open(&bmpSDFile
, filename
, FA_READ
| FA_WRITE
| FA_CREATE_ALWAYS
)!=FR_OK
)
277 return BMP_ERROR_UNABLETOCREATEFILE
;
282 lcdWidth
= lcdGetWidth();
283 lcdHeight
= lcdGetHeight();
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
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;
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
);
323 // Write image data to disk (starting from bottom row)
324 for (y
= lcdHeight
; y
!= 0; y
--)
326 for (x
= 0; x
< lcdWidth
; x
++)
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
);
339 // Write EOF (2 bytes)
341 f_write(&bmpSDFile
, &eof
, 2, &bytesWritten
);
347 return BMP_ERROR_NONE
;
349 #endif // End of read-only check to write bitmaps
351 #endif // End of CFG_SDCARD check