%!PS % Auto precision bitmap exploration % =================================== % by Don Lancaster %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 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 % Auto precision bitmap initial exploration % ========= % 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, 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 % ========= % 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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % FONT CHARACTER AND ARRAY CREATION ROUTINES % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % /setfontfamily allows more than one root font per session. the /fontcount % counter is used to keep track of generated font libraries. Gonzo fonts % not appropriate here. At present, each font family should only be used ONCE. /setfontfamily {/fontcount where % is this the first font? {pop /fontcount fontcount % no, increment fountcount 1 add store} {/fontcount 0 store} ifelse % yes, initialize counter findfont 100 scalefont setfont % 100 points hard coded } store % /setbmsize initializes a font pattern library for a given size and font. % If reused, it selects an older font pattern library. A font pattern library % has a name of form /fxwyhz where x is the fontcount, y is the requested % bitmap height and z is the requested width of the letter "A" in the bitmap. /setbmsize { /yy exch store % save global pixel height /xx exch store % save global pixel width (f) fontcount 20 string cvs mergestr % create name for fpl array (w) xx 20 string cvs mergestr mergestr % (h) yy 20 string cvs mergestr mergestr cvn dup /cfpln exch store % save name of current fpl array cfpln where {cfpln load pop} if % needed for reuse - not sure why where not { % does this fpl name exist? cfpln mark 256 {null} repeat % create new array ] store cfpln load /cfpl exch store % define current fpl } if definechara % define (A) character } store % /findcharboundaries slides bounding box in till an infill hit is found. % Note: space must be excluded. currently using a quarter pixel scan. % this can be increased if response time is too slow. Note that character is at 100,100 /findcharboundaries { /reallyexit false store % begin left boundary 90 1 rpos 100 add { /clb exch store % scnning to right 0 2 200 {/yy1 exch store % check all vertical pixels clb yy1 infill {/reallyexit true store exit} if % till ink is found } for reallyexit {exit} if } for /clb clb 1 sub store % adjust to no ink /reallyexit false store % begin right boundaryrpos 0.25 rpos 100 add -1 90 { /crb exch store % scnning left 0 2 200 {/yy2 exch store % check all vertical pixels crb yy2 infill {/reallyexit true store exit} if % till ink is found } for reallyexit {exit} if } for /crb crb 1 add store % adjust to no ink /reallyexit false store % begin top boundary 200 -1 0 {/ctb exch store % scanning down -90 2 rpos 100 add {/xx1 exch store % check all horizontal pixels xx1 ctb infill {/reallyexit true store exit} if % till ink is found } for reallyexit {exit} if } for /ctb ctb 1 add store % adjust to no ink /reallyexit false store % begin bottom boundary 0 1 200 {/cbb exch store % scanning up 90 2 rpos 100 add {/xx2 exch store % check all horizontal pixels xx2 cbb infill {/reallyexit true store exit} if % till ink is found } for reallyexit {exit} if } for /cbb cbb 1 sub store % adjust to no ink adjustcharboundaries % reduce bounding box for curvies } store % /adjustcharboundaries shrinks the bounding box to put the curvies on the outside % value of /shrinkfactor is presently internal. /adjustcharboundaries { /clb clb crb clb sub shrinkfactor mul add store % and adjust /crb crb crb clb sub shrinkfactor mul sub store crb clb sub /cwide exch store % find character width /ctb ctb ctb cbb sub shrinkfactor mul sub store % and adjust /cbb cbb ctb cbb sub shrinkfactor mul add store ctb cbb sub /chigh exch store % find character height } store % /definechara initially defines character (A) and allows saving of % global h and v default sizes... /definechara { gsave newpath % make scratch space /char (A) store char stringwidth pop % find character width and save /rpos exch store findcharboundaryvalues % find values of clb crb ctb cbb /gcwide cwide store % save global width of A reference /gchigh chigh store % save global height of A reference /gctb ctb store % save global top of A reference (A) makeorgetfontarray % make or get the font array for "A" pop % do not need actual array this time createspacechar % create space character chrs32 grestore } store % /findcharboundaryvalues finds clb crb ctb cbb cwide and chigh for the selected character. /findcharboundaryvalues { newpath % make scratch space 100 100 mt % position inside possible clip space gsave black char show grestore char stringwidth pop % find character width and save /rpos exch store char false charpath % get path for character findcharboundaries % find values of clb crb ctb cbb false { % use for debug gsave newpath 0.5 0.5 0 setrgbcolor line1 % temp draw cropped bounding box clb cbb mt 0 ctb cbb sub rlineto crb clb sub 0 rlineto 0 cbb ctb sub rlineto clb crb sub 0 rlineto stroke grestore } if } store % /makeorgetfontarray sees if the character has been generated, generates it if % needed, and retrives it as an array. /makeorgetfontarray {dup 0 get /chrs exch store % save char position /char exch store % save char string cfpl chrs get type /nulltype % has character been built? eq {addnewchar} if % no, build it cfpl chrs get % now get it } store % /addnewchar unconditionally adds a new character to the current cfpl bitmap array % have variables % gcwide gchigh gctb % clb crb ctb cbb % xx yy /addnewchar { char print flush findcharboundaryvalues % find edge values for new character gctb ctb sub % top position versus "A"? gchigh div % fraction of "A" character height? yy mul % times "A" character vertical pixels round cvi % gchigh mul gchigh div round cvi % should be zero for caps /sss exch store % save suppression sss crb clb sub gcwide div % width versus "A"? xx mul round cvi % should equal A for most caps /xxx exch store % pixel width needed ctb cbb sub gchigh div % height versus "A"? yy mul round cvi % should equal A for most caps /yyy exch store % pixel height needed ctb cbb sub yyy div % find whole pixel y increment dup /bigyinc exch store % and save linsamps div /lilyinc exch store % and sample y increment crb clb sub xxx div % find whole pixel x increment dup /bigxinc exch store % and save linsamps div /lilxinc exch store % and sample x increment reallyaddnewchar % add char with size known } store % /reallyaddnewchar uses {xxx yyy sss bigyinc lilyinc bigxinc lilxinc to create the % font character and store it in cfpl /reallyaddnewchar { /sss sss 2 add store % lc "h" possible padding sss 0 le {/sss 0 store} if % adjust minimum width mark % start array sss { mark xxx { 1 } repeat ] } % create suppression lines repeat yyy 1 sub -1 0 {bigyinc mul cbb add % add to shrunk top /curvv exch store % go downhill mark 0 1 xxx 1 sub {bigxinc mul clb add % add to shrunk left /curhh exch store averagepixels % average the pixels } for % each row of pixels ] } for % needed number of rows ] cfpl exch chrs exch put % place in array % showpage % used in debug } store % /averagepixels uses infill to sample a pixel linesamps squared times to come % up with its average brightness. base of character is curhh and curvv... /averagepixels { 0 % initial something to add to 0 1 linsamps 1 sub { % start double loop /intypos exch store 0 1 linsamps 1 sub { /intxpos exch store curhh lilxinc 2 div add % calculate x position lilxinc intxpos mul add % move to start curvv lilyinc 2 div add % calculate y position lilyinc intypos mul add false { % make true to show sample dots gsave 1 0 0 setrgbcolor 2 copy moveto gsave 2.5 dup scale dot grestore grestore } if infill {0}{1} ifelse add } for % for each h sample } for % for each row of samples linsamps dup mul div % calculate average } bind store % temp % /createspacechar initially creates the space character /createspacechar { xxx spacecharwidth mul round % adjust space width cvi /spacewide exch store mark yyy { % 1 = white or use old [ spacewide {1} repeat ] } repeat ] cfpl exch 32 exch put } store %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % BITMAP TYPEWRITER ROUTINES % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % [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 % 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 % /makeclonebitmap sets up a black array of bitmap row strings. The LOWEST number % is at the BOTTOM of the .BMP bitmap. This can be sped up by reading % the generated array as a file. Note that BLUE goes first in the BMP data quads. /makeclonebitmaps { /xbstring mark 120 hbits 1 sub {dup} repeat ] makestring store % a string of "x" values /redmap mark vbits {xbstring dup length string cvs} repeat ] store /greenmap mark vbits {xbstring dup length string cvs} repeat ] store /bluemap mark vbits {xbstring dup length string cvs} repeat ] store } def % /setbackA through /setbackD places background colors in the clone bitmap. % /setbackA is the bottom quarter, presently hardwired to 400x400. /setbackA {0 setback} store % bottom 0-99 /setbackB {100 setback} store % lower quardant 100-199 /setbackC {200 setback} store % upper quardant 200-299 /setbackD {300 setback} store % top 300-399 /setback { /posnstart exch store % save initial position /redval curcolor 0 get store % grab current colors /greenval curcolor 1 get store /blueval curcolor 2 get store /redline mark 400 {redval} repeat ] % make color string for red line makestring store /greenline mark 400 {greenval} repeat ] % make color string for green line makestring store /blueline mark 400 {blueval} repeat ] % make color string for blue line makestring store posnstart 1 posnstart 99 add % start loading loop {/curpos exch store redmap curpos redline 400 string cvs put greenmap curpos greenline 400 string cvs put bluemap curpos blueline 400 string cvs put } for } store % /writebitmap creates the actual bitmap from the clone string arrays /writebitmap { (\nWriting final bitmp to disk...) print flush % stopwatchon /targetbmpfilename targetfilenameprefix targetfilename mergestr def targetbmpfilename (w+) file /writefile exch def % make a .BMP file to write writeheader % write defined .BMP header writebitmapx % write BGRX bitmap writefile closefile % close & complete file % stopwatchoff } def % /writeheader creates the header in standard .BMP format The format can be found at % http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html and elsewhere on the web. /writeheader { (BM) ws % ASCI BM identifier /filesize hbits vbits mul 3 mul 54 add cvi def % calculate file length filesize 256 mod 256 mod dup strx exch 0 exch put strx ws % LSB filesize exch sub 256 mod strx exch 0 exch put strx ws % next lsb filesize 65536 idiv strx exch 0 exch put strx ws % next ldb writenull % msb writenull writenull % reserved 2 bytes writenull writenull % reserved 2 bytes 54 strx exch 0 exch put strx ws % offset lsb writenull writenull writenull % high offset bytes 40 strx exch 0 exch put strx ws % begin infoheader (size) writenull writenull writenull hbits 256 mod strx exch 0 exch put strx ws % horizontal bytes lsb hbits 256 idiv strx exch 0 exch put strx ws % horizontal bytes lsb writenull writenull % high offset bytes vbits 256 mod strx exch 0 exch put strx ws % vertical bytes lsb vbits 256 idiv strx exch 0 exch put strx ws % vertical bytes lsb writenull writenull % high offset bytes 1 strx exch 0 exch put strx ws % planes = 1 writenull % and msb 24 strx exch 0 exch put strx ws % bits per pixel = 24 writenull % and msb writenull writenull writenull writenull % no compression writenull writenull writenull writenull % 0 size if no compression 0 strx exch 0 exch put strx ws writenull writenull writenull % writenull % 0 h display pixels per meter 0 strx exch 0 exch put strx ws writenull writenull writenull % writenull % 0 v display pixels per meter writenull writenull writenull writenull % BiBitCount for color count writenull writenull writenull writenull % All colors are important } def % /writebitmap writes the bitmap portion to the .BMP file /writebitmapx { 0 1 vbits 1 sub {/vv exch store % working backwards from bottom /curred redmap vv get store % get current red row array /curgreen greenmap vv get store % get current green row array /curblue bluemap vv get store % get current blue row array 0 1 hbits 1 sub {/hh exch store % save pixel position curblue hh 1 getinterval ws % grab three pixels BLUE first curgreen hh 1 getinterval ws % grab three pixels then GREEN curred hh 1 getinterval ws % grab three pixels then RED } for } for } def % /ws is a housekeeping utility... /ws {writefile exch writestring} def % file writing utility /strx (X) def /writenull {0 strx exch 0 exch put strx ws } def % /setgraystring places a string of true antialiased characters onto the bitmap... % All characters build from TOP DOWN to handle descenders. /setgraystring {/str exch store % save the string repositioncheck % 0 0 = do not reposition /ypos1 exch store % save the yposition /xpos1 exch store % save the xposition /xpos xpos1 store % set initial LEFT position /ypos ypos1 store % set initial TOP position 0 1 str length 1 sub % for each character in string {/kk exch store str kk 1 getinterval % get the current character /curchar1 exch store % and save adjustlocalkerning % is local kerning needed? {curchar1 makeorgetfontarray % get or build char array setgraychar } if % map character into cfpl } for } def % /repositioncheck looks for a 0 0 positioning, and uses the old xpos and y pos % instead. /repositioncheck {2 copy mul 0 eq % use old currentpoint if 0 0 {pop pop xpos ypos} if} store % /adjustlocalkerning looks for kern+char or kern-char characters, then adjusts % position, returning false if kerned, true otherwise /adjustlocalkerning { true curchar1 0 get kern+char % rightkern? eq {/xpos xpos 1 % move one pixel to right add store pop false} if % no real character needed curchar1 0 get kern-char % rightkern? eq {/xpos xpos 1 % move one pixel to right sub store pop false} if % no real character needed } store % /setgraychar accepts xpos ypos (x) and places the character into the bitmap string. % Or else adjusts for a carriage return and linefeed /setgraychar { curchar1 0 get dup % test for LF or CR 10 eq exch 13 eq or {pop docr} % do LF or CR, dump array {setgraychar1} ifelse % otherwise set character } def % /setgraychar1 sets the actual character matrix into the cfpl array after % local kerning and crlf have been dealt with. Enters with char matrix on stack % Note that blue goes first in the bitmap. /setgraychar1 {/curmat1 exch store % save current character matrix curmat1 length /jj exch store % save pixels high curmat1 0 get length /ii % save pixels wide exch store 0 1 jj 1 sub {/jjj exch store % save y pixel offset 0 1 ii 1 sub {/iii exch store % save x pixel offset % blue first bluemap ypos jjj sub get % find old blue pixel xpos iii add get dup curcolor 2 get % find full new blue pixel sub % find difference curmat1 jjj get iii get 1 sub % find alpha fraction mul add % calculate new blue pixel round cvi bluemap ypos jjj sub get % and replace exch xpos iii add exch put % then green greenmap ypos jjj sub get % find old green pixel xpos iii add get dup curcolor 1 get % find full new blue pixel sub % find difference curmat1 jjj get iii get 1 sub % find alpha fraction mul add % calculate new green pixel round cvi greenmap ypos jjj sub get % and replace exch xpos iii add exch put % red last redmap ypos jjj sub get % find old blue pixel xpos iii add get dup curcolor 0 get % find full new red pixel sub % find difference curmat1 jjj get iii get 1 sub % find alpha fraction mul add % calculate new red pixel round cvi redmap ypos jjj sub get % and replace exch xpos iii add exch put } for % for each glyph h pixel } for % for eabh glyph row findnextcharacterstart % calculate next start position } store % temp % /findnextcharacterstart readjusts xpos and ypos, checking for line overflow /findnextcharacterstart {/xpos xpos ii add % move to next character start globalkern add store xpos 400 ii 2 mul sub gt % is enough room left for {/xpos 3 store % one double width character? /ypos ypos yinc % no, move down a line sub store} if ypos 0 lt % force error message {ypos_below_bitmap} if } store % /docr uses above routine to force a linefeed or carriage return /docr {/xpos 9999 store findnextcharacterstart} % force too far to the right store % then do lfcr %%% DEFAULTS %%%%% /MyriadPro-Bold setfontfamily /shrinkfactor 0 store % set internal shrink factor .04 for small /linsamps 6 store % samples per pixel 6=36 8=64 /spacecharwidth 0.67 store % width of space character compared to "A" /kern+char (~) 0 get def % define positive kerning character /kern-char (`)0 get def % define negative kerning character /xpos 3 store % default x starting position /ypos 390 store % defualt y starting position /yinc 18 store % default y increment %% initial setup /hbits 400 def % horizontal bits in BMP bitmap /vbits 400 def % vertical bits in BMP bitmap makeclonebitmaps % create data array that matches bitmap %% matching color pallettes /teklight {/curcolor [161 171 163 ] store} store % for Tektronix TM501 /tekdark {/curcolor [ 83 89 74 ] store} store %%%%%%%%%%% DEMO - Remove or alter before reuse %%%%%%%%%%%%%%%%% % BE SURE TO RESET YOUR targetfilenameprefix!!!! stopwatchon /targetfilename (bmdemo1.bmp) def % short name of file to be generated /targetfilenameprefix % full filename prefix to be appended (C:\\Documents and Settings\\don\\Desktop\\image_tools_copy\\new bm type\\) def /teklight {/curcolor [161 171 163 ] store} store % for Tektronix TM501 /tekdark {/curcolor [ 83 89 74 ] store} store /geigerlight {/curcolor [ 118 133 136 ] store} store /geigerpcboard {/curcolor [ 67 82 85 ] store} store /blackic {/curcolor [ 37 48 61 ] store} store /lettic{/curcolor [ 84 94 99 ] store} store /globalkern 2 store % normal spacing between characters teklight % pick background color setbackA % background 0-99 setbackB % background 100-199 setbackC % background 200-299 setbackD % background 300-399 tekdark 12 12 setbmsize 3 380 (THIS IS A 12~x~12 BITMAP EX`AMPLE) setgraystring 6 8 setbmsize % print another line 3 350 (THIS IS A 6~x~8 BITMAP EX`AMPLE.) setgraystring /globalkern 1 store 8 6 setbmsize % print another line 3 320 (THIS IS AN 8~x~6 BITMAP EXAMPLE.) setgraystring 4 4 setbmsize 3 290 (THIS IS A 4~x~4 BITMAP EXAMPLE.) setgraystring 3 3 setbmsize 3 260 (THIS IS A 3x3 BITMAP EXAMPLE.) setgraystring writebitmap % create the actual bitmap stopwatchoff % showpage % EOF