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.
widgets/EAImage.cpp
- Committer:
- richardparker
- Date:
- 2010-03-04
- Revision:
- 1:f04bcaea1d60
- Parent:
- 0:839ecbf5cb2a
- Child:
- 3:24fbf4dbd7e5
File content as of revision 1:f04bcaea1d60:
// Copyright 2010 Richard Parker #include "mbed.h" #include "EAImage.h" #include "../graphics/EAPen.h" #include "../graphics/EAColor.h" #include "../screen/EALCD.h" EAImage::EAImage() : _path(NULL), _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) { // Invalid path passed in. return false; } // Try and open the file, check type and load width and height. FILE* fp = fopen(path, "r"); if (fp == NULL) { return false; } unsigned int bufint = 0; unsigned int offset = 0; // Read the magic numbers at start. fread(&bufint, 1, 2, fp); if (bufint != 0x4d42) { // Clean up file handle. fclose(fp); // Header incorrect. return false; } // Now read the bmp file size. fread(&bufint, 1, 4, fp); // Now read the two creator values and throw away. fread(&bufint, 1, 2, fp); fread(&bufint, 1, 2, fp); // Now read the offset for the bitmap data. fread(&bufint, 1, 4, fp); offset = bufint; // Retrieve the header. fread(&_header, sizeof(EABMPHeader), 1, fp); // 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); // Header incorrect. return false; } // Set the values for later. _dataOffset = offset; 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; } int pathLen = strlen(path); // If already loaded an image then clear to load the new one. if (_path != NULL) { delete[] _path; _path = NULL; } // Now allocate enough space to hold path. Note +1 for null character. _path = new char[pathLen+1]; // Now copy over passed in path to path variable. strcpy(_path, path); // Image loaded successfully. 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()); } void EAImage::paint(EALCD& lcd, unsigned int x, unsigned int y, unsigned int w, unsigned int h) { if (isValid() == false) { return; } // Don't allow draw out of range. if (x + w > width()) { return; } if (y + h > height()) { return; } // 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"); if (fp == NULL) { 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); // Prepare the lcd for drawing. lcd._window(this->x(), this->y(), w, h); lcd._moveTo(this->x(), this->y()); // Move in the file to the first pixel in the window. fseek(fp, (y*wordsInRow*4)+(_wordForX(x)*4), SEEK_CUR); // Now read the data. while (!feof(fp)) { wordOffset = _xWordOffset(x); int sizeRead = fread(&buffer, 4, wordsInRow, fp); for (int i = 0; i < sizeRead; 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; // When written all required pixels exit. if (xD == w) { xD = 0; break; } } // Keep count of curernt y value. yD++; if (yD == h) { break; } } // Clear the palette. if (_palette != NULL) { delete[] _palette; _palette = NULL; } // Close the file and release handle. fclose(fp); }