Home / Alt manpages / ppmforge(1)

  • ppmforge(1)
  • User command
  • linux

Generate Repeatable Fractal Planets and Skies with ppmforge

You will finish with a repeatable way to generate planet, cloud and star-field images as PPM files, plus checks for their dimensions and reproducibility. The examples use ppmforge from Netpbm 11.5.2, packaged here as netpbm 2:11.05.02-1.1build1. Allow about fifteen minutes for a first run, including time to inspect the output.

You need a shell, the Netpbm package and a directory where you can write temporary images. These commands do not need elevated privileges. Do not run the generator as root merely to write an image: choose a directory you own instead.

1. Check the installed command

Confirm which binary will run and record the package version. This is a read-only checkpoint and also protects you from comparing results produced by a different Netpbm build:

$ command -v ppmforge
/usr/bin/ppmforge
$ ppmforge -version 2>&1 | sed -n '1,2p'
ppmforge: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
ppmforge: Built from source dated 2024-03-31 09:09:47
$ dpkg-query -W -f='${Package} ${Version}\n' netpbm
netpbm 2:11.05.02-1.1build1

The manual says options may be abbreviated to the shortest unique prefix. Use full option names in scripts, because they make the intended settings easier to review and survive additions to the command's option list.

2. Make a small cloud image first

Start with a small image and an explicit seed. -clouds selects the cloud renderer. -seed makes the result repeatable, while the size and mesh keep this first test quick:

$ ppmforge -clouds -seed 123 -width 256 -height 192 -mesh 64 \
    > /tmp/ppmforge-clouds.ppm
ppmforge: clouds: -seed 123 -dimension 2.15 -power 0.75 -mesh 64
$ file /tmp/ppmforge-clouds.ppm
/tmp/ppmforge-clouds.ppm: Netpbm image data, size 256 x 192, rawbits, pixmap

The height request is lower than the width, so this is a valid rectangular image. The installed command preserves those dimensions. The manual also requires an even width. Verify the actual result rather than trusting a graphical preview. On this build, run this direct header check as the authoritative test:

$ od -An -c -N 20 /tmp/ppmforge-clouds.ppm
   P   6  \n   2   5   6       1   9   2  \n   2   5   5  \n

PPM pixel data is binary, so do not open the whole file in a text editor. The first three lines are the PPM header; P6 means raw colour data, followed by width, height and maximum channel value.

Checkpoint

You have a non-empty PPM and have checked its actual header. Keep this file until the larger render has been inspected.

3. Choose the image type deliberately

Without a type option, ppmforge generates a planet. Use -clouds for a cloud texture or -night for a frame filled with stars. The same seed and dimensions do not make those different modes equivalent: the selected renderer changes the image.

$ ppmforge -night -seed 123 -width 256 -height 256 -mesh 64 \
    > /tmp/ppmforge-night.ppm
ppmforge: night: -seed 123 -stars 100 -saturation 125.
$ od -An -c -N 20 /tmp/ppmforge-night.ppm
   P   6  \n   2   5   6       2   5   6  \n   2   5   5  \n

Night images use -saturation to control the colour variation of stars. The default is 125. Set -saturation 0 when you want uncoloured stars and no more than 256 colours, which can make later indexed-image conversion simpler. Higher values create more coloured stars and can produce many distinct colours.

Planet images can also contain tens of thousands of colours. If your display or export format needs a colour limit, process the completed PPM with a separate Netpbm tool such as ppmdither, pnmquant or pamdepth. That is a conversion step, not an option to ppmforge.

4. Tune a planet with a fixed seed

Use a fixed seed while comparing settings. The default planet uses fractal dimension 2.4 and power 1.2. The following command makes a larger, well-lit planet with a 23.5 degree inclination and explicit ice settings:

$ ppmforge -seed 123 -width 800 -height 600 -mesh 256 \
    -hour 12 -inclination 23.5 -dimension 2.4 -power 1.2 \
    -ice 0.4 -glaciers 0.75 \
    > /tmp/ppmforge-planet.ppm
$ file /tmp/ppmforge-planet.ppm
/tmp/ppmforge-planet.ppm: Netpbm image data, size 800 x 600, rawbits, pixmap

-hour 12 puts the central meridian at full illumination. The default hour is random, so two otherwise identical planet commands can show different lighting unless you set it. -inclination controls the latitude at which the star is overhead, with positive values representing northern summer. -ice controls polar caps; -glaciers lets high terrain carry ice towards lower latitudes.

Quality has a cost. The FFT mesh is square, and both memory use and computation increase roughly with the square of its size. Doubling -mesh 256 to -mesh 512 needs about four times the mesh memory and takes about four times as long. Do not increase mesh and output dimensions together until the smaller test is acceptable.

The generated image must be at least as wide as it is high, and the width must be even. If you need a tall or narrow final image, generate a valid wider image first and crop it afterwards with pamcut. Do not assume that the requested dimensions are the final dimensions: inspect the PPM header or use file.

5. Re-render a result instead of guessing

The seed is printed unless you use -quiet. Save a seed you like, then reuse it with the same image settings. This lets you change viewing parameters or render at a higher resolution without changing the underlying random scene:

$ ppmforge -seed 123 -width 800 -height 600 -mesh 256 \
    -hour 12 -inclination 23.5 > /tmp/planet-v1.ppm
$ ppmforge -seed 123 -width 1600 -height 1200 -mesh 512 \
    -hour 12 -inclination 23.5 > /tmp/planet-v2.ppm
$ cmp -s /tmp/planet-v1.ppm /tmp/planet-v2.ppm; printf 'same bytes: %s\n' "$?"
same bytes: 1

A non-zero status from cmp is expected here because the dimensions and mesh differ. To check determinism, render the exact same command twice and compare the files:

$ ppmforge -seed 123 -width 256 -height 256 -mesh 64 > /tmp/a.ppm
$ ppmforge -seed 123 -width 256 -height 256 -mesh 64 > /tmp/b.ppm
$ cmp /tmp/a.ppm /tmp/b.ppm
$ echo $?
0

If you omit -seed, the program chooses a seed from the date and time. That is useful for variation, but it is the wrong default for a build or a reproducible asset pipeline.

6. Recover from failed or unwanted renders

Shell redirection truncates its destination before the program starts. Do not redirect a valuable image straight over its only copy. Render to a new temporary name, inspect it, then move it into place:

$ ppmforge -seed 123 -width 800 -height 600 -mesh 256 \
    > /tmp/planet.ppm.new
$ file /tmp/planet.ppm.new
$ mv /tmp/planet.ppm.new /path/to/checked/planet.ppm

If the render fails, the old destination is untouched. Remove the incomplete /tmp/planet.ppm.new only after checking that it is the failed temporary file. If you already overwrote an output, there is no ppmforge undo operation; regenerate it from the recorded seed and options, or restore your own backup.

For a memory or time problem, reduce -mesh first, then reduce output dimensions. For an unexpectedly dark planet, set an explicit -hour between 4 and 20, with 12 as the simplest test. For a missing converter, keep the verified PPM and install or invoke the later conversion tool through your normal package-management process. None of these problems requires sudo.

Done means

  • You confirmed the installed Netpbm version and ppmforge path.
  • You generated a PPM in the intended mode: planet, clouds or night sky.
  • You used an explicit seed when the image needs to be reproducible.
  • You verified the actual PPM dimensions rather than trusting the request.
  • You kept mesh size proportionate to available memory and render time.
  • You rendered replacement files separately, so a failed command could not destroy the previous image.