When it comes to helper utilities, coders are usually not very keen to release them. Or to create them in the first place. ;) So when I needed to process some graphics on ST/Falcon, my workflow would be something like:
- is it ST graphics? => google (yet again) that tool which I vaguely remember that outputs .PI1 and .NEO images (XnConvert was it?)
- is it Falcon bitplane graphics? => convert it into GIF, load in Pixart, save as .PIX
- is it Falcon hicolour graphics? => convert it into TGA (first find a tool which still outputs uncompressed TGA...), load in EscPaint, save as .TRP
And yes, every time I had to modify the source graphics, I went through this again and again. IIRC at one point I did code a TGA -> TRP converter but that was it. But the older we get, the less time we have for such perks... I tried to find something to ease my pain but (un)surprisingly except the ST-oriented PNGconv by Troed and MI-3 by Rockyone (AF thread) there was virtually nothing.
So I told myself: ok, let's create a really nice tool which will feature all the things I've been missing so much over the years! Namely:
- store arbitrary sizes, not only screen sizes (applies mainly to ST graphics)
- support every Atari machine's bitmap formats
- swich to/experiment with various palette sizes and screen modes
- import as many formats as possible with some common (C/C++) API
- keep original bit depth without any hidden implicit conversions
- offer optional resizing/filtering/dithering but offer also a way to keep the original format/bit depth
- import its own format so one can do two-way conversions (i.e. with bitmap data generated in assembler)
- easy to extend
- multiplatform
After some research, I came up with GraphicsMagick (a fork of well-known ImageMagick). There's a plenty of documentation (for both projects which are interchangeable) and a simple (but definitely not very elegant) C++ API.
Please note that this is mostly a converter (it has it in its name!), so if you are looking for a tool to get best possible visual results, try some of the more specialised tools:
- Zerkman's MPP
- dml's PhotoChrome and CryptoChrome (AF thread, Bitbucket repository)
- Anima's Image Color Remapping Tool (AF thread), Experimental Atari STE image enhancement website (AF thread and AF post), Retro Image Tool (AF thread, AF thread, AF thread) and Image converter for the Atari Falcon high colour mode
- cyg's ST hicolor video encoder & player
- ppera's page about movie playback
- DecAns's DaDither image converter
uConvert is distributed in source form only, sorry. For Linux and Mac users that perhaps makes sense (it's a command line tool after all) but for possible Windows users I'd recommend installing either a Virtual Machine + Ubuntu or even better, Microsoft's very own WSL. In theory it is possible to build uConvert as a native Windows binary but that requires some non-trivial fun with GraphicsMagick's Windows installation. Patches are welcome. :)
Then it's really simple (assuming you have g++
and make
already installed):
sudo apt install libgraphicsmagick++1-dev
(Ubuntu)
sudo pacman -S graphicsmagick
(Arch Linux)
make
There are also project files for Qt Creator available but you don't really need them.
uConvert offers a quick summary every time you enter an uknown option but it's better to explain in more detail here. Options can go in random order, only the source bitmap must be the last. Also, all options offer some sane defaults.
Resize input bitmap to given dimensions. Aspect ratio is not preserved but a warning message is printed if it has changed. Resizing takes -filter
switch into account. It is possible to enter just one dimension, the other one is taken from source bitmap (same as entering value of -1
).
Filter (smoothen) edges when resizing. This usually leads to increased number of colours and an implicit colour conversion process takes place. This conversion can be altered using -dither
.
For output bitmap with 1 - 8 bpp an implicit conversion takes place if source bitmap is stored in a higher bit depth. This parameters enables dithering - sometimes it offers better resulting image, sometimes not.
Note: 16, 24 and 32 bpp bitmaps are never converted, individual pixels are just stored with as many bits as possible.
Bits per pixel in destination bitmap. Bitmap data generation can be disabled using 0
(i.e. only header & palette would be stored). 1
- 8
can be stored both in bitplane and chunky formats, 16
- 32
in chunky only. 16
uses Falcon hicolour RGB565 format.
Bytes per chunk in destination bitmap. 0
means generating bitplane data, 1
- 4
means chunky data of 1, 2, 3 or 4 bytes per pixel (default for bpp > 8). -1
means a special packed chunky mode, where pixels are stored as dense as possible, i.e. for 2 bpp it would be 0bAABBCCDD
per byte (instead of 0b000000AA
, 0b000000BB
, 0b000000CC
, 0b000000DD
with -bpc 1
).
Number of bits for each palette entry. Palette generation can be disabled using 0
(i.e. only header & bitmap data would be stored). By default, palette is exported in Falcon palette format (RRRRRRrr GGGGGGgg 00000000 BBBBBBbb
), this can be changed for 9- and 12-bit palette using -st
and -tt
respectively.
Store 9- and 12-bit palette in 16-bit ST/E palette format (0000 rRRR gGGG bBBB
).
Store 9- and 12-bit palette in 16-bit TT palette format (0000 RRRR GGGG GBBB
).
Export source bitmap as an image in the format specified by <ext>
. This includes all popular formats like GIF, JPEG, PNG, WEBP, ... whatever GraphicsMagick supports. Atari switches are ignored (but still validated), only resizing/dithering is applied. Useful for reading uConvert's native Atari formats and displaying on the host platform but usable as a generic bitmap converter, too.
All values are stored in big endian format.
// 'UIMG' (4 bytes)
char id[4];
// 0xAABB (AA = major, BB = minor, 2 bytes)
uint16_t version;
// flags: bit 15-8 7 6 5 4 3 2 1 0
// | |
// +-+- 00: no palette
// 01: ST/E compatible palette
// 10: TT compatible palette
// 11: Falcon compatible palette
uint16_t flags;
// 0, 1, 2, 4, 6, 8, 16, 24, 32
uint8_t bitsPerPixel;
// -1, 0, 1, 2, 3, 4
int8_t bytesPerChunk;
// in pixels, present only if bitsPerPixel > 0
uint16_t width;
// in pixels, present only if bitsPerPixel > 0
uint16_t height;
// (1<<bitsPerPixel) palette entries, present only if flags & 0b11 != 0b00
union {
uint16_t stePaletteEntry;
uint16_t ttPaletteEntry;
uint32_t falconPaletteEntry;
} Palette[1<<bitsPerPixel];
// present only if bitsPerPixel > 0
char* bitmapData;
For example of UIMG handling, see ushow.
uconvert -width 320 -height 200 -bpp 4 -pal 12 test.png
outputstest.bp4
in native ST Low format using STE's 12-bit paletteuconvert -width 320 -height 240 -bpp 8 -bpc 1 -pal 24 test.png
outputstest.c08
in 8-bit (SuperVidel compatible) chunky format using SuperVidel's 24-bit paletteuconvert -width 320 -height 240 -filter -bpp 16 test.png
outputstest.c16
in 16-bit (Falcon compatible) chunky format with smoothened edgesuconvert -width 640 -height 400 -out test.gif test.bp4
outputstest.gif
in twice as big dimensions as the originaltest.bp4
from aboveuconvert -out test.bp8 test.bp4
outputstest.bp8
withtest.bp4
stored in 8 bitplanes- asm-generated bitmap (save as
vasm -Fbin -o img.c04 img.asm
):
dc.b 'UIMG' ; id
dc.w $0100 ; v1.0
dc.w %11 ; falcon palette present
dc.b 4 ; 4 bpp
dc.b 1 ; 1 byte per chunk
dc.w 304 ; width
dc.w 150 ; height
REPT 16 ; use 'REPTN' (0-16) as blue in
dc.l 128+REPTN*4 ; RRRRRRrr GGGGGGgg 00000000 BBBBBBbb
ENDR
; 150 lines
REPT 150
dc.b 0,0
; 300 pixels
REPT 10
; 30 pixels
dc.b 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
ENDR
; pad with 2 pixels (must be divisible by 16!)
dc.b 0,0
ENDR ; REPT 150
Save as a Falcon 4bpp bitplane bitmap: uconvert -bpp 4 img.c04
By the way, if you are looking for an easy way how to create gradients for the Atari, see Gradient Blaster. It supports all ST/STE/TT/Falcon/SuperVidel colour formats and exports to a directly usable output.