# FractInt

FractInt home page.

# 1 GIF Metadata

GIF images exported from FractInt have embedded metadata. You can load GIFs back into FractInt (or xFractInt on Linux) and continue exploring from the same location.

The original FractInt.exe (which works on Linux with Wine and DOSBox) has a command line option for converting GIF to PAR (PAR is FractInt’s parameter format based on ASCII text):

wine fractint.exe foo.gif makepar=bar.par/foo

The bar.par file can contain many parameters, they will be appended each time.

# 2 PAR to KFR conversion

KFR is the parameter file format of Kalle’s Fraktaler 2. It is rather simple, consisting of Key: Value pairs, each on their own line in a text file with DOS line endings. The tools dos2unix and unix2dos are useful for converting.

PAR format has a few awkward aspects, so the conversion is done in 3 parts.

# 2.1 Split PAR to PPAR

MightyMandel (an abandoned fractal program of mine) has a script that splits a PAR collection into multiple files with a slightly simpler format. Line continuations (lines ending in backslash) are merged. Key/value pairs are separated by newlines instead of commas.

The script split2ppar.sh is reproduced here:

#!/bin/bash
tmp="$(mktemp -d --tmpdir=. split2ppar.XXXXXXXX)"
for file in "${@}"
do
  name="$(basename "${file}")"
  file="$(readlink -e "${file}")"
  pushd "${tmp}"
  awk "/{/{n++}{print > \"${name}_\"n\".par\" }" "${file}"
  popd
done
pushd "${tmp}"
for file in *.par
do
  ident="$(head -n 1 "${file}" | sed 's/ .*$//')"
  mv "${file}" "${ident}.par"       # rename input
  cat < "${ident}.par" |            # read input
  sed 's/;.*$//' |                  # delete ; comments
  tr '\n' ' ' |                     # join on one line with spaces
  sed 's/\\ *//g' |                 # merge lines ended with '\'
  tr -s ' ' |                       # compress multiple ' ' to single ' '
  sed 's/^.*{\([^}]*\)}.*$/\1/' |   # extract the part between { }
  tr ' ' '\n' |                     # split into separate lines
  cat > "${ident}.ppar"             # write output
done
popd
ls "${tmp}/"*

# 2.2 Palette Conversion

FractInt palettes have 256 colours (of which the first is reserved for interior). They are stored as 6bit RGB, encoded in ASCII. Gradients of slowly changing colours are compressed as two endpoints and a count. Check FractInt documentation Topic=Color Specification for details.

My decoder ppar2kfp.c is reproduced here (implemented in C):

#include <assert.h>
#include <stdio.h>

int main(int argc, char **argv)
{
  unsigned char palette[256][3];
  // decompress palette spec
  int lastindex = 0;
  int index = 0;
  int channel = 0;
  int count = 0;
  char input;
  while (EOF != (input = fgetc(stdin)))
  {
    if (input == ' ' || input == '\r' || input == '\n' || input == '\\')
    {
      continue;
    }
    if (input == '<')
    {
      assert(index > 0);
      assert(channel == 0);
      lastindex = index - 1;
      count = 0;
      while ('>' != (input = fgetc(stdin)))
      {
        assert(EOF != input);
        assert('0' <= input);
        assert(input <= '9');
        count *= 10;
        count += input - '0';
      }
      index += count;
      assert(index < 256);
    }
    else
    {
      int sixbit = 0;
      if ('0' <= input && input <= '9') sixbit = input - '0';
      else if ('A' <= input && input <= 'Z') sixbit = input - 'A' + 10;
      else if ('_' == input) sixbit = 36;
      else if ('`' == input) sixbit = 37;
      else if ('a' <= input && input <= 'z') sixbit = input - 'a' + 38;
      else
      {
        assert(! "expected encoded channel value character");
      }
      int eightbit = (sixbit << 2) | (sixbit >> 4); // scale so that 0 -> 0, 63 -> 255
      palette[index][channel] = eightbit;
      channel++;
      if (channel == 3)
      {
        channel = 0;
        if (count > 0)
        {
          assert(count == index - (lastindex + 1));
          for (int fillindex = lastindex + 1; fillindex < index; ++fillindex)
          {
            for (int fillchannel = 0; fillchannel < 3; ++fillchannel)
            {
              // linear interpolation
              palette[fillindex][fillchannel] = (int) palette[lastindex][fillchannel] +
                ( ((int) palette[index][fillchannel] - (int) palette[lastindex][fillchannel])
                * (fillindex - lastindex)
                + (index - lastindex) / 2 // for rounding instead of truncation
                ) / (index - lastindex);
            }
          }
        }
        count = 0;
        index++;
        if (index == 256)
        {
          break;
        }
      }
    }
  }
  assert(index == 256);
  printf("InteriorColor: %d,%d,%d,\n", palette[0][2], palette[0][1], palette[0][0]);
  printf("Colors: ");
  for (index = 1; index < 256; ++index)
  {
    printf("%d,%d,%d,", palette[index][2], palette[index][1], palette[index][0]);
  }
  printf("\n");
  return 0;
}

It expects the value of the colors= key on standard input and outputs a converted palette on standard output

# 2.3 Export KFR

This script ppar2kfr.sh extracts the coordinates, using ghc as a calculator to multiply the zoom factor by 2 to match KF convention. The script assumes the parameter is for Mandelbrot set without checking.

It uses the above C program (which must be compiled and put next to this script) to extract the palette colours.

It also sets various values so that the colours match better (though they weren’t 100% exact matches in my tests).

Some PAR files have other colour mappings that make the output from KF look completely different from the original output from FractInt, please check before starting a big render.

#!/bin/bash
(
cat $1 |
grep ^center-mag= |
sed "s|^center-mag=||g" |
tr "/" " " |
(
read Re Im Zoom XMag RotateAngle Skew
echo "Re: $Re"
echo "Im: $Im"
Zoom="$(ghc -e "2 * $Zoom")"
echo "Zoom: $Zoom"
cat $1 |
grep ^maxiter= |
sed "s|^maxiter=\(.*\)$|Iterations: \1|g"
if [ ! "${XMag}" ]
then
  XMag=1
fi
if [ "${XMag}" != "1" ]
then
  echo "unsupported XMag $XMag" >&2
fi
if [ ! "${RotateAngle}" ]
then
  RotateAngle=0
fi
echo "RotateAngle: $RotateAngle"
if [ ! "${Skew}" ]
then
  Skew=0
fi
if [ Skew != "0" ]
then
  echo "unsupported Skew $Skew" >&2
fi
)
) |
sed 's|: +|: |g'
cat $1 |
grep ^colors= |
sed "s|^colors=||g" |
"$(dirname "$(readlink -e "$0")")"/ppar2kfp
cat <<EOF
ColorOffset: 1020
IterDiv: 0.2490234375
JitterSeed: 1
ImagPointsUp: 1
SmoothMethod: 1
SmoothingMethod: 1
Smooth: 0
Flat: 1
BailoutRadiusPreset: 1
BailoutRadiusCustom: 2
BailoutNormPreset: 1
BailoutNormCustom: 2
ColorMethod: 0
Differences: 0
ColorPhaseStrength: 0
MultiColor: 0
BlendMC: 0
MultiColors: 
Power: 2
FractalType: 0
Slopes: 0
SlopePower: 50
SlopeRatio: 20
SlopeAngle: 45
real: 1
imag: 1
SeedR: 0
SeedI: 0
FactorAR: 1
FactorAI: 0
Period: 0
TextureEnabled: 0
TextureMerge: 1
TexturePower: 200
TextureRatio: 100
TextureFile: 
StretchAngle: 0
StretchAmount: 0
Version: 2150100
ImageWidth: 1024
ImageHeight: 768
EOF

Use it like ppar2kfr.sh foo.ppar > foo.kfr. The output has UNIX line endings, convert it to something compatible with KF using unix2dos.