Search code examples
imageimage-processingfile-format

Converting simple image to intel hex


So I am developing a type of tamagotchi (virtual pet) for my microprocessors final. I made my own images 128x64 pixels long, as I am using a display with that resolution, so each image weighs 1Kbytes. I am using an at89s52 (8052) microcontroller and it doesn't have enough memory to store all the animations I want. My plan (and I kind of want to keep it that way) is to use an EPROM to save all my images with intel hex format (the programmer I am using is SUPERPRO and it imports that type of files). Of course the assembly code will be easy for me after the point where I have the data in the ROM. I am not that good of a programmer to develop a code that does exaclty what I want (convert images to intel hex), and all the software I have tried doesn't generate them correctly (inserts hex values that aren't supposed to be there, for example: in a blank space there is supposed to be only zeroes, and there is another value). I have tried with png with transparent background, with white background and jpg. The images I have are such:

https://i.sstatic.net/86yCD.jpg (it seems I am not allowed to post images here)

I don´t see much help in other places of the internet, so the answer to this question would be of great help for future MCU-based programmers. Thank you.


Solution

  • It's about 30 years since I last made an EPROM :-)

    Anyway, you need 2 things...

    Part One

    Firstly, your files are PNG format which means they have dates, times, palettes, gamma chunks and a bunch of zlib compressed data and you can't just copy that to a screen buffer. So, you need to convert the PNGs to a simple binary format where 0 is off and 1 is on and there is nothing else in the file. The easiest way to do that is with ImageMagick which is installed on most Linux platforms and is available for free on macOS and Windows. Let's say one of your frames is called anim.png and we want to get it to a simple format, like PGM (Portable GreyMap - see Wikipedia description) we can use ImageMagick like this at the console:

    convert anim.png -compress none anim.pgm
    

    The first few lines will be:

    P2
    128 64
    255
    255 255 255 255 255 255 255 ...
    ...
    ...
    

    because the image is 128x64 and the maximum brightness in the file is 255. Then all the data follows in ASCII (because I put -compress none). In there, 255 represents white and 0 represents black.

    As that is too big for the screen, here is an image of how it looks - hopefully you can see your black box as a bunch of zeroes in the middle at the bottom:

    enter image description here

    Now, if you run that same command again, but remove the -compress none, the same header will be produced but the data will follow in binary.

    convert anim.png anim.pgm
    

    And we can also use sed to delete the 3 lines of header:

    convert anim.png anim.pgm | sed '1,3d' > anim.bin
    

    Now you have a binary file of just pure pixels that is free of dates/times, author and copyrights, palettes and compressed data, you can pass to the next part.

    Part 2

    Secondly, once you have got your data in a sensible binary format you need to convert it to Intel Hex, and for that you need srec_cat which is available for Linux daily and via homebrew on a Mac.

    Then, I haven't tested this and have never used it, I think you will want something like:

    srec_cat anim.bin -binary -output -intel 
    
    :020000040000FA
    :20000000323535203235352032353520323535203235352032353520323535203235352000
    :200020003235352032353520323535203235352032353520323535203235352032353520E0
    :200040003235352032353520323535203235352032353520323535203235352032353520C0
    :200060003235352032353520323535203235352032353520323535203235352032353520A0
    :20008000323535203235352032353520323535203235352032353520323535203235352080
    ...
    :207E8000353520323535203235352032353520323535203235352032353520323535203202
    :207EA0003535203235352032353520323535203235352032353520323535203235352032E2
    :147EC000353520323535203235352032353520323535200A2A
    :00000001FF
    

    Summary

    You can abbreviate and simplify what I am suggesting above - I will leave it there so folks can understand it in future though!

    convert YourImage.png gray: | srec_cat - -binary -output -intel 
    

    The gray: is a very simple ImageMagick format equivalent to just the binary part of a PGM file without any header. Like PGM it uses one byte per pixel so it will be somewhat inefficient for your pure black and white needs. You can see that by looking at the file size - the PGM file is 8192 bytes, so 1 byte per pixel. If you really, really want 1 bit per pixel, you could use PBM format like this:

    convert YourImage.png pbm: | sed '1,3d' | srec_cat - -binary -output -intel 
    

    Note:

    1. From v7 of ImageMagick onwards, you should replace convert by magick so as to avoid clashing with Windows' built-in convert command that converts filesystems to NTFS.

    2. ImageMagick is quite a large package, you could do this equally well just with the NetPBM suite, and use the tool called pngtopnm in place of convert.