avr-chat
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-chat] Storing B&W bitmap images into Flash : file format sugges


From: Jim Brain
Subject: Re: [avr-chat] Storing B&W bitmap images into Flash : file format suggestion ?
Date: Wed, 13 Jan 2010 01:09:18 -0600
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091204 Thunderbird/3.0

On 1/12/2010 8:07 PM, Vincent Trouilliez wrote:

If uncompressed B&W is the format, grab ImageMagick and install.  Then do:

convert filename.jpg myfile.xbm

The XBM image format (X bitmap format) is exactly a C source file:

#define matrix_width 180
#define matrix_height 60
static char matrix_bits[] = {
  0x68, 0x6B, 0xDB, 0xCD, 0xD3, 0xDA, 0x56, 0x56, 0xDD, 0x7E, 0x76, 0xF7,



I don't think it's suited to my project though... it would save me
space, but there is too much decoding for the case at hand, and it
would be too much work when displaying font digits. So I prefer an
uncompressed format, where I can just dump my array of bits straight
onto the LCD, to draw very fast, with maybe some shifting or masking
or trivial things, but no arythmetic/calculations...

The code is very simple:

void rle_decode(uint8_t* array, uint16_t len) {
  uint16_t i = 0, j;
  uint8_t run;

  while(i < len) {
    run = array[i] & 0x7f;
    if(array[i++] & 0x80) { // sequence of bytes
       for(j = 0; j <= run; j++)
           lcd_send(array[i + j]);
       i+=j;
    } else {  // run of single byte
       for(j = 0; j <= run; j++)
           lcd_send(array[i]);
       i++;
    }
  }
}

For longer runs of common data, RLE can save space, and the code is very minimal. However, with a bit of extra code in the above, you could easily do:

if(array[0] == MAGIC_RLE)
    rle_decode(...);
else
   raw_decode(...);

and have the best of both worlds

Interestingly, I didn't find a simple RLE decoder on the Interwebs, so I wrote this one. The test app takes 1 or 2 arguments. The first is the input file, the optional second is the array name. If the array name is present, it will output C source. If the array name is omitted, it will output the decoded data, for testing purposes.

I've not yet cleaned or optimized the code (error checking is extremely minimal, almost all the FILE IO code is copied from the web), so please don't yell at me for any issues. The entire app is below:

// Jim Brain ----  free to use, cut/paste, etc.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

void rle_encode(uint8_t* src, uint8_t* dest, uint16_t srclen, uint16_t* destlen) {
  uint8_t state = 0;
  uint16_t i = 0, j=0, k = 0;
  uint8_t pre;
  uint16_t start;

  while(i < srclen) {
    switch(state) {

      case 0:  // no RLE yet
        pre = src[i];
        state = 1;
        start = i;
        break;
      case 1:  // check
        if(src[i] == pre) {
          state = 2;
        } else {
          state = 3;
        }
        break;
      case 2:  // we're on a common run
        if(src[i] != pre || (i - start) == 128) {  // run ended
          dest[j++] = (uint8_t)(i - start - 1);
          dest[j++] = pre;
          pre = src[i];
          state = 1;
          start = i;
        }
        break;
      case 3:  // we're on a sequence run
        if(src[i] == pre || (i - start) == 128) {  // run ended
          if(src[i] == pre) {
            i--;
          }
          dest[j++] = 0x80 | (uint8_t)(i - start - 1);
          for(k = start; k < i; k++) {
            dest[j++] = src[k];
          }
          pre = src[i];
          state = 1;
          start = i;
        } else {
          pre = src[i];
        }
        break;
    }
    i++;
  }
  if(start != i) {
    dest[j] = (uint8_t)(i - start - 1);
    switch(state) {
      case 1:
      case 3:
        dest[j++] |= 0x80;
        for(k = start; k < i; k++) {
          dest[j++] = src[k];
        }
        break;
      case 2:
        j++;
        dest[j++] = pre;
        break;
    }

  }
  *destlen= j;
}

void lcd_send(uint8_t b) {
  printf("%c",b);
}

void rle_decode(uint8_t* array, uint16_t len) {
  uint16_t i = 0, j;
  uint8_t run;

  while(i < len) {
    run = array[i] & 0x7f;
    if(array[i++] & 0x80) { // sequence of bytes
       for(j = 0; j <= run; j++)
           lcd_send(array[i + j]);
       i+=j;
    } else {  // run of single byte
       for(j = 0; j <= run; j++)
           lcd_send(array[i]);
       i++;
    }
  }
}



int main (int argc, char** argv) {
  FILE * pFile;
  uint16_t lSize;
  char * buffer;
  size_t result;
  uint16_t dSize;
  char* dest;

  pFile = fopen ( argv[1] , "rb" );
  if (pFile==NULL) {fputs ("File error",stderr); exit (1);}

  // obtain file size:
  fseek (pFile , 0 , SEEK_END);
  lSize = ftell (pFile);
  rewind (pFile);

  // allocate memory to contain the whole file:
  buffer = (char*) malloc (sizeof(char)*lSize);
  if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}

  dest = (char*) malloc (sizeof(char)*lSize);
  if (dest== NULL) {fputs ("Memory error",stderr); exit (2);}

  // copy the file into the buffer:
  result = fread (buffer,1,lSize,pFile);
  if (result != lSize) {fputs ("Reading error",stderr); exit (3);}

  /* the whole file is now loaded in the memory buffer. */

  // terminate
  fclose (pFile);


  rle_encode (buffer , dest, lSize, &dSize);
  if(argc == 3) {
    printf("/* Original Size = %d, Compressed Size = %d */\n",lSize,dSize);
    printf("static char %s[] = {",argv[2]);
    for(lSize = 0;lSize < dSize;lSize++) {
      if(lSize % 8 == 0)
        printf("\n");
      if(lSize != 0)
        printf(",");
      printf("0x%2.2X",(uint8_t)dest[lSize]);
    }
    printf("\n};\n");
  } else {
    rle_decode( dest,dSize);
  }
  return 0;
}









reply via email to

[Prev in Thread] Current Thread [Next in Thread]