%!PS % Combined automottling background and vignette utilities % ======================================================= % by Don Lancaster %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Copyright c 2005, 2010 by Don Lancaster & Synergetics, Box 809, Thatcher, AZ, 85552 %% ATTEMPTED MODIFICATION FOR BLACK= 0 Red % (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 mottling % NOTE THAT ALL PS FILENAME STRINGS !!!DEMAND!!! DOUBLE REVERSE SLASHES. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /sourcefilename (tsash03t.bmp) store /targetfilename (tsashx3v.bmp )store /sourcefilename (assbacj.bmp) store /targetfilename (assbacjv.bmp)store /sourcefilename (hanson1dt.bmp) store /targetfilename (hanson01f.bmp)store /sourcefilename (altab01t1.bmp) store /targetfilename (altab01t1m.bmp)store /background [ 33 ] store % one digit for 216 web colors; three digits for true RGB /sourcefilenameprefix (C:\\Documents and Settings\\don 2\\Desktop\\Madeline Rework\\ready to outline\\) store /targetfilenameprefix sourcefilenameprefix store /mv 22 store % mottle variance /includemottle true store % Provide mottled background? /includefills false store % include internal background fills? /includevignette true store % Provide shaded border? /vigwide 150 store % twice the vignette width in pixels at current resolution /vigtrips 400 store % trips to unify corners big=slow %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /showtime true store % make timings visible? % 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 (\nElapsed time: ) print 20 string cvs print ( seconds.\n) 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 /random {rand 65536 div 32768 div mul cvi} def % as in -- 6 random -- % no longer used %%%%%%%%% 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 showtime { (Bitmap width is ) exch mergestr ( pixels.\n) mergestr print flush } if % 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 showtime { (Bitmap height is ) exch mergestr ( pixels.\n) mergestr print flush } if % 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 { showtime { (\nReading initial bitmap from disk...) print flush } if -2 vmreclaim /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 2 vmreclaim 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 { showtime {(\nSaving processed bitmap image to disk...) print flush } if 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 %%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (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 /outstrarray instrarray length array store % build empty output string outstrarray 0 instrarray 0 get put includemottle{ % mottle background if wanted. domottlestuff} if % working from WESN includefills{ % do internal fills if wanted redfill} if % replacing internal reds or whites includevignette{ % vignette edges if wanted dovignette} if 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 store % max right pixel start /westendarray mark howhigh 1 add {9999} repeat ] store % make position arrays /eaststartarray mark howhigh 1 add {0} repeat ] store % for bounding box -2 vmreclaim % stop excessive vm reclamation % begin WE data gathering stopwatchon 0 1 howhigh { /curvpos exch store % save line number UP FROM BOTTOM /curline instrarray curvpos get % grab current rgb line with crucial dup length string cvs store % dereference to preserve instarray 2 2 3 maxew {dup % scan w to e until white or red curline exch get 255 pop 0 eq {exch pop exit} if exch pop} for dup 3 maxew {dup curline exch get 255 pop 0 ne % scan w to e until no more white or red {pop 3 sub /curhpos exch store exit} if exch pop } for % place WE data motstring mottlecanmaxstart random 3 mul curhpos maxew 6 sub ge % crude repair bizarre full line bug {/curhpos curhpos 3 add store} if curhpos 1 add % adjust length for triads getinterval dup length string cvs % dereference -- not sure if needed curline exch 0 exch putinterval outstrarray curvpos curline put % save WE ranges westendarray curvpos curhpos 1 add 3 div cvi 1 sub put % save easternmost continuous position } for % end WE replacements %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% showtime { (\n\n West to East fillins took ) print flush stopwatchoff } if %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % calculate N,W, and S values for bounding box % E value has to wait till after E fillin % find west minimum and east maximum /shortestwest 9999 store 0 1 westendarray length 1 sub {/curatest exch store westendarray curatest get dup /curwvalue exch store shortestwest lt {/shortestwest curwvalue store} if } for 0 1 westendarray length 1 sub {/minsouth exch store westendarray minsouth get outstrarray 0 get length 9 sub 3 div cvi le {/minsouth minsouth 1 sub store exit} if } for westendarray length 1 sub -1 minsouth {/maxnorth exch store westendarray maxnorth get outstrarray 0 get length 9 sub 3 div cvi le {/maxnorth maxnorth 1 add store exit} if } for % (\n\n westendarray is now \n) print flush westendarray == % ( minsouth is now ) print flush minsouth == % ( shortestwest is now ) print flush shortestwest == % ( maxnorth is now ) print flush maxnorth == 2 vmreclaim 0 vmreclaim %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -2 vmreclaim stopwatchon % begin EW data gathering /curepos 255 1 sub store % huh initialize? minsouth 1 add 1 maxnorth 1 sub { /curvpos exch store % save line number UP FROM MINSOUTH /curline instrarray curvpos get % grab current rgb line with crucial dup length string cvs store % dereference to preserve instarray maxew 1 sub dup -3 shortestwest 3 mul {dup % eliminate bunches of stores? curline exch get 255 pop 0 eq {exch pop exit} if exch pop} for dup -3 shortestwest 3 mul {dup curline exch get 255 pop 0 ne {pop /curepos exch store exit} if exch pop } for % (\ncurepos is now ) print flush curepos 3 div == % place EW data /curline1 outstrarray curvpos get store /ewmottlewidth maxew curepos 1 add sub store % find ew substitute width motstring mottlecanmaxstart random 3 mul ewmottlewidth getinterval dup length string cvs % dereference -- not sure needed curline1 exch curepos 1 add exch putinterval outstrarray curvpos curline1 put % save EW ranges eaststartarray curvpos curepos 1 add 3 div cvi 1 sub put % save easternmost continuous position } for % (\n\naststartarray is ) print flush eaststartarray == % find western edge of bounding box /maxwest 0 store 0 1 eaststartarray length 1 sub { /curapos exch store eaststartarray curapos get dup maxwest gt {/maxwest exch store}{pop} ifelse } for %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% showtime { (\n\n East to West fillins took ) print flush stopwatchoff } if %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % (maxwest is now ) print flush maxwest == 2 vmreclaim 0 vmreclaim % begin SN data gathering -2 vmreclaim stopwatchon shortestwest 1 add 1 maxwest { /curcolumn exch store % column under test % find northernmost southern valid line minsouth 1 add 1 maxnorth 1 sub { /currow exch store westendarray currow get curcolumn ge eaststartarray currow get curcolumn lt or not {exit} if % true if one or other has filled } for % each row in a column /currow currow 1 sub store % exit on last valid ro /currow currow dup 0 le {pop 0} if store % test for outside or edge. If existing fill WAS red 255, this is possibly % the start of a vertical edge. % If not, this is the continuance of the original outside background. instrarray currow get curcolumn 3 mul 2 add get 255 pop 0 eq {sedgeproc}{soutproc} ifelse } for % for each column gottoh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% showtime { (\n\n South to North fillins took ) print flush stopwatchoff } if %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 vmreclaim -2 vmreclaim % begin NS data gathering stopwatchon (\nstarting ns data gathering ) print flush shortestwest 1 add 1 maxwest { /curcolumn exch store % column under test % (\ncurcolumn is now ) print flush curcolumn == % find northernmost southern valid line % temp starting line false { outstrarray maxnorth 1 sub get dup length string cvs /temphold exch store temphold curcolumn 3 mul (zzz) putinterval outstrarray minsouth 1 add temphold put } if maxnorth 1 sub -1 minsouth { /currow exch store % (\currow is now ------------------> ) print flush currow == % westendarray currow get curcolumn ge % eaststartarray currow get curcolumn lt % or not {exit} if westendarray currow get curcolumn lt { % progressive slightly faster eaststartarray currow get curcolumn ge {exit} if } if } for % each row in a column /currow currow 1 add store % exit on last valid row % (exited with currow of ) print flush currow == % temp limit check false { outstrarray currow get dup length string cvs /temphold exch store temphold curcolumn 3 mul (000) putinterval outstrarray currow temphold put } if % test for outside or edge. If existing fill WAS red 255, this is possibly % the start of a vertical edge. % If not, this is the continuance of the original outside background. instrarray currow get curcolumn 3 mul 2 add get 255 pop 0 eq {nedgeproc}{noutproc} ifelse } for % for each column %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% showtime { (\n\n North to South fillins took ) print flush stopwatchoff } if %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 vmreclaim 0 vmreclaim } bind store % end of domottlestuff proc %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % fill edge pixels /sedgeproc { % (edge\n) print flush currow 1 add 1 maxnorth 1 sub {/presentloc exch store instrarray presentloc get curcolumn 3 mul 2 add get 255 pop 0 eq { outstrarray presentloc get curcolumn 3 mul motstring mottlecanmaxstart random 3 mul 3 getinterval putinterval } {exit} ifelse } for } store /soutproc { % (outside\n) print flush % fill outside pixels currow 1 add 1 maxnorth 1 sub {/presentloc exch store instrarray presentloc get curcolumn 3 mul 2 add get 255 pop 0 ne { outstrarray presentloc get curcolumn 3 mul motstring mottlecanmaxstart random 3 mul 3 getinterval putinterval }{exit} ifelse } for % fill edge pixels presentloc 1 maxnorth 1 sub {/presentloc exch store instrarray presentloc get curcolumn 3 mul 2 add get 255 pop 0 eq { outstrarray presentloc get curcolumn 3 mul motstring mottlecanmaxstart random 3 mul 3 getinterval putinterval } {exit} ifelse } for } store /nedgeproc { % (edge\n) print flush currow 1 sub -1 minsouth 1 add {/presentloc exch store instrarray presentloc get curcolumn 3 mul 2 add get 255 pop 0 eq { outstrarray presentloc get curcolumn 3 mul motstring mottlecanmaxstart random 3 mul 3 getinterval putinterval } {exit} ifelse } for } store /noutproc {% (outside\n) print flush % fill outside pixels currow 1 sub -1 minsouth 1 add {/presentloc exch store instrarray presentloc get curcolumn 3 mul 2 add get 255 pop 0 ne { outstrarray presentloc get curcolumn 3 mul motstring mottlecanmaxstart random 3 mul 3 getinterval putinterval }{exit} ifelse } for % fill edge pixels presentloc -1 minsouth 1 add {/presentloc exch store instrarray presentloc get curcolumn 3 mul 2 add get 255 pop 0 eq { outstrarray presentloc get curcolumn 3 mul motstring mottlecanmaxstart random 3 mul 3 getinterval putinterval } {exit} ifelse } for } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % /redfill is a mottled background option that replaces any true red or white pixels inside % the subject with a mottled background. This is useful to eliminate undercuts that % have been prepainted white or true red. Or to deal with "holes" in the image % such as boltholes or gaps in a coil of wire. The routine is an option because it % can be considerably slower than the actual mottling process. /redfill { stopwatchon (\nbeginning red or white contained fillins ) print flush minsouth 1 maxnorth 1 sub {/currow exch store /currow currow dup 0 le {pop 0} if store westendarray currow get 1 eaststartarray currow get { /curcol exch store outstrarray currow get curcol 3 mul 2 add get 255 pop 0 eq { % ( gotone ) print flush outstrarray currow get curcol 3 mul motstring mottlecanmaxstart random 3 mul 3 getinterval putinterval } if } for % each pixel } for % each row and ps string %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% showtime { (\n\n Random white or true red fillins took ) print flush stopwatchoff } if %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% } 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 /lessgreen { curcolor 2 get dup trim gt {trim sub} if curcolor exch 2 exch put} store % ( this is supposed to offset ) print flush curcolor == } store %%%%%%%%%%%%%%%%%% 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 2500 store % max bitmap width currently 2500 bgr pixels /mottlecanmaxstart 250 store /randfactor 2 31 exp 1 sub mv div floor cvi store /randsfactor 2 31 exp 1 sub mottlecanmaxstart div floor cvi store 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 { /redmotval curcolor 0 get mv 2 div floor cvi sub % shift down to center random dup 0 lt {pop 0} if % lock out underadjustment dup nowhite % lock out overadjustment and possibly white {254 mv sub ge {pop 253 mv sub} if} % one extra cause of glitch {255 mv sub ge {pop 254 mv sub} if} ifelse store /greenmotval curcolor 1 get mv 2 div floor cvi sub % shift down to center random dup 0 lt {pop 0} if % lock out underadjustment dup nowhite % lock out overadjustment and possibly white {254 mv sub ge {pop 253 mv sub} if} {255 mv sub ge {pop 254 mv sub} if} ifelse store /bluemotval curcolor 2 get mv 2 div floor cvi sub % shift down to center random dup 0 lt {pop 0} if % lock out underadjustment dup nowhite % lock out overadjustment and possibly white {254 mv sub ge {pop 253 mv sub} if} {255 mv sub ge {pop 254 mv sub} if} ifelse store /curcolor mark redmotval greenmotval bluemotval ] store % (\n\n\ncurcolor is now ) print flush curcolor == } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % (N) Vignetting option /dovignette % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % /dovignette optionally provides a luminance shaded edge to the image. % It is an inserted continuance to the moddling code. % The input image must be of a correctly cropped final ratio to include % reasonable room for the vignetted border. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% start vignetting routines with a cornerblock generator % This one is rather fancy as it uses electromagnetic field relaxation techniques % for best appearance. /buildcornerblock { newpath truesize dup dup 2 div 0 360 arc % draw circle once /cornerblock mark truesize { % build initial midlum array mark truesize { 1 darkening sub 2 div darkening add } repeat ]} repeat ] store cornerblock dup 0 mark truesize {darkening} repeat ] put % boundary bottom row 0 1 truesize 1 sub {/colnum exch store % boundary left column cornerblock colnum get 0 darkening put } for /edgeinc 1 darkening sub truesize 2 div div store % calculate edge increment 0 1 truesize 2 div 1 pop 0 sub cvi {/curpos exch store % build partial top row boundary cornerblock truesize 1 sub get curpos darkening edgeinc curpos mul add put } for 0 1 truesize 2 div 1 sub cvi {/curpos exch store % build partial right column boundary cornerblock curpos get truesize 1 sub darkening edgeinc curpos mul add put} for boundarycircle % assert boundary quarter circle relaxtrips {relax % remap using field relaxation false {cornerblock 7 get 7 get = } if % optionally monitor convergence } repeat false {cornerblock == }if % optionally report full array } store % /boundarycircle places a quarter unit luminance circle in the upper righthand corner % It does not need reasserted because /relax kicks out on the first 1 in a row. /boundarycircle { truesize 2 div cvi 1 % map unity luminance values upper right truesize 1 sub { /vv exch store truesize 2 div cvi 1 truesize 1 sub {/hh exch store hh vv infill % use magic infill operator { cornerblock vv get hh 1 put} if % one white pixel per row is enough } for } for } store % /relax averages the four nearest neighbors of each internal array luminance value % repeating many times converges on a true field solution and the smoothest corners /relax { 1 1 truesize 2 sub {/vvv exch store % for each internal row /cur cornerblock vvv get store % save rows for speed /prev cornerblock vvv 1 sub get store /post cornerblock vvv 1 add get store 1 1 truesize 2 sub {/hhh exch store % for each internal lum value cur hhh get 1 eq {exit} if % stop row at circle edge cur hhh 1 sub get % calculate NSEW average cur hhh 1 add get add prev hhh get add post hhh get add 4 div cur exch hhh exch put % and replace } for } for } store % /placecornerblocksw places the selected cornerblock in the southwest corner /placecornerblocksw { /numlines cornerblock length store 0 1 numlines 1 sub {/currownum exch store /currowstring outstrarray currownum get store /curcornline cornerblock currownum get store 0 1 numlines 1 sub { /curpixel exch store /curtriad curpixel 3 mul store /curlum curcornline curpixel get store curlum 1 ne { currowstring dup dup curtriad get curlum mul cvi % adjust blue pixel curtriad exch put dup dup curtriad 1 add get curlum mul cvi % adjust green pixel curtriad 1 add exch put dup curtriad 2 add get curlum mul cvi % adjust red pixel curtriad 2 add exch put } {exit} ifelse } for % for each pixel to be corrected } for % for each row of the corner } store /placecornerblocknw { /numlines cornerblock length store 0 1 numlines 1 sub {/currownum exch store /currowstring outstrarray dup length 1 sub currownum sub get store /curcornline cornerblock currownum get store 0 1 numlines 1 sub { /curpixel exch store /curtriad curpixel 3 mul store /curlum curcornline curpixel get store curlum 1 ne { currowstring dup dup curtriad get curlum mul cvi % adjust blue pixel curtriad exch put dup dup curtriad 1 add get curlum mul cvi % adjust green pixel curtriad 1 add exch put dup curtriad 2 add get curlum mul cvi % adjust red pixel curtriad 2 add exch put } if } for % for each pixel to be corrected } for % for each row of the corner } store /placecornerblockne { /numlines cornerblock length store 0 1 numlines 1 sub {/currownum exch store /currowstring outstrarray dup length 1 sub currownum sub get store /curcornline cornerblock currownum get store 0 1 numlines 1 sub { /curpixel exch store % /curtriad curpixel 3 mul store /curtriad outstrarray 0 get length 3 sub curpixel 3 mul sub store /curlum curcornline curpixel get store curlum 1 ne { currowstring dup dup curtriad get curlum mul cvi % adjust blue pixel curtriad exch put dup dup curtriad 1 add get curlum mul cvi % adjust green pixel curtriad 1 add exch put dup curtriad 2 add get curlum mul cvi % adjust red pixel curtriad 2 add exch put } if } for % for each pixel to be corrected } for % for each row of the corner } store /placecornerblockse { /numlines cornerblock length store 0 1 numlines 1 sub {/currownum exch store /currowstring outstrarray currownum get store /curcornline cornerblock currownum get store 0 1 numlines 1 sub { /curpixel exch store % /curtriad curpixel 3 mul store /curtriad outstrarray 0 get length 3 sub curpixel 3 mul sub store /curlum curcornline curpixel get store curlum 1 ne { currowstring dup dup curtriad get curlum mul cvi % adjust blue pixel curtriad exch put dup dup curtriad 1 add get curlum mul cvi % adjust green pixel curtriad 1 add exch put dup curtriad 2 add get curlum mul cvi % adjust red pixel curtriad 2 add exch put } if } for % for each pixel to be corrected } for % for each row of the corner } store /placesouthrows { /numlines cornerblock length store 0 1 numlines 1 sub {/currownum exch store /currowstring outstrarray currownum get store /curlum cornerblock currownum get numlines 1 sub get store curlum 1 ne { 0 cornerblock length add 3 mul 3 outstrarray 0 get length 1 sub cornerblock length 3 mul sub {/curtriad exch store currowstring dup dup curtriad get curlum mul cvi % adjust blue pixel curtriad exch put dup dup curtriad 1 add get curlum mul cvi % adjust green pixel curtriad 1 add exch put dup curtriad 2 add get curlum mul cvi % adjust red pixel curtriad 2 add exch put } for % for each pixel triad }{exit} ifelse % when not times one } for % for each row } store /placewestrows { /numlines cornerblock length store 0 1 numlines 1 sub {/currownum exch store % for each row of the corner /currowstring outstrarray currownum get store /curlum cornerblock currownum get numlines 1 sub get store /curtriad currownum 3 mul store curlum 1 ne { numlines 1 outstrarray length 1 sub numlines sub {/curline exch store curline outstrarray exch get /currowstring exch store currowstring dup dup curtriad get curlum mul cvi % adjust blue pixel curtriad exch put dup dup curtriad 1 add get curlum mul cvi % adjust green pixel curtriad 1 add exch put dup curtriad 2 add get curlum mul cvi % adjust red pixel curtriad 2 add exch put } for % for each pixel triad } if % when not times one } for % for each row } store /placeeastrows { /numlines cornerblock length store 0 1 numlines 1 sub {/currownum exch store % for each row of the corner /currowstring outstrarray currownum get store /curlum cornerblock currownum get numlines 1 sub get store /curtriad outstrarray 0 get length 3 sub currownum 3 mul sub store curlum 1 ne { numlines 1 outstrarray length 1 sub numlines sub {/curline exch store curline outstrarray exch get /currowstring exch store currowstring dup dup curtriad get curlum mul cvi % adjust blue pixel curtriad exch put dup dup curtriad 1 add get curlum mul cvi % adjust green pixel curtriad 1 add exch put dup curtriad 2 add get curlum mul cvi % adjust red pixel curtriad 2 add exch put } for % for each pixel triad } {exit} ifelse % when not times one } for % for each row } store /placenorthrows { /numlines cornerblock length store 0 1 numlines 1 sub {/currownum exch store /currowstring outstrarray dup length 1 sub currownum sub get store /curlum cornerblock currownum get numlines 1 sub get store curlum 1 ne { 0 cornerblock length add 3 mul 3 outstrarray 0 get length 1 sub cornerblock length 3 mul sub {/curtriad exch store currowstring dup dup curtriad get curlum mul cvi % adjust blue pixel curtriad exch put dup dup curtriad 1 add get curlum mul cvi % adjust green pixel curtriad 1 add exch put dup curtriad 2 add get curlum mul cvi % adjust red pixel curtriad 2 add exch put } for % for each pixel triad } {exit} ifelse % when not times one } for % for each row } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % this is the new field based high level vignetting code /dovignette { -2 vmreclaim stopwatchon showtime {(\n\nBeginning vignetting) print flush } if /darkening 0.60 store % minimum edge luminance multiplier /truesize 76 store % side or top width is one-half corner map size % /truesize 120 store % /relaxtrips 400 store /truesize vigwide store /relaxtrips vigtrips store buildcornerblock placecornerblocksw placecornerblockse placecornerblocknw placecornerblockne placesouthrows placenorthrows placeeastrows placewestrows %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% showtime { (\n\n Vignetting took ) print flush stopwatchoff } if %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 vmreclaim 0 vmreclaim } store %%%%%%%%%%%%%%% demos -- remove or alter before reuse %%%%%%%%%%%%%%%%%%%%%%%%%%% % Demo #10 mottled background replacer ( other demos removed) % requires data at top of this file predefined % [127 210 210 ] pop [34] % enter average background color 94= tan background mottleback %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % showpage % EOF