image converter from jpg to .h

I am using ImageConverter 565 and realizing that a 5k jpg turns into 1.5mb .h file.

Tried online tool and .exe and same result. The image converter doesn't have much options...

I have seen examples from TFT_ESPI lib and the images are more complex than mine but they are really light in terms of size.

Wondering what I am doing wrong?

hello.jpg

hello.c (1.37 MB)

hello.jpg

You open the JPG, PNG, BMP in Irfanview or other program.
Scale to the pixel dimensions that you like. e.g. 320x240
Save as a JPG with the desired ‚Äúoptimisation‚ÄĚ e.g. 95%

95% will be virtually unnoticeable. 70% will be fairly severe but give you a tiny file.

Then simply use Bodmer’s utility to read the resultant binary .JPG file into a C array to store in PROGMEM.

Experiment with the compression values. It is surprising how you can fit most JPEGs into < 32kB

Note that ARM or ESP don’t care what size the C array is. But an AVR like MEGA2560 requires an array to be < 32kB

Oh, if your target is ESP32 or ESP8266, it is much easier to just store your compressed JPG files in SPIFFS

David.

david_prentice:
Then simply use Bodmer's utility to read the resultant binary .JPG file into a C array to store in PROGMEM.

I am confused as Bodmer suggest to use ImageConverter 565 their sketches:

TFT_eSPI/examples/Generic/TFT_Flash_Bitmap/TFT_Flash_Bitmap.ino

// Arrays containing FLASH images can be created with UTFT library tool:
// (libraries\UTFT\Tools\ImageConverter565.exe)
// Convert to .c format then copy into a new tab

Forgot to mention I am using ESP32.

My apologies. ImageConverter565 and similar is only for uint16_t arrays. It is only suitable for arrays of raw pixels. It does not contain information about dimensions, colours, palettes, …

When you want to handle general purpose binary files you need a uint8_t array. For example, .BMP or .JPG format files contain header information like size, width, height, …

So a simple PC command line program like this:

#include <stdio.h>
#include <string.h>
#include <stdint.h>

char *bmp_to_C(char *name)
{
    FILE *fp;
    uint8_t buf[16];
    static char array[100];
    char *p;
    int n, i, len = strlen(name);
    long sz;
    strcpy(array, name);
    fp = fopen(name, "rb");
    if (fp == NULL)
        return NULL;

    fseek (fp, 0, SEEK_END);   // non-portable
    sz = ftell (fp);
    fseek (fp, 0, SEEK_SET);   // non-portable

    array[len - 4] = '_'; 
    printf("const unsigned char PROGMEM %s[%ld] = {\n", array, sz);
    do {
        n = fread(buf, 1, 16, fp);
        for (i = 0; i < n; i++) {
            printf("0x%02X,", buf[i]);
        }
        printf("\n");
    }while(n > 0);
    printf("};\n");
    fclose(fp);
    return array;
}

int main(int argc, char **argv)
{
    while (--argc) {
        bmp_to_C(*++argv);
    }
    return (0);
}

Process files to stdout. Redirect to an H file. e.g.

bmp_to_C file.jpg

Untested. I have just pasted functions from my one of my own programs.
I am sure that Bodmer has published a similar (but tested) command line utility.

Thanks David. I couldn't find the Bodmer's version and I don't know how to run yours ( should I use a C compiler? )

Also a couple of questions:

which is the reason why my 4096 bytes empty image turns into 1.5 mb when converting ?

If I do 480 x 320 I get : 153600 which is the 1.5 mb after converting I guess... but if the original jpg size is 4096 bytes then it's C counterpart file size is the same? converted C file size is different for uint16_t arrays and uint8_t array?

Thanks

Look at Bodmer's examples. e.g. C:\Users\David Prentice\Documents\Arduino\libraries\TFT_eSPI\examples\480 x 320\TFT_flash_jpg\jpeg1.h

I presume that Bodmer had simply taken the binary file baboon.jpg and dumped as a big array of uint8_t

One byte with value 0xd8 of a binary fine is going to need 5 letters e.g. 0xD8,

The jpeg1.h file is 121kB so I would guess the original baboon.jpg binary file will be about 24kB

If you don't know how to use a command line I suggest that you Google for bin_to_C or bin_2_C or bin2C
This will probably find a utility that you can use via the Web or by a GUI.

But quite honestly, it is much easier to copy straight JPG binary files to SPIFFS. No command line or H files involved. Run Bodmer's
C:\Users\David Prentice\Documents\Arduino\libraries\TFT_eSPI\examples\Generic\TFT_SPIFFS_BMP\TFT_SPIFFS_BMP.ino
example and use the same strategy but for JPEG files.

I am pretty sure that either myself or Bodmer has posted ESP examples that do this.

Yes, I seem to have attached a project several times e.g. TFT_SPIFFS_Jpeg_kbv

The data directory has probably got too many files for your SPIFFS. I suggest that you use 3MB for SPIFFS and 1MB for application. Or just move unwanted JPEGs to another directory.

David.

Thanks for make it clear, all working now.

I see David has provided the help you needed. For others that may raise similar questions:

For the ESP32 and ESP8266 there are quite a few ways that an image file can be stored locally, for example:

  1. A "C" array, example here with the online image-> c array converter link.
  2. SPIFFS, a flash filing system - (recently deprecated in favour of the faster LittleFS)
  3. LittleFS, a flash filing system - faster than SPIFFS, now supported in board packages for ESP8266 (LittleFS) and ESP32 (LITTLEFS)
  4. SD card

It is also possible via WiFi to fetch images from the web, but this needs more complex code and is slower.

The C array in FLASH memory has best performance as there is no filing system overhead.
SPIFFS and LittleFS are more convenient for multiple images, extra upload tools must be installed in the IDE
SD cards are good for multiple images but is less convenient and typically slower

Thanks for replying.

In my experience:

  1. A "C" array does not work for me as 17 kbytes image turns into 1.5 mb c file (this was the original post question)
  2. SPIFFS, Currently using this method and happy.
  3. LittleFS I would like ti investigate this.
  4. SD card : Don't have SD in the current project.
  1. A "C" array does not work for me as 17 kbytes image turns into 1.5 mb c file (this was the original post question)

I would be impressed by a 1.5 milli bit file. Seriously, if you are asking a technical question you should get your units correct.

Regarding file size. Your ImageConverter565 program just stored every pixel on your screen as a 16-bit colour value.

A completely Black screen would also have 320x480 16-bit values in the C array. i.e. another 1.37MB file.

The JPG file on my PC screen looks very nice i.e. smooth curves
If I expand the image on the PC I can see that the edges are anti-aliased. Which is why the curves look smooth.

This accounts for the JPG being "as big" as 4.77kB.
If you had a non-aliased image it would be much smaller.

Most people would simply set Font, text colour, text position. And print "Hello".
Ok, this is 4 or 5 statements. A C or C++ statement uses a few bytes on your PC. Compiling a C++ program creates extra files on your PC.

If you don't understand things like Source Code, Compiling, File formats, ... visit Wikipedia.
Personally, I find that Wikipedia articles are written much better than many C++ textbooks.

Oh, it is very wasteful putting a big array in PROGMEM or SPIFFS.
Much better to use a JPG.
Or if you only want "Hello" simply use print() statements.

David.

A "C" array is actually a more efficient storage approach than SPIFFS, so less FLASH memory is used for the same original data set size.

The ImageConverter 565 converter you used takes the 5k jpg and turns into 1.5MB because it "decompresses" it into a "raw" image file.

You can convert the 5k jpg into a 5kByte array "without" decompressing it. The processor must then do the work of decompressing and sending it to the display, this needs a jpg decoder library.

The link I provided is a 240x320 jpg image in C array form and is about 8kbytes. That is what the referenced file converter does.

You can read more about data and image formats on Wikipedia.

1 Like

Thanks David and Bodmer for the info, it makes it a lot clear . Also I will look into the units for the next technical question.

I am having a look into this now. Thanks

You can convert the 5k jpg into a 5kByte array "without" decompressing it. The processor must then do the work of decompressing and sending it to the display, this needs a jpg decoder library.

The link I provided is a 240x320 jpg image in C array form and is about 8kbytes. That is what the referenced file converter does.

This topic was automatically closed after 120 days. New replies are no longer allowed.