%!PS % Universal Bitmap Image Manipulation Utilities % ============================================= % by Don Lancaster %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Copyright c 2005 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 2.1 % This is an expanding set of universal bitmap imaging utilities that % potentially offer ultra fancy calculated image manipulation possibilities. % Certain XY mnipulations may be 5X slower and increase with the resolution square. % A minimum of 250 megabytes of system RAM is recommended with no other programs active. % Image must be EXTERNALLY converted to/from .JPG or other non .BMP format. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /nowfile 4 store /sourcefilename [(utestk01.bmp)(kkk01.bmp) (keystx01.bmp) (tiltx01.bmp)(lines01.bmp) ] nowfile get def % short name of input .BMP file /sourcefilenameprefix % full source filename prefix to be appended (C:\\Documents and Settings\\don\\Desktop\\gurugrams\\Universal image 56\\) def /targetfilename [(utestkx1.bmp)(kkkx1.bmp) (keystxx1.bmp) (tiltxx1.bmp)(linesx1.bmp) ] nowfile get def % short name of output .BMP file /targetfilenameprefix % full target filename prefix to be appended (C:\\Documents and Settings\\don\\Desktop\\gurugrams\\Universal image 56\\) def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % deltatilt values: /tiltaxis 0.50 store % 0.50 is center of screen 1.0 is right /howmuchtilt 0.10 store % 0.10 is ten percent edge moved to center %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % IMPORTANT NOTE: Don Lancaster's file gonzo.ps is recommended but not % required for this program. % After obvious location mods, uncomment ONE of the following two lines: % (C:\\Documents and Settings\\don\\Desktop\\gonzo\\gonzo.ps) run % use internal % (A:\\gonzo.ps) run % use external gonzo % NOTE THAT ALL PS FILENAME STRINGS !!!DEMAND!!! DOUBLE REVERSE SLASHES. % GONZO20A Guru Gonzo PostScript power tools (Interim release) % Includes gonzo justification and layout utilities. % Copyright c 1990, 1996, 2005 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. % ======== /guru { gonzo begin ps.util.1 begin printerror nuisance begin} def % guru % optionally activate gonzo utilities % ========= % gonzo excerpts /mt {moveto} store /black {0 setgray} store % 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 % 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 % [yourarray] makestring converts an array to a string... /makestring {dup length string dup % new string of right size /NullEncode filter % make a file out of string 3 -1 roll {1 index exch write} forall pop } def %%%%%%%%% end gonzo excerpts % bitmap and file manipulation basics... /wholesourcefilename sourcefilenameprefix sourcefilename mergestr store /wholetargetfilename targetfilenameprefix targetfilename mergestr store /readfile wholesourcefilename (r) file store % establish input read file /writefile wholetargetfilename (w+) file store % establish output target file /bitsperpixelposition 28 store % BMP header positioning info /datastartposition 10 store /horizontalpixels 18 store /verticalpixels 22 store /backcount 0 store %%%%%%%%% CHECK FOR VALID 24-BIT UNCOMPRESSED BITMAP %%%%%%%%%%%%% % BM check: readfile (XX) readstring pop % error message if file not two chars long (BM) eq {(File has correct "BM" as first two bytes.\n) print } { sourcefilename ( is not in .BMP format; further eval terminated.\n\n\n) mergestr print quit } ifelse % 24 bit check: readfile bitsperpixelposition setfileposition % access 2 {readfile read pop} repeat % get color planes error if not present 1 {256 mul add} repeat % calculate bits per pixel dup /bpp exch store % save for expanded analysis 10 string cvs % make string (24) eq {(File has correct 24-bit color format.\n) print } { sourcefilename ( is not in 24-bit format; further eval terminated.\n\n\n) mergestr print quit } ifelse % Compression mode: 4 {readfile read pop} repeat % get color planes error if not present 3 {256 mul add} repeat % calculate compression mode dup /cmm exch store % save for expanded analysis 10 string cvs % make string (0) eq {(File has correct 0 uncompressed format.\n) print } { sourcefilename ( is not in uncompressed format; further action terminated.\n\n\n) mergestr print quit } ifelse % Bitmap Width: readfile horizontalpixels setfileposition % access 4 {readfile read pop} repeat % get bitmap width bytes error if not present 3 {256 mul add} repeat % calculate data start dup /hres exch def 10 string cvs % make string (Bitmap width is ) exch mergestr ( pixels.\n) mergestr print flush % Bitmap Width: readfile verticalpixels setfileposition % access 4 {readfile read pop} repeat % get bitmap width bytes error if not present 3 {256 mul add} repeat % calculate data start dup /vres exch def 10 string cvs % make string (Bitmap height is ) exch mergestr ( pixels.\n) mergestr print flush % Find padding % .BMP rows MUST end on a 32-bit boundary! Zero, one, two, or three 00 % padding bits are required depending upon the actual width. /padding hres 3 mul cvi 4 mod % find start of next 32-byte block [ 0 3 2 1 ] exch get % TLU correction def (Padding 8-bit bytes per line are ) padding 10 string cvs mergestr ( .\n\n) mergestr print flush (Active storage 8-bit RGB bytes per line are ) hres 3 mul dup cvi /activestore exch store 10 string cvs mergestr ( .\n) mergestr print flush activestore 4 div ceiling cvi 4 mul /totalbytesperline exch store % find data start readfile datastartposition setfileposition % access 4 {readfile read pop} repeat % get data start bytes error if not present 3 {256 mul add} repeat % calculate data start /actualdatastart exch store % define read strings /linestring hres 3 mul string store % read file line buffer %%%%%%%%%%%%%%%% COPY HEADER TO TARGET FILE %%%%%%%%%%%%%%%%%% % The entire old header gets reused. outwidth and outlength is then % overwritten. /writeoutfileheader { readfile datastartposition setfileposition % access 4 {readfile read pop} repeat % get data start bytes error if not present 3 {256 mul add} repeat % calculate data start /actualdatastart exch store readfile 0 setfileposition readfile actualdatastart 1 sub string readstring not { sourcefilename ( has a short header; further action terminated.\n\n\n) mergestr print quit } if writefile exch writestring % write the entire header to new file writefile actualdatastart setfileposition % go to end of header } store % /correctoutlenwidth adjusts the output file size if it is different from the % original. As may happen in a crop or rotation. /correctoutlenwidth { writefile horizontalpixels setfileposition % file position t0 first horizontal posn byte 0 % assume highest byte is zero outwidth dup 65536 idiv % find next highest byte exch 65536 mod % find remainder dup 256 idiv % and final two bytes exch 256 mod 4 {writefile exch write} repeat % overwrite pixel width writefile verticalpixels setfileposition % file position t0 first vertical posn byte 0 % assume highest byte is zero outlength dup 65536 idiv % find next highest byte exch 65536 mod % find remainder dup 256 idiv % and final two bytes exch 256 mod 4 {writefile exch write} repeat % overwrite pixel width writefile actualdatastart setfileposition % go to end of header } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (A) BITMAP FILE CAPTURE ROUTINE /grabbitmap % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % /grabbitmap reads a disk file and converts its underlying bitmap to % a PostScript /instrarray image array of STRINGS. Each horizontal line % is one subarray, and the arrays build from the image BOTTOM UPWARDS... % In general, PostScript strings can be manipulated as arrays without % needing the overhead of string to array or array to string conversion. % The speed savings can be quite significant. % This is normally the FIRST step in any image manipulation. % Note that there is NO PADDING in instrarray. /grabbitmap { (\nReading initial bitmap from disk...) print flush /instrarray mark % start input data array 0 = bottom 0 1 vres 1 sub { % begin line reading loop /vline exch store % start of next hires line vline hres 3 mul padding add mul actualdatastart add % position read file readfile exch setfileposition readfile linestring readstring % grab a line of characters not {Error_reading_input_file_data} if % error trap dup length string cvs % must dereference } for ] store % complete instrarray definition } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (B) COPY STRING TO OUTPUT /instr2outstr % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is a simple string replicator that also does dereferencing. % Dereferencing allows the instrarray to be reused without surprises. /instr2outstr { -2 vmreclaim (\nCopying input to output...) print flush /outstrarray mark instrarray { dup length string cvs} forall ] store 0 vmreclaim } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (C) BITMAP FILE STORAGE ROUTINE /savebitmap % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % /savebitmap saves the internal PostScript /outarray to disk in % the .BMP format a chosen disk file. % This is normally the LAST step in any image manipulation. % Note that input and output files can be different sizes for certain % operations such as cropping or rotations. /savebitmap { (\nSaving processed bitmap image to disk...) print flush outstrarray length /outlength exch store % find output pixelslength outstrarray 0 get length 3 div cvi % find output pixels width /outwidth exch store % note three RGB bytes per pixel writeoutfileheader % write the outfile header correctoutlenwidth % correct the data size 0 1 outstrarray length 1 sub { % for each data line outstrarray exch get % get data line as string dup length 4 mod % add padding if needed dup 0 gt {[ (xxx) threepad twopad onepad] exch get mergestr}{pop}ifelse writefile exch writestring } for } store /onepad [ 0 ] makestring store % null padding strings used by /savebitmap /twopad [0 0] makestring store /threepad [ 0 0 0 ] makestring store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (D) RETANGULAR CROPPING /cropimage % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % /cropimage gathers an image subarray. Remember that there are % three bytes per pixel horizontally. There is currently no range % checking or error trapping. /cropimage { /ury exch store % upper right vertical count 3 mul cvi % upper right horizontal count /urx exch store /lly exch store % lower left vertical count 3 mul cvi % lower left horizontal count /llx exch store /outstrarray mark % begin new output array lly 1 ury { % begin loop instrarray exch get llx dup urx sub neg getinterval } for ] def % complete output array } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (E) FLIP IMAGE VERTICALLY /flipimagevertically % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % mirrors the image vertically. /flipimagevertically { /outstrarray [ % start output array instrarray length 1 sub -1 0 { % for each horizontal line instrarray exch get } for ] store % save new array } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (F) FLIP IMAGE HORIZONTALLY /flipimagehorizontally % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % mirrors the image horizontally by copying into second string. /flipimagehorizontally { 0 vmreclaim -2 vmreclaim (\nflipping image horizontally) print flush /outstrarray [ % start output array 0 1 instrarray length 1 sub { % for each horizontal line dup 200 mod 0 eq {(.) print flush % report progress 0 vmreclaim -2 vmreclaim } if instrarray exch get % get string to be reversed /curhstr exch store /csmax curhstr length 3 sub store % calculate maximum pixel position /tempstring csmax 3 add string store csmax -3 0 { /iii exch store % for each pixel group curhstr iii 3 getinterval % isolate rgbstring tempstring exch csmax iii sub % put into new string exch putinterval } for tempstring } for ] store % save new array 0 vmreclaim } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (G) ROTATE IMAGE 180 DEGREES /rotateimage180 % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /rotateimageby180 { 0 vmreclaim -2 vmreclaim (\nRotating image by 180 degrees) print flush /outstrarray [ % start output array instrarray length 1 sub -1 0 { % for each horizontal line dup 200 mod 0 eq {(.) print flush % report progress 0 vmreclaim -2 vmreclaim } if instrarray exch get % get string to be reversed /curhstr exch store /csmax curhstr length 3 sub store % calculate maximum pixel position /tempstring csmax 3 add string store csmax -3 0 { /iii exch store % for each pixel group curhstr iii 3 getinterval % isolate rgbstring tempstring exch csmax iii sub % put into new string exch putinterval } for tempstring } for ] store % save new array 0 vmreclaim } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (H) ROTATE IMAGE +90 DEGREES CLOCKWISE /rotateimageby90 % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % rotates the image by 90 degrees. /rotateimageby90 { 0 vmreclaim -2 vmreclaim (\nRotating image by 90 degrees) print flush /outstrarray [ % start output array /oldhlength instrarray 0 get length store % save old hlength oldhlength 3 sub -3 0 { % count old hline by threes dup 200 mod 0 eq {(.) print flush 0 vmreclaim -2 vmreclaim } if % show progress /oldhposn exch store % save old hposn /newhstring instrarray length 3 mul % create new output hstring string store instrarray length 1 sub -1 0{ % for each vertical position /oldvposn exch store instrarray oldvposn get oldhposn 3 getinterval % grab rgb triad newhstring exch oldvposn 3 mul cvi exch putinterval % and plut into newhstring } for newhstring } for % for each gathered line string ] store % save new array 0 vmreclaim } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (I) ROTATE 270 DEGREES CLOCKWISE /rotateimageby270 % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % rotates the image by 270 degrees (90 degrees counterclockwise). /rotateimageby270 { 0 vmreclaim -2 vmreclaim (\nRotating image by 270 degrees) print flush /outstrarray [ % start output array /oldhlength instrarray 0 get length store % save old hlength 0 3 oldhlength 3 sub { % count old hline by threes dup 200 mod 0 eq {(.) print flush 0 vmreclaim -2 vmreclaim } if % show progress /oldhposn exch store % save old hposn /newhstring instrarray length 3 mul % create new output hstring string store 0 1 instrarray length 1 sub { % for each vertical position /oldvposn exch store instrarray oldvposn get oldhposn 3 getinterval % grab rgb triad newhstring exch oldvposn 3 mul cvi exch putinterval % and plut into newhstring } for newhstring } for % for each gathered line string ] store % save new array 0 vmreclaim } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (J) REPLACE IMAGE WITH ITS NEGATIVE /negateimage % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % /negateimage replaces an entire image with its negative. Each color value of n % is replaced by abs (n-255). Since RGB are all treated the same, the entire % horizontal line can be processed at once % attempts to avoid time intensive makestring took longer so far. /negateimage { 0 vmreclaim -2 vmreclaim (\nConverting image to negative) print flush /outstrarray [ % start output array 0 1 instrarray length 1 sub { dup 200 mod 0 eq {(.) print flush 0 vmreclaim -2 vmreclaim } if instrarray exch get mark exch {256 sub abs} forall ] makestring } for ] store 0 vmreclaim } store % REWORK --- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (L) Background Eliminator /knockback % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Uses EWNS algorithm to replace everything from left margin to first % all white pixel string only. Then from right margin left. Then % top margin down. Then bottom margin up. % There MUST be ZERO breaks in the white outline! Diagonal whites are % permitted. Extra white pixels or thicker borders are permitted. % Random white pixels in the background should be preremoved. % Currently limited to 255 255 255 hardwire white replacement /triwhite [255 255 255] makestring store % whites used by top down /knockback { 0 vmreclaim -2 vmreclaim instr2outstr % replicate output string /spacestring1 % create white array string mark outstrarray 0 get length {255} repeat ] makestring store % begin left scan... 0 1 outstrarray length 1 sub {/vposn exch store % for each horizontal line outstrarray vposn get /curhstring exch store % get current string 0 3 curhstring length 3 sub { % get current posn /curhpos exch store curhstring curhpos get 255 eq { % scan rgb triads for white curhstring curhpos 1 add get 255 eq { curhstring curhpos 2 add get 255 eq {exit} if } if } if } for % for each triad spacestring1 0 curhpos getinterval % replace white to left outstrarray vposn get exch 0 exch putinterval } for % for each line % begin right scan... 0 1 outstrarray length 1 sub {/vposn exch store % for each horizontal line instrarray vposn get /curhstring exch store % get current string curhstring length 3 sub -3 0 { % get current posn /curhpos exch store curhstring curhpos get 255 eq { % scan rgb triads for white curhstring curhpos 1 add get 255 eq { curhstring curhpos 2 add get 255 eq {exit} if } if } if } for % for each triad spacestring1 dup length curhpos sub 0 exch getinterval outstrarray vposn get exch curhpos exch putinterval } for % for each line % begin slower top scan... 0 3 outstrarray 0 get length 4 sub {/hposn exch store % for each horizontal line outstrarray length 1 sub -1 0 { % scan downward /vposn exch store instrarray vposn get hposn get 255 eq { instrarray vposn get hposn 1 add get 255 eq { instrarray vposn get hposn 2 add get 255 eq {exit} if } if } if outstrarray vposn get hposn triwhite putinterval } for % for each vertical line } for % completing h sweep % begin slower bottom scan... 0 3 outstrarray 0 get length 4 sub {/hposn exch store % for each horizontal line 0 1 outstrarray length 1 sub { % scan upward /vposn exch store instrarray vposn get hposn get 255 eq { instrarray vposn get hposn 1 add get 255 eq { instrarray vposn get hposn 2 add get 255 eq {exit} if } if } if outstrarray vposn get hposn triwhite putinterval } for % for each vertical line } for % completing h swee 0 vmreclaim } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (M.1) HIRES Pixel Interpolators /xinterp and /yinterp % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % These use ultra high performance cubic spline basis functions for % pixel interpolation. While the best available, they are computationally % intensive. An XY interpolation can be done Y first, then X. % /basistab is a cubic spline interpolation lookup table. % [pix-1 + pix + pix+1 + pix+2] coeffients /basistab % from http://www.tinaja.com/psutils/imtable.psl reduced to 20 lowres values [ [ 0.000 1.000 0.00 -0.000 ] [ -0.007 0.999 0.007 -0.000 ] [ -0.026 0.998 0.028 -0.001 ] [ -0.053 0.992 0.064 -0.003 ] [ -0.083 0.979 0.113 -0.009 ] [ -0.111 0.954 0.176 -0.020 ] [ -0.132 0.916 0.252 -0.036 ] [ -0.145 0.863 0.338 -0.057 ] [ -0.147 0.795 0.432 -0.080 ] [ -0.140 0.715 0.529 -0.103 ] [ -0.125 0.625 0.625 -0.125 ] [ -0.103 0.529 0.715 -0.140 ] [ -0.080 0.432 0.795 -0.147 ] [ -0.057 0.338 0.863 -0.145 ] [ -0.036 0.252 0.916 -0.132 ] [ -0.020 0.176 0.954 -0.111 ] [ -0.009 0.113 0.979 -0.083 ] [ -0.003 0.064 0.992 -0.053 ] [ -0.000 0.028 0.998 -0.026 ] [ -0.000 0.007 0.999 -0.007 ] [ -0.000 0.000 1.000 -0.000 ] ] store /b0 % extracted from above [0.000 -0.007 -0.026 -0.053 -0.083 -0.111 -0.132 -0.145 -0.147 -0.140 -0.125 -0.103 -0.080 -0.057 -0.036 -0.020 -0.009 -0.003 -0.000 -0.000 -0.000 ] store /b1 % extracted from above [1.000 0.999 0.998 0.992 0.979 0.954 0.916 0.863 0.795 0.715 0.625 0.529 0.432 0.338 0.252 0.176 0.113 0.064 0.028 0.007 0.000 ] store /b2 % extracted from above [0.00 0.007 0.028 0.064 0.113 0.176 0.252 0.338 0.432 0.529 0.625 0.715 0.795 0.863 0.916 0.954 0.979 0.992 0.998 0.999 1.000 ] store /b3 % extracted from above [-0.000 -0.000 -0.001 -0.003 -0.009 -0.020 -0.036 -0.057 -0.080 -0.103 -0.125 -0.140 -0.147 -0.145 -0.132 -0.111 -0.083 -0.053 -0.026 -0.007 -0.000 ] store %% See Gurugram #04 for further details http://www.tinaja.com/gurgrm01.asp % /xinterp accepts a fractional value on the stack and returns its % best pixel based upon four adjacent horizontal pixels. % CONVENTION: Receives row data from tempstring1; outputs to tempstring2. % enter with fractional hposn on stack. Exit with interpolated pixels in /targetstring. % execution time on fast machine is approximately 30 seconds per megapixel % a /nopunch value of 254 prevents white punchthrough. /nopunch 254 store % 254 = prevent 255 = allow /xinterp { % fractional hposn on stack dup 3 le {pop 3} if % but never less than one dup hclip ge {pop hclip} if % or more than hres-3 dup dup floor sub 20 mul cvi % change fractional offset to 0-20 % will automagically be 0 at line ends. /ct exch store % table lookup cspline coefficients cvi 3 mul % always round low THEN 3x for pixels tempstring1 exch 3 sub % back up one pixel for -1 12 getinterval % grab twelve linestring RGB pixels /st exch store % store as /st % calc interpol via cubic spline /b0x b0 ct get store % pregrab for slight speedup /b1x b1 ct get store /b2x b2 ct get store /b3x b3 ct get store tempstring hposn 3 mul 2 copy % pregrab for slight speedup st 0 get b0x mul % new blue pixel using bicubic interpolation st 3 get b1x mul add st 6 get b2x mul add st 9 get b3x mul add cvi dup 0 lt {pop 0} if dup 255 gt {pop nopunch} if % correct possible over/under plus punchthru put 2 copy 1 add st 1 get b0x mul % new green pixel st 4 get b1x mul add st 7 get b2x mul add st 10 get b3x mul add cvi dup 0 lt {pop 0} if dup 255 gt {pop 255} if put 2 add st 2 get b0x mul % new red pixel st 5 get b1x mul add st 8 get b2x mul add st 11 get b3x mul add cvi dup 0 lt {pop 0} if dup 255 gt {pop 255} if put } bind def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (M.2) Bilineal Pixel Interpolator /xybilini /xilini /yilini % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % /xybilini Accepts a fractional X and Y position, and returns the best % linearly interpolated RGB color values for that position. % reads from instrarray pokes to tempstring1 location hposn*3 /xybilini { dup 0 le {pop 0} if % make sure y value is legal dup ylim ge {pop ylim} if dup cvi dup /yfloor exch store % save yfloor and yfract values sub dup /yfract exch store 1 sub neg /yfminus exch store dup 0 le {pop 0} if % make sure x value is legal dup xlim ge {pop xlim} if dup cvi dup 3 mul /xfloor exch store % save xfloor and xfract values sub dup /xfract exch store 1 sub neg /xfminus exch store tempstring1 hposn 3 mul 2 copy instrarray yfloor get xfloor get % interpolate blue pixel ll xfminus mul yfminus mul instrarray yfloor 1 add get xfloor get % ul xfminus mul yfract mul add instrarray yfloor 1 add get xfloor 3 add get % ur xfract mul yfract mul add instrarray yfloor get xfloor 3 add get xfract mul yfminus mul add % lr cvi put 2 copy 1 add instrarray yfloor get xfloor 1 add get % interpolate green pixel ll xfminus mul yfminus mul instrarray yfloor 1 add get xfloor 1 add get % ul xfminus mul yfract mul add instrarray yfloor 1 add get xfloor 4 add get % ur xfract mul yfract mul add instrarray yfloor get xfloor 4 add get xfract mul yfminus mul add % lr cvi put % (\nyfloor ----> ) print yfloor == % (xfloor ----> ) print xfloor == 2 add instrarray yfloor get xfloor 2 add get % dup == % interpolate red pixel ll xfminus mul yfminus mul instrarray yfloor 1 add get xfloor 2 add get %dup == % ul xfminus mul yfract mul add instrarray yfloor 1 add get xfloor 5 add get % dup == % ur xfract mul yfract mul add instrarray yfloor get xfloor 5 add get % dup == xfract mul yfminus mul add % lr cvi put } bind store % /ybilini Accepts a fractional Y position, and returns the best % linearly interpolated RGB color values for that position. % reads from instrarray pokes to tempstring1 location hposn*3 /ybilini { dup 0 le {pop 0} if % make sure y value is legal dup ylim ge {pop ylim} if dup cvi dup /yfloor exch store % save yfloor and yfract values sub dup /yfract exch store 1 sub neg /yfminus exch store tempstring1 hposn 3 mul 2 copy instrarray yfloor get hposn get yfract mul % interpolate blue pixel instrarray yfloor 1 add get hposn get yfminus mul add cvi put 2 copy 1 add instrarray yfloor get hposn 1 add get yfract mul % interpolate green pixel instrarray yfloor 1 add get hposn 1 add get yfminus mul add cvi put 2 add instrarray yfloor get hposn 2 add get yfract mul % interpolate green pixel instrarray yfloor 1 add get hposn 2 add get yfminus mul add cvi put } bind store % /xbilini Accepts a fractional Y position, and returns the best % linearly interpolated RGB color values for that position. % reads from instrarray pokes to tempstring1 location hposn*3 /xbilini { dup 0 le {pop 0} if % make sure x value is legal dup xlim ge {pop xlim} if dup cvi dup /xfloor exch store % save yfloor and yfract values sub dup /xfract exch store 1 sub neg /xfminus exch store instrarray yposn get xfloor 6 getinterval % get six sequential pixels /hstr exch store tempstring2 hposn 3 mul 2 copy % interpolate blue pixel hstr 0 get xfminus mul hstr 3 get xfract mul add cvi put 2 copy 1 add % interpolate green pixel hstr 1 get xfminus mul hstr 4 get xfract mul add cvi put 2 add % interpolate red pixel hstr 2 get xfminus mul hstr 5 get xfract mul add cvi put } bind store { % temp test area /ylim 1000 store /xlim 1000 store /yposn 2 store /tempstring1 (0000000000000000000000000000000000000000000000000000000000000000000) store /hposn 5 store /instrarray [(wertwertwertwert)(eehhsdfgsdfgsdfgsdfg)(kksdfgsdfgsdfgsdfg)(mmsfgsdfgsdfgsdfg) ] store stopwatchon 100000 { 1.23332 pop 2.667345 xbilini } repeat stopwatchoff tempstring1 asdf } pop %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (N) Deltatilt SimpleTtilt corrector % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % A simple tilt corrector for a digital camera. Accepts a /tiltaxis % whose vertical center is 0 at left, 0.5 at center and 1.0 at right % Plus a /howmuchtilt that is the percentage of screen change at % top left or right for a centered tiltaxis. % A positive /howmuchtilt moves the top towards the center as would % normally be needed when the camera is above the subject being imaged. % Best used with /howmuchtilt values less than 0.15. Distortion of % diagonals may become unacceptable above 0.20. % /tiltaxis 0.753 store % entered at top or later for convenience % /howmuchtilt 0.10 store % newpixel = (oldpixel - cen)gain + cen % needs solved for oldpixel % newpixel = oldpixel*gain - cen*gain + cen = oldpixel*gain - cen(gain-1) % newpixel + cen(gain-1) = oldpixel*gain % oldpixel = (newpixel + cen(gain-1)/gain /deltatilt { (\nDoing Delta Tilt Image Correction ) print flush /vsize instrarray length store % find image sizes /hsize instrarray 0 get length 3 sub 3 div cvi store /hcen hsize tiltaxis mul round cvi store /hclip instrarray 0 get length 3 div cvi 3 sub store % save for interpolation /outstrarray mark % start output array 0 1 vsize 1 sub { % for each horizontal line dup 100 mod 0 eq {(.) print flush % report progress 0 vmreclaim -2 vmreclaim } if /vline exch store /curgain { % calculate current line gain vline vsize div 2 mul 1 sub % calculate -1 0 1 vfraction howmuchtilt mul neg 1 add } store /tempstring2 hsize 1 add 3 mul string store % create output line string /tempstring hsize 1 add 3 mul string store /tempstring1 instrarray vline get store % /adj hcen curgain 1 sub mul store % precalculate constants for speed /xlim hclip store % patch for xbilini /yposn vline store % patch for bilin 3 1 tempstring length 3 div 1 sub cvi { % for each pixel triad /hposn exch store % save new PIXEL h position hposn % hcen sub curgain div hcen add xinterp % xfinterp % and interpolate % xbilini } for tempstring % tempstring1 } for % de keystone next line ] store % store output array 0 vmreclaim } bind store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (O) Proportional Resizer % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /scalefactor 0.82 store /propresize { (\n\n doing a proportional resize of ) scalefactor 10 string cvs mergestr (.\n) mergestr print /vsize instrarray length cvi store % input y image size in lines /hsize instrarray 0 get length 3 div cvi store % input x image size in pixels /outstrarray mark 0 1 vsize 1 sub scalefactor mul cvi { /vposn exch store /ylim vsize 1 sub store % set size limit /xlim hsize 3 sub store % set size limit /tempstring1 hsize scalefactor mul 3 mul cvi string store % create new line string to be filled 0 1 hsize 1 sub scalefactor mul cvi { /hposn exch store hposn scalefactor div % glotz add % temp improver? vposn scalefactor div % glotz add xybilini % reads instrarray writes tempstring hposn } for tempstring1 } for ] store % complete output array } store %%%%%%%%%%%%%%% demos -- remove or alter before reuse %%%%%%%%%%%%%%%%%%%%%%%%%%% % Uncomment ONE needed demo at a time! % Demo #1 -- simple unmodified image read and write (1 seconds for 1000x1000) % grabbitmap % read the input BMP file % instr2outstr % copy input to output array % savebitmap % save the output BMP file % Demo #2 -- crop image. Four data bytes are llx, lly, urx, ury % (1 seconds for 1000x1000 depends on crop tightness) % grabbitmap % 150 175 500 557 cropimage % crop image to positions shown % savebitmap % Demo #3 -- Flip image vertically. (1 seconds for 1000x1000) % grabbitmap % flipimagevertically % flip image vertically % savebitmap % Demo #4 -- Flip image horizontally. (3 seconds for 1000x1000) % grabbitmap % flipimagehorizontally % flip image vertically % savebitmap % Demo #5 -- Rotate image 180 degrees. (3 seconds for 1000x1000) % grabbitmap % rotateimageby180 % flip image vertically % savebitmap % Demo #6 -- Rotate image 90 degrees. (5 seconds for 1000x1000) % grabbitmap % rotateimageby90 % flip image by 90 degrees CW % savebitmap % Demo #7 -- Rotate image 270 degrees. (5 seconds for 1000x1000) % grabbitmap % rotateimageby270 % flip image by 270 degrees CW % savebitmap % Demo #8 -- Replace image with negative. (6 seconds for 1000x1000) % grabbitmap % negateimage % replace image with negative % savebitmap % Demo #9 -- quick background knockout to white % grabbitmap % knockback % quick background knockout % savebitmap % Demo #10 -- Proportionally resize image using bilineal interpolation stopwatchon grabbitmap /scalefactor 0.73 store /glotz 0 store propresize savebitmap stopwatchoff { % Demo #10 -- Delta keystone correction /howmuchtilt 0.50 store /tiltaxis 0.5 store stopwatchon grabbitmap deltatilt savebitmap stopwatchoff % Demo #999 interpolate pixel horizontally % grabbitmap } pop { /tempstring (000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000asdfasdfasfdasdfasdfasdfasdfasdfsadfasdfasdfasdfasdfasdf) store /linestring 200 string store /hposn 14 store /hresminus3 tempstring length 3 sub store % max clip limit 47.225 xinterp % interpolate this pixel horizontally tempstring == % savebitmap } pop %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % showpage % EOF