Fractals/Computer graphic techniques/2D/gfile

Graphic files


One can :

  • directly create graphic file
  • open existing graphic file

Types of graphic files :

  • static images
    • raster : png, pgm,ppm,pam,bmp
    • special files : dot files
    • vector : svg
  • video

Static images

Raster files

PGM image file and C++ program by Ilya Voyager

raster files



Assembler

; create a ppmb file by ker2x
; http://www.fractalforums.com/programming/an-absolute-beginner-to-x64-asm-on-linux/
: yasm -f elf64 ppmb.asm 
; gcc -o ppmb ppmb.o 
; ./ppmb | hexdump
 
segment .data
    header:     db  'P6 4 4 255', 0x0a
    headerlen:  equ $-header
    image:      db  255,0,0, 0,255,0, 0,0,255, 255,255,255
    imagelen:   equ $-image
 
segment .text
global main
 
main:
    mov eax, 4
    mov ebx, 1
    mov ecx, header
    mov edx, headerlen
    int 0x80
    mov eax, 4
    mov ebx, 1
    mov ecx, image
    mov edx, imagelen
    int 0x80
    mov eax, 4
    int 0x80
    mov eax, 4
    int 0x80
    mov eax, 4
    int 0x80
    ; Call sys_exit(0)
    mov eax, 1
    xor ebx, ebx
    int 0x80

C

Static array for one color

Code in C for creating pgm text file :

#include <stdio.h>
 
int main(){
  int iX,iY;
  const int iXmax = 300; 
  const int iYmax = 300;
  /* color  is coded from 0 to 255 */
  /* it is 8 bit color RGB file */
  const int MaxColorComponentValue=255; 
  FILE * fp;
  char *filename="m.pgm";
  char *comment="# this is my new text pgm file ";  /* comment should start with # */
  static unsigned char color;
 
 
 
  /*create new file,give it a name and open it in text mode  */
  fp= fopen(filename,"w"); /*  text mode */
  /*write ASCII header to the file*/
  fprintf(fp,"P2\n%s\n%d %d\n%d\n",comment,iXmax,iYmax,MaxColorComponentValue);
  /*write image data bytes to the file*/
  for(iY=0;iY<iYmax;++iY){
    for(iX=0;iX<iXmax;++iX){         
      color=150;   /* compute  pixel color (8 bit = 1 byte) */
      fprintf(fp," %d ", color);   /*write color to the file*/
    }
    fprintf(fp," \n ");
  }
  fclose(fp);
  printf("OK\n");
  getchar();
  return 0;
}

To compile it :

  gcc m.c

To run it :

./a.out

Remember that :

  • fwrite is used for binary files
  • fprintf is used for binary and text files

so if you want to use fwrite then you will get binary file ( even if you will open it in text mode ):

Static 2D array for whole image

#include <stdio.h>
 
int main(){
 
  int iX,iY;
  const int iXmax = 100; 
  const int iYmax = 100;
  unsigned char data[iYmax][iXmax]; /* 2D array for colors ( shades of gray ) */
  const int MaxColorComponentValue=255; /* color component is coded from 0 to 255 ;  it is 8 bit color file */
  FILE * fp;
  char *filename="n.pgm";
  char *comment="# this is my new binary pgm  file";/* comment should start with # */
 
  /* fill the data array */
  for(iY=0;iY<iYmax;++iY){  
    for(iX=0;iX<iXmax;++iX){ 
      data[iY][iX]=255;
    }
  }
}
 
/* write the whole data array to ppm file in one step */      
fp= fopen(filename,"wb"); /*create new file,give it a name and open it in binary mode  */
fprintf(fp,"P5\n %s\n %d %d\n %d\n",comment,iXmax,iYmax,MaxColorComponentValue);  /*write header to the file*/
fwrite(data,sizeof data,1,fp);  /*write image data bytes to the file*/
fclose(fp);
printf("OK - file %s saved\n", filename);
return 0;
}

Virtual 2D array and dynamic 1D array

Here image is a virtual 2D array, but in program we use 1D array.

Relations between indexes :

i = ix + iy*iWidth; // index of 1D array 
ix = i % iWidth;
iy = (i- ix) / iWidth;

Here is whole program where we only check ranges of array's indexes without using explicit array :

#include <stdio.h>
 
/* --------- global variables ----------------- */
 
// 2D array 
// Indexes of array starts from 0 not 1 
unsigned int ix, iy;
unsigned int ixMin = 0;
unsigned int ixMax = 3; //
unsigned int iWidth ; // = (ixMax -ixMin + 1) = 4
unsigned int iyMin = 0;
unsigned int iyMax = 3; //
unsigned int iHeight ; //= (iyMax -iyMin + 1) =  4
// The size of array has to be a positive constant integer 
unsigned int i2Dsize ; // = iWidth*iHeight = 16
 
 
// 1D array 
unsigned int i; // index of 1D array
unsigned int iMin = 0;
// Indexes of array starts from 0 not 1 so the highest elements of an array is = array_name[size-1].
unsigned int iMax ; // = i2Dsize-1; // = 15
// The size of array has to be a positive constant integer 
unsigned int i1Dsize ; // = i2Dsize  = (iMax -iMin + 1) = 16 ;  1D array with the same size as 2D array
 
 
 
/* ---------- functions ----------------*/
 
/* gives position of 2D point (iX,iY) in 1D array  ; uses also global variable iWidth */
unsigned int f(unsigned int ix, unsigned int iy)
{ return ix + iy*iWidth; }
 
 
/* ---------------------- main ------------------*/
int main()
{
 
iWidth = (ixMax -ixMin + 1); // 
iHeight = (iyMax -iyMin + 1); //
i2Dsize = iWidth*iHeight; // number of points in array 
iMax = i2Dsize-1; // Indexes of array starts from 0 not 1 so the highest elements of an array is = array_name[size-1].
i1Dsize = i2Dsize; // 1D array with the same size as 2D array
 
 
// first method using 1D index i 
for (i=iMin; i<i1Dsize; ++i) printf(" %d \n", i ); // from 0 to 15
 
// second method using 1D index i 
for (i=iMin; i<=iMax ;  ++i) printf(" %d \n", i ); // from 0 to 15
 
// check second method using 1D index i
for (i=iMin; i<=iMax ;  ++i)  // i from 0 to 15
 { ix = i % iWidth;
   iy = ( i- ix) / iWidth; // inversion of f function
   printf(" ix = %d ; iy = %d ; i = %d \n",ix , iy , i );} 
 
// using 2D indexes :  iy and ix
for(iy=iyMin;iy<=iyMax;++iy)
  for(ix=ixMin;ix<=ixMax;++ix) printf(" ix = %d ; iy = %d ; i = %d \n", ix, iy, f(ix,iy) );     
 
return 0;
}

Lua

Lua code for binary B@W PBM file :

-- The Computer Language Shootout
-- http://shootout.alioth.debian.org/
-- contributed by Mike Pall
 
local width = tonumber(arg and arg[1]) or 100
local height, wscale = width, 2/width
local m, limit2 = 50, 4.0
local write, char = io.write, string.char
 
write("P4\n", width, " ", height, "\n")
 
for y=0,height-1 do
  local Ci = 2*y / height - 1
  for xb=0,width-1,8 do
    local bits = 0
    local xbb = xb+7
    for x=xb,xbb < width and xbb or width-1 do
      bits = bits + bits
      local Zr, Zi, Zrq, Ziq = 0.0, 0.0, 0.0, 0.0
      local Cr = x * wscale - 1.5
      for i=1,m do
        local Zri = Zr*Zi
        Zr = Zrq - Ziq + Cr
        Zi = Zri + Zri + Ci
        Zrq = Zr*Zr
        Ziq = Zi*Zi
        if Zrq + Ziq > limit2 then
          bits = bits + 1
          break
        end
      end
    end
    if xbb >= width then
      for x=width,xbb do bits = bits + bits + 1 end
    end
    write(char(255-bits))
  end
end

Octave

Octave code that creates array ( memory image) and saves it to the file[2]

# octave m-file based on the m-file by Chris King
# http://www.dhushara.com/DarkHeart/Viewers/source/siegel.m
# an MyImage here is a matrix for 24 bit (3 byte) colors 
 
# load packages
pkg load image; # imwrite
pkg load miscellaneous; # waitbar
 
# constan values 
nx = 480;
ny = 480;
MyImage = zeros(ny,nx,3); # 2D matrix filled with zeros
magc=0.65;
dSide=1/magc;
Zxmin = -dSide;
Zxmax = dSide;
Zymin = -dSide;
Zymax = dSide;
 
stepy = (Zymax - Zymin)/(ny - 1);
stepx = (Zxmax - Zxmin)/(nx - 1);
 
# computations 
waitbar(0,'Please wait...'); # info 
for iy = 1:ny
  Zy = Zymax - iy*stepy; # invert y axis
  for ix= 1:nx
    Zx = Zxmin + ix*stepx;
    if(Zy>0 && Zx>0)  # first quadrant should be in upper right position
    MyImage(iy,ix,2)=255-MyImage(iy,ix,2);
    endif;
  end # for ix
  waitbar(iy/ny);
end # for iy
# 
image(MyImage); # display image 
imwrite(MyImage,'s.png' ); # save image to the file
↑Jump back a section

Special files

Dot files

Dot files are text files describing graphs in dot language. Example file :

digraph "BinaryAddingMachine" {
a [shape=circle]
b [shape=circle]
 a -> a [label="1/1",color=red];
 a -> a [label="2/2",color=blue];
 b -> a [label="1/2",color=red];
 b -> b [label="2/1",color=blue];
}

This file can be coverted to other formats using command line program dot. For example to svg :

dot -Tsvg b.dot -o b.svg


Parameter files

"Fractint uses Parameter files to save/restore all options and settings,[5] required to recreate particular images. The parameters required to describe an image require very little disk space, especially compared with saving the image itself. " [6]

Most important settigs are :

Example file :

{ ; quite good spirals 
  reset=2000 type=mandel passes=1
  corners=-0.6014129278/-0.5990935452/0.427747516/0.429487053
  params=0/0 float=y maxiter=1000 inside=0 outside=15
  distest=1/10/320/200 
  }

To use it :

  • Save file to fractint main directory.
  • Run fractint.
  • press 2 key
  • press F6 key
  • select file


Reset causes Fractint to reset all calculation related parameters to their default values. Non-calculation parameters such as "printer=", "sound=", and "savename=" are not affected. [7]The reset=1730 in the parameter file shows that it was created with 17.3 version of Fractint. [8]

Video

↑Jump back a section

Animated gif

Convert pgm ( or other ) static files into animated gif using BASH and Image Magic : [10]

#!/bin/bash
 
# script file for BASH 
# which bash
# save this file as g
# chmod +x g
# ./g
 
# for all pgm files in this directory
for file in *.pgm ; do
  # b is name of file without extension
  b=$(basename $file .pgm)
  # convert from pgm to gif and add text ( level ) using ImageMagic
  convert $file -pointsize 100 -annotate +10+100 $b ${b}.gif
  echo $file
done
 
# convert gif files to animated gif
convert -delay 100   -loop 0 %d.gif[0-24] a24.gif
 
echo OK
# end

Dont forget about : 12.5MP limit = 500 x 500 x 50 frames = 600 x 600 x 34 frames = 1000 x 1000 x 12 frames

↑Jump back a section

MPEG

Steps from pgm to video using Image Magic convert :

  • pgm files to gif files
  • gif files to video
convert -delay 100   -loop 0 %d.gif[0-25] a25.mpg
↑Jump back a section

Ogv

#!/bin/bash
 
# script file for BASH 
# which bash
# save this file as g
# chmod +x g
# ./g
 
i=0
# for all pgm files in this directory
for file in *.pgm ; do
  # b is name of file without extension
  b=$(basename $file .pgm)
  # change file name to integers and count files
  ((i= i+1))
  # convert from pgm to gif and add text ( Cx from name of file ) using ImageMagic
  convert $file -pointsize 50 -annotate +10+100 $b ${i}.gif
  echo $file
done
 
echo convert all gif files to one ogv file
ffmpeg2theora %d.gif --framerate 12 --videoquality 9  -o output129.ogv
 
echo b${i} OK
# end
↑Jump back a section

WebM

One can made a video from images. For examp

e creating WebM video files using ffmpeg [11][12]

ffmpeg -i x%08d.png -r 24 tifa.webm

or ffmpeg2theora[13]:

ffmpeg2theora %d.gif --framerate 5 --videoquality 9 -f webm --artist "your name" -o otput.webm 

If you use files names containing parameter ( here Cx ), then it would be easy to sort files and make video :

  char name [10]; /* name of file */
  i = sprintf(name,"%2.7f",Cx); /* result (is saved in i) but is not used */
  char *filename =strcat(name,".pgm"); /* new name thru concatenate of  strings  */

Viewer for programmers

This programm opens ppm/pgm binary files. It can be used to check image by checking output in console as mouse moves. Add your code to Motion function and update Zxmin and Zymin ( world coordinate).


/* 
 * image.c
 *
 * read in a PPM or PGM binary image and display it, full size
 
  Based on code by : 
   Dr. Lori L. Scarlatos
   Stony Brook University
   http://ms.cc.sunysb.edu/~lscarlatos/
   "I do not have a license for image.c; 
   it was created as an example for my students.
   Please feel free to use it.
   Best regards,
   Lori"
* ----------------------------
* it does not opens asci versions of these files 
* examples files : 
* http://people.sc.fsu.edu/~jburkardt/data/data.html
 
  gcc i.c -lm -lGLU -lglut -Wall
  ./a.out p.pgm
 
 */
 
//#include <Windows.h>
 
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h> /* fabs*/
//#include <malloc.h>
 
 
 
/* Global variables */
 
#define MAXLINE 80      /* maximum length of a line of text */
GLint ImageWidth, ImageHeight;  /* size of the Image in pixels */
GLint iYmax,iXmax;
GLubyte *Picture;       /* Array of colors (GLubyte)  */
 
const double  ZyMin=-1.5;
const double  ZxMin=-1.5;
const double  PixelHeight=0.005008347;
const double  PixelWidth=0.005008347;
 
int filetype;
enum {P2, P3, P5, P6};  /* possible file types */
 
/* gives position of point (iX,iY) in 1D array  ; uses also global variables */
unsigned int f(unsigned int _iX, unsigned int _iY)
{return (_iX + (iYmax-_iY-1)*iXmax );}
 
/* 
* Read from a PPM or PGM (binary) file 
* Output is a array of GLubyte 
*/
void readPPM (char *filename, GLubyte **pic) {
 
        FILE *fp;
        char line[MAXLINE];
        int i, j, size, rowsize;
        GLubyte *ptr;
 
/* Read in file type */
 
  fp = fopen(filename, "r"); /* in Unix rb = r */
  if (fp==NULL) printf("I can't open %s file' !\n", filename);
  else printf("File %s has been opened !\n", filename);
  /* Each file starts with aa two-byte magic number (in ASCII) that explains :
   * - the type of file it is (PBM, PGM, and PPM) 
   * - its encoding (ASCII or binary). 
   * The magic number is a capital P followed by a single digit number. 
  */
  fgets (line, MAXLINE, fp); /* 1st line : Magic Number  */
  switch (line[1])
  {
   case '2':
       filetype = P2; 
       printf("This is PGM text file (P2) !\n");
       break;
   case '3' :
      filetype = P3;
      printf("This is PPM text file (P3) !\n");
      break; 
   case '5':
       filetype = P5; 
       printf("This is PGM binary file (P5) !\n");
       break;
   case '6' :
      filetype = P6;
      printf("This is PPM binary file (P6) !\n");
      break;
   default : 
      printf("Error: need PPM or PGM file as input!\n");
      exit(1);
   }
 /* if this is a comment, read next line. Maybe in binary files ther is no comment ?*/
/* there maybe more then one line of comment */
 //fgets (line, MAXLINE, fp); 
 //if (line[0]=='#') /* 2nd line : comment, not used */
/* Read in width and height, & allocate space */
/* these 2 numbers should be in one line with space between them */
  fgets (line, MAXLINE, fp); /* 3nd line: width  and height */
  sscanf(line, "%d %d", &ImageWidth, &ImageHeight);
  printf ("iWidth = %d\n", ImageWidth);
  printf ("iHeight = %d\n",  ImageHeight);
  iXmax=ImageWidth-1;
  iYmax=ImageHeight-1;
 
  if (filetype == P5) {
          size = ImageHeight * ImageWidth; /* greymap: 1 byte per pixel */
          rowsize = ImageWidth;
  }
  else /* filetype == P6 */ {
          size = ImageHeight * ImageWidth * 3; /* pixmap: 3 bytes per pixel */
          rowsize = ImageWidth * 3;
  }
  *pic = (GLubyte *)malloc (size); /* create dynamic array */
 
/* Read in maximum value (ignore) */
  fgets (line, MAXLINE, fp); /* 3rd line */
 
  if (filetype==P5 || filetype==P6){
    /* Read in the pixel array row-by-row: 1st row = top scanline */
    ptr = *pic + (ImageHeight-1) * rowsize;
    for (i = ImageHeight; i > 0; i--) {
          /* For binary File I/O you use fread and fwrite */
          j = fread((void *)ptr, 1, rowsize, fp); 
          ptr -= rowsize;
    }
   printf("File %s has been read !\n", filename);
  }
  else printf("Error: I can't read %s file !\n", filename);
  fclose(fp);
  printf("File %s has been closed !\n", filename);
}
 
 
 
 
 
 
/* Draw the picture on the screen */
 
void Draw(void) {
        /* black background of GLUT window */
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our window to red
        glClear(GL_COLOR_BUFFER_BIT); //Clear the colour buffer (more buffers later on)
        glLoadIdentity(); // Load the Identity Matrix to reset our drawing locations
        glFlush(); // Flush the OpenGL buffers to the window
 
        glRasterPos2i(0, 0);
 
        switch (filetype){
          case P5 :     /* greymap: use as illumination values */
                glDrawPixels(ImageWidth, ImageHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, Picture);
                printf("Image has been drawn !\n");
                break;
          case  P6 :
                glDrawPixels(ImageWidth, ImageHeight, GL_RGB, GL_UNSIGNED_BYTE, Picture);
                printf("Image has been drawn !\n");
                break;
         default : 
                printf("Error: There is no image to draw !\n");
          }
}
 
 
 
 
 
void Motion(int x, int y) {
 
   double Zx,Zy;
   int index;
   GLubyte Gray;
 
   /* invert y axis */
   y = glutGet(GLUT_WINDOW_HEIGHT) - y;
   index=f(x,y); 
   Gray=Picture[index];
  /* convert pixel/screen coordinate to world/double coordinate */
   Zy=ZyMin + y*PixelHeight; 
   if (fabs(Zy)<PixelHeight/2) Zy=0.0; 
   Zx=ZxMin + x*PixelWidth;
 
   /* prints to console */
   if ((filetype==P5 || filetype==P6) && -1<x && x< ImageWidth  && y<ImageHeight)
   printf("iX=%3d  iY=%3d Zx=%2.9f Zy= %2.9f  Gray=%3d \n", x, y,Zx,Zy,Gray);
}
 
 
 
 
static void Key(unsigned char key, int x, int y)
{
    switch (key) {
        case 27:  /* esc */
        case 'q':
        case 'Q':exit(1);
        default: return ;
    }
}
 
 
 
/* Resize the picture  */
 
void Reshape(GLint w, GLint h) {
    /* the viewport is the rectangular region of the window where the image is drawn */ 
    glViewport(0, 0, ImageWidth-1, ImageHeight-1); 
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, ImageWidth-1, 0, ImageHeight-1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
 
 
 
 
 
/* Initialization: create window */
void MyInit(void) {
  glutInitWindowPosition(0, 0); 
  glutInitWindowSize(ImageWidth, ImageHeight);
  glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
  if (glutCreateWindow("Image") == GL_FALSE) exit(1);
 
}
 
 
/* ------------------ Main program ---------------------------------------*/
int main(int argc, char **argv)
{
  char filename[MAXLINE];
 
  /* Read in the file (allocates space for Picture) */
  if (argc < 2) 
    {
        printf ("Enter the name of a PPM or PGM file: ");
        scanf("%s", filename);
        readPPM ((char *)filename, &Picture);
    }
    else { readPPM (argv[1], &Picture); }
 
    glutInit(&argc, argv);
    MyInit();
    glutPassiveMotionFunc(Motion);
    glutReshapeFunc(Reshape);
    glutDisplayFunc(Draw);
    glutKeyboardFunc(Key);
 
    glutMainLoop();
    return 0;
}

See also

References

  1. The Computer Language Benchmarks Game
  2. Sigel disc in Matlab by Chris King
  3. A short Introducion to PAR Files by Laurent Chabin
  4. julian haight : filmer instructions
  5. Fractint doc index
  6. Fractint par files by Rupert Russell
  7. fractint Image Calculation Parameters
  8. [Fractint] FOTD 27-07-11 (Bad Moon on the Rise [No Rating])
  9. Gnu Parallel
  10. Moebius transformation animated GIFs by Fritz Mueller
  11. How this video was made by Mukund
  12. mini-fract in Lisp by Yannick Gingras
  13. wikibooks help about converting video : ffmpeg2theora
↑Jump back a section
Last modified on 26 August 2012, at 13:53