Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: widgets/EAImage.cpp
- Revision:
- 1:f04bcaea1d60
- Parent:
- 0:839ecbf5cb2a
- Child:
- 3:24fbf4dbd7e5
--- a/widgets/EAImage.cpp Thu Feb 11 12:21:18 2010 +0000
+++ b/widgets/EAImage.cpp Thu Mar 04 10:54:06 2010 +0000
@@ -10,14 +10,75 @@
EAImage::EAImage()
: _path(NULL),
- _dataOffset(0)
+ _palette(NULL),
+ _dataOffset(0),
+ _mask(false)
{
+ // Start from known state.
+ unload();
}
EAImage::~EAImage()
{
}
+bool EAImage::_loadPalette(FILE* fp)
+{
+ // Can't do anything with a null pointer.
+ if (fp == NULL)
+ {
+ return false;
+ }
+
+ // Clear any previously loaded palette.
+ if (_palette != NULL)
+ {
+ delete[] _palette;
+ _palette = NULL;
+ }
+
+ // If the number of bits is not less than 16 then return after having cleared the
+ // palette. There is no palette required.
+ if (info().bitsPerPixel >= 16)
+ {
+ return true;
+ }
+
+ // First create a palette of the required size.
+ unsigned int noColors = info().noColors;
+
+ // When 0 the number of colors is equal to 2^n where n is the bits per pixel.
+ if (noColors == 0)
+ {
+ noColors = pow((double)2, info().bitsPerPixel);
+ }
+
+ // Create the palette and assign the memory.
+ _palette = new EAColor[noColors];
+
+ // Now parse the palette. First seek to the start of the palette. This must be the
+ // start of the bitmap data minus the number of colour entries multiplied by 4 (the
+ // colours are stored as 4 byte long entries, the last byte can be ignored).
+ unsigned int offset = _dataOffset - (noColors*4);
+
+ // Seek to the start of the table.
+ fseek(fp, offset, SEEK_SET);
+ unsigned char buffer[4];
+
+ // Iterate through the table filling the palette as needed.
+ for (int i = 0; i < noColors; i++)
+ {
+ int sizeRead = fread(&buffer, 4, 1, fp);
+
+ if (sizeRead == 1)
+ {
+ _palette[i].setRgb(buffer[2], buffer[1], buffer[0]);
+ }
+ }
+
+ return true;
+}
+
bool EAImage::_loadHeader(const char* path)
{
if (path == NULL)
@@ -35,7 +96,6 @@
unsigned int bufint = 0;
unsigned int offset = 0;
- EABMPHeader header;
// Read the magic numbers at start.
fread(&bufint, 1, 2, fp);
@@ -60,11 +120,11 @@
offset = bufint;
// Retrieve the header.
- fread(&header, sizeof(EABMPHeader), 1, fp);
+ fread(&_header, sizeof(EABMPHeader), 1, fp);
- // Make sure the bits per pixel is 16 and compression type is bit fields.
- if ((header.bitsPerPixel != 16) || (header.compressionType != 3))
- {
+ // Make sure the compression type is a value that can be dealt with.
+ if ((info().compressionType != 3) && (info().compressionType != 0))
+ {
// Clean up file handle.
fclose(fp);
@@ -74,25 +134,140 @@
// Set the values for later.
_dataOffset = offset;
- setWidth(header.width);
- setHeight(header.height);
-
+ setWidth(info().width);
+ setHeight(info().height);
+
// Close the file.
fclose(fp);
return true;
}
+int EAImage::_wordsInRow()
+{
+ // If there were no padding to 32 bit boundaries this would be the number of bits per row
+ // in the file.
+ int bitsPerWidth = width() * info().bitsPerPixel;
+
+ // This is the row size with padding on the end.
+ int remainder = (bitsPerWidth % 32);
+ int bitsPerRow = (remainder == 0) ? bitsPerWidth : bitsPerWidth + (32 - remainder);
+
+ // Return the size in number of words.
+ return (bitsPerRow / 32);
+}
+
+int EAImage::_wordForX(unsigned int x)
+{
+ int bitForX = x * info().bitsPerPixel;
+
+ return (bitForX / 32);
+}
+
+int EAImage::_xWordOffset(unsigned int x)
+{
+ int bitForX = x * info().bitsPerPixel;
+
+ return (bitForX % 32);
+}
+
+unsigned short EAImage::_getColourAtOffset(unsigned int word, int offset)
+{
+ // Sort bytes for endianness.
+ unsigned char* cptr;
+ unsigned short result = 0x0000;
+
+ // Now need to decide how to cast the value to a colour.
+ switch (info().bitsPerPixel)
+ {
+ // Swap the bytes around.
+ case 32:
+ case 4:
+ case 8:
+ case 1:
+ unsigned char tmp;
+ cptr = (unsigned char*)&word;
+ tmp = cptr[0];
+ cptr[0] = cptr[3];
+ cptr[3] = tmp;
+ tmp = cptr[1];
+ cptr[1] = cptr[2];
+ cptr[2] = tmp;
+ break;
+
+ default:
+ // Swap the 16bits around.
+ case 16:
+ unsigned char tmpa;
+ unsigned char tmpb;
+ cptr = (unsigned char*)&word;
+ tmpa = cptr[1];
+ tmpb = cptr[0];
+ cptr[1] = cptr[3];
+ cptr[0] = cptr[2];
+ cptr[3] = tmpa;
+ cptr[2] = tmpb;
+ break;
+ }
+
+ // First shift off the pixels above.
+ word = word << offset;
+
+ // Now shift down so that pixel is in lsb.
+ word = word >> (32 - info().bitsPerPixel);
+
+ EAColor c;
+
+ // Now need to decide how to cast the value to a colour.
+ switch (info().bitsPerPixel)
+ {
+ case 8:
+ case 4:
+ case 1:
+ if (_palette != NULL)
+ {
+ result = _palette[word].rawValue();
+ } else {
+ result = 0x0000;
+ }
+ break;
+
+ // By default just cast to unsigned short and return.
+ default:
+ case 16:
+ result = (unsigned short)(word);
+ break;
+
+ case 24:
+ case 32:
+ unsigned char b = ((word << 0) >> 24);
+ unsigned char g = ((word << 8) >> 24);
+ unsigned char r = ((word << 16) >> 24);
+
+ c.setRgb(r, g, b);
+ result = c.rawValue();
+ break;
+ }
+
+ return result;
+}
+
bool EAImage::load(const char* path)
{
if (path == NULL)
{
+ // Reset all of the state.
+ unload();
+
// Invalid path passed in.
return false;
}
if (_loadHeader(path) == false)
{
+ // Reset all of the state.
+ unload();
+
return false;
}
@@ -115,6 +290,46 @@
return true;
}
+void EAImage::unload()
+{
+ // Empty the header struct.
+ _header.headerSize = 0;
+ _header.width = 0;
+ _header.height = 0;
+ _header.noColorPlanes = 0;
+ _header.bitsPerPixel = 0;
+ _header.compressionType = 0;
+ _header.bmpSize = 0;
+ _header.horizontalRes = 0;
+ _header.verticalRes = 0;
+ _header.noColors = 0;
+ _header.noImportantColors = 0;
+
+ // Clear the path.
+ if (_path != NULL)
+ {
+ delete[] _path;
+ _path = NULL;
+ }
+
+ // Clear the palette.
+ if (_palette != NULL)
+ {
+ delete[] _palette;
+ _palette = NULL;
+ }
+
+ // Clear the data offset.
+ _dataOffset = 0;
+
+ // Set the size to 0.
+ setWidth(0);
+ setHeight(0);
+
+ // Set as not a mask.
+ _mask = false;
+}
+
void EAImage::paint(EALCD& lcd)
{
paint(lcd, 0, 0, width(), height());
@@ -138,11 +353,16 @@
return;
}
- // Buffer to hold load one line at a time.
- int pixelsInLine = width() + (width() % 2);
- unsigned short buffer[pixelsInLine];
+ // Buffer to hold load one line at a time this must be large enough to hold all of the data used
+ // for a line in the file. Note that the line in the file is padded so that it always ends on a
+ // 32 bit boundary.
+ int wordsInRow = _wordsInRow();
+ unsigned int buffer[wordsInRow];
int xD = 0;
int yD = 0;
+ int wordOffset = 0;
+ int bitsPerPixel = info().bitsPerPixel;
+ unsigned short data = 0;
// Try and open the file, skip straight to the data.
FILE* fp = fopen(_path, "r");
@@ -151,6 +371,10 @@
return;
}
+ // If the bits per pixel are less than 16 then the bitmap is using a colour
+ // palette which should be loaded first.
+ _loadPalette(fp);
+
// Skip the header and size.
fseek(fp, _dataOffset, SEEK_SET);
@@ -159,19 +383,49 @@
lcd._moveTo(this->x(), this->y());
// Move in the file to the first pixel in the window.
- fseek(fp, (y*pixelsInLine*2)+(x*2), SEEK_CUR);
-
+ fseek(fp, (y*wordsInRow*4)+(_wordForX(x)*4), SEEK_CUR);
+
// Now read the data.
while (!feof(fp))
{
- int sizeRead = fread(&buffer, 2, pixelsInLine, fp);
+ wordOffset = _xWordOffset(x);
+
+ int sizeRead = fread(&buffer, 4, wordsInRow, fp);
for (int i = 0; i < sizeRead; i++)
- {
- lcd._writeToDisplay(buffer[i]);
+ {
+ while (wordOffset < 32)
+ {
+ // Convert the colour to a 16 bit colour value that can be written directly to the screen.
+ data = _getColourAtOffset(buffer[i], wordOffset);
+
+ if (isMask() == true)
+ {
+ // When a mask the 0x0000 value is transparent anything else is drawn with the pen color.
+ if (data == 0x0000)
+ {
+ lcd.noop();
+ } else {
+ lcd._writeToDisplay(lcd.pen().color().rawValue());
+ }
+ } else {
+ // Not a mask so just use colour that have loaded.
+ lcd._writeToDisplay(data);
+ }
+
+ // Got to next pixel in the word.
+ wordOffset += bitsPerPixel;
+
+ // Keep count of current x value.
+ xD++;
+ if (xD == w)
+ {
+ break;
+ }
+ }
+ wordOffset = 0;
- // Keep count of current x value.
- xD++;
+ // When written all required pixels exit.
if (xD == w)
{
xD = 0;
@@ -187,9 +441,15 @@
}
}
+ // Clear the palette.
+ if (_palette != NULL)
+ {
+ delete[] _palette;
+ _palette = NULL;
+ }
+
// Close the file and release handle.
fclose(fp);
-
}