%!PS % Universal Bitmap Image Manipulation Utilities -- Red 255 eliminator % =================================================================== % by Don Lancaster %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Copyright c 2005, 2011, later 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. % presently setup for background knockout %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /sourcefilename (rltdom09.bmp) store /targetfilename (rltdom09nr.bmp) store % must have different filename /sourcefilenameprefix (C:\\Documents and Settings\\don 2\\Desktop\\Madeline Rework\\) store /targetfilenameprefix sourcefilenameprefix store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 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: % NOW USE GONZO FOR RANDOM (C:\\Documents and Settings\\don\\Desktop\\gonzo\\gonzo.ps) run % use internal % (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) Background Replacer /mottleback % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This reads a bitmap that has a complete true red or true white % subject outline but no other true red or white pixels and then uses % EW (later NS) techniques similar to knockback to replace the nonsubject % areas with a mottled background. % THERE MUST BE ZERO BREAKS IN THE WHITE OUTLINE! Actual test is red 255. % Any undercuts will still require manual intervention /mottleback { setcolorarray % interpret and create 0-255 colors makerandstring % build up RGB mottle reference area grabbitmap % build line by line RGB PS strings instr2outstr % replicate input strings to output stopwatchon domottlestuff % do NESW replacements stopwatchoff savebitmap % rewrite bitmap } store %%%%%%%%%% do motlestuff %%%%%%%%%%% /domottlestuff { /howwide outstrarray 0 get length 3 div cvi store % number of horizontal pixels /howhigh outstrarray length 1 sub store % number of vertical pixels /maxew instrarray 0 get length 1 sub store % max right pixel start /eastendarray mark howwide 3000 add {0} repeat ] store % make position arrays /weststartarray mark howwide 3000 add {howwide} repeat ] store % for possible NS use /shortestwest maxew store % initialize all columns filled /shortesteast 0 store % for each horizontal line... 0 1 howhigh { /curvpos exch store % save line number UP FROM BOTTOM /curline instrarray curvpos get store % grab current rgb line % begin WE data gathering 2 3 maxew {/curhpos exch store % grab current RED pixel as in bgr bitmap curline curhpos get 255 eq {exit} if } for % stop on red or white curhpos 3 maxew {/curhpos exch store % continue till no red or white curline curhpos get 255 ne{exit} if } for eastendarray curvpos curhpos put % save easternmost continuous position shortestwest dup curhpos gt % save shortest WE value { pop curhpos}if /shortestwest exch store % place WE data motstring mottlecanmaxstart random 3 mul curhpos 1 sub getinterval curline exch 0 exch putinterval outstrarray curvpos curline put % begin EW data gathering maxew -3 curhpos {/curewhpos exch store curline curewhpos get 255 eq {exit} if} for curewhpos -3 curhpos {/curewhpos exch store curline curewhpos get 255 ne {exit} if} for weststartarray curvpos curewhpos put shortesteast dup curewhpos lt { pop curhpos}if /shortestwest exch store % place WE data motstring mottlecanmaxstart random 3 mul maxew curewhpos sub getinterval curline exch curewhpos 1 add exch putinterval outstrarray curvpos curline put } for % end EW and WE substitutions { (\n\n\n) print flush eastendarray == shortestwest == } pop % continue with NS and SN (maybe)... { 0 1 outstrarray length 1 sub {/curtestline exch store % for each horizontal line instrarray curtestline get /curstring exch store % use unmodified lines! 0 % start rgb position counter 2 3 curstring length 1 sub {/curposn exch store curposn dup curstring exch get % check for red 255 255 eq {pop exit}{exch pop }ifelse } for dup 3 add % huh? 3 curstring length 1 sub {dup curstring exch get % check for red 255 255 ne {pop exit}{exch pop }ifelse } for 1 add % adjust??? /motwidth exch store eastendarray curtestline motwidth put % save position to array %%% save shortest line end to date shortestwest dup motwidth ge {pop motwidth} if /shortestwest exch store % save westernmost end (\n\nshortestwest is now ) print flush shortestwest == %%% motstring mottlecanmaxstart random 3 mul motwidth getinterval curstring exch 0 exch putinterval outstrarray curtestline curstring put %% start west pass nored /curwpixelpos curstring length 1 sub store % initialize /wcount 0 store % temp - stack may be faster if needed curstring length 1 sub -3 motwidth 1 add { % only to the right of WE pass /curwpixelpos exch store curstring curwpixelpos get 255 ne {/wcount wcount 1 add store} {exit} ifelse %% maybe continue west pass red or white } for % paint west pass motstring % from mottled string array mottlecanmaxstart random 3 mul 1 sub % ? color phasing? wcount getinterval % get a long enough west string curstring exch curwpixelpos exch putinterval % insert mottled string segment outstrarray curtestline curstring put % place modified line % save west info %% end west pass } for % for each horizontal line (\n\neastendarray is now...\n) print flush eastendarray == shortestwest == } pop } store % temporary /motstringblack [ 15000 {0} repeat ] makestring store %%%%%%%%%%%%%%%%% % [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 %%%%%%%%%%% color setting %%%%%%%%%%%%%%%% % /setcolorarray allows entry of unmottled color either as rgb (3 values) or 216 (1 value) array /setcolorarray { dup length 1 eq % how many colors entered? {set216color} % just one - use 216 {/curcolor exch store} ifelse % three - use RGB } store % setwebtint accepts a color number 0 to 215 and then % sets the PostScript color generator for later use... % tintmat is a self-generating list of 216 triple color values /webtintmat256 [ % needs reversed for paint? 0 1 5 { /a exch store 0 1 5 { /b exch store 0 1 5 {/c exch store c 5 div 255 mul cvi b 5 div 255 mul cvi a 5 div 255 mul cvi }for } for } for ] def /set216color { 0 get abs cvi 216 cvi mod % restrict range webtintmat256 exch 3 mul 3 getinterval % get values from tabl /curcolor exch store } def %%%%%%%%%%%%% curcolor adjustments %%%%%%%%%%%%%%%%% % optional color trimming tools. works both old and new method. /trim 15 store % amount of trim 25 = 10 percent /nowhite true store % prevent true whites? /morewhite { curcolor 0 get dup nowhite{254 trim sub}{255 trim sub} ifelse lt {trim add} if curcolor exch 0 exch put curcolor 1 get dup nowhite {254 trim sub}{255 trim sub} ifelse lt {trim add} if curcolor exch 1 exch put curcolor 2 get dup nowhite {254 trim sub}{255 trim sub} ifelse lt {trim add} if curcolor exch 2 exch put } store /morered { curcolor 0 get dup nowhite {254 trim sub}{255 trim sub} ifelse lt {trim add} if curcolor exch 0 exch put} store /moregreen { curcolor 1 get dup nowhite {254 trim sub}{255 trim sub} ifelse lt {trim add} if curcolor exch 1 exch put} store /moreblue { curcolor 2 get dup nowhite {254 trim sub}{255 trim sub} ifelse lt {trim add} if curcolor exch 2 exch put } store /lesswhite { curcolor 0 get dup trim gt {trim sub} if curcolor exch 0 exch put curcolor 1 get dup trim gt {trim sub} if curcolor exch 1 exch put curcolor 2 get dup trim gt {trim sub} if curcolor exch 2 exch put} store /lessred { curcolor 0 get dup trim gt {trim sub} if curcolor exch 0 exch put} store /lessgreen { curcolor 1 get dup trim gt {trim sub} if curcolor exch 1 exch put} store /lessblue { curcolor 2 get dup trim gt {trim sub} if glotz curcolor exch 2 exch put ( this is supposed to offset ) print flush curcolor == } store %%%%%%%%%%%%%%%%%%%%% % lessblue is currently not working put does not seem to work % temptest { [123] setcolorarray curcolor [45 56 67] setcolorarray curcolor lessblue orhere curcolor trim asdfasdf } pop %%%%%%%%%%%%%%%%%% make random arrays %%%%%%%%%%%%%% % one long random string is used in rgb sequence for a background pattern % a random start is then chosen for each new line to be mottleized. % not splitting rgb is likely much faster. % a table lookup can optionally be used to restrict patterns if useful % rotating 4-step might be faster than strange access % mv mottlevariance needs predefined in header /mottlecanlength 5000 store /mottlecanmaxstart 2500 store % /randfactor 2 31 exp 1 sub mv div floor cvi store % restore for knockback 12345 srand % use same pattern each time /makerandstring { % currently takes 31? milliseconds, adjustcurcolor /motstring mark mottlecanlength 3 mul { % reverse for bmp sequence! curcolor 2 get rand randfactor idiv add curcolor 1 get rand randfactor idiv add curcolor 0 get rand randfactor idiv add } repeat ] makestring store } store % adjustcurcolor centers the variance but prevents underflows /adjustcurcolor { /curcolor mark curcolor 0 get mv 2 div floor cvi sub dup 0 le {pop 0} if curcolor 1 get mv 2 div floor cvi sub dup 0 le {pop 0} if curcolor 2 get mv 2 div floor cvi sub dup 0 le {pop 0} if ] store % (\n\n\ncurcolor is now ) print flush curcolor == } store %%%%%%%%%%%%% nored - replaces red 255 with red 254 /nored { grabbitmap % build line by line RGB PS strings instr2outstr % replicate input strings to output donored % do nored -- can become noblue or nogreen savebitmap % rewrite bitmap } store % temporarily replace 255 with 0 to check red dropout... /donored { 0 1 outstrarray length 1 sub {/curvpos exch store /curline outstrarray curvpos get store 2 3 curline length 1 sub {/curpos exch store curline curpos get 255 eq { curline curpos 254 put} if } for % for each red pixel outstrarray curvpos curline put % index in middle of put } for % for each string } 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 % stopwatchon % grabbitmap % knockback % quick background knockout % savebitmap % stopwatchoff % Demo #10 -- mottled background replacer % requires data at top of this file predefined % stopwatchon % [127 210 210 ] % pop [167] % backgroundcolor % mottleback % stopwatchoff %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Demo #11 red 255 eliminator % requires data at top of this file predefined stopwatchon nored stopwatchoff % showpage % EOF