Fractals/Computer graphic techniques/2D/gfile

< Fractals < Computer graphic techniques < 2D
                                                                                           "Any computer-generated picture is a finite collection of pixels." ( A Dudko, M Yampolsky)[1]


Graphic files


One can :

Types of graphic files :

Static images

Raster files

PGM image file and C++ program by Ilya Voyager

bmp

jpeg

pgm

// create 1D array
 iLength = iWidth*iHeight; // size = number of points in array  
  /* create dynamic 1D arrays for colors ( shades of gray ) */
  
  data = malloc( iLength * sizeof(unsigned char) );
  
  if (data == NULL )
    {
      fprintf(stderr," Could not allocate memory\n");
      return 1;
    }
  

// save data array to pgm file 
int SaveArray2PGMFile( unsigned char A[], double k, char* comment )
{
  
  FILE * fp;
  const unsigned int MaxColorComponentValue=255; /* color component is coded from 0 to 255 ;  it is 8 bit color file */
  char name [100]; /* name of file */
  snprintf(name, sizeof name, "%.0f", k); /*  */
  char *filename =strncat(name,".pgm", 4);
  
  
  
  /* save image to the pgm file  */      
  fp= fopen(filename,"wb"); /*create new file,give it a name and open it in binary mode  */
  fprintf(fp,"P5\n # %s\n %u %u\n %u\n", comment, iWidth, iHeight, MaxColorComponentValue);  /*write header to the file*/
  fwrite(A,iLength,1,fp);  /*write image data bytes to the file in one step */
  
  //
  printf("File %s saved. \n", filename);
  //if (comment == NULL)  printf ("empty comment \n");
  //                 else printf (" comment = %s \n", comment); 
  fclose(fp);

  return 0;
}



// free memory
free(data);

ppm

P3
#the P3 means colors are in ascii, then 3 columns and 2 rows, then 255 for max color, then RGB triplets
3 2
255
255 0 0
0 255 0
0 0 255
255 255 0
255 255 255
0 0 0

The image (expanded): w:Image:tiny6pixel.png

The above image was expanded without interpolation, using the imagemagick command

convert -sample %6400 tiny6pixel.ppm tiny6pixel.png

The P6 format of the same image will store each color component of each pixel with one byte (thus three bytes per pixel) in the order Red, Green then Blue. The file will be smaller but the color information will not be readable by humans:

P6
#any comment string
3 2
255
!@#$%^&*()_+|{}:"<

The PPM format is not compressed and thus requires more space and bandwidth than a compressed format would require. For example, the above 192x128 PNG image has a file size of 187 bytes. When converted to a 192x128 PPM image, the file size is 73848 bytes. The PPM format is generally an intermediate format used for image work before converting to a more efficient format, for example the PNG (Portable Network Graphics) format. The PPM format can be converted to PNG without loss of information.

The PPM format is certainly simple to write from scratch. The following Python code makes the above example image. It can be adapted to making useful images by reading or constructing an array of numerical data, and programming a conversion of the data to color triplets.

#!/usr/bin/python
triplets=[ [255, 0, 0], [0, 255, 0], [0, 0, 255], [255, 255, 0], [255, 255, 255], [0, 0, 0] ]
width=3; height=2
comment='any comment string'
ftype='P6' #use 'P3' for ascii, 'P6' for binary

ppmfile=open('testimage.ppm','wb')
ppmfile.write("%s\n" % (ftype)) 
ppmfile.write("#%s\n" % comment ) 
ppmfile.write("%d %d\n" % (width, height)) 
ppmfile.write("255\n")

if ftype=='P3':
    for red,green,blue in triplets:
        ppmfile.write("%d %d %d\n" % (red,green,blue)) 
elif ftype=='P6': #print 1 byte per color
    for red,green,blue in triplets:
        ppmfile.write("%c%c%c" % (red,green,blue))

ppmfile.close()

Similar code in C :

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define xor(a, b) (((!a && b)) || (a && !b))

int main (int argc, char * argv[]){

   /* Declare the variables */
   FILE* ppmFile;
   int columns, rows, numberOfPixelsInPicture;

   /* Check the input arguments */
   if(argc != 4){
      printf("Usage: %s cols rows fname.ppm\n\n", *argv);
      return 1;
   }

   /* Open the file and write the first 4 lines to it */
   ppmFile = fopen(argv[3], "w");
   columns = atoi(argv[1]);
   rows = atoi(argv[2]);
   numberOfPixelsInPicture = rows * columns;
   fprintf(ppmFile, "P3\n%d\n%d\n255\n", columns, rows);

   int m, n;
   for(m=0;m<rows;m++) {
      for(n=0;n<columns;n++) {
         /* Set the pixels in the bottom left of the picture a green-yellow color */
         if(m>n) {
            fprintf(ppmFile, "%d 255 %d\n", (256*m)/rows, (256*n)/columns);
         } else if(xor((m/10)%2,(n/10)%2)) {
            /* Create a checkerboard pattern in the upper-right of the picture */
            /* Create the blue-red pixels in the checkerboard pattern */
            fprintf(ppmFile, "%d 0 %d\n", (255*m*n)/numberOfPixelsInPicture, 255 -(255*m*n)/numberOfPixelsInPicture);
         } else {
            /* Create the black pixels in the checkerboard pattern */
            fprintf(ppmFile, "0 0 0\n");
         }
      }
      /* Print a blank line between rows */
      fprintf(ppmFile, "\n");
   }

   fclose(ppmFile);
   return 0;
}


Assembler code

; 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 code

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 :

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

C code : 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;
}

C code : 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 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


Python code

#!/usr/bin/python
# -*- coding: utf8 -*-
# code by User:Geek3
# https://commons.wikimedia.org/wiki/User:Geek3/ImageScripting
# use the PNM format (http://en.wikipedia.org/wiki/Netpbm_format)
# no need for external libraries

import colorsys
from math import *


width, height = 800, 600

# create header
image = open('pnm-example.ppm', 'w')
image.write('P3\n') # color image
image.write('{0} {1}\n'.format(width, height))
image.write('255\n')


def color(ix, iy):
    '''return color for specific position'''
    # create a rainbow ring
    rx = (ix + 0.5 - width / 2.) / 100.
    ry = (iy + 0.5 - height / 2.) / 100.
    angle = pi + atan2(rx, ry)
    amplitude = (rx**2 + ry**2) * exp(1 - (rx**2 + ry**2))
    return colorsys.hsv_to_rgb(angle / (2*pi), amplitude, 1)


for iy in range(height):
    for ix in range(width):
        c = color(ix, iy)
        image.write('{0} {1} {2}'.format(*[int(max(0, min(256*i, 255))) for i in c]))
        if (ix < width - 1):
            image.write(' ')
        else:
            image.write('\n')
	
image.close()

png

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

# 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

raw

Raw file format :

Example programs :

SVG


Moving images

Animated gif

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

#!/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


or another version by ClaudiusMaximus[8]

for i in ??.svg
do
  rsvg $i ${i%svg}png
  convert ${i%svg}png ${i%svg}gif
done
gifsicle --delay 4 --loop --optimize ??.gif > out.gif

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

MPEG


Steps from pgm to video using Image Magic convert :

convert -delay 100   -loop 0 %d.gif[0-25] a25.mpg

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

WebM


One can made a video from images. For examp

e creating WebM video files using ffmpeg [9][10]

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

or ffmpeg2theora[11]:

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  */

Graphic file documentation

Meta

EXIF

Comment


Using Image Magic :


Image Magic one can add comment to png image using mogrify :[15]

mogrify -comment "My test comment" p.png

or using convert :[16]

convert in.png \
        -set 'Copyright' 'CC-BY-SA 4.0' \
        -set 'Title' 'A wonderful day' \
        -set comment 'Photo taken while running' \
        out.png

To read comment from png :

identify -verbose p.png  | grep -i "comment:"
   comment: My test comment

or :

identify -format "%c" X.ppm

Chunk

A chunk is a fragment of information which is used in many multimedia formats, such as PNG, IFF, MP3 and AVI. Each chunk contains a header which indicates some parameters (e.g. the type of chunk, comments, size etc.) In the middle there is a variable area containing data which are decoded by the program from the parameters in the header.[17]

Text chunk is a one of standard ancillary PNG chunks. It's name is a tEXt.[18]


Standard keywords for PNG text chunks:

   Title            Short (one line) title or caption for image
   Author           Name of image's creator
   Description      Description of image (possibly long)
   Copyright        Copyright notice
   Creation Time    Time of original image creation
   Software         Software used to create the image
   Disclaimer       Legal disclaimer
   Warning          Warning of nature of content
   Source           Device used to create the image
   Comment          Miscellaneous comment; conversion from GIF comment

The ancillary chunks currently known to ImageMagick are bKGD, cHRM, gAMA, iCCP, oFFs, pHYs, sRGB, tEXt, tRNS, vpAg, and zTXt.


Example with convert from Image Magic :

convert in.png -define png:include-chunk=tEXt file.txt out.png

On can use pnmtopng utility :

pnmtopng -text file.txt 1000.pgm > 1000.png


where text file file.txt is :

Title            Short (one line) title or caption for image
Author           Name of image's creator
Description      Description of image (possibly long)
Copyright        Copyright notice
Creation Time    Time of original image creation
Software         Software used to create the image
Disclaimer       Legal disclaimer
Warning          Warning of nature of content
Source           Device used to create the image
Comment          Miscellaneous comment; conversion from GIF comment


png-text-embaded[19]

separate text file

Save pgm file and also text file with some description of the image:

// save "A" array to pgm file and info txt file
int SaveArray2PGMFile( unsigned char A[], double k, char* text)
{
 
  FILE * fp;
  const unsigned int MaxColorComponentValue=255; /* color component is coded from 0 to 255 ;  it is 8 bit color file */
  char name [100]; /* name of file  , error Naruszenie ochrony pamięci  */
  snprintf(name, sizeof name, "%f", k); /*  */
  char *filename =strncat(name,".pgm", 4);
  char *comment="# ";/* comment should start with # */
 
 
  /* save image to the pgm file  */      
  fp= fopen(filename,"wb"); /*create new file,give it a name and open it in binary mode  */
  fprintf(fp,"P5\n %s\n %u %u\n %u\n",comment,iWidth,iHeight,MaxColorComponentValue);  /*write header to the file*/
  fwrite(A,iLength,1,fp);  /*write A array to the file in one step */
  printf("File %s saved. \n", filename);
  fclose(fp);

  // save info text filename
 filename =strcat(name,".txt");
 fp= fopen(filename,"wb");
 
 fprintf(fp,"This  image shows rectangle part of dynamic plane of discrete complex dynamical system  z(n+1) = fc(zn) \n");
 fprintf(fp," where  fc(z)= z^2 + c \n");
 fprintf(fp,"with numerical approximation of parabolic Julia set \n\n");
 
 fprintf(fp,"parameter c is a root point between iPeriodParent = %d and iPeriodOfChild  = %d hyperbolic components of Mandelbrot set \n", iPeriodParent , iPeriodChild);
 fprintf(fp,"on the end of the internal ray of parent component of Mandelbrot set with angle = 1/%d in turns \n", iPeriodChild);
 fprintf(fp," c = ( %f ; %f ) \n", Cx, Cy); 
 fprintf(fp," \n");
 fprintf(fp,"critical point z = Zcr= ( %f ; %f )  \n", creal(Zcr), cimag(Zcr)); 
 fprintf(fp,"parabolic alfa fixed point z = ZA = ( %f ; %f )  \n", creal(ZA), cimag(ZA)); 
 fprintf(fp," radius around parabolic fixed point AR =  %.16f ; Pixel width = %.16f   \n", AR, PixelWidth);
 fprintf(fp," iMaxN =  %d ; ARn = %.16f \n",iMaxN, ARn);    // info 
 fprintf(fp," EscapeRadius ER =  %f ; \n", EscapeRadius);
 fprintf(fp," Fatou coordinate U(Zcr) = Ux0 =  %f ; \n", Ux0);
 fprintf(fp," Maxima number of iterations : iMax = %d \n\n", iMax);
 fprintf(fp," Image shows rectangular part of  dynamic plane  with %s\n", text);
 fprintf(fp," from ZxMin = %f to ZxMax = %f\n", ZxMin, ZxMax);
 fprintf(fp," from ZyMin = %f to ZyMax = %f\n\n", ZyMin, ZyMax);
 fprintf(fp," iWidth = %d and iHeight = %d\n", iWidth, iHeight);
 fprintf(fp," distortion = %f ; It should be 1.0 \n", ((ZxMax-ZxMin)/(ZyMax -ZyMin)/(iWidth/iHeight)));
 if (t==0) fprintf(fp," No lost pixels : t = %d ; Parameters iMax and AR are good \n",t);
    else fprintf(fp," Error : there are lost pixels : t > 0 ; you should increase iMax or make bigger AR \n\n"); 
 fprintf(fp," computations made with double type numbers \n\n");
 fprintf(fp,"use (k+AR) for file names where k is a number of file ; range(k) =[0,k] so there are (k+1) png files nad (k+1) text files \n\n");
 fprintf(fp,"made with c console program  \n");
 //

 printf("File %s saved. \n", filename);
 fclose(fp); 


  return 0;
}

Parameter files

Dot

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

fractint parfiles

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

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 :


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. [24]The reset=1730 in the parameter file shows that it was created with 17.3 version of Fractint. [25]

Viewer for programmers

This program :

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).

It not works for newest version of OpenGl.

/* 
 * 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


http://web.eecs.umich.edu/~sugih/courses/eecs487/glut-howto/sample.c

  // gcc v.c -lm -lGLU -lglut -Wall // ? windows 
    gcc v.c -lm -lglut -lGL -lGLU -Wall // ubuntu 
  ./a.out 5.pgm

 */

/*

locate glut.h
/usr/include/GL/freeglut.h
/usr/include/GL/glut.h

#ifdef FREEGLUT
#include <GL/freeglut.h>
#else
#include <GL/glut.h>
#endif

*/



//#include <Windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
//#include <GL/glut.h> // oryginal glut 
#include <GL/freeglut.h> // freeglut 
#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 */

/*

3.2 Conventions

In developing the freeglut library, we have taken careful steps to ensure consistency in function operation across the board, 
in such a manner as to maintain compatibility with GLUT's behavior whenever possible. In this section some of the important conventions of FreeGLUT, 
and their compatibility with GLUT, are made explicit.

3.2.1 Window placement and size

There is considerable confusion about the "right thing to do" concerning window size and position. GLUT itself is not consistent between Windows and UNIX/X11; 
since platform independence is a virtue for freeglut, we decided to break with GLUT's behaviour. 
Under UNIX/X11, it is apparently not possible to get the window border sizes in order to subtract them off the window's initial position until some time after the window has been created. 
Therefore we decided on the following behavior, both under Windows and under UNIX/X11:

When you create a window with position (x,y) and size (w,h), the upper left hand corner of the outside of the window (the non-client area) is at (x,y) and the size of the drawable (client) area is (w,h). 
The coordinates taken by glutInitPosition and glutPositionWindow, as well as the coordinates provided by FreeGLUT when it calls the glutPositionFunc callback, specify the top-left of the non-client area of the window.
When you query the size and position of the window using glutGet, FreeGLUT will return the size of the drawable area
--the (w,h) that you specified when you created the window
--and the coordinates of the upper left hand corner of the drawable (client) area
--which is NOT the (x,y) position of the window you specified when you created it.




*/




GLint ImageWidth, ImageHeight;	         /* size of the Image in pixels */
GLint WindowWidth, WindowHeight;	/* size of the window in pixels */
GLint MaxScreenWidth, MaxScreenHeight;	/* size of the screen in pixels */


GLubyte *Picture;	/* Array of colors (GLubyte)  */
int size; 



// mouse position as a global variables 
//static float mx=0.0f,my=0.0f ;
int iX, iY; // 
int centerX = 200, centerY = 200;
GLint iYmax,iXmax; // mouse coordinate inside image 

unsigned char pixel[3];

// change it manually !!!!!


const double  ZyMin=-1.0;
const double  ZxMin=-2.0;
const double  PixelHeight=0.0020010005002501  ;
const double  PixelWidth=0.0020010005002501  ;

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, rowsize;
        // int size; // moved to global var 
        int j ;
	GLubyte *ptr;

/* Read in file type */
  
  fp = fopen(filename, "r"); /* in Unix rb = r */
  if (fp==NULL) {perror(" perror : " ); printf("Error from fopen : I can't open %s file' ! ", filename); exit(1); }
  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), but now I do not have procedure for opening it \n");
       break;
   case '3' :
      filetype = P3;
      printf("This is PPM text file (P3), but now I do not have procedure for opening it !\n");
      break; 
   case '5':
       filetype = P5; 
       printf("This is PGM binary file (P5) and I can open it !\n");
       break;
   case '6' :
      filetype = P6;
      printf("This is PPM binary file (P6) and I can open it !\n");
      break;
   default : 
      printf("Error from readPPM : need binary PPM or binary PGM file as input!\n");
      exit(1);
   }
 /* if this is a comment, read next line. Maybe in binary files there is no comment ?*/
/* there maybe more then one line of comment */
 fgets (line, MAXLINE, fp); 
 while  (line[0]=='#') 
  { printf(" comment  = %s \n", line); /* 2nd or more line  starting with # =  comment, print it   */
    fgets (line, MAXLINE, fp); // read next line 
  } 

/* Read in width and height, & allocate space */
/* these 2 numbers should be in one line with space between them */
   /* 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); /* next  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;
    }
   if (j) printf("File %s has been read !\n", filename);
          else printf(" j Error from readPPM procedure : I can't read %d file !.\n", j);
  }
  else printf("Error from readPPM procedure : I can't read %s file !. It should be P5 or P6 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 black
        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
        // left lower corner of displayed image 
	glRasterPos2i(-1,-1); // By default, OpenGL assumes a system running from -1 to 1, 
        switch (filetype){
          case P5 : 	/* greymap: use as illumination values */
		glDrawPixels(ImageWidth, ImageHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, Picture);
                printf("P5 Image has been drawn !\n");
                break;
	  case  P6 :
		glDrawPixels(ImageWidth, ImageHeight, GL_RGB, GL_UNSIGNED_BYTE, Picture);
                printf("P6 Image has been drawn !\n");
                break;
         default : 
                printf("Error from Draw procedure : There is no image to draw !\n");
          }


       
}




// Detecting Mouse Clicks
// x and y specify the location (in window-relative coordinates) of the mouse when
// the event occurred
void MouseClicks (int button, int state, int x, int y)
{
switch (button)
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
// do something
case GLUT_RIGHT_BUTTON: ;
// etc., etc.
}





// mouse motion 
//The x and y callback parameters 
// indicate the  mouse  location 
// in window relative coordinates
//
// x, y –> coordinates of the mouse relative to upper left corner of window

// setting the mouse position to be relative to the mouse
// position inside the window
//

void PassiveMouseMotion(int x, int y) {
  
   //double Zx,Zy;
   //double Ux; 
   //int index;
   //GLubyte Gray;

   // put your code here  ???? 
   iX = x;
   /* invert y axis */
   iY = WindowHeight - y -1 ; //+ (glutGet(GLUT_WINDOW_HEIGHT) - ImageHeight); ///glutGet(GLUT_WINDOW_HEIGHT) - y; // ????
   
  

   
   /* output : prints to console  */
  if ((filetype==P5 || filetype==P6) && -1<iX && iX< ImageWidth  && iY<ImageHeight) // && iY<ImageHeight
   {

     
     glReadPixels(iX, iY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixel);
   // pixel coordinates of the mouse relative to upper left corner of window
   printf(" pixel iX=%3d / %d ;  iY=%3d  color = %d  \n", iX, MaxScreenWidth,  iY, pixel[1] );
  }
}




static void Key(unsigned char key, int x, int y)
{
    switch (key) {
	case 27 : {glutLeaveFullScreen(); break;}/* esc */
        case 'f': {glutFullScreen(); break; }
        case 'q': {printf("Key preseed and exit \n"); exit(1) ;}
        case 'Q': {printf("Key preseed and exit \n"); exit(1) ;}
        case 't': {glutFullScreenToggle(); break; } // GLUT does not include the glutLeaveFullScreen and glutFullScreenToggle functions from freeglut 
	default: return ;
    }
}



/* 
 Resize the picture  ; OpenGL calls this function whenever the window is resized 
 Called when window is resized,  also when window is first created,    before the first call to display().
*/
void Reshape(GLint w, GLint h) {

/* save new screen dimensions */
     WindowWidth = w;
     WindowHeight = h;
    /* the viewport is the rectangular region of the window where the image is drawn */
   // Viewport : A rectangular region in the screen for display  (in screen coordinate system) 
    glViewport(0, 0, ImageWidth-1, ImageHeight-1); // glViewport( 0.f, 0.f, SCREEN_WIDTH, SCREEN_HEIGHT );
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    // Define a world window : A rectangular region in the world that is to be displayed (in world coordinate system)
    // By default, OpenGL assumes a system running from -1 to 1, 
    gluOrtho2D(-1, 1, -1, 1); // An orthographic projection is basically a 3D projection that does not have perspective
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}





/* 
Initialization: create window 
glutInitWindowSize(600, 600);
*/
void MyInit(int argc, char *argv[]) {
    char filename[MAXLINE];
  
  /* Read in the file (allocates space for Picture) */
  if (argc < 2) 
    {
	printf ("Enter the name of a binary PPM or PGM file: ");
	scanf("%s", filename);
	readPPM ((char *)filename, &Picture);
    }
    else { readPPM (argv[1], &Picture); }
  
  glutInit(&argc, argv);

  MaxScreenWidth  = glutGet(GLUT_SCREEN_WIDTH);
  MaxScreenHeight = glutGet(GLUT_SCREEN_HEIGHT);   
    
  glutInitWindowPosition(-1, 1); // upper  left  corner
  glutInitWindowSize(MaxScreenWidth, MaxScreenHeight ); // full screen of my monitor
 
  glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
  if (glutCreateWindow("OpenGl binary pgm/ppm Image viewer ") == GL_FALSE) 
      {printf("Error from  MyInit , glutCreateWindow\n"); exit(1);}
       
}


/* ------------------ Main program ---------------------------------------*/
int main(int argc, char **argv)
{
  
    MyInit(argc, argv);
    glutPassiveMotionFunc(PassiveMouseMotion); // mouse move with no key pressed 
    glutReshapeFunc(Reshape); //  move or resize of screen window 
    glutDisplayFunc(Draw); // 
    glutKeyboardFunc(Key);
    //
    glutMainLoop();
    return 0;
}

References

  1. [Computability of the Feigenbaum Julia set by Artem Dudko, Michael Yampolsky ]
  2. The Computer Language Benchmarks Game
  3. Sigel disc in Matlab by Chris King
  4. [:w:Raw image format|Raw image format in wikipedia]
  5. Faking distance estimate colouring by Claude Heiland-Allen
  6. Gnu Parallel
  7. Moebius transformation animated GIFs by Fritz Mueller
  8. ReCode Project - Topographic Form animated by ClaudiusMaximus
  9. How this video was made by Mukund
  10. mini-fract in Lisp by Yannick Gingras
  11. wikibooks help about converting video : ffmpeg2theora
  12. [pngmeta]
  13. PNG and exif
  14. Image Magic - escape
  15. Stackoverflow : How to add extra meta data to PNG?
  16. Stackoverflow : Insert a text chunk into a png image
  17. wikipedia : Chunk (information)
  18. PNG (Portable Network Graphics) Specification, Version 1.2 : chunk
  19. https://github.com/gbenison/png-text-embed
  20. A short Introducion to PAR Files by Laurent Chabin
  21. julian haight : filmer instructions
  22. Fractint doc index
  23. Fractint par files by Rupert Russell
  24. fractint Image Calculation Parameters
  25. [Fractint] FOTD 27-07-11 (Bad Moon on the Rise [No Rating])
This article is issued from Wikibooks. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.