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: images/EAImage.cpp
- Revision:
- 7:6cf21b018420
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/images/EAImage.cpp Mon Nov 01 13:07:40 2010 +0000
@@ -0,0 +1,453 @@
+// 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()
+{
+ unload();
+}
+
+int EAImage::_feof(FILE* stream)
+{
+ return feof(stream);
+}
+
+
+int EAImage::_fseek(FILE* stream, long int offset, int origin)
+{
+ return fseek(stream, offset, origin);
+}
+
+size_t EAImage::_fread(void* ptr, size_t size, size_t count, FILE* stream)
+{
+ return fread(ptr, size, count, stream);
+}
+
+bool EAImage::_loadPalette(FILE* fp)
+{
+ // Can't do anything with a null pointer unless cached.
+ 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 std::string& path)
+{
+ if (path.empty() == true)
+ {
+ // Invalid path passed in.
+ return false;
+ }
+
+ // Try and open the file, check type and load width and height.
+ FILE* fp = fopen(path.c_str(), "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);
+ unload();
+
+ // 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);
+ unload();
+
+ // Header incorrect.
+ return false;
+ }
+
+ // Set the values for later.
+ _dataOffset = offset;
+ setWidth(info().width);
+ setHeight(info().height);
+
+ // If the bits per pixel are less than 16 then the bitmap is using a colour
+ // palette which should be loaded first.
+ if (_loadPalette(fp) == false)
+ {
+ fclose(fp);
+
+ return false;
+ }
+
+ // 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 std::string& path)
+{
+ if (path.empty() == true)
+ {
+ // Reset all of the state.
+ unload();
+
+ // Invalid path passed in.
+ return false;
+ }
+
+ if (_loadHeader(path) == false)
+ {
+ // Reset all of the state.
+ unload();
+
+ return false;
+ }
+
+ _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 palette.
+ if (_palette != NULL)
+ {
+ //delete[] _palette;
+ _palette = NULL;
+ }
+
+ // Clear the path.
+ _path.clear();
+
+ // Clear the data offset.
+ _dataOffset = 0;
+
+ // Set the size to 0.
+ setWidth(0);
+ setHeight(0);
+}
+
+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 = NULL;
+ fp = fopen(_path.c_str(), "r");
+ if (fp == NULL)
+ {
+ return;
+ }
+
+ // 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;
+ }
+ }
+
+ // Close the file and release handle.
+ fclose(fp);
+}
+
+