%!PS % PostScript Array to Image Conversion Ap: II PERFIX01.PSL % ==================================== % by Don Lancaster %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Copyright c 2008 by Don Lancaster & Synergetics, Box 809, Thatcher, AZ, 85552 % (928) 428-4073 Email: don@tinaja.com Website: http://www.tinaja.com % Consulting services available http://www.tinaja.com/info01.html % All commercial rights and all electronic media rights ~fully~ reserved. % Linking usually welcome. Reposting expressly forbidden. Version 1.5 % ========= % IMPORTANT NOTE: Don Lancaster's file gonzo.ps is recommended for the demos in % this program. The actual utilities can stand alone as they include Gonzo excerpts. % After obvious location mods, uncomment ONE of the following two lines: % (C:\\Program Files\\Gonzo\\gonzo.ps) run % use internal gonzo % A:\\gonzo.ps) run % use external gonzo % NOTE THAT ALL PS FILENAME STRINGS !!!DEMAND!!! DOUBLE REVERSE SLASHES. % Also note that Acrobat 8.1 or higher defaults to prevent most PS disk access. % The workaround is to prerun Distiller from the Windows command line using "acrodist -F". % Any .PSL file can then be dragged and dropped into any Distiller on or under the desktop. % GONZO20A Guru Gonzo PostScript power tools (Interim release) % Includes gonzo justification and layout utilities. % Copyright c 1990, 1996, 2001 by Don Lancaster and Synergetics, Box 809, % Thatcher Arizona, 5552 (928) 428-4073 don@tinaja.com support % via http://www.tinaja.com All commercial rights and all electronic % media rights **FULLY** reserved. Reposting is expressly forbidden. % ===================================== % The PostScript string operator has a number of advantages over a normal % array in that it stores info more compactly, can be read and written to as a % file, has more operators available to it, and still behaves as an array % with such operators as get, put, or {} forall. % A data structure of an array-of-strings can be a potent means of storing % and manipulating x-y data that ultimately comes from or becomes a PS image % or a conventional .BMP data file. % A group of utilities that simplify and ease the use of PostScript % array-of-strings is presented here. % A complete tutorial appears as http://www.tinaja.com/glib/bmp2psa.pdf % Its sourcecode is available as http://www.tinaja.com/glib/bmp2psa.psl %%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% START GONZO EXCERPTS. %%%%%%%%%%%%%%%%% % Complete Gonzo code appears at http://www.tinaja.com/psutils/gonzoutils.psl % Gonzo use tutorial appears at http://www.tinaja.com/glib/gonzotut.pdf % mergestr merges the two top stack strings into one top stack string /mergestr {2 copy length exch length add string dup dup 4 3 roll 4 index length exch putinterval 3 1 roll exch 0 exch putinterval} def /random {rand 65536 div 32768 div mul cvi} def % as in -- 6 random -- % timing utilities. use stopwatchon and stopwatchoff for simple % one shot timing. For multiple time totals, use resettimer % starttimer stoptimer ... starttimer stoptimer reporttimer /stopwatchoff {stoptimer reporttimer} def % for single shots /stopwatchon {resettimer starttimer} def % for single shots /reporttimer {mytime 1000 div (\rElapsed time: ) print 20 string cvs print ( seconds.\r) print flush} def % to host /resettimer {/mytime 0 def} def % reset timer /starttimer {usertime /mytimenow exch def} def % add to time so far /stoptimer {usertime mytimenow sub /mytime exch mytime add def} def % for multiple timing intervals %%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% START BITMAP TO ARRAY OF STRINGS CORE UTILITIES %%%%%%%%%%%%%%%%% % file variable names have been improved %%%%%%%%%% (A) MERGE STRING UTILITY %%%%%%%%%%%%%%%%%%%%%% % Excerpted from the Gonzo Utilities at http://www.tinaja.com/glib/gonzotut.pdf % Useful in combining filenames and as a general tool. /mergestr {2 copy length exch length add string dup dup 4 3 roll 4 index length exch putinterval 3 1 roll exch 0 exch putinterval} def % uncomment for demo % (Hello ) (there.) mergestr % should return (Hello there.) %%%%%%%%%% (B) STRING TO ARRAY CONVERTER %%%%%%%%%%%%%%%%%%%%%% /string2array {mark exch { } forall ] } store % uncomment for demo % (Hello!) string2array % should return [72 101 108 108 111 33]. %%%%%%%%%% (C) ARRAY TO STRING CONVERTER %%%%%%%%%%%%%%%%%%%%%% /array2string {dup length string dup /NullEncode filter 3 -1 roll {1 index exch write} forall pop } def % uncomment for demo % [72 105 32 116 104 101 114 101] array2string % should return a (Hi there). %%%%%%%%%%%% (D) STRING READ FROM AS A FILE %%%%%%%%%%%%%%%%%%%%%%% /str1 (This is a test) store /file1 str1 0 (%EOF) /SubFileDecode filter store % uncomment for demo % 6 { file1 read pop == } repeat % should return 84 104 105 115 32 105. %%%%%%%%%%%% (E) STRING WRITTEN TO AS A FILE %%%%%%%%%%%%%%%%%%%%%%% /str2 (zzzzzzzzzzzzzzzzzzz) store /file2 str2 /NullEncode filter store % uncomment for demo % file2 65 write file2 66 write file2 67 write % should return (ABCzzzzzzzzzzzzzzzz). %%%%%%%%%% (F) CREATE DEMO ARRAY-OF-STRINGS FILES %%%%%%%%%%%%% % these workfiles can be useful for developing and testing the utilities that follow % data shown creates a 6 pixel wide by 3 pixel high image with a rainbow on the bottom % row, gray elsewhere except for an upper right red pixel. /redAOS [ [250 250 0 0 0 250 ] array2string [100 100 100 100 100 100 ] array2string [100 100 100 100 100 250 ] array2string ] store /greenAOS [ [ 0 250 250 250 0 0 ] array2string [100 100 100 100 100 100 ] array2string [100 100 100 100 100 0 ] array2string ] store /blueAOS [ [ 0 0 0 250 250 250 ] array2string [100 100 100 100 100 100 ] array2string [100 100 100 100 100 0 ] array2string ] store %%%%%%%%%%%% (G) CONVERT ARRAYS-OF-STRINGS TO A POSTSCRIPT IMAGE %%%%%%%%%%% % three AOS string gathering procs needed by image... % /xx {dup {==} forall (\n) print } store /getredAOSrow {redAOS AOSrowcount get } store /getgreenAOSrow {greenAOS AOSrowcount get } store /getblueAOSrow {blueAOS AOSrowcount get /AOSrowcount AOSrowcount 1 add store } store % increment row counter for all gets % the AOS to image converter maps the AOS into a unit square. Scaling to final size and shape % must be done by CTM mods... /convertAOStoPSimage { /AOSrowcount 0 store << /ImageType 1 /Width redAOS 0 get length /Height redAOS length /ImageMatrix [redAOS 0 get length 0 0 redAOS length 0 0 ] % /MultipleDataSources true /DataSource [ {getredAOSrow} {getgreenAOSrow} {getblueAOSrow}] /BitsPerComponent 8 /Decode [ 0 1 0 1 0 1 ] /Interpolate false /AOSrowcount 0 % custom proc added here >> dup begin image end } bind store % true for demo false { 0 0 0 setrgbcolor 50 50 10 setgrid % requires Gonzo 20 20 showgrid % requires Gonzo convertAOStoPSimage showpage } if %%%%%%%%%%%% (H) CONVERT ARRAY-OF-STRINGS TO A .BMP BITMAP %%%%%%%%%%% % requires bmpoutfileprefix path and bmpoutfilename filenames defined. % Also valid data in redAOS, greenAOS, and blueAOS. /convertAOS2BMPimage { /bmpoutfile bmpoutfileprefix % make bmp write file bmpoutfilename mergestr (w) file store /xpixels redAOS 0 get length store % calc bmp data /ypixels redAOS length store /padcount xpixels 4 mod store % calc bmp padding simplified? /totalbmpsize xpixels padcount % calc file length add ypixels mul 54 add store bmpoutfile 66 write % BEGIN HEADER bmpoutfile 77 write % with ASCII "BM". totalbmpsize 256 3 exp cvi idiv % calc length byte /byte4 exch store totalbmpsize 256 3 exp cvi mod /res3 exch store res3 65536 idiv /byte3 exch store res3 65536 mod /res2 exch store res2 256 idiv /byte2 exch store res2 256 mod /byte1 exch store bmpoutfile byte1 write % write length as modulo 256 bmpoutfile byte2 write bmpoutfile byte3 write bmpoutfile byte4 write 4 {bmpoutfile 0 write} repeat % four reserved nulls bmpoutfile 54 write % start of data offset bmpoutfile 0 write bmpoutfile 0 write bmpoutfile 0 write bmpoutfile 40 write % write data header size bmpoutfile 0 write bmpoutfile 0 write bmpoutfile 0 write bmpoutfile xpixels 256 mod write % write x size lsbs bmpoutfile xpixels 256 idiv write bmpoutfile 0 write % assume < 65K bmpoutfile 0 write % (\n\nypixels are --------------------> ) print flush ypixels == bmpoutfile ypixels 256 mod write % write y size lsbs bmpoutfile ypixels 256 idiv write bmpoutfile 0 write % assume < 65K bmpoutfile 0 write bmpoutfile 1 write % number of bit planes bmpoutfile 0 write bmpoutfile 24 write % write color mode bmpoutfile 0 write 4 {bmpoutfile 0 write} repeat % compression mode 4 {bmpoutfile 0 write} repeat % pixel data size 4 {bmpoutfile 0 write} repeat % width resolution 4 {bmpoutfile 0 write} repeat % height resolution 4 {bmpoutfile 0 write} repeat % colors used 4 {bmpoutfile 0 write} repeat % important colors 0 1 ypixels 1 sub {/currow exch store % start data write % (\n processing row ---> ) print currow == /curred redAOS currow get store % grab RGB row data /curgreen greenAOS currow get store /curblue blueAOS currow get store 0 1 xpixels 1 sub {/curpos exch store % BGR pixel write bmpoutfile curblue curpos get write bmpoutfile curgreen curpos get write bmpoutfile curred curpos get write } for % finish row padcount {bmpoutfile 0 write } repeat % add row padding } for % finish image bmpoutfile closefile % close file } bind store % and exit % true for demo false { /bmpoutfileprefix (C:\\Program Files\\Gonzo\\) store /bmpoutfilename (bmpout1.bmp) store convertAOS2BMPimage } if %%%%%%%%%%%% (I) CONVERT A .BMP BITMAP TO A PS ARRAY-OF-STRINGS %%%%%%%%%%% % requires a predefined bmpinfileprefix and bmpinfilename /inputbitmap2AOS { % START ANALYSIS /bmpinfile bmpinfileprefix % create .BMP read file bmpinfilename mergestr (r) file store bmpinfile read % check for ok format pop 66 eq % "B" as first character? bmpinfile read pop 77 eq and % "M" as second char? bmpinfile 26 setfileposition % one color plane? bmpinfile read pop 1 eq and not {NOT_A_BITMAP_FILE!} if % report bitmap error bmpinfile 28 setfileposition % report color message bmpinfile read pop 24 eq not {NOT_24_BIT_COLOR!} if bmpinfile 10 setfileposition % find the offset bmpinfile read pop bmpinfile read pop 256 mul add /offset exch store bmpinfile 18 setfileposition % find the xpixels bmpinfile read pop bmpinfile read pop 256 mul add /xpixels exch store bmpinfile 22 setfileposition % find the ypixels bmpinfile read pop bmpinfile read pop 256 mul add /ypixels exch store /padcount xpixels 4 mod store % calculate padding simplified? /redAOS ypixels array store % empty AOS arrays /greenAOS ypixels array store /blueAOS ypixels array store 0 1 ypixels 1 sub % 1 sub % temp skip last line {/rowcount exch store % GRAB DATA by rows % (rowcount ---> ) print rowcount 10 string cvs == bmpinfile offset % go to row start rowcount xpixels 3 mul % X3 for triads padcount add mul % plus padding add setfileposition % set row start /redAOSrow xpixels string store % create rows /greenAOSrow xpixels string store /blueAOSrow xpixels string store 0 1 xpixels 1 sub {/posn exch store % for each pixel triad blueAOSrow posn bmpinfile read pop put % blue greenAOSrow posn bmpinfile read pop put % green redAOSrow posn bmpinfile read pop put % red } for % till row done redAOS rowcount redAOSrow put % place strings greenAOS rowcount greenAOSrow put blueAOS rowcount blueAOSrow put } for % for each row } bind store % completing proc % true for round trip demo BMP ----- PS AOS ----> BMP and PS AOS ---> PS IMAGE % requires preplaced .BMP file data source or name change false { /bmpinfileprefix (C:\\Program Files\\Gonzo\\) store /bmpinfilename (small.bmp) store /bmpoutfilename (smallz.bmp) store inputbitmap2AOS convertAOS2BMPimage gsave 0 0 0 setrgbcolor 50 50 translate 372 354 scale convertAOStoPSimage grestore showpage } if %%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% END BITMAP TO ARRAY OF STRINGS CORE UTILITIES %%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% START POSSIBLY EXPORTABLE GLOBAL UTLILITIES %%%%%%%%%%%%%%%%% % PS LINEAR EQUATION SOLVER FOR N=4 LINEQ04.PS % ============================================ % Copyright c 1999 by Don Lancaster and Synergetics, Box 809, Thatcher, AZ, 85552 % (520) 428-4073 don@tinaja.com http://www.tinaja.com % Consulting services available per http://www.tinaja.com/info01.html % All commercial rights and all electronic media rights fully reserved. % Personal use permitted provided header and entire file remains intact. % Linking is welcome. Reposting expressly forbidden. % This utility demo shows how to use PostScript to solve linear algabraic equations % by use of Gaussian elimination. It is easily extended to higher orders. % Additional details in http://www.tinaja.com/glib/muse142.pdf % This code currently includes temporary test and reporting utils. % temp report utility /aaa {20 string cvs print ( ) print} def /rrr {(\n\n) print w0 aaa x0 aaa y0 aaa z0 aaa ( ) print a0 aaa (\n) print w1 aaa x1 aaa y1 aaa z1 aaa ( ) print a1 aaa (\n) print w2 aaa x2 aaa y2 aaa z2 aaa ( ) print a2 aaa (\n) print w3 aaa x3 aaa y3 aaa z3 aaa ( ) print a3 aaa (\n) print } def % Define or capture your data. To avoid any div0 problems, preplace your largest % absolute values on your principle diagonals... false { % dummy data set for testing /w0 -3.997 store /x0 2.075 store /y0 -0.997 store /z0 1.436 store /a0 29.223 store /w1 2.345 store /x1 -0.654 store /y1 -8.231 store /z1 1.234 store /a1 -13.491 store /w2 -3.224 store /x2 12.223 store /y2 -1.06 store /z2 4.987 store /a2 1.342 store /w3 0.334 store /x3 -1.653 store /y3 2.724 store /z3 -7.003 store /a3 -13.365 store } if /solven04 { % (\n\nraw equations) == rrr % normalize w0 to unity... /a0 a0 w0 div store /z0 z0 w0 div store /y0 y0 w0 div store /x0 x0 w0 div store /w0 1.000 store % (\n\nforcew0 to unity) == rrr % force w1 to zero... /a1 a1 a0 w1 mul sub store /z1 z1 z0 w1 mul sub store /y1 y1 y0 w1 mul sub store /x1 x1 x0 w1 mul sub store /w1 w1 w0 w1 mul sub store % check % /w1 0 store % (\n\nforce w1 to zero)== rrr % normalize x1 to unity... /a1 a1 x1 div store /z1 z1 x1 div store /y1 y1 x1 div store /x1 x1 x1 div store % /x1 1.000 store % (\n\nnormalize x1 to zero) == rrr % force w2 to zero /a2 a2 w2 a0 mul sub store /z2 z2 w2 z0 mul sub store /y2 y2 w2 y0 mul sub store /x2 x2 w2 x0 mul sub store /w2 w2 w2 w0 mul sub store % /w2 0 store % (\n\nforce w2 to zero) == rrr % force x2 to zero... /a2 a2 a1 x2 mul sub store /z2 z2 z1 x2 mul sub store /y2 y2 y1 x2 mul sub store /x2 x2 x1 x2 mul sub store % /x2 0 store % (\n\nforce x2 to zero) == rrr % normalize y2 to unity... /a2 a2 y2 div store /z2 z2 y2 div store /y2 y2 y2 div store % /y2 1.000 store % (\n\nnormalize y2 to unity) == rrr % force w3 to zero (w3 - w0/w3) /a3 a3 a0 w3 mul sub store /z3 z3 z0 w3 mul sub store /y3 y3 y0 w3 mul sub store /x3 x3 x0 w3 mul sub store /w3 w3 w0 w3 mul sub store % /w3 0 store % (\n\n force w3 to zero) == rrr % force x3 to zero /a3 a3 a1 x3 mul sub store /z3 z3 z1 x3 mul sub store /y3 y3 y1 x3 mul sub store /x3 x3 x1 x3 mul sub store % /x3 0 store % (\n\nforce x3 to zero) == rrr % force y3 to zero /a3 a3 a2 y3 mul sub store /z3 z3 z2 y3 mul sub store /y3 y3 y2 y3 mul sub store % /y3 0 store % (\n\nforce y3 to zero) == rrr % normalize y3 to unity (solving for z) /z a3 z3 div store % solve for y by back substitution... /y a2 z2 z mul sub store % solve for x by back substitution... /x a1 z1 z mul sub y1 y mul sub store % solve for w by back substitution... /w a0 z0 z mul sub y0 y mul sub x0 x mul sub store % report the results false { (w = ) print w 20 string print (\n) print (x = ) print x 20 string cvs print (\n) print (y = ) print y 20 string cvs print (\n) print (z = ) print z 20 string cvs print (\n) print } if } store %%%%%%%%%%%%% end %%%%%%%%% bilineal interpolator for unit square /dobilin1 { /yfract exch store /xfract exch store 1 yfract sub 1 xfract sub mul w mul 1 yfract sub xfract mul x mul add yfract 1 xfract sub mul y mul add yfract xfract mul z mul add } bind store % /reportbmpasintegers lets you look at actual bytes in a .BMP file as 0-255 integers. % This can be handy for resolving code issues. bmpinfileprefix and bmpinfilename % must be predefined. A fancier version might pad one and two digit results. /reportbmpasintegers { /bmpinfile bmpinfileprefix % create .BMP read file bmpinfilename mergestr (r) file store bmpinfile 0 setfileposition % verify start at beginning 1000 {bmpinfile read {==} if % number of bytes as needed } repeat } store %%%%%%%%% bilineal AOS interpolators % /doredbilin et al do the bilineal interpolation. Their terms have been % rearranged for a significant speedup... y variables are also pregotten % once per line rather than once per pixel. /doredbilin { curcred dup xi get xr- mul exch xi+ get xr mul add yr- mul curcred+ dup xi get xr- mul exch xi+ get xr mul add yr mul add } bind store /dogreenbilin { curcgreen dup xi get xr- mul exch xi+ get xr mul add yr- mul curcgreen+ dup xi get xr- mul exch xi+ get xr mul add yr mul add } bind store /dobluebilin { curcblue dup xi get xr- mul exch xi+ get xr mul add yr- mul curcblue+ dup xi get xr- mul exch xi+ get xr mul add yr mul add } bind store %% PostScript tangent (sort of) /tan {dup sin exch cos dup 0 eq {pop 0.000001} if div} store %%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% START PERSPECTIVE II APPLICATION %%%%%%%%%%%%%%%%% % Corrects the "architects perspective" tilt by making building or test equipment % sides perfectly vertical. Attempts to eliminate curvature caused by older procs % by translating both width and height. % "old-new top positions" is the supported input method %% key calculation math... %% ycnew = ycold [zzz /(zzz + ycold)] y forward transform in censpace %% xcnew = xcold [zzz /(zzz + ycold)] %% xcnew = xcold [ ycold/ycnew ] !!!! x forward transform in censpace %% ycnew*zzz + ycold*ycnew = ycold*zzz %% ycnew*zzz = ycold*zzz - ycold*ycnew %% ycnew*zzz = ycold (zzz -ycnew) %% ycold = ycnew*zzz /(zzz - ycnew) y reverse transform in censpace %% NEEDS DONE ONLY ONCE PER LINE %% xcold = xcnew [ycold/ycnew] x reverse transform in censpace %% xcold = xcnew*fract A SIMPLE RATIO becomes a constant. %%%%%%%%%%%%%%% % /fixtilt is the high level routine that corrects to architects perspective. /fixtilt { inputbitmap2AOS % convert intput file to array of strings /xwide redAOS 0 get length 1 sub store % find size limits /yhigh redAOS length 1 sub store /ycen yhigh 2 div round cvi store createAOS1arrays % create new target arrays proctilt % process tilt corr via loops /redAOS redAOS1 store % redefine new AOS array output /greenAOS greenAOS1 store /blueAOS blueAOS1 store convertAOS2BMPimage % convert array of strings to bitmap image } store %%%%%%%%% % /proctilt is a pixel loop within a line loop that first calculates limits, then % does some progress pretty printing, then sets up the actual processing... /proctilt { /xcen leftxshift dup rightxshift sub div % fract xcorrwidth mul % times new size oldxleft leftxshift add add round cvi store /zzz oldxleft xcorrwidth add xcen sub % prevents recalculation ycorrheight ycen sub mul leftxshift div store (\nxcen is now ---> ) print xcen == (zzz is now ------> ) print zzz == (tilt angle is ---> ) print flush zzz ycen div 1 exch atan == /topfract zzz dup ycen add div store /ycmax topfract 1 lt {ycen topfract mul floor cvi 1 sub} {ycen 1 sub} ifelse store /ycmin topfract 1 ge {ycen topfract mul floor cvi 1 sub neg} {ycen 1 sub neg} ifelse store /scaledots 0 store % optional pretty printer ycmin 1 ycmax { /ycnew exch store % begin line loops /scaledots scaledots 1 add store % pretty print progress scaledots 100 mod 0 eq {(.) print flush} if /ycold ycnew zzz zzz ycnew sub div mul store % calc for later /curfract ycold 0 ne {ycnew ycold div} % trap div0 {1} ifelse store /xcmin curfract 1 le {xcen neg curfract mul floor 1 add cvi} {xcen neg} ifelse store /xcmax curfract 1 le {xwide xcen sub curfract mul floor 2 sub cvi} {xwide xcen sub 2 sub} ifelse store ycold ycen add dup floor cvi dup /yi exch store sub /yr exch store /yyy ycnew ycen add store /curred redAOS1 yyy get store /curgreen greenAOS1 yyy get store /curblue blueAOS1 yyy get store /curcred redAOS yi get store /curcgreen greenAOS yi get store /curcblue blueAOS yi get store /curcred+ redAOS yi 1 add get store /curcgreen+ greenAOS yi 1 add get store /curcblue+ blueAOS yi 1 add get store /yr- 1 yr sub store xcmin 1 xcmax { /xcnew exch store % begin pixel loop procrgbpixels } for % for each pixel } for % for each line } store %%%%%%%%%% % /procrgbpixels calls the red, green, and blue bilineal interpolations for % the reverse transformed locations, then writes them to the new locations... /procrgbpixels { xcnew curfract div xcen add % calculated xcold not defined for speed dup floor cvi dup /xi exch store sub /xr exch store /xr- 1 xr sub store /xi+ 1 xi add store curred xcnew xcen add doredbilin cvi put curgreen xcnew xcen add dogreenbilin cvi put curblue xcnew xcen add dobluebilin cvi put } bind store %%%%%%%%%%%% % /createAOS1 arrays creates new target arrays, avoiding string dereferencing /createAOS1arrays { /redAOS1 mark redAOS length % make new red AOS array { redAOS 1 get length string} repeat ] store /greenAOS1 mark redAOS length % and green { redAOS 1 get length string} repeat ] store /blueAOS1 mark redAOS length % and blue { redAOS 1 get length string} repeat ] store } store %%% Demo -- Remove or alter before reuse. reenter above defaults % A "WARNING: No PDF file created" is normal and expected as output is a .BMP file % If using Acrobat 8.1 or higher, enter via "acrodist -F" from command line. /bmpinfilename (nukeyt01.bmp) store /bmpinfileprefix (C:\\Documents and Settings\\don\\Desktop\\aarawpix\\) store /bmpoutfilename (nukeyc1.bmp) store /bmpoutfileprefix {bmpinfileprefix} store % if same /ycorrheight 436 store % verical position where xshifts are defined /oldxleft 103 store % left neutral position /xcorrwidth 244 store % old x width at ycorrheight /leftxshift 38 store % amount of left correction at ycorrheight /rightxshift -54 store % amount of right correction at ycorrheight stopwatchon fixtilt % this does the actual perspective correction stopwatchoff % EOF