The sample images in the project are the work and copyright of Birdy...

When Tweety is run, it opens a dialog allowing you to to load an image. You can do this at any time with the Load Image button.

The display shows a preview of what Tweety will do when you click Save Image, and the Dimensions field shows its width and height in Pixels.

Tweety's main interface

Dimensions

You can change the width and/or height to save the image at the new size. You only need to supply a width or a height, as Tweety computes them to keep the Aspect Ratio of the image.

eg. 'W800' will save a 800x600 image, or 'H768' will save a 1024x768 image.

Deliberately specifying both width and height will stretch the image to the new dimensions.

The Options Dialog

Selecting one of the buttons changes the preview of the image.

Grey

Grey does a simple Colour Brightness average and produces a greyscale image similar to what you'd see on a black-and-white TV, simply removing the colour.

Tint

Tint transforms the image to Grey first, and then applies amounts of Red, Green and Blue from the sliders to apply a colour change like a coloured transparency over it. Bottoming out all the sliders will result in a black image.

B & W

B & W uses a formula to calculate how much white light would fall on a theoretical monochromatic photo plate at any point. It compensates for the green-red bias and computes the exposure level controlled by the Gain slider.

A Gain of 1 provides an equivalent to a Grey image when the Watershed slider is in the middle.

Watershed is the point at which a part of the image will either expose the emulsion or not, in effect describing the darkest colour that would show up on the photo, and is set to 50% Black as standard.

Original

Simply shows the original unmodified image.

Crop Region

Crop Region saves just that part of the image to a picture with the dimensions specified.

The Crop Region can also be used to deform all or part of an image.

Holding the CTRL, Shift or Alt keys while dragging a handle allows that handle to move freely to make a polygon instead of a rectangle. If for example the image contains a plane surface that has been photographed from an angle, the Crop Region can correct the Parallax Distortion and produce a rectangular picture from the deformed image.

Before and after processing.


To run Tweety you will need a folder containing at least 'tweety.py' and 'tweetypie', the interface and main code respectively. You will also need a working installation of Python 2.x with Tkinter and the Python Imaging Library. There is a zip file in the downloads with a pre-compiled version for Linux, however it should work on Windows or Mac with a little modification. It uses TKinter to handle the interface.

#!/usr/bin/env python

from PIL import Image as image
from Tkinter import *
import tkFileDialog
from subprocess import Popen,PIPE
from time import sleep
from os import remove

window=Tk()
window.title('Tweety Photo Image Enhancer')

#---------------------------------------------------------------------------------------------------------
# functions
#---------------------------------------------------------------------------------------------------------

def __clickitem(event,src):
  global drag,dragx,dragy
  if src[:6]=='handle':
    i=int(src[6:])
    canvas.itemconfigure(src,fill='#ff0000')
    drag=src; dragx=event.x; dragy=event.y
  if src=='screen':
    for i in range(4):
      canvas.itemconfigure('handle'+str(i),fill='#ffff00')
        
#---------------------------------------------------------------------------------------------------------

def __unclickitem(event,src):
  global drag,dragx,dragy,cropped,x1,y1,x2,y2,x3,y3,x4,y4
  if drag==src:
    cropped=True
    dx=event.x-dragx;dy=event.y-dragy
    canvas.move(src,dx,dy)
    cc=canvas.coords('cursor')
    x1=canvas.coords('handle0')[0]-3;y1=canvas.coords('handle0')[1]-3
    x2=canvas.coords('handle1')[2]-3;y2=canvas.coords('handle1')[1]-3
    x3=canvas.coords('handle2')[2]-3;y3=canvas.coords('handle2')[3]-3
    x4=canvas.coords('handle3')[0]-3;y4=canvas.coords('handle3')[3]-3
    if event.state!=276:
      i=int(src[6:])
      if i==0:
        y2=y1; x4=x1
      if i==1:
        y1=y2; x3=x2
      if i==2:
        y4=y3; x2=x3
      if i==3:
        y3=y4; x1=x4
    if x1<0: x1=0
    if y1<0: y1=0
    if x1>799: x1=799
    if y1>599: y1=599
    if x2<0: x2=0
    if y2<0: y2=0
    if x2>799: x2=799
    if y2>599: y2=599
    if x3<0: x3=0
    if y3<0: y3=0
    if x3>799: x3=799
    if y3>599: y3=599
    if x4<0: x4=0
    if y4<0: y4=0
    if x4>799: x4=799
    if y4>599: y4=599
    canvas.coords('cursor',3+x1,3+y1,3+x2,3+y2,3+x3,3+y3,3+x4,3+y4)
    canvas.coords('handle0',3+x1,3+y1,3+x1+8,3+y1+8)
    canvas.coords('handle1',3+x2-8,3+y2,3+x2,3+y2+8)
    canvas.coords('handle2',3+x3-8,3+y3-8,3+x3,3+y3)
    canvas.coords('handle3',3+x4,3+y4-8,3+x4+8,3+y4)
    drag=''
  if src[:6]=='handle':
    i=int(src[6:])
    canvas.itemconfigure(src,fill='#ffff00')
  if src=='screen':
    for i in range(4):
      canvas.itemconfigure('handle'+str(i),fill='#ffff00')
        
#---------------------------------------------------------------------------------------------------------

def __mouseoveritem(event,src):
  global drag,dragx,dragy,cropped,x1,y1,x2,y2,x3,y3,x4,y4
  if drag==src:
    dx=event.x-dragx;dy=event.y-dragy
    canvas.move(src,dx,dy)
    cc=canvas.coords('cursor')
    x1=canvas.coords('handle0')[0]-3;y1=canvas.coords('handle0')[1]-3
    x2=canvas.coords('handle1')[2]-3;y2=canvas.coords('handle1')[1]-3
    x3=canvas.coords('handle2')[2]-3;y3=canvas.coords('handle2')[3]-3
    x4=canvas.coords('handle3')[0]-3;y4=canvas.coords('handle3')[3]-3
    if event.state!=276:
      i=int(src[6:])
      if i==0:
        y2=y1; x4=x1
      if i==1:
        y1=y2; x3=x2
      if i==2:
        y4=y3; x2=x3
      if i==3:
        y3=y4; x1=x4
    if x1<0: x1=0
    if y1<0: y1=0
    if x1>799: x1=799
    if y1>599: y1=599
    if x2<0: x2=0
    if y2<0: y2=0
    if x2>799: x2=799
    if y2>599: y2=599
    if x3<0: x3=0
    if y3<0: y3=0
    if x3>799: x3=799
    if y3>599: y3=599
    if x4<0: x4=0
    if y4<0: y4=0
    if x4>799: x4=799
    if y4>599: y4=599
    canvas.coords('cursor',3+x1,3+y1,3+x2,3+y2,3+x3,3+y3,3+x4,3+y4)
    canvas.coords('handle0',3+x1,3+y1,3+x1+8,3+y1+8)
    canvas.coords('handle1',3+x2-8,3+y2,3+x2,3+y2+8)
    canvas.coords('handle2',3+x3-8,3+y3-8,3+x3,3+y3)
    canvas.coords('handle3',3+x4,3+y4-8,3+x4+8,3+y4)
    dragx=event.x;dragy=event.y
#  print event,src
#  if src[:6]=='handle':
#    i=int(src[6:])
#    canvas.itemconfigure(src,fill='#ff0000')
  if src=='screen':
    for i in range(4):
      canvas.itemconfigure('handle'+str(i),fill='#ffff00')
        
#---------------------------------------------------------------------------------------------------------

def loadimg(hidedlg=False):
  global dimensions,canvas,gamma,delta,filename,mode,redscr,grnscr,bluscr,x1,y1,x2,y2,x3,y3,x4,y4,cropped,scrw,scrh
  if not hidedlg:
#    x1=0;y1=0;x2=799;y2=0;x3=799;y3=599;x4=0;y4=599
    filename=tkFileDialog.askopenfilename(defaultextension='.jpg',title='Open Photo',filetypes=[('Image Files','*.jpg'),('Image Files','*.JPG')])
  if filename:
    im=image.open(filename)
    w=im.size[0]; h=im.size[1]
    dw=w;dh=h
    if w>800:
      h=h*(800.0/w); w=800
    if h>600:
      w=w*(600.0/h); h=600
    canvas.config(width=int(w)+4,height=int(h)+4)
    if not hidedlg: 
      x1=0;y1=0;x2=w;y2=0;x3=w;y3=h;x4=0;y4=h
    im=im.resize((int(w),int(h)))
    im.save('tweetyin.ppm') #gim.save('tweety.ppm')
    (d,d)=delta.get()
    (gm,gm)=gamma.get()
    (r,r)=redscr.get(); r=1.0-r
    (g,g)=grnscr.get(); g=1.0-g
    (b,b)=bluscr.get(); b=1.0-b
    if mode=='-orig': Popen(['./tweetypie','tweetyin.ppm','-o','tweetyout.ppm','-orig','-q'])
    if mode=='-bw': Popen(['./tweetypie','tweetyin.ppm','-o','tweetyout.ppm','-bw','-gamma',str(gm*10),'-delta',str(d),'-q'])
    if mode=='-grey': Popen(['./tweetypie','tweetyin.ppm','-o','tweetyout.ppm','-grey','-q'])
    if mode=='-tint': Popen(['./tweetypie','tweetyin.ppm','-o','tweetyout.ppm','-grey','-tint',str(r),str(g),str(b),'-q'])
    fs=0
    while fs<(w*h*3):
      try:
        fhdl=open('tweetyout.ppm','rb')
        fhdl.seek(0,2)
        fs=fhdl.tell()
        fhdl.close()
      except: sleep(0.1)
    timg=PhotoImage(file='tweetyout.ppm')
    if not hidedlg: dimensions.set('W'+str(dw)+' H'+str(dh))
    canvas.delete('screen')
    canvas.delete('cursor')
    canvas.delete('handle0');canvas.delete('handle1');canvas.delete('handle2');canvas.delete('handle3');
    canvas.create_image(int(w/2)+4,int(h/2)+4,image=timg,tag='screen')
    canvas.background=timg
    c=[3+x1,3+y1,3+x2,3+y2,3+x3,3+y3,3+x4,3+y4]
    canvas.create_polygon(c,fill='',outline='#ffff00',tag='cursor')
    canvas.create_rectangle(3+x1,3+y1,3+x1+8,3+y1+8,fill='#ffff00',outline='#ffff00',tag='handle0')
    canvas.create_rectangle(3+x2-8,3+y2,3+x2,3+y2+8,fill='#ffff00',outline='#ffff00',tag='handle1')
    canvas.create_rectangle(3+x3-8,3+y3-8,3+x3,3+y3,fill='#ffff00',outline='#ffff00',tag='handle2')
    canvas.create_rectangle(3+x4,3+y4-8,3+x4+8,3+y4,fill='#ffff00',outline='#ffff00',tag='handle3')
    for n in range(4):
      def starthandle(event,n='handle'+str(n)):
        return __clickitem(event,n)
      def endhandle(event,n='handle'+str(n)):
        return __unclickitem(event,n)
      def motionhandle(event,n='handle'+str(n)):
        return __mouseoveritem(event,n)
      canvas.tag_bind('handle'+str(n),'<Button-1>',starthandle)
      canvas.tag_bind('handle'+str(n),'<ButtonRelease-1>',endhandle)
      canvas.tag_bind('handle'+str(n),'<Motion>',motionhandle)
    def startscreen(event,n='screen'):
      return __clickitem(event,n)
    def endscreen(event,n='screen'):
      return __unclickitem(event,n)
    canvas.tag_bind('screen','<Button-1>',startscreen)
    canvas.tag_bind('screen','<ButtonRelease-1>',endscreen)
    canvas.tag_bind('screen','<Motion>',motionhandle)
    remove('tweetyin.ppm')
    remove('tweetyout.ppm')
    
#---------------------------------------------------------------------------------------------------------

def saveimg():
  global dimensions,canvas,gamma,delta,filename,mode,redscr,grnscr,bluscr,cropped
  if filename:
    newfilename=tkFileDialog.asksaveasfilename(defaultextension='.jpg',title='Save Photo',filetypes=[('Image Files','*.jpg')])
    if newfilename:
      im=image.open(filename)
      if cropped: im=cropimg(im)
      w=im.size[0]; h=im.size[1]
      d=dimensions.get().split()
      dw=w; dh=h
      if len(d)>1:
        dw=int(d[0][1:]); dh=int(d[1][1:])
      elif len(d)==1:
        if d[0][0].upper()=='W':
          dw=int(d[0][1:])
          dh=dw/(float(w)/h)
        if d[0][0].upper()=='H':
          dh=int(d[0][1:])
          dw=dh*(float(w)/h)
        if (d[0][0].upper()!='W' and d[0][0].upper()!='H'):
          dh=int(d[0][1:])
          dw=dh*(float(w)/h)
      im.save('tweetyin.ppm')
      (d,d)=delta.get()
      (gm,gm)=gamma.get()
      (r,r)=redscr.get(); r=1.0-r
      (g,g)=grnscr.get(); g=1.0-g
      (b,b)=bluscr.get(); b=1.0-b
      if mode=='-orig': Popen(['./tweetypie','tweetyin.ppm','-o','tweetyout.ppm','-orig','-q'])
      if mode=='-bw': Popen(['./tweetypie','tweetyin.ppm','-o','tweetyout.ppm','-bw','-gamma',str(gm*10),'-delta',str(d),'-q'])
      if mode=='-grey': Popen(['./tweetypie','tweetyin.ppm','-o','tweetyout.ppm','-grey','-q'])
      if mode=='-tint': Popen(['./tweetypie','tweetyin.ppm','-o','tweetyout.ppm','-grey','-tint',str(r),str(g),str(b),'-q'])
      fs=0
      while fs<(w*h*3):
        try:
          fhdl=open('tweetyout.ppm','rb')
          fhdl.seek(0,2)
          fs=fhdl.tell()
          fhdl.close()
        except: sleep(0.1)
      sim=image.open('tweetyout.ppm')
      sim=sim.resize((int(dw),int(dh)))#sim.thumbnail((dw,dh),image.ANTIALIAS)
      dimensions.set('W'+str(int(dw))+' H'+str(int(dh)))
      sim.save(newfilename)
      remove('tweetyin.ppm')
      remove('tweetyout.ppm')
      if filename==newfilename:
        mode='-orig'
        pushbtns.set('orig')
      x1=0;y1=0;x2=799;y2=0;x3=799;y3=599;x4=0;y4=599
      loadimg(True)

#---------------------------------------------------------------------------------------------------------

def deltascroll(event,sp1=0,sp2=0):
  global delta,scroll,filename
#  print event,sp1,sp2
  if event=='scroll':
    if sp2=='units': dt=int(sp1)/256.0
    if sp2=='pages': dt=int(sp1)/16.0
    (a,b)=delta.get()
    a+=dt; b+=dt;
    delta.set(a,b)
  if event=='moveto':
    a=float(sp1); b=a
    delta.set(a,b)
  if not scroll:
    scroll=True
    if filename: loadimg(True)
    scroll=False

#---------------------------------------------------------------------------------------------------------

def gammascroll(event,sp1=0,sp2=0):
  global gamma,scroll,filename
  if event=='scroll':
    if sp2=='units': dt=int(sp1)/100.0
    if sp2=='pages': dt=int(sp1)/10.0
    (a,b)=gamma.get()
    a+=dt; b+=dt;
    gamma.set(a,b)
  if event=='moveto':
    a=float(sp1); b=a
    gamma.set(a,b)
  if not scroll:
    scroll=True
    if filename: loadimg(True)
    scroll=False

#---------------------------------------------------------------------------------------------------------

def redscroll(event,sp1=0,sp2=0):
  global redscr,scroll,filename
  if event=='scroll':
    if sp2=='units': dt=int(sp1)/100.0
    if sp2=='pages': dt=int(sp1)/10.0
    (a,b)=redscr.get()
    a+=dt; b+=dt;
    redscr.set(a,b)
  if event=='moveto':
    a=float(sp1); b=a
    redscr.set(a,b)
  if not scroll:
    scroll=True
    if filename: loadimg(True)
    scroll=False

#---------------------------------------------------------------------------------------------------------

def grnscroll(event,sp1=0,sp2=0):
  global grnscr,scroll,filename
  if event=='scroll':
    if sp2=='units': dt=int(sp1)/100.0
    if sp2=='pages': dt=int(sp1)/10.0
    (a,b)=grnscr.get()
    a+=dt; b+=dt;
    grnscr.set(a,b)
  if event=='moveto':
    a=float(sp1); b=a
    grnscr.set(a,b)
  if not scroll:
    scroll=True
    if filename: loadimg(True)
    scroll=False

#---------------------------------------------------------------------------------------------------------

def bluscroll(event,sp1=0,sp2=0):
  global bluscr,scroll,filename
  if event=='scroll':
    if sp2=='units': dt=int(sp1)/100.0
    if sp2=='pages': dt=int(sp1)/10.0
    (a,b)=bluscr.get()
    a+=dt; b+=dt;
    bluscr.set(a,b)
  if event=='moveto':
    a=float(sp1); b=a
    bluscr.set(a,b)
  if not scroll:
    scroll=True
    if filename: loadimg(True)
    scroll=False
    
#---------------------------------------------------------------------------------------------------------

def chgmode():
  global pushbtns,mode,filename
  mode='-'+str(pushbtns.get())
  if filename: loadimg(True)
  
#---------------------------------------------------------------------------------------------------------

def cropimg(img):
  global x1,y1,x2,y2,x3,y3,x4,y4
  w=img.size[0]; h=img.size[1]
  if (x1==x4 and x2==x3 and y1==y2 and y3==y4):
    img=img.crop((int(x1*(w/800.0)),int(y1*(h/600.0)),int(x3*(w/800.0)),int(y3*(h/600.0))))
  else:
    print 'perspective crop'
    img=img.transform((w,h), image.QUAD, (int(x1*(w/800.0)),int(y1*(h/600.0)),int(x4*(w/800.0)),int(y4*(h/600.0)),int(x3*(w/800.0)),int(y3*(h/600.0)),int(x2*(w/800.0)),int(y2*(h/600.0))))
  return img

#---------------------------------------------------------------------------------------------------------
# main
#---------------------------------------------------------------------------------------------------------

try:
  remove('tweetyin.ppm')
except:
  sleep(0.1)
try:
  remove('tweetyout.ppm')
except:
  sleep(0.1)

frame=Frame(window); frame.grid()
dimensions=StringVar()
dimensions.set('W### H###')    
pushbtns=StringVar()
pushbtns.set('orig')    
mode='-orig'
canvas=Canvas(frame,width=804,height=604,bd=0); canvas.grid(column=0,row=0,columnspan=5)  
loadbtn=Button(frame,text='Load Image',command=loadimg); loadbtn.grid(column=0,row=1,sticky=E+W,rowspan=2)
savebtn=Button(frame,text='Save Image',command=saveimg); savebtn.grid(column=1,row=1,sticky=E+W,rowspan=2)
dimfld=Entry(frame,textvariable=dimensions,bg='#ffffff',width=10);dimfld.grid(column=2,row=1,sticky=N+S+E+W,rowspan=2)
dlg=Toplevel(window); dlg.transient(window); dlg.title('Options')
bwbtn=Radiobutton(dlg,text='B & W',value='bw',variable=pushbtns,indicatoron=0,padx=10,pady=5,command=chgmode); bwbtn.grid(column=0,row=0,sticky=N+S+E+W)
tintbtn=Radiobutton(dlg,text='Tint',value='tint',variable=pushbtns,indicatoron=0,padx=10,pady=5,command=chgmode); tintbtn.grid(column=1,row=0,sticky=N+S+E+W)
greybtn=Radiobutton(dlg,text='Grey',value='grey',variable=pushbtns,indicatoron=0,padx=10,pady=5,command=chgmode); greybtn.grid(column=0,row=1,sticky=N+S+E+W)
origbtn=Radiobutton(dlg,text='Original',value='orig',variable=pushbtns,indicatoron=0,padx=10,pady=5,command=chgmode); origbtn.grid(column=1,row=1,sticky=N+S+E+W)
gamma=Scrollbar(dlg,orient=HORIZONTAL,jump=1,width=23); gamma.grid(column=0,row=2,columnspan=2,sticky=N+S+E+W)
gamma['command']=gammascroll
gamma.set(0.1,0.1)
delta=Scrollbar(dlg,orient=HORIZONTAL,jump=1,width=23); delta.grid(column=0,row=3,columnspan=2,sticky=N+S+E+W)
delta['command']=deltascroll
delta.set(0.5,0.5)
redscr=Scrollbar(dlg,orient=VERTICAL,jump=1,width=23); redscr.grid(column=2,row=0,rowspan=4,sticky=N+S+E+W)
redscr['command']=redscroll
redscr.set(0.0,0.0)
grnscr=Scrollbar(dlg,orient=VERTICAL,jump=1,width=23); grnscr.grid(column=3,row=0,rowspan=4,sticky=N+S+E+W)
grnscr['command']=grnscroll
grnscr.set(0.0,0.0)
bluscr=Scrollbar(dlg,orient=VERTICAL,jump=1,width=23); bluscr.grid(column=4,row=0,rowspan=4,sticky=N+S+E+W)
bluscr['command']=bluscroll
bluscr.set(0.0,0.0)
x1=0;y1=0;x2=799;y2=0;x3=799;y3=599;x4=0;y4=599

filename=''
scroll=False
drag='';dragx=0;dragy=0
cropped=False

scrw=804;scrh=604

loadimg()

mainloop()
The code calls this C++ routine.
Usage: ./tweetypie <filename> -o <filename> -bw -grey -sepia -gamma # -delta # -tint # # # -v -q
-o          : Output File
-bw         : Black and White Photo
-grey       : Greyscale Image
-sepia      : Sepia Photo
-tint # # # : Tint Red (0-1) Green (0-1) Blue (0-1)
-gamma      : Contrast Level (1 - 10)
-delta      : Contrast Centre (0 - 1)
-v          : Verbose output
-q          : Quiet output
#include <iostream>
#include <string.h>
#include <fstream>
#include <cmath>

#define W 800
#define H 600
#define BP 3

using namespace std;

struct rgb {
int r;
int g;
int b;
};

char* outbuff;
char* inbuff;
char* hdr;
int hdrlen;
int buflen;

//=========================================================================================//

int filesize(char* filename) {
    std::ifstream in(filename, std::ifstream::in | std::ifstream::binary);
    in.seekg(0, ifstream::end);
    return in.tellg(); 
}

//=========================================================================================//

int putpix(int x, int y, rgb colour) {

  if (x<(W/2) and x>=-(W/2) and y<(H/2) and y>=-(H/2)) {
    int i=((x+(W/2))+((H-(y+(H/2)))*W))*3;
      if (i>=0 and i<W*H*BP) {
        outbuff[i]=colour.r;
        outbuff[i+1]=colour.g;
        outbuff[i+2]=colour.b;
      }
    } 
  return 0;
}

//=========================================================================================//

rgb getpix(int x, int y) {

  rgb colour;

  if (x<(W/2) and x>=-(W/2) and y<(H/2) and y>=-(H/2)) {
    int i=((x+(W/2))+((H-(y+(H/2)))*W))*3;
    if (i>=0 and i<W*H*BP) {
      colour.r=outbuff[i];
      colour.g=outbuff[i+1];
      colour.b=outbuff[i+2];
    }
  } 
  return colour;
}

//=========================================================================================//

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

  char* ifilnam;
  char* ofilnam;
  bool verbose=false,quiet=false,bw=false,grey=false,sepia=false,tint=false;
  double gamma=1.0,delta=0.5,tintr=1.0,tintg=1.0,tintb=1.0;
  rgb buff;
  if (argc<=2) {
    cerr << "Usage: " << argv[0] << " <filename> -o <filename> -bw -grey -sepia -gamma # -delta # -tint # # # -v -q" << endl;
    cerr << "-o          : Output File" << endl;
    cerr << "-bw         : Black and White Photo" << endl;
    cerr << "-grey       : Greyscale Image" << endl;
    cerr << "-sepia      : Sepia Photo" << endl;
    cerr << "-tint # # # : Tint Red (0-1) Green (0-1) Blue (0-1)" << endl;
    cerr << "-gamma      : Contrast Level (1 - 10)" << endl;
    cerr << "-delta      : Contrast Centre (0 - 1)" << endl;
    cerr << "-v          : Verbose output" << endl;
    cerr << "-q          : Quiet output" << endl;
  } else {
    ifilnam=argv[1];
    for (int a=0;a<argc;a++) {
      if (string(argv[a])=="-o") { ofilnam=argv[a+1]; }
      if (string(argv[a])=="-gamma") { gamma=atof(argv[a+1]); }
      if (string(argv[a])=="-delta") { delta=atof(argv[a+1]); }
      if (string(argv[a])=="-bw") { bw=true; grey=false; sepia=false; }
      if (string(argv[a])=="-grey") { grey=true; bw=false; sepia=false; }
      if (string(argv[a])=="-sepia") { sepia=true; grey=false; }
      if (string(argv[a])=="-tint") {
        tint=true;
        tintr=atof(argv[a+1]); if (tintr>1.0) { tintr=1.0; } if (tintr<0.0) { tintr=0.0; }
        tintg=atof(argv[a+2]); if (tintg>1.0) { tintg=1.0; } if (tintg<0.0) { tintg=0.0; }
        tintb=atof(argv[a+3]); if (tintb>1.0) { tintb=1.0; } if (tintb<0.0) { tintb=0.0; }
      }
      if (string(argv[a])=Usage: ./tweetypie <filename> -o <filename> -bw -grey -sepia -gamma # -delta # -tint # # # -v -q
-o          : Output File
-bw         : Black and White Photo
-grey       : Greyscale Image
-sepia      : Sepia Photo
-tint # # # : Tint Red (0-1) Green (0-1) Blue (0-1)
-gamma      : Contrast Level (1 - 10)
-delta      : Contrast Centre (0 - 1)
-v          : Verbose output
-q          : Quiet output="-v") { verbose=true; }
      if (string(argv[a])=="-q") { quiet=true; }
    }

  if (not quiet) { cout << ifilnam << "->" << ofilnam << " : BW " << bw << " Grey " << grey << " Contrast " << gamma << "," << delta << " Tint " << tintr << " " << tintg << " " << tintb << endl; }

  string h1,h2,h3;
  ifstream inhdr (ifilnam);
  getline(inhdr,h1);
  getline(inhdr,h2);
  getline(inhdr,h3);
  string h=h1+h2+h3;
  inhdr.close();
  buflen=filesize(ifilnam);
  hdrlen=h1.length()+h2.length()+h3.length()+3;
  outbuff = new char [buflen];
  inbuff = new char [buflen];
  hdr = new char [hdrlen];
  if (verbose) { cout << "Opening file" << endl; }
  ifstream infile (ifilnam,ios::binary);
  infile.read(hdr,hdrlen);
  infile.read(inbuff,buflen);
  infile.close();