%!PS % Improved PS Bitmap "Magic" Background Filler % =================================== % by Don Lancaster %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /rootfilename (milmlt01.bmp) store /backgroundselect { % bottommost uncommented gets chosen % aqua1 blue1 % brown1 % dark1 % green1 % gray1 % gray2 ivory1 % magenta2 % tan1 % white1 } store /dovignette true store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Combines magic fill with optional vignette. MUST be final crop! % Copyright c 2003 by Don Lancaster & Synergetics, Box 809, Thatcher, AZ, 85552 % (928) 428-4073 Email: don@tinaja.com Website: http://www.tinaja.com % Consulting services available http://www.tinaja.com/info01.html % All commercial rights and all electronic media rights ~fully~ reserved. % Linking usually welcome. Reposting expressly forbidden. Version 1.1 % PostScript-as-language utility reads a 24-bit uncompressed bitmap file and % replaces each FF FF FF white occurrance with a random selection of a few % closely related colors. This creates a pleasant "rich" background while % dramatically reducing JPEG edge artifacts. At a price of moderately larger files. % Improved version generates rich backgrounds from a minimal array. % Note that NOWHITE.PSL ~must~ be used before knocking out background to white!!! % Note also that sharpening or contrast changes may add unwanted additional whites. % To use, load into wp or editor, change filenames below and send to Distiller. % A "no Acrobat PDF file produced" error is normal and expected. % ========= % IMPORTANT NOTE: Don Lancaster's file gonzo.ps is 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 gonzo % (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, 2001 by Don Lancaster and Synergetics, Box 809, % Thatcher Arizona, 5552 (928) 428-4073 don@tinaja.com support % via http://www.tinaja.com All commercial rights and all electronic % media rights **FULLY** reserved. Reposting is expressly forbidden. % ======== /guru { gonzo begin ps.util.1 begin printerror nuisance begin} def guru % activate gonzo utilities % ========= % dink with filenames rootfilename (.) search {dup length string cvs /pre exch store /gotcha exch store /post exch store pre dup length 2 sub (c) putinterval pre gotcha mergestr post mergestr /wfilename exch store }{mistook_in_filename} ifelse % Define colors here. Each color array consists of [red blue green variation]. % A variation of 30 gives mild patterns, 80 gives strong. /tan1 { [244 146 47 40] makebackpat} store /aqua1 { [22 220 231 90] makebackpat} store /gray1 { [160 160 160 65] makebackpat} store /gray2 { [160 160 160 32] makebackpat} store /magenta1 { [112 57 153 80] makebackpat} store % bright and dark /magenta2 { [162 137 213 80] makebackpat} store /brown1 { [208 141 59 35] makebackpat} store /ivory1 { [227 219 199 40] makebackpat} store /white1 { [255 255 255 0] makebackpat} store % for white only vignette /blue1 {[120 180 230 60] makebackpat} store /green1 {[80 205 140 60] makebackpat} store /dark1 {[85 85 85 65] makebackpat} store /numbackcolors 3 store % presently set to three different pixel colors 12345 srand % sets random pattern seed /str1 (XXX) store % patterns as rgb strings /str2 (YYY) store /str3 (ZZZ) store % /makebackpat generates an array of form [(r1 g1 b1) (r2 g2 b2) (r3 g3 b3) ] /makebackpat {aload pop /texture exch store /b0 exch store /g0 exch store /r0 exch store 123 srand /r1 r0 texture random texture 2 div sub add cvi dup 255 ge {pop 255}if dup 0 lt {pop 0} if store /g1 g0 texture random texture 2 div sub add cvi dup 255 ge {pop 255}if dup 0 lt {pop 0} if store /b1 b0 texture random texture 2 div sub add cvi dup 255 ge {pop 255}if dup 0 lt {pop 0} if store /r2 r0 texture random texture 2 div sub add cvi dup 255 ge {pop 255}if dup 0 lt {pop 0} if store /g2 g0 texture random texture 2 div sub add cvi dup 255 ge {pop 255}if dup 0 lt {pop 0} if store /b2 b0 texture random texture 2 div sub add cvi dup 255 ge {pop 255}if dup 0 lt {pop 0} if store /r3 r0 texture random texture 2 div sub add cvi dup 255 ge {pop 255}if dup 0 lt {pop 0} if store /g3 g0 texture random texture 2 div sub add cvi dup 255 ge {pop 255}if dup 0 lt {pop 0} if store /b3 b0 texture random texture 2 div sub add cvi dup 255 ge {pop 255}if dup 0 lt {pop 0} if store str1 0 b1 put % stuff strings str1 1 g1 put str1 2 r1 put str2 0 b2 put str2 1 g2 put str2 2 r2 put str3 0 b3 put str3 1 g3 put str3 2 r3 put /backpat mark str1 str2 str3 ] store % make bgr string array } store %%%%% demo - remove or alter before reuse. especially filenames! %%%%%%% % select the background pattern % tan1 aqua1 gray1 brown1 ivory1 % gray1 % magenta2 dark1 gray2 % magenta2 % brown1 % aqua1 % blue1 % green1 backgroundselect % input name of bmp file to be evaluated here... /diskfileheader (C:\\Documents and Settings\\don\\Desktop\\aarawpix\\) store /diskfilesourcename rootfilename store /diskfiletargetname wfilename store /sourcefilename diskfileheader diskfilesourcename mergestr store /targetfilename diskfileheader diskfiletargetname mergestr store /readfile sourcefilename (r) file store % establish input read file /writefile targetfilename (w+) file store % establish output target file /colortoreplace (XXX) def % color to be replaced colortoreplace 0 255 put colortoreplace 1 255 put colortoreplace 2 255 put /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 %%%%%%%%%%%%%%%% COPY HEADER TO TARGET FILE %%%%%%%%%%%%%%%%%% % 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 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 %%%%%%%%%%%%%%%% COPY DATA TO TARGET FILE, ELIMINATING WHITES %%%%%%%%%%%%%%%%%% /linestring hres 3 mul string store % read file line buffer /targetstring hres 3 mul padding add string store % write file line buffer targetstring dup length 1 sub 0 put % zero max padding targetstring dup length 2 sub 0 put targetstring dup length 3 sub 0 put /oldcolor (ZZZ) def /whitecount 0 store /mainloop { 0 1 vres 1 sub { /vline exch store % start of next hires line vline hres 3 mul padding add mul actualdatastart add dup % position read and write identically readfile exch setfileposition writefile exch setfileposition readfile linestring readstring % grab a line of characters not {big_time_read_error} if /sourcestring exch store 0 3 hres 1 sub 3 mul { /posn exch store % start line pixel loop sourcestring posn 3 getinterval dup colortoreplace eq {pop backpat numbackcolors random get /backcount backcount 1 add store } if targetstring exch posn exch putinterval } for % next line MUST start on an even 32-bit boundary writefile targetstring writestring } for (\nA total of ) backcount 12 string cvs mergestr ( pixels have been substituted\n\n) mergestr print flush } bind def stopwatchon mainloop % this does it all stopwatchoff (\nFinished.\n) print % report %%%%%%%%%% zzzz vignette sequence starts here writefile closefile readfile closefile % dink with filenames wfilename (.) search {dup length string cvs /pre exch store /gotcha exch store /post exch store pre dup length 2 sub (v) putinterval pre gotcha mergestr post mergestr /wfilename1 exch store }{mistook_in_filename} ifelse % ========= % define color weights here .11 .59 .30 is tv and PostScript standard. /redweight 0.30 store % red component of luminance /greenweight 0.59 store % green component of luminance /blueweight 0.11 store % blue component of luminance /dodgeburn {dbmap} store % current choices: dbluminance dbsaturation dbmap % dbgamma dbhue dbvignette dbgray /gamma [0 .25 .5 .75 1.0] store % default gamma /plotgammaflag false store % % don't plot % The image is split up into (n)^2 areas contolled by (n+1)^2 data points that get % expanded and filtered into 32*(n+1)^2 final data values. Each area % interpolates between its four corner data points. % /makeredchanges, etc.. lets you selectively change one or more colors only. /makeredchanges true store % false = do not change red /makegreenchanges true store /makebluechanges true store % /dbdata controls the effect of each area. A 10x10 matrix controls 81 areas. % 1.0 = normal less is darker or lower saturation, more is lighter % map can be any size above 3x3 and need not be square. /dbdata [ [1.00 1.00 1.00 1.00 0.88 0.76 0.64 0.52 0.40 0.28] % row at top of screen [1.00 1.00 1.00 1.00 1.00 0.88 0.76 0.64 0.52 0.40] [1.00 1.00 1.00 1.00 1.00 1.00 0.88 0.76 0.64 0.52] [1.00 1.00 1.00 1.00 1.00 1.00 1.00 0.88 0.76 0.64] [1.00 1.00 1.00 0.55 1.00 1.00 1.00 1.00 0.88 0.76] [1.00 1.00 0.55 0.55 1.00 1.00 1.00 1.00 1.00 0.88] [1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00] [1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00] [0.65 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00] [0.30 0.65 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00] % row at bottom of screen ] store % dbdata arrays can be any length. /dbdata [ % example of full contrast white ul to black lr [1 0.75 0.5 ] [0.75 0.5 0.25] [0.5 0.25 0 ] ]store /dbdata [ % example of typical flash correction mask [0.5 0.6 0.7 ] [0.4 0.5 0.6 ] [0.3 0.4 0.5 ] ]store /dbdata [ % vignette example [0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5] [0.5 0.667 0.833 1 1 1 1 1 1 1 1 1 1 0.833 0.667 0.5] [0.5 0.833 1 1 1 1 1 1 1 1 1 1 1 1 0.833 0.5] [0.5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.5] [0.5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.5] [0.5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.5] [0.5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.5] [0.5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.5] [0.5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.5] [0.5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.5] [0.5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.5] [0.5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.5] [0.5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.5] [0.5 0.833 1 1 1 1 1 1 1 1 1 1 1 1 0.833 0.5] [0.5 0.667 0.833 1 1 1 1 1 1 1 1 1 1 0.833 0.667 0.5] [0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5] ] store /dbdata [ % example of typical flash correction mask [0 0 0 0 0 0 0 ] [0 1 1 1 1 1 0 ] [0 0 0 0 0 0 0 ] ]store /dbdata [ % example of typical flash correction mask [0 0 0 ] [1 1 1 ] [1 0 1 ] [1 0 1 ] [1 0 1 ] [1 0 1 ] [1 0 1 ] [1 1 1 ] [1 0 1 ] [0 0 0 ] [0 1 0 ] [0 0 0 ] [1 0 1 ] [1 1 1 ] [ 0 0 0 ] ]store % input name of bmp file to be evaluated here... /diskfileheader (C:\\Documents and Settings\\don\\Desktop\\aarawpix\\) store /diskfilesourcename (biosymw1.bmp) store /diskfiletargetname (biosymv1.bmp) store /setupfiles { /sourcefilename diskfileheader diskfilesourcename mergestr store /targetfilename diskfileheader diskfiletargetname mergestr store /readfile sourcefilename (r) file store % establish input read file /writefile targetfilename (w+) file store % establish output target file currentdict /auxdiskfilesourcename known { % auxfile used for transparency /auxsourcefilename diskfileheader auxdiskfilesourcename mergestr store /auxreadfile auxsourcefilename (r) file store % establish aux input read file } if } def /dbmapscale 1.0 store % Use 0.5 if map values exceed 1.0 /whiteref (XXX) def % truewhite reference whiteref 0 255 put whiteref 1 255 put whiteref 2 255 put /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 %%%%%%%%%%%%% /checkvalidity { % 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 } store %%%%%%%%%%%%%%%% COPY HEADER TO TARGET FILE %%%%%%%%%%%%%%%%%% /writeheader { % 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 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 } store %%%%%%%%%%%%%% SERVICE UTILS %%%%%%%%%% % filterdbdata smooths the data to ease eye sensitivity to sudden changes. Current % algorithm is to double data points, then use (value + ((prev + post)/2))/2 /filterdbdata { mark dbdata {xdblarray xfiltdbarray} forall ] ydblarray ydbfilt } store % redoubling for further smoothing /dblfilterdbdata { mark filtdbdata {xdblarray xfiltdbarray} forall ] ydblarray ydbfilt } store /xdblarray {/curarray exch store mark 0 1 curarray length 2 sub {/caposn exch store curarray caposn get dup dup curarray caposn 1 add get exch sub 2 div add } for curarray dup length 1 sub get ] } store /ydblarray {/curarray exch store mark 0 1 curarray length 2 sub {/caposn exch store /wuz curarray caposn get store /wilby curarray caposn 1 add get store wuz % get previous then make new interpolated mark 0 1 wuz length 1 sub {/curele exch store wuz curele get dup wilby curele get exch sub 2 div add } for ] } for curarray dup length 1 sub get ] } store /ydbfilt { /curarray3 exch store mark curarray3 0 get % get first element 1 1 curarray3 length 2 sub {/curyposn1 exch store /prev curarray3 curyposn1 1 sub get store /curr curarray3 curyposn1 get store /post curarray3 curyposn1 1 add get store mark 0 1 curr length 1 sub {/yypos exch store curr yypos get prev yypos get post yypos get add 2 div add 2 div } for ] } for curarray3 dup length 1 sub get % get last element ] /filtdbdata exch store } store % xfiltdbarray low pass filters an array to value + (value + ((prev + post)/2))/2 % by expanding input dbarrays. This does the horizontal expansion and filtering. /xfiltdbarray {/curarray1 exch store mark curarray1 0 get 1 1 curarray1 length 2 sub {/caposn1 exch store curarray1 caposn1 get curarray1 caposn1 1 sub get curarray1 caposn1 1 add get add 2 div add 2 div } for curarray1 dup length 1 sub get ] } store % calcrowdbfiltdata interpolates array values for the selected line. /calcrowdbfiltdata { vline vres 1 sub div 1 exch sub filtdbdata length 2 sub 0.99999 add % as in 8.999 for 10 array values mul 0.00001 add /vfract exch store /abovedbdata filtdbdata vfract floor cvi get store /belowdbdata filtdbdata vfract ceiling cvi get store /vfractfract vfract dup floor sub store /rowdbdata mark 0 1 filtdbdata 0 get length 1 sub {/iii exch store % want single array length! abovedbdata iii get belowdbdata iii get sub vfractfract mul abovedbdata iii get exch sub } for ] def } def % calccurdatavalue interpolates the line rowdbdata for the current value. /calccurdatavalue { /hfract posn hres 1 sub 3 mul div rowdbdata length 2 sub 0.99999 add % as in 8.999 for 10 values mul store /hfractfract hfract dup floor sub store rowdbdata hfract floor cvi get dup rowdbdata hfract ceiling cvi get exch sub hfractfract mul add /curdatavalue exch store } store %%%%%%%% ACTUAL ROUTINES USED BY dodegburn %%%%%%%%%% % dbmap maps the data value as a gray. /dbmap {curpixelstring 0 curdatavalue 255 mul dbmapscale mul cvi clipcheck put curpixelstring 1 curdatavalue 255 mul dbmapscale mul cvi clipcheck put curpixelstring 2 curdatavalue 255 mul dbmapscale mul cvi clipcheck put } store % dbluminance brightens or darkens each pixel per the data map. /dbluminance { curpixelstring 2 get % get red, green blue curpixelstring 1 get curpixelstring 0 get 3 copy add add 765 eq % check for 256-256-256 pure white holdwhite and not { makebluechanges { curdatavalue mul % adjust blue luminance round cvi % change to integer clipcheck254 % restrict range curpixelstring exch 0 % and replace exch put }{pop} ifelse makegreenchanges { curdatavalue mul % adjust green luminance round cvi % change to integer clipcheck254 % restrict range curpixelstring exch 1 % and replace exch put }{pop} ifelse makeredchanges { curdatavalue mul % adjust red luminance round cvi % change to integer clipcheck254 % restrict range curpixelstring exch 2 % and replace exch put }{pop} ifelse } {pop pop pop} ifelse % no change if white } store % dbsaturation enhances or reduces color saturation. Also used to force NTSC gray /dbsaturation { curpixelstring 2 get % get red, green blue /curred exch store curpixelstring 1 get /curgreen exch store curpixelstring 0 get /curblue exch store curred redweight mul curgreen greenweight mul add curblue blueweight mul add % calculate current luminance /curlumin exch store /bluedelta curblue curlumin sub store /greendelta curgreen curlumin sub store /reddelta curred curlumin sub store makeredchanges { reddelta curdatavalue mul curlumin add cvi clipcheck curpixelstring exch 2 exch put } if makegreenchanges { greendelta curdatavalue mul curlumin add cvi clipcheck curpixelstring exch 1 exch put } if makebluechanges { bluedelta curdatavalue mul curlumin add cvi clipcheck curpixelstring exch 0 exch put } if } store % dbgray is a simpler variant on dbsaturation that forces a NTSC gray /dbgray { curpixelstring 2 get % get red, green blue /curred exch store curpixelstring 1 get /curgreen exch store curpixelstring 0 get /curblue exch store curred redweight mul curgreen greenweight mul add curblue blueweight mul add % calculate current luminance cvi /curlumin exch store curpixelstring 0 curlumin put curpixelstring 1 curlumin put curpixelstring 2 curlumin put } store % db gamma causes a progrmmable gamma correction... /dbgamma { curpixelstring 2 get % get red, green blue /curred exch store curpixelstring 1 get /curgreen exch store curpixelstring 0 get /curblue exch store makeredchanges { /gammawant gamma1 curred get store gammawant curred sub curdatavalue mul curred add cvi clipcheck curpixelstring exch 2 exch put } if makegreenchanges { /gammawant gamma1 curgreen get store gammawant curgreen sub curdatavalue mul curgreen add cvi clipcheck curpixelstring exch 1 exch put } if makebluechanges { /gammawant gamma1 curblue get store gammawant curblue sub curdatavalue mul curblue add cvi clipcheck curpixelstring exch 0 exch put } if } store % dbmask replaces everything under the mask value with black. Used to form a black mask. /dbmask { curpixelstring 2 get % get red, green blue /curred exch store curpixelstring 1 get /curgreen exch store curpixelstring 0 get /curblue exch store curred curdatavalue le {0 curpixelstring exch 2 exch put} if curgreen curdatavalue le {0 curpixelstring exch 1 exch put} if curblue curdatavalue le {0 curpixelstring exch 0 exch put} if } def % dbredsep creates a red separation. Same for dbgreensep and dbbluesep. % One underappreciated use is that certain colors may have more detail and % dynamic range when very dark or very light. /dbredsep { curpixelstring 0 0 put curpixelstring 1 0 put } def /dbgreensep { curpixelstring 0 0 put curpixelstring 2 0 put } def /dbbluesep { curpixelstring 1 0 put curpixelstring 2 0 put } def % dbtransblend overlays two similar sized images /dbtransblend { curpixelstring 2 get /curred exch store % get red, green blue curpixelstring 1 get /curgreen exch store curpixelstring 0 get /curblue exch store auxcurpixelstring 2 get /auxcurred exch store % get red, green blue auxcurpixelstring 1 get /auxcurgreen exch store auxcurpixelstring 0 get /auxcurblue exch store curblue auxcurblue exch sub curdatavalue mul curblue add round cvi curpixelstring exch 0 exch put curgreen auxcurgreen exch sub curdatavalue mul curgreen add round cvi curpixelstring exch 1 exch put curred auxcurred exch sub curdatavalue mul curred add round cvi curpixelstring exch 2 exch put } store % dbhue adjusts the hue in degrees of correction. There are six subprograms dbh0 to dbh5 % that calculate hsb, and six subprograms set0 to set300 that shift the colors. /dbhue { curpixelstring 2 get /curred exch store % get red, green blue curpixelstring 1 get /curgreen exch store curpixelstring 0 get /curblue exch store % 0 1 2 3 4 5 % red green green blue blue red max % green red blue green red blue % blue blue red red green green min curred curgreen ge {curred curblue ge {curblue curgreen ge {dbh5}{dbh0}ifelse} % cases 045 {dbh4} ifelse } {curred curblue ge {dbh1} % cases 123 {curblue curgreen ge {dbh3}{dbh2}ifelse} ifelse } ifelse /newhue curhue curdatavalue add dup 0 lt {360 add} if % if curdatavalue + curhue < 0 dup 360 ge {360 sub} if % if curdatavalue + curhue > 360 store % find new hue [{set0}{set60}{set120}{set180}{set240}{set300}] newhue 60 div floor cvi get exec } store /dbh0 {/brt curblue store % red to yellow /sat curred curblue sub store /curhue 0 curgreen brt sub sat div1 60 mul add store} store /dbh1 {/brt curblue store % yellow to green /sat curgreen curblue sub store /curhue 60 1 curred brt sub sat div1 sub 60 mul add store} store /dbh2 {/brt curred store % green to aqua /sat curgreen curred sub store /curhue 120 curblue brt sub sat div1 60 mul add store} store /dbh3 {/brt curred store % aqua to blue /sat curblue curred sub store /curhue 180 1 curgreen brt sub sat div1 sub 60 mul add store} store /dbh4 {/brt curgreen store % blue to violet /sat curblue curgreen sub store /curhue 240 curred brt sub sat div1 60 mul add store} store /dbh5 {/brt curgreen store % violet to red /sat curred curgreen sub store /curhue 300 1 curblue brt sub sat div1 sub 60 mul add store} store /div1 {dup 0 eq {pop pop 0}{div} ifelse} store % define gray as hue=0 % these set the new hue depending on which hexant they are in... /set0 { brt % blue to brightness for red to yel newhue 60 div sat mul brt add % green proportional sat brt add % full red stuffstring} store /set60 { brt cvi clipcheck % blue to brightness for yel to grn sat brt add % full green 1 newhue 60 sub 60 div sub sat mul brt add % red inverse proportional stuffstring} store /set120 {newhue 120 sub 60 div sat mul brt add % blue proportional for grn to aqua sat brt add % full green brt % red to brightness stuffstring} store /set180 { sat brt add % full blue for aqua to blue 1 newhue 180 sub 60 div sub sat mul brt add % green inverse proportional brt % red to brightness stuffstring} store /set240 { sat brt add % full blue for blue to violet brt % green to brightness newhue 240 sub 60 div sat mul brt add % red proportional stuffstring } store /set300 {1 newhue 300 sub 60 div sub sat mul brt add % blue inverse for violet to red brt % green to brightness sat brt add % full red stuffstring } store /stuffstring { makeredchanges {cvi clipcheck curpixelstring exch 2 exch put}{pop} ifelse makegreenchanges {cvi clipcheck curpixelstring exch 1 exch put}{pop} ifelse makebluechanges {cvi clipcheck curpixelstring exch 0 exch put}{pop} ifelse } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % expandgamma expands and filters the gamma curve to additional data points /gammatrips 5 store % number of filter trips /expandgamma { /gamma1 gamma store gammatrips { % multiply values by 32 mark 0 1 gamma1 length 2 sub {/gpos exch store % interpolate points gamma1 gpos get dup gamma1 gpos 1 add get add 2 div } for gamma1 dup length 1 sub get ] /gamma1 exch store mark gamma1 0 get 1 1 gamma1 length 2 sub {/gpos exch store % filter to (point + slope) /2 gamma1 gpos get gamma1 gpos 1 sub get dup gamma1 gpos 1 add get exch sub 2 div add add 2 div } for gamma1 dup length 1 sub get ] /gamma1 exch store } repeat mark % change to 256 element array 0 1 254 {255 div gamma1 length 1 sub mul /ggpos exch store /glow gamma1 ggpos floor cvi get store /ghi gamma1 ggpos ceiling cvi get store /gfract ggpos dup floor sub store { (ggpos -------------------------------> ) print ggpos == (glow ---> ) print glow == (ghi --> ) print ghi == (gfract -----------------> ) print gfract == } pop ghi glow sub gfract mul glow add % ( raw interpol --->) print dup == 255 mul round cvi (\n\n) print } for 255 ] /gamma1 exch store gamma1 == } store %%%%%%%%%%%%% % plotgamma makes a gamma plot for viewing... /plotgamma { save /gammasnap exch store [/CropBox [0 0 400 400] % set the wierd size /PAGES pdfmark [ {Catalog} << /ViewerPreferences << /FitWindow true /CenterWindow true >> /PageLayout /OneColumn % continous /Pagemode /UseNone % no thumbs /View [/XYZ null null 1 ] % force 100% >> /PUT pdfmark 100 100 10 setgrid 20 20 showgrid line1 0 0 mt 0 1 gamma1 length 1 sub {/ppos exch store ppos 20 mul gamma1 length div gamma1 ppos get 256 div 20 mul dup == lineto } for stroke 0 1 gamma length 1 sub {/gggposn exch store gggposn gamma length 1 sub div 20 mul gamma gggposn get 20 mul mt dot } for /cstretch 0.0 store /sstretch 0.0 store /font1 /Helvetica-Bold 1.05 gonzofont font1 10 23.3 (gamma curve for) cc 10 22 ([ ) gamma { 10 string cvs mergestr ( ) mergestr} forall (]) mergestr cc showpage gammasnap restore} store %%%%%%%%%%%%%%%%%%%%%%%%%%%% % clipcheck restricts color values to 0-255 range /clipcheck { dup 255 ge {pop 255} if dup 0 le {pop 0 } if } store % clipcheck254 restricts color values to 0-254 range. Used to preserve transparency. % / true store % do not change 255-255-255 for transparency? /clipthresh {holdwhite {254}{255} ifelse} store /clipcheck254 { dup clipthresh ge {pop clipthresh}if dup 0 le {pop 0 } if } store %%%%%%%%%%%%%%%% COPY DATA TO TARGET FILE, ADJUSTING AS NEEDED %%%%%%%%%%%%%%%%%% /filtertrips 4 store % used to smooth dbmaps. Reduce if db data > 20x20. /dodge&burn {12345 srand % make randoms repeat setupfiles % grab current filenames checkvalidity % make sure image is .BMP writeheader % write .BMP header /linestring hres 3 mul string store % set read file line buffer /targetstring hres 3 mul padding add string store % set write file line buffer targetstring dup length 1 sub 0 put % zero max padding targetstring dup length 2 sub 0 put targetstring dup length 3 sub 0 put /auxlinestring hres 3 mul string store % set aux read file line buffer /auxtargetstring hres 3 mul padding add string store % set aux write file line buffer auxtargetstring dup length 1 sub 0 put % zero max padding auxtargetstring dup length 2 sub 0 put auxtargetstring dup length 3 sub 0 put /oldcolor (ZZZ) def /whitecount 0 store filterdbdata % smooth mask filtertrips {dblfilterdbdata} repeat % experimental quad filtering makes 32x array expandgamma % expand gamma curve to additional filtered values plotgammaflag {plotgamma} if % start main loop here 0 1 vres 1 sub { /vline exch store % start of next hires line vline 24 mod 0 eq % pretty print progress {(.) print flush} if vline hres 3 mul padding add mul actualdatastart add dup dup % position read and write identically readfile exch setfileposition writefile exch setfileposition currentdict /auxreadfile known {auxreadfile exch setfileposition}{pop} ifelse readfile linestring readstring % grab a line of characters not {big_time_read_error} if currentdict /auxreadfile known { auxreadfile auxlinestring readstring % grab an aux line of characters not {big_time_aux_read_error} if /auxsourcestring exch store } if /sourcestring exch store calcrowdbfiltdata % interpolate filtered dbdata for line % start row line loop 0 3 hres 1 sub 3 mul { /posn exch store % start line pixel loop sourcestring posn 3 getinterval /curpixelstring exch store currentdict /auxreadfile known { auxsourcestring posn 3 getinterval /auxcurpixelstring exch store } if calccurdatavalue dodgeburn % does the selected mode curpixelstring targetstring exch posn exch putinterval } for % next line MUST start on an even 32-bit boundary writefile targetstring writestring } for % (\nA total of ) backcount 12 string cvs mergestr % ( pixels have been substituted\n\n) mergestr print flush (\nFinished.\n) print % report } bind def % end dodgeandburn %%%%%%%%%%%%%% EXAMPLE (F) ADD VIGNETTE BORDER %%%%%%%%%%%% % first create a vignette border and view as a map... /vignette1 { % localized burn example /holdwhite false store /vv 0.55 store /dbdata [ [vv vv vv vv vv vv vv vv vv vv vv vv vv vv vv vv] [vv 0.7 1 1 1 1 1 1 1 1 1 1 1 1 0.7 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 1 1 1 1 1 1 1 1 1 1 1 1 1 1 vv] [vv 0.7 1 1 1 1 1 1 1 1 1 1 1 1 0.7 vv] [vv vv vv vv vv vv vv vv vv vv vv vv vv vv vv vv] ] store } store /diskfileheader (C:\\Documents and Settings\\don\\Desktop\\aarawpix\\) store % set directories /diskfilesourcename wfilename store % set source .BMP /diskfiletargetname wfilename1 store % set dest .BMP /dodgeburn {dbluminance} store % select operating mode vignette1 % create mask map % uncomment the start of the next line to run this demo... /holdwhite false store dovignette { dodge&burn } if % do actual vignette % EOF % EOF