![]() |
Florian & Alain's Blender.fab v0.9: A command line tool to create and manipulate images. (c) Alain Brobecker 2009-2022 Non commercial use allowed |
1. Command line? 2. File formats 3. List of commands. 3.1. File conversion 3.2. Drawing primitives 3.3. Standard image manipulation 3.4. Arithmetic and logic functions 3.5. Sampling et scaling functions 3.6. Standard color manipulation 3.7. Color dithering 3.8. Convolution filter 3.9. Misc functions 4. Some examples 5. Future |
1. Command line?
fab is a command line tool to create and manipulate images. This
means there is no graphical user interface (gui) and you must execute the
fab program with parameters so that it will perform operations on
the image files. To give commands and parameters to the program, the first
method is to open a command line interpreter (command prompt on m$do$,
cli on RiscOS, shell on Unixes...) and write your orders
one after another. For example on m$do$:
(niko_heart.bmp)
C:\baah\c\fab>fab bmp2rgb niko_heart.bmp red.g green.g blue.g bmp2rgb: 32 x 32 OK C:\baah\c\fab>fab rgb2bmp green.g blue.g red.g niko_heart_blue.bmp rgb2bmp: 32 x 32, 11 colors OK
The second method is to make a file with the different commands and ask the system to execute them (batch file on m$do$, obey file on RiscOS, shell file on Unixes...). For the example above, again of m$do$, you create a text file called "example.txt", write the following orders in it:
fab bmp2rgb niko_heart.bmp red.g green.g blue.g fab rgb2bmp green.g blue.g red.g niko_heart_blue.bmp del *.gThen you rename it to "example.bat" and execute it by typing C:\baah\c\fab>example under m$do$ or by double clicking on it under m$window$ (the last one will not allow to see errors).
2. File formats
fab uses the following fileformats:
3. List of commands
Commands and parameters are shown in bold. Comments are in normal text. Functions that might be added in the future are shown between interrogation marks.
3.1. File conversion
3.2. Drawing primitives
The bottom left corner has coordinates (0;0).
3.3. Standard image manipulation
3.4. Arithmetic and logic functions
When two images with different width and/or height are given as source, the resulting image has minimum width and/or height.
Arithmetic and logic functions can be used for many purposes.
One of them is putting an image above another, as explained below:
step 1: background image (blurred random noise on R/G/B channels)
step 2: sprite (ie image to put above the other one)
step 3: mask for sprite (pixels in sprite set to 0, others set to 255)
step 4: background AND mask
step 5: (background AND mask) OR sprite
You can also have smoother edges for the sprite if its mask contains more
than on/off information. Below the mask has been blurred (using a convolution filter,
but we could also use the distance function).
The sprite is modified with "(sprite MUL NOT mask) DIV 255", and we also replace step 4 above
by "(background MUL mask) DIV 255".
3.5. Sampling et scaling functions
3.6. Standard color manipulation
3.7. Color dithering
The output of all this functions will be a grey image with intensity in [0;nb_colors-1].
You'll often use the range function afterward to put the intensity back in
[0;255]. Also note that you must use the range function to make
nearest neighbourgs dithering.
The image shows a texture (fractal landscape with modulo) with colors reduced
using nearest neighbourgs as method 0, then the dithering as numbered below:
. 7 and divide by 16 3 5 1
. 8 4 2 4 8 4 2 and divide by 42 1 2 4 2 1
???fab ordereddithering + page flip => 5+4=9 grey levels???
???fab floyd palette.pal red.g green.g blue.g out.g // <65536 colors???
* There are many ways to find the nearest palette color with varying levels of efficiency
and quality. A trivial algorithm is to search the color with minimum straight line
distance in the color cube from the given color.
* We can alternate between left-to-right and right-to-left (also reflect the diffusion
matrix), this avoids some kind of artifacts.
3.8. Convolution filter
Only one function in here, but it's an important one since it can be used for a lot of effects. The filter is wrapping, ie for pixels with x=0 we also take in account the pixels with x=width-1, same for y... To avoid wrapping, use addsimilarborders + removeborders.
(a b c) (d e f) :n + offset (g h i)
Some usefull filters:
fab filter 0 1 0 1 1 1 0 1 0 5 0 in.g out.g // smooth1
fab filter 1 2 1 2 4 2 1 2 1 16 0 in.g out.g // smooth2
fab filter -1 1 -1 1 1 1 -1 1 -1 1 0 in.g out.g // unsmooth
fab filter -2 -1 0 -1 0 1 0 1 2 1 128 in.g out.g // relief1
fab filter -1 1 -1 1 0 1 -1 1 -1 1 128 in.g out.g // relief2
fab filter 0 -1 0 -1 2 0 0 0 0 1 128 in.g out.g // relief3
fab filter 1 0 1 0 -1 0 1 0 1 3 0 in.g out.g // strange1
fab filter 0 1 0 1 -1 1 0 1 0 3 0 in.g out.g // strange2
fab filter 0 -n 0 -n 4n+1 -n 0 -n 0 1 0 in.g out.g // sharpness
fab filter -n -n -n -n 8n+1 -n -n -n -n 1 0 in.g out.g // sharpness2
fab filter -1 -1 -1 -1 8 -1 -1 -1 -1 1 0 in.g out.g // edge=laplace
fab filter 0 -1 0 -1 4 -1 0 -1 0 1 0 in.g out.g // laplace2
fab filter -1 -1 -1 0 0 0 1 1 1 1 0 in.g out.g // edge2
fab filter -5 0 0 0 0 0 0 0 5 1 0 in.g out.g // edge3
fab filter 0 0 0 0 -1 0 0 0 1 1 0 in.g out.g // emboss
fab filter 2 0 0 0 -1 0 0 0 -1 1 0 in.g out.g // emboss2
fab filter -2 -1 0 -1 1 1 0 1 2 1 0 in.g out.g // repoussage
3.9. Misc functions
fab allows for easy implementation of graphical routines. The ones below are less classical than previous ones, but might be of interest.
4. Some examples
To make a shadow, we get two shifted copies of the same image,
we enlighten (or darken) the shadow with range, blur it with filter and then put the original
image above:
fab bmp2grey fab_1bpp.bmp shape.g fab rsbI 255 shape.g shape.g rem Now the logo is set to 0, outside to 255 fab addborders 10 0 10 0 255 shape.g shadow.g fab range 160 255 shadow.g shadow.g fab filter 1 2 1 2 4 2 1 2 1 16 0 shadow.g shadow.g fab filter 1 2 1 2 4 2 1 2 1 16 0 shadow.g shadow.g fab addborders 0 10 0 10 255 shape.g shape.g fab and shape.g shadow.g shape.g rem Since shape.g contains only 0 and 255 values, rem a simple "and" had the same effect as masking fab sampledown 2 2 shape.g shape.g fab grey2bmp shape.g TutorialShadow.bmp del *.g |
![]() |
Many textures are in the more_examples folder, i'll just speak about Txtr2D.
Quite simply we create a random 4x4 image, expand it with the fractal landscape
function, blur it, take the values modulo 32 (with the andI function)
and use a cycling color palette with 32 entries.
I advise you to launch the batch files for other textures in the more_examples
folder. Some modifications have been obtained just by changing the color palette!
![]() |
fab mknoise 0 200 4 4 grey.g fab landscape 6 grey.g grey.g fab filter 1 2 1 2 4 2 1 2 1 16 0 grey.g grey.g fab andI 31 grey.g grey.g fab textpalette2rgb pal_Txtr2D.txt grey.g red.g green.g blue.g fab rgb2bmp red.g green.g blue.g Txtr2D.bmp del *.g |
The fillwithOs function is very slow, but interesting in my humble opinion.
Here we had to increase the size of the fab logo using the edge function,
and enlarge the image since fillwithOs requires big monochrome images.
fab bmp2grey fab_1bpp.bmp shape.g fab addborders 10 10 10 10 0 shape.g shape.g fab edge 9 0 255 shape.g shape.g fab scaleup 3 3 shape.g shape.g fab rsbI 255 shape.g logo.g rem Now the logo is set to 0, outside to 255 fab fillwithOs 10 25 5 15 0 0 255 logo.g logo.g fab and shape.g logo.g logo.g fab sampledown 6 6 logo.g logo.g fab rsbI 255 logo.g logo.g fab grey2bmp logo.g TutorialFillWithCircles.bmp del *.g |
![]() |
Now for a more complex example. The picture by BriteLite was created for a contest with the constraint of using 4 colors only. I have always loved the special dithering in it, and wanted to make something similar. The background is similar to Txtr2D but converted to 2 colors with ordered4x4 dithering. The logo is reduced with sampledown, the mask is created with an edge, then both are expanded with scaleup, the logo is converted to 4 colors with ordered2x2 dithering. Last, using the mask, the background and logo are mixed.
![]() BriteLite-Pain remixed with fab ![]() |
rem background fab mknoise 0 255 4 4 background.g fab landscape 8 background.g background.g fab filter 1 2 1 2 4 2 1 2 1 16 0 background.g background.g fab andI 31 background.g background.g fab ordered4x4 2 background.g background.g rem start shape (expand size to multiples of 8) fab bmp2grey fab_1bpp.bmp shape.g fab addborders 129 129 51 51 0 shape.g shape.g fab sampledown 8 8 shape.g shape.g rem mask for the shape fab edge 2 0 255 shape.g mask.g fab allcolorsbelow 1 mask.g mask.g fab mulI 255 mask.g mask.g fab rsbI 255 mask.g mask.g fab scaleup 2 2 mask.g mask.g rem continue shape (we can put details in it) fab scaleup 2 2 shape.g shape.g fab ordered2x2 4 shape.g shape.g rem mix background, mask and shape fab and mask.g background.g background.g fab or background.g shape.g shape.g fab textpalette2rgb pal_britelite.txt shape.g red.g green.g blue.g fab rgb2bmp red.g green.g blue.g TutorialBriteLite.bmp del *.g |
Another one inspired by pixelart: The upper right picture by exocet
has a nice background and remembered me about such shapes seen when playing
around with fractal landscape. Here we simply add a linear
gradient then decrease the number of colors with the range
function applied twice, because the result was looking better when reducing
to 6 colors just before reducing to 3 colors (!). You can see the result of
the small program on the right.
I also played a bit to create a full remix of exocet's artpiece, you can
see it on the bottom left, but the program is too long to copy here.
In the more_examples directory you'll also find a similar
background created with a circular gradient and another one using the
minimum/maximum functions.
rem fractal landscape 256*512 in range [0;73] fab mknoise 0 255 32 64 frac.g fab sampleup_miller 3 frac.g frac.g fab range 0 73 frac.g frac.g rem heights made of vgradient in range [0;127] fab mknoise 0 0 256 512 grad.g fab vgradientfill 0 127 0 grad.g grad.g rem mix both and convert to 3 colors fab add frac.g grad.g both.g fab range 0 5 both.g both.g fab range 0 2 both.g both.g fab addI 1 both.g both.g fab scaledown 2 2 both.g both.g fab textpalette2rgb pal_Suburbs.txt both.g r.g g.g b.g fab rgb2bmp r.g g.g b.g TutorialSuburbs.bmp del *.g | ![]() exocet-Suburbs ![]() |
  | < ![]() |
The example below shows some results of the tiling command with different tilesets. On the last three ones a vertical gradient was added and they where dithered beforhand with the stucki method, so as to have a more irregular result. Also an older, bugged, routine for tiles in 1bpp can be seen in the old directory, and the result even looks a bit better.
![]() MOJO-ClintMauro |
>>> | ![]() remixed with fab |
The power parameters in the star command are controlling the roundedness of the "spikes". In order to see which ones are nice i wrote a small .c program that gives the list of commands to draw stars with various roundedness. The image shows a star with inner_power=50, outer_power=50 (note that powers are multiplied by 100) on the bottom left, then the powers increase by steps of 50 horizontally (inner_power) or vertically (outer_power).
#include <stdio.h> #include <stdlib.h> int main() { int x,y,power1,power2; printf("fab mknoise 255 255 1024 1024 t.g\n"); y=64; for(power2=50;power2<=400;power2+=50) { x=64; for(power1=50;power1<=400;power1+=50) { printf("fab star %d %d 5 0 32",x,y); printf("%d 64 %d 0 t.g t.g\n",power1,power2); x+=128; } y+=128; } printf("fab sampledown 2 2 t.g t.g\n"); printf("fab grey2bmp t.g TutorialStars.bmp\n"); printf("del *.g\n"); exit(0); } | ![]() |
For the picture below i used MkNoise, allcolorsabove and subI to have a limited amount of points randomly placed. Then i used the voronoi command to make the Voronoi diagram of those points. Then the filter command is applied to find the edges of the diagram, and i used many times the edge function to create nice patterns. After the image is downsampled, reduced to 4 colours, cropped, and darkened on the borders.
![]() |
fab mknoise 0 3000 1200 840 t.g fab allcolorsabove 2999 t.g t.g fab subI t.g 2999 t.g fab voronoi 0 t.g t.g rem fab grey2bmp t.g Test_Voronoi.bmp fab filter -1 -1 -1 -1 8 -1 -1 -1 -1 1 0 t.g t.g fab allcolorsbelow 1 t.g t.g fab mulI 255 t.g t.g fab edge 4 0 255 t.g t.g fab edge 9 0 1 t.g t.g fab edge 9 0 255 t.g t.g [...] fab edge 9 0 1 t.g t.g fab edge 9 0 255 t.g t.g rem sampledown, reduce to 4 colors, darken the borders, etc [...] fab mulI 48 t.g t.g fab addI 64 t.g t.g fab grey2bmp t.g Test_Voronoi.bmp del *.g |
The taglia effect is adapted from a BBC Basic program by Jan Vibe (he made a lot of nice graphical effects on RiscOS). You give the width and height of the picture, the size of the randomly walking ball and its border, then the number of iterations (the higher the longer the path will be) and the output name. I will try to make more variations on that one.
![]() |
5. Future
The image below show some cool drawing techniques i would like to find an algorithm
for (edges for the first two, dithering for the others).
![]() exocet-GPeur |
![]() exocet-MrGland |
![]() exocet-Dither |
![]() Brian The Great-roflmao |