A basic graphics package for the LPC4088 Display Module.

Dependents:   lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI lpc4088_displaymodule_fs_aid ... more

Fork of DMBasicGUI by EmbeddedArtists AB

Application/Image.cpp

Committer:
embeddedartists
Date:
2015-01-26
Revision:
10:651861441108
Parent:
6:7917b0894655
Child:
17:6e2abf107800

File content as of revision 10:651861441108:

/*
 *  Copyright 2014 Embedded Artists AB
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include "mbed.h"
#include "Image.h"

#include "bmp.h"
#include "lodepng.h"

struct eaimg_header_t
{
  char prefix[6];
  uint16_t width;
  uint16_t height;
} __attribute__ ((packed));

int Image::decode(const unsigned char* pDataIn, unsigned int sizeIn, Resolution resolution, ImageData_t* pDataOut)
{
  Image::Type type = imageType(pDataIn, sizeIn);
  int result = -1;
  switch (type)
  {
    case BMP:
    {
      struct BMPHeader* hdr = (struct BMPHeader *) pDataIn;
      if (resolution == RES_16BIT) {
        pDataOut->pixels = (uint16_t*)malloc(hdr->width * hdr->height * 2);
      } else if (resolution == RES_24BIT) {
        pDataOut->pixels = (uint16_t*)malloc(hdr->width * hdr->height * 4);
      } else {
        return -1;
      }
      pDataOut->pointerToFree = pDataOut->pixels;
      if (pDataOut->pixels != NULL)
      {
        unsigned char error = BMP_Decode((void*)pDataIn, (unsigned char*)pDataOut->pixels, 
                                         hdr->width, hdr->height, 24, ((resolution == RES_16BIT) ? 16 : 24));
        if (error == 0)
        {
          pDataOut->width = hdr->width;
          pDataOut->height = hdr->height;
          pDataOut->res = resolution;
          return 0;
        }
        free(pDataOut->pixels);
        pDataOut->pointerToFree = NULL;
      }
    }
    break;
      
    case PNG:
    {
      unsigned char* pTmp;
      unsigned error = lodepng_decode24(&pTmp, (unsigned*)&pDataOut->width, (unsigned*)&pDataOut->height, pDataIn, sizeIn);
      pDataOut->res = resolution;
      if (error == 0)
      {
        uint32_t x, y;
        uint8_t r;
        uint8_t g;
        uint8_t b;
        int off = 0;
    
        result = 0;
        if (resolution == RES_16BIT) {
            pDataOut->pixels = (uint16_t*)malloc(pDataOut->width * pDataOut->height * 2);
            pDataOut->pointerToFree = pDataOut->pixels;
            if (pDataOut->pixels != NULL)
            {
                uint16_t* pConverted = pDataOut->pixels;
            
                for (y = 0; y < pDataOut->height; y++) {
                  for (x = 0; x < pDataOut->width; x++) {
                    r = pTmp[off    ];
                    g = pTmp[off + 1];
                    b = pTmp[off + 2];
                    *pConverted = (((unsigned short)r & 0xF8) << 8) |
                                   (((unsigned short)g & 0xFC) << 3) |
                                   (((unsigned short)b & 0xF8) >> 3);
                    pConverted++;
                    off += 3;
                  }
                }
            }
        } else if (resolution == RES_24BIT) {
            uint32_t* pConverted = (uint32_t*)malloc(pDataOut->width * pDataOut->height * 4);
            pDataOut->pixels = (uint16_t*)pConverted;
            pDataOut->pointerToFree = pDataOut->pixels;
            if (pDataOut->pixels != NULL)
            {
                uint8_t* p = pTmp;
                int num = pDataOut->width * pDataOut->height;
                for (int i = 0; i < num; i++) {
                    uint32_t a = 0;
                    a |= (*p++) << 16;  // red
                    a |= (*p++) <<  8;  // green
                    a |= (*p++) <<  0;  // blue
                    *pConverted++ = a;
                }
            }
        } else {
            // unknown format
            result = -2;
        }
        free(pTmp);
        return result;
      }
    }
    break;
    
    case RAW:
    {
      eaimg_header_t* hdr = (eaimg_header_t*)pDataIn;
      pDataOut->width = hdr->width;
      pDataOut->height = hdr->height;
      pDataOut->pointerToFree = malloc(sizeIn-sizeof(eaimg_header_t));
      pDataOut->pixels = (uint16_t*)pDataOut->pointerToFree;
      pDataOut->res = RES_16BIT;
      if (pDataOut->pixels != NULL)
      {
        memcpy(pDataOut->pixels, pDataIn+sizeof(eaimg_header_t), sizeIn-sizeof(eaimg_header_t));
        return 0;
      }
    }
    break;

    default:
      break;
  }
  
  pDataOut->pixels = NULL;
  pDataOut->pointerToFree = NULL;
  pDataOut->width = 0;
  pDataOut->height = 0;
  pDataOut->res = resolution;
  return result;
}

int Image::decode(const char* filename, Resolution res, ImageData_t* pDataOut, Mutex* pLock)
{
  FILE* fh = NULL;
  uint8_t* buff = NULL;
  int result = 1;

  pDataOut->height = 0;
  pDataOut->width = 0;
  pDataOut->pixels = NULL;
  pDataOut->pointerToFree = NULL;
  pDataOut->res = res;

  if (pLock != NULL) {
      pLock->lock();
  }

  do 
  {
    fh = fopen(filename, "r");
    if (fh == NULL) {
      break;
    }
    
    uint32_t size = fileSize(fh);
    buff = (uint8_t*)malloc(size);
    if (buff == NULL) {
      return 1;
    }
    
    uint32_t num;
    uint32_t left = size;
    uint32_t off = 0;
    do
    {
      num = fread(buff+off, 1, left, fh);
      if (num > 0) {
        left -= num;
        off += num;
      }
    } while (left > 0 && num > 0);
    if (left > 0) {
      break;
    }
    
    fclose(fh);
    if (pLock != NULL) {
      pLock->unlock();
    }
    
    Type type = imageType(buff, size);
    if (type == RAW) {
        pDataOut->width = ((eaimg_header_t*)buff)->width;
        pDataOut->height = ((eaimg_header_t*)buff)->height;
        pDataOut->pointerToFree = buff;
        pDataOut->res = RES_16BIT;
        pDataOut->pixels = (uint16_t*)(buff + sizeof(eaimg_header_t));
    } else {
        result = Image::decode(buff, size, res, pDataOut);
        free(buff);
        return result;
    }
    
    // success
    return 0;
    
  } while (false);
  
  if (fh != NULL) {
    fclose(fh);
  }
  if (buff != NULL) {
    free(buff);
  }
  if (pLock != NULL) {
      pLock->unlock();
  }
  return result;
}

Image::Type Image::imageType(const unsigned char* pDataIn, unsigned int sizeIn)
{
  if (sizeIn > 4)
  {
    if (pDataIn[0] == 0x89 && pDataIn[1] == 'P' && pDataIn[2] == 'N' && pDataIn[3] == 'G')
    {
      return PNG;
    }
  }
  if (BMP_IsValid((void*)pDataIn))
  {
    return BMP;
  }
  if (sizeIn >= sizeof(eaimg_header_t))
  {
    eaimg_header_t* hdr = (eaimg_header_t*)pDataIn;
    if (memcmp(hdr->prefix, "eaimg:", 6) == 0)
    {
      return RAW;
    }
  }
  return UNKNOWN;
}

uint32_t Image::fileSize(FILE* f)
{
  uint32_t pos = ftell(f);
  fseek(f, 0, SEEK_END);
  uint32_t size = ftell(f);
  fseek(f, pos, SEEK_SET);
  return size;
}