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:
- 6:4fe6f365cbeb
- Parent:
- 3:24fbf4dbd7e5
--- a/widgets/EAImage.cpp Tue Apr 27 23:13:21 2010 +0000 +++ b/widgets/EAImage.cpp Thu May 06 23:32:14 2010 +0000 @@ -12,7 +12,11 @@ : _path(NULL), _palette(NULL), _dataOffset(0), - _mask(false) + _mask(false), + _cached(false), + _cache(NULL), + _size(0L), + _pos(0L) { // Start from known state. unload(); @@ -20,23 +24,166 @@ EAImage::~EAImage() { - if (_path != NULL) + unload(); +} + +int EAImage::_feof(FILE* stream) +{ + if (isCached() == true) { - delete[] _path; - _path = NULL; + return (_pos < _size) ? 0 : 1; + } else { + return feof(stream); + } +} + + +int EAImage::_fseek(FILE* stream, long int offset, int origin) +{ + if (isCached() == true) + { + switch (origin) + { + default: + case SEEK_SET: + _pos = offset; + break; + case SEEK_CUR: + _pos = _pos + offset; + break; + case SEEK_END: + _pos = (_size-1) + offset; + break; + } + + // Make sure position within range. + if (_pos < 0) + { + _pos = 0; + return 0; + } + + if (_pos > (_size-1)) + { + _pos = (_size-1); + return 0; + } + + // Error. + return 1; + } else { + return fseek(stream, offset, origin); + } +} + +size_t EAImage::_fread(void* ptr, size_t size, size_t count, FILE* stream) +{ + if (isCached() == true) + { + // Truncate size to fit array if needed. + if (_pos + (count*size) > _size) + { + count = (_size - _pos)/size; + } + + if (count <= 0) + { + return 0; + } + + // Now copy out of cache to array. + memcpy(ptr, &_cache[_pos], count*size); + + // Update the file position. + _pos = _pos + (count*size); + + // Return the number of bytes read. + return count; + } else { + return fread(ptr, size, count, stream); + } +} + +bool EAImage::_loadCache(FILE* fp) +{ + // Can't do anything with a null pointer. + if (fp == NULL) + { + return false; } - if (_palette != NULL) + // Clear any previously loaded cache. + if (_cache != NULL) + { + delete[] _cache; + _cache = NULL; + } + _size = 0L; + _pos = 0L; + + if (isCached() == false) + { + return true; + } + + // Get the size of the file. + fseek(fp, 0, SEEK_END); + long int size = ftell(fp); + + if (size == -1) + { + // Something went wronmg with the command. + return false; + } + + // Now create a cache large enough to hold all of the image data. + _cache = new char[size]; + + if (_cache == NULL) { - delete[] _palette; - _palette = NULL; + // Unable to allocate enough space for the font. + return false; } + + // Now rewind file pointer back to the beginning. + rewind(fp); + + const unsigned int CHUNK_SIZE = 100; + long int sizeRead = 0; + long int totalSizeRead = 0; + + // Load in small chunks at a time. + while (!feof(fp)) + { + // Read into the buffer. + sizeRead = fread(&_cache[totalSizeRead], 1, CHUNK_SIZE, fp); + + // Update total count of amount of data loaded. + totalSizeRead += sizeRead; + } + + // Check that the whole file loaded. + if (totalSizeRead != size) + { + // Clear cache. + delete[] _cache; + _cache = NULL; + + // Return error. + return false; + } + + // Record size and position. + _size = size; + _pos = 0L; + + return true; } bool EAImage::_loadPalette(FILE* fp) { - // Can't do anything with a null pointer. - if (fp == NULL) + // Can't do anything with a null pointer unless cached. + if ((fp == NULL) && (isCached() == false)) { return false; } @@ -73,13 +220,13 @@ unsigned int offset = _dataOffset - (noColors*4); // Seek to the start of the table. - fseek(fp, offset, SEEK_SET); + _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); + int sizeRead = _fread(&buffer, 4, 1, fp); if (sizeRead == 1) { @@ -114,6 +261,7 @@ { // Clean up file handle. fclose(fp); + unload(); // Header incorrect. return false; @@ -137,7 +285,8 @@ if ((info().compressionType != 3) && (info().compressionType != 0)) { // Clean up file handle. - fclose(fp); + fclose(fp); + unload(); // Header incorrect. return false; @@ -147,6 +296,17 @@ _dataOffset = offset; setWidth(info().width); setHeight(info().height); + + // If the image is to be cached then load the cache. + if (_loadCache(fp) == false) + { + // Clean up file handle. + fclose(fp); + unload(); + + // Header incorrect. + return false; + } // Close the file. fclose(fp); @@ -337,8 +497,14 @@ setWidth(0); setHeight(0); - // Set as not a mask. - _mask = false; + // Empty the cache. + if (_cache != NULL) + { + delete[] _cache; + _cache = NULL; + } + _size = 0L; + _pos = 0L; } void EAImage::paint(EALCD& lcd) @@ -376,32 +542,44 @@ unsigned short data = 0; // Try and open the file, skip straight to the data. - FILE* fp = fopen(_path, "r"); - if (fp == NULL) + FILE* fp = NULL; + if (isCached() == false) { + 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. + if (_loadPalette(fp) == false) + { + if (isCached() == false) + { + fclose(fp); + } + 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); + _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); + _fseek(fp, (y*wordsInRow*4)+(_wordForX(x)*4), SEEK_CUR); // Now read the data. - while (!feof(fp)) + while (!_feof(fp)) { wordOffset = _xWordOffset(x); - int sizeRead = fread(&buffer, 4, wordsInRow, fp); + int sizeRead = _fread(&buffer, 4, wordsInRow, fp); for (int i = 0; i < sizeRead; i++) { @@ -409,7 +587,7 @@ { // 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. @@ -419,7 +597,7 @@ } else { lcd._writeToDisplay(lcd.pen().color().rawValue()); } - } else { + } else { // Not a mask so just use colour that have loaded. lcd._writeToDisplay(data); } @@ -459,8 +637,11 @@ _palette = NULL; } - // Close the file and release handle. - fclose(fp); + if (isCached() == false) + { + // Close the file and release handle. + fclose(fp); + } }