%!PS % PostScript Array to Image Conversion Ap: III BMPPMAP1.PSL (perspective pastein) % ==================================== % 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 III PASTEIN APPLICATION %%%%%%%%%%%%%%%%% % Takes an image xwidth by yleftheigh and converts it to a perspective trapezoid % for pastein to another image. xwidth remains the same. Top right of new image is at % yrightheight. Bottom right of new image is at yrightclimg. % ycen is the point of zero vertical shift % yslope = [(yrightheight - yleftheight) - (yrightclimb0 ] / yleftheight % ycen = yrightclimb + [yrightclimb / yslope] % Speed is not yet optimized. But pasteins are normally fairly small and % quite fast executing. %%%%%%%%%%%%%%% % /makeperspaste is the high level routine that corrects to architects perspective. /makeperspaste { inputbitmap2AOS % convert intput file to array of strings findpastesize % calculate image size & shift createAOS2arrays % create new target arrays procperspaste % process tilt corr via loops /redAOS redAOS2 store % redefine new AOS array output /greenAOS greenAOS2 store /blueAOS blueAOS2 store convertAOS2BMPimage % convert array of strings to bitmap image } store %%%%%%%%% % /findpastesize determines the overall size of the final image and the % amount of yshift needed for correct mapping. /findpastesize { /pastetop yleftheight yrightheight gt % find image top {yleftheight}{yrightheight} ifelse store /pastebot yrightclimb 0 lt {yrightclimb}{0} ifelse store /pasteheight pastetop pastebot sub store } store % /createAOS2 arrays creates new target arrays, avoiding string dereferencing. % The target array will be xwidth wide and leftyheight high. % At present xwidth and leftyheight are manually reentered and must match % the original bitmap to be pasted. /createAOS2arrays { /redAOS2 mark pasteheight 1 add % make new red AOS array { xwidth string} repeat ] store /greenAOS2 mark pasteheight 1 add % and green { xwidth string} repeat ] store /blueAOS2 mark pasteheight 1 add % and blue { xwidth string} repeat ] store } store % /procperspaste does the actual constant calculations and remapping... % There is a speed advantage to having x the outer loop and y the inner /procperspaste { findzzz % find the zzz constant findycen % find the ycen constant 0 1 redAOS2 0 get % start horizontal counter length 1 sub {/xposn exch store (.) print flush findxold % calculate old x position findhhh % calculate constant needed by yold pastebot 1 pastetop % start vertical counter 1 sub {/yposn exch store findyold % find old y remappixels } for % end row } for % end bitmap } store % /findzzz is a service proc that derives zzz for later use. % kkk is the proportioned amount of shift. % It is also the horizontal distance to the vanishing point. And follows by % simple proportional triangles. % zzz/(zzz + xwidth) = (yrightheight - yrightclimb)/ yleftheight % zzz /(zzz + xwidth) = lrratio % zzz = lrratio*zzz + lratio*xwidth % zzz (1 - lrratio) = lratio*xwidth % zzz = xwidth [ lratio/(1-lratio) ] /findzzz { /lrratio yrightheight yrightclimb sub yleftheight div store /zzz xwidth lrratio 1 lrratio sub div mul store true { (\n\nlrratio is now ---> ) print flush lrratio == (\n\nzzz is now --------> ) print flush zzz == } if } store % /findycen is a service proc that derives ycen for later use... % ycen is the vertical point of zero correction. It MUST follow % /findzzz. It is calculated by substituting at yrightclimb. % let aaa = zzz/(zzz + xwide) % ynew = (yold - ycen) * aaa + ycen % yrightclimb = (-ycen)*aaa + ycen % yrightclimb = (1 - aaa) ycen % ycen = yrightclimb/(1-aaa) /findycen { /ycen yrightclimb 1 zzz zzz xwidth add div sub div store true { (\n\nycen is now ---> ) print flush ycen == } if } store % /xold is a service proc that finds the original x position given the new one. % It needs done only once per column.. /findxold {/xold zzz dup xwidth add xposn sub div xposn mul store} store % /findhhh is a service proc that will find the kkk needed later by yold /findhhh {/hhh zzz zzz xold add div store} store % /yold is a service proc that finds the original y position given the new one. % It needs done once per pixel... % yold = [ ynew + ycen*(hhh-1) ] / hhh where hhh = [ zzz/(zzz + xold)] /findyold {/yold {hhh 1 sub ycen mul yposn add hhh div} store} store % /backgroundxxx sets the color of the pasted portion NOT found in the original % image. It is normally 255-255-255 for white, but can be gray or black for debug. /backgroundred 255 store /backgroundgreen 255 store /backgroundblue 255 store % /remappixels first finds yold (xold is known from column loop) and checks % both for permissible range. It then does a bilineal transformation if % in range or a background substitution if out of range. % ((( xold should never be out of range -- temp backup }}} /remappixels { yold yleftheight 2 sub gt yold 0 lt or xold xwidth 2 sub gt or xold 0 lt or { redAOS2 yposn pastebot sub get % color out of range pixel xposn backgroundred put greenAOS2 yposn pastebot sub get xposn backgroundgreen put blueAOS2 yposn pastebot sub get xposn backgroundblue put } { % placein range pixel xold dup floor cvi dup /xi exch store sub /xr exch store % can move yold dup floor cvi dup /yi exch store sub /yr exch store /xr- 1 xr sub store /xi+ 1 xi add store /yr- 1 yr sub store /yi+ yi 1 add store redAOS yi get % do red bilineal transform dup xi get xr- mul exch xi+ get xr mul add yr- mul redAOS yi+ get dup xi get xr- mul exch xi+ get xr mul add yr mul add floor cvi redAOS2 yposn pastebot sub get exch xposn exch put greenAOS yi get % do green bilineal transform dup xi get xr- mul exch xi+ get xr mul add yr- mul greenAOS yi+ get dup xi get xr- mul exch xi+ get xr mul add yr mul add floor cvi greenAOS2 yposn pastebot sub get exch xposn exch put blueAOS yi get % do bluebilineal transform dup xi get xr- mul exch xi+ get xr mul add yr- mul blueAOS yi+ get dup xi get xr- mul exch xi+ get xr mul add yr mul add floor cvi blueAOS2 yposn pastebot sub get exch xposn exch put } ifelse % temp bypass to check background } 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 (flatart1.bmp) store /bmpinfileprefix (C:\\Documents and Settings\\don\\Desktop\\aarawpix\\) store /bmpoutfilename (flatout1.bmp) store /bmpoutfileprefix {bmpinfileprefix} store % if same /xwidth 355 store % width of original image (manual entry for now) /yleftheight 112 store % height of original image (manual entry for now) /yrightheight 235 pop 85 pop 235 pop 235 20 sub store % right height of pasted image /yrightclimb 150 pop 20 pop -200 pop 150 50 sub store % right base of pasted image stopwatchon makeperspaste % this does the actual perspective correction stopwatchoff % EOF