Gbimg -- By AceyT

GBImg

Author :  AceyT

Source code

Introduction

GBImg is a command-line tool that allow you to convert BMP and PNG images into the Gamebuino flash memory format.

It can also handle animated images and spritesheets

It currently support only uint8_t[] flash images in the indexed mode


Usage:
  GBImg [OPTION...]

-o, --output-path arg File name of the export (default: code.hpp)
-i, --image-input arg Image path to convert
-c, --code-name arg identifier in the exported code (default:
image)
–transparency [=N(=0)] Choosen color index used for transparency.
Value greater than 15 (0x0F) will make the
program not handle transparency (default: 255)
–palette default / edge16
Choosen color palette used for finding
correct indexes (default: default)
–palette-file arg File from which the color palette will be
used (override palette option)
-h, --help Print the help

Spritesheet options:
-s, --spritesheet Activate the spritesheets mode
–tile-x N Number of tiles on X axis Sub width will be deduced
with image-width / tile-x (default: 0)
–tile-y N Number of tiles on Y axis | Sub height will be deduced
with image-height / tile-y (default: 0)
–framerate N Framerate of the animation | number of frame per
animation (default: 0)


The download link provide a compiled version for Windows 7 and some test / example in bat files


Todo

  • Loading custom color palette from file
  • Support for uint16_t[] images
  • Convert RGB888 to RGB565
  • Multiples images at once
  • Other export methods
Author :  Sorunome

Just asking, i didn't check the source / try but the web-tool has this bug:

on indexed images with an odd width you are supposed to pad the last nibble so that each row is always a whole number of bytes

Author :  AceyT

Well, I'm not sure of what you mean by asking if I "pad the last nibble" on odd-width indexed image.
In my understanding, padding is adding extra byte correct ? 'Cause that's what I'm doing.

According to tests I've done with my Gamebuino, I've decided to let an extra nibble if the width is odd, because it work as expected when the image is rendered. For example, if I take this french flag with 3x3 pixels, my program will allocate 4x3 memory with the formula [height  * (width+1)/2].


And the outputted code will be :

const uint8_t imageData[] = {
3,3,
0,0,0,
0xFF,
1,

0xFD,0x40,
0xFD,0x40,
0xFD,0x40
};
Image image = Image(imageData);
//index numbers are from edge16 palette

Author :  Sorunome

Okay, then you are doing it the correct way, great!


EDIT: i'd recommend using `Image myimg(imgdata);` instead of `Image myimg = Image(imgdata);`

Author :  AceyT

Okay, I'll make the change and commit it :)

EDIT : change made and updated the compiled version

Author :  Aurélien Rodot

Hey, would you mind explaining why quickly or share a link to the reason why ? I would have used the same syntax as AceyT ^^

Author :  Sorunome

Let's break `Image img = Image(blah);` down.

So, what happens here first is that a temporary Image is created, with the `Image(blah);` call. Afterwards a new Image called `img` is created. Next, the temporary Image is been copied over to img, calling the copyconstructor.

When you use `Image img(blah);` it just creates a new image img and initializes it with blah


Author :  AceyT

Theoretically, I would said the same as you, but after some tests on my computers and gamebuino, I got other results.

I don't know if this is a compiler optimization or the standard way of interpreting it in C++, but the syntax `Image img = Image(data);` still call the appropriate constructor, and not a constructor + copy constructor;

EDIT : It would appear to be an authorized optimization. It's kind of like Return Value Optimization but named in this case " Copy Elision (cpp reference) ".
So indeed, for clarity && to avoid surprise, it's better to do a direct initialization. There's so many things that you can think about in C++

Author :  Sorunome

It would appear to be an authorized optimization

Yeah, compiler optimizes it, except if you turn off optimizations

So indeed, for clarity && to avoid surprise, it's better to do a direct initialization

Yep!


Also, direct initialization is shorter to type xP