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); - }