|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T h
Length: 20917 (0x51b5) Types: TextFile Names: »hp.ch«
└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89 └─⟦this⟧ »./DVIware/lpr-viewers/crudetype/hp.ch« └─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12 └─⟦af5ba6c8e⟧ »unix3.0/DVIWARE.tar.Z« └─⟦ca79c7339⟧ └─⟦this⟧ »DVIware/lpr-viewers/crudetype/hp.ch«
% HP.CH Provisional change file for the HP Laserjet... % NOTE the system change file must normally be inserted above this point. % This file reads PXL files, so cannot be tested at our site % @x When this module starts, the \.{DVI} file should be positioned at or before a BOP. @<For each page...@>= read_BOP; if (counter[0] >= first_page) then start := true ; if start and (count_pages > 0 ) then begin decr(count_pages); if not quiet then display('[', counter[0]:1 ); {Progress report} Read_one_page ; @<Sort the page@> Send_page ; @<Formfeed@>; if not quiet then display( ']' ); end else if ( count_pages > 0) then Skip_page else time_to_stop := true; @y When this module starts, the \.{DVI} file should be positioned at or before a BOP. This is where the printer change file proper begins. This change file goes with \.{Crudetype} version 2. First, it should be explained that the HP is not at all a "crude" printer, and the mechanisms of \.{Crudetype} are not really suitable for it. It is really stretching the program a very long way from its intended purpose. In particular, some changes have to be spliced into the middle of the program, instead of going at the end as printer changes ought to. It seems that the only reasonable way to drive a HP is by downloading all the required characters. As stated in \.{Crudetype}, the problems of downloading are extremely difficult and I have not solved them in any satisfactory manner. The code given below manages downloading in the simplest and crudest way possible. First, I have added flags to print either even or odd pages only. In principle, this will allow double sided printing. Also, we do not sort the page as the HP can jump about. @<For each page...@>= read_BOP; if (counter[0] >= first_page) then start := true ; if start and (count_pages > 0 ) and ( ( odd( counter[0]) = odds) or (( not evens) and ( not odds)) ) then begin decr(count_pages); if not quiet then display('[', counter[0]:1 ); {Progress report} Read_one_page ; @<Dont sort the page but |reset| it @> Send_page ; @<Formfeed@>; if not quiet then display( ']' ); end else if ( count_pages > 0) then Skip_page else time_to_stop := true; @z % Next, the HP has its own rule-setting commands. @x procedure set_rule; var D_p,D_q: integer; begin D_p:=get_integer(dvi) (-4); D_q:=get_integer(dvi)(-4); if (D_p<=0)or(D_q<=0) then {an invisible rule! Dont ask me why \TeX\ wants to do this} else if D_p*v_conv <= post_height/2 then do_rail(D_p, D_q) else do_post(D_p, D_q); end; @y procedure set_rule; var D_p,D_q: integer; rule_h, rule_v, rule_ht, rule_wid: integer ; {all in pixels} begin D_p:=get_integer(dvi) (-4); D_q:=get_integer(dvi)(-4); if (D_p<=0)or(D_q<=0) then {an invisible rule! Dont ask me why \TeX\ wants to do this} else begin @<Find the pixel sizes and reference point@> @<Send it to the printer@> end; end; @z @x @d out_of_sequence == ( ( Old_v > Set_v) or ( ( Old_v = Set_v) and ( Old_h > Set_h))) @y Since we do not sort, we will not separate the characters into runs. @d out_of_sequence == false @z @x @<Const...@>= device_ID = 'Lineprinter'; @y @<Const...@>= device_ID = 'Laserjet +'; @z @x @ The first lot of data describes the printer's overall style of carriage control. |fortran| means that the carriage control character gets put at the start of the line, and it is here assumed that it must be inserted explicitly. Note also that the program makes no attempt to check all these values for consistency. @<Carriage control constants@>= list = false ; b_feed_absolute = false ; b_feed_by_string = false ; feed_absolute = false ; b_feed_scream = true ; b_space_absolute = false ; b_space_by_string = false ; space_absolute = false ; abs_is_incr = false ; w_l_does_c_r = false ; want_split = true ; is_header = false ; {each page needs a header} @y @ The first lot of constants describes the HP's overall style of carriage control. Many of them are completely irrelevant to the HP, but still needed in order for the program to compile. @<Carriage control constants@>= list = false ; b_feed_absolute = true ; b_feed_by_string = false ; feed_absolute = true ; b_feed_scream = true ; b_space_absolute = true ; b_space_by_string =false ; space_absolute = true ; abs_is_incr = false ; w_l_does_c_r = false ; want_split = true ; is_header = false ; {each page needs a header} @z @x @ This batch is concerned with distances and resolutions. @<Const...@>= l_margin = 6 ; top_margin = 6 ; h_resolution = 10 ; {|h_steps| per inch} v_resolution = 6 ; {|v_steps| per inch} fixed_width = true ; {printers characters are fixed width} char_width = 1 ; {all printer characters are this width, in units of |h_step|. Normally, |space_dist| will be equal to this, but some printers are not normal!} gap_width = 1 ; {Intended minimum space between words} char_ht = 1 ; @y @ This batch is concerned with distances and resolutions. @<Const...@>= l_margin = 220 ; top_margin = 220 ; h_resolution = 300 ; {|h_steps| per inch} v_resolution = 300 ; {|v_steps| per inch} fixed_width = false ; char_width = 30 ; {default char. sizes in |h_steps| -- a guess} gap_width = 5 ; {Intended minimum space between words} char_ht = 42 ; @z @x @ The general run of \TeX\ characters are narrower than line-printer chars. So we spread them out to make them fit. @<Set init...@>= h_fudge := 7.227 {number of points per |h_step|} / 5.25 ; {A typical design width} v_fudge := 2.0 ; { Force double-spacing, in hope that suffixes will come out right} @y @ The general run of \TeX\ characters are narrower than line-printer chars. But the HP prints them at their proper widths. @<Set init...@>= h_fudge := 1.0 ; v_fudge := 1.0 ; @z @x @ The next batch are concerned with fonts. @<Const...@>= min_font = 1 ; {smallest and largest number of printers resident fonts} max_font = 1 ; only_one_font = true ; can_dl_font = false ; min_dl_font = 0 ; max_dl_font = 0 ; {printers down-loadable fonts} max_codes = 60 ; {no. of known \TeX\ coding schemes} max_char = 127 ; {max. no. of chars per \TeX\ font} max_plain = 4 ; {Max number of a plain text font} @y @ The next batch are concerned with fonts. @<Const...@>= min_font = 1 ; {smallest & largest number of printers resident fonts} max_font = 40 ; only_one_font = false ; can_dl_font = true ; min_dl_font = 8 ; max_dl_font = 40 ; {printers down-loadable fonts. The HP allows up to 32} max_codes = 40 ; {no. of possible \TeX\ coding schemes} max_char = 127 ; {max. no. of chars per \TeX\ font} max_plain = 3 ; {Max number of a plain text font} @z @x @<Assign char...@>= @<Assign Lineprinter coding schemes@> @<Define Lineprinter code tables@> @<Set rule characters@> @y @<Assign char...@>= do_nothing @z @x *** Attach printer change file here *** @y @ The remaining changes can all go at the end of the program. Before getting onto the hardest task (namely, downloading) lets clear up the loose ends that were left lying about in the body of the program. First, there are a number of extra command options: @<If the |key|...@>= else if ( key = "O") then odds := true {Print odd-numbered pages only} else if ( key = "E") then evens := true {Even ditto} else if ( key = "L") then begin land := true ; {Print Landscape} start_stuff.data[ 6] := '1' ; end @ @<Glob...@>= land, odds, evens: boolean ; @ @<Set init...@>= land := false ; odds := false ; evens := false ; @ Where will the printed file go to? @<Set init...@>= set_string( print_ex, '.HPL', ' ', 0); @ @<Dont sort the page but |reset| it @>= L_reset( run) ; Add_run ; L_reset( mid) ; page_ptr := son( next( mid) ) ; @ Now lets dispose of rule-setting. \TeX\ puts the reference point of a rule at bottom left, the HP at top left. Sizes must be rounded up. @<Find the pixel sizes and reference point@>= rule_ht := round(v_conv*D_p + 0.5) ; rule_wid := round(h_conv*D_q + 0.5) ; D_dis := D_q ; IM_dis := rule_wid ; round_IM_h ( 0); rule_h := IM_h ; rule_v := IM_v - rule_ht ; @ @<Send it to the printer@>= set_v_abs(rule_v) ; set_h_abs(rule_h) ; print(chr(27), '*c', rule_ht:1, 'B') ; print(chr(27), '*c', rule_wid:1, 'A') ; print(chr(27), '*c0P') ; print_ln; @ Consider command strings. @<Set init...@>= set_string (start_stuff, '$E$&l0O', '$', 27 ); {Reset everything to default state} set_string (font_command, '$(&DX', '$', 27 ); set_string (v_abs_com, '$*p&DY', '$', 27 ); set_string (h_abs_com, '$*p&DX ', '$', 27 ); stop_stuff := start_stuff ; page_top := blank ; pause_after := blank ; @ On the HP, we must explicitly start a new page at a set position. Also since rules get set before any characters, we must then reset the position. @<Set up an empty page image@>= set_v_abs(0) ; set_h_abs(0) ; @ @<Pause reset@>= set_v_abs(0) ; set_h_abs(0) ; @* Downloading a font. The simplest and crudest way this could possibly be done is: read the \.{PXL} file and load the entire font, as soon as the |font_def| command is read from the \.{DVI} file. On VAX/VMS, this turned out to be unbearably slow. So it is here changed as follows: When a |font_def| command is read, we read the whole pixel file into a very large array. Then download each character before trying to print it. This `lazy downloading' makes the program run much faster, at the price of an enormous |pixels| array. See \.{TUG}boat (Vol.2, No.3) for a description of the \.{PXL} file format. @^\.{TUG}boat@> @<Download a whole font@>= begin @<Prepare to read the |raster_file|@> @<Read the pixel file into |pixels|, checking for errors @> @<Get the overall font parameters and send font header@> @<Make the coding scheme point to the new font@> goto good_font; {Bypass the rest of the \.{TFM} file } end @ First we have to determine the file name. @<Prepare to read...@>= raster_mag := round( 1500 * font_mag * magnification ) ; if not hunt_for_size( font_name, raster_mag) then font_error('cannot load this font') ; @.Error: cannot load@> @ @<Medium...@>= function open_font( name: var_string; mag: integer; ask: boolean ): boolean; begin splice( raster_name, raster_def, mag) ; open_font := open_and_ask( raster_file, raster_indx, name, raster_name, ask) ; end; @ @<Set init...@>= set_string( raster_def, 'TEX$PXL:.&DPXL', ' ', 0) ; @ Frequently the {\.DVI} file calls for a font at a magnification that is almost but not quite one of the standard sizes. So we try a few steps up or down before giving up. |range| is the maximum percentage that we allow the magnification to vary. @<Forw...@>= function hunt_for_size ( name: var_string; mag: integer): boolean; forward ; @ @<Medium...@>= function hunt_for_size ; label exit ; const range = 5 ; var try_mag, n , max : integer; hh: boolean; begin max := round( raster_mag* range / 100); n := 0 ; while ( n <= max) do begin try_mag := mag + n ; hh := open_font( name, try_mag, false) ; if hh then return else if ( n>0) then n:= -n else n := 1 - n ; end; hh := open_font( name, mag, true) ; exit: hunt_for_size := hh; end; @ Then we actually read the file into an array called |pixels|. In VMS, the short block at the end of the file ought to be padded with zeroes, but actually seems to be full of garbage. So we must do a fudge to find the true end of the file. @<Read the pixel...@>= pxl_start [ nf] := pxl_end ; repeat pixels[ pxl_end] := get_byte( raster) ; incr( pxl_end); if pxl_end = max_pixels then font_error('overflowed pixel array'); @.error: font: overflowed pixel array@> until eof(raster_file) ; while (pixels[ pxl_end] <> pixels[ pxl_start[ nf]+3]) or (pixels[ pxl_end-1] <> pixels[ pxl_start[ nf]+2]) or (pixels[ pxl_end-2] <> pixels[ pxl_start[ nf]+1]) or (pixels[ pxl_end-3] <> pixels[ pxl_start[ nf]]) do decr(pxl_end) ; close_binary(raster_file) ; @.System dependencies@> @ |pxl_end| is the highest used point in |pixels|; the fonts will be piled in on top of one another and |pxl_start[n]| points to the start of font n . @<Glob...@>= pixels: packed array[1..max_pixels] of byte ; pxl_mag, pxl_check, pxl_end, dir_ptr : integer; pxl_start, dir_start: array [D_font_ptr] of integer ; raster_mag: integer; @ @<Set init...@>= pxl_end := 1 ; @ @<Const...@>= max_pixels = 1000000 ; @ @<|font_def| vars@>= font_i, tex_chr : byte ; @ This is of course a guess, and perhaps we may want to refine it. @<Clean...@>= display_ln ('Used ', pxl_end:1, ' bytes of pixel memory out of ', max_pixels:1) ; @ Now |pxl_end| should be pointing to the very last byte of the file; so we will do some checking. |next_half| gets a 16-bit half word from the file, and |two_comp| negates it in twos-complement. @d next_half == pixels[dir_ptr] * 256 + pixels[dir_ptr+1] ; dir_ptr := dir_ptr +2 @d two_comp(#) == if # > 32767 then # := # - 65536 ; @<Read the pixel...@>= if pxl_end < 2000 + pxl_start[ nf] then font_error('Pixel file truncated!'); dir_ptr := pxl_end - 19 ; pxl_check := next_half ; two_comp(pxl_check) ; pxl_check := pxl_check * 65536 + next_half ; if pxl_check <> TFM_check then begin warn('pixel checksum disagrees with TFM checksum') ; display('pixel sum is', pxl_check) ; end; @.error: pixel checksum@> @.error: font: Pixel file truncated@> @ Next, look at the directory pointer. @<Read the pixel...@>= dir_ptr := pxl_end - 7 ; dir_start[ nf] := next_half ; dir_start[ nf] := dir_start[ nf] * 65536 + next_half ; dir_start[ nf] := dir_start[ nf] * 4 + pxl_start[ nf] ; {we count bytes, not words} if dir_start[ nf] + 2067 <> pxl_end then warn('pixel directory pointer disagrees with file size') ; @.Error: pixel directory pointer@> @ Finally, does the printer have enough room for the font? The HP allows 32 fonts per job and 395 KB memory. I have not checked the restriction of only 16 fonts per page. @<Read the pixel...@>= incr(PR_dl_font ) ; if PR_dl_font > max_dl_font then font_error('tried to load too many fonts') ; @.Error: font: tried to load@> @.Error: font: overflowed printer memory@> @ @<Set init...@>= PR_dl_font := min_dl_font ; PR_mem_used := 0 ; PR_max_mem := 395000; @ @<Glob...@>= PR_dl_font, PR_max_mem, PR_mem_used: integer ; @ If the error tests succeed, then we come here. Before we can load any characters, we have to send a command to the printer to declare the new font. This section assembles the necessary information. |dir_start[ nf]| should be pointing to the start of the font directory. The main task is that the printer must be given the size of a character cell; this must be large enough to contain all the characters. @<Get the overall font...@>= cell_bot := 0 ; cell_top := 0 ; cell_wid := 0 ; dir_ptr := dir_start[ nf] ; for tex_chr := 0 to 127 do begin @<Stretch the cell to make the character fit inside, and adjust the characters width@> end; cell_ht := cell_bot + cell_top ; {FUDGE} @ @<Stretch...@>= C_pxl_w := next_half ; C_pxl_h := next_half ; C_h_off := next_half ; C_v_off := next_half ; two_comp(C_h_off) ; two_comp(C_v_off) ; if C_h_off < 0 then C_pxl_w := C_pxl_w - C_h_off ; if C_pxl_w > cell_wid then cell_wid := C_pxl_w ; if C_v_off > cell_top then cell_top := C_v_off ; if C_v_off < 0 then C_pxl_h := C_pxl_h - C_v_off ; if C_pxl_h > cell_bot then cell_bot := C_pxl_h ; @ @<Glob...@>= C_width, cell_ht, cell_top, cell_bot, cell_wid, C_pxl_w, C_pxl_h, C_h_off, C_v_off : integer; @ Next, consider the character's width. This must be calculated exactly as in \.{DVItype}, for the reasons given there. @<Stretch...@>= dir_ptr := dir_ptr + 4 ; b0 := pixels[ dir_ptr ]; b1 := pixels[ dir_ptr + 1]; b2 := pixels[ dir_ptr + 2]; b3 := pixels[ dir_ptr + 3]; dir_ptr := dir_ptr + 4 ; C_width:= (((((b3*z)div@'400)+(b2*z))div@'400)+(b1*z))div beta; if b0 = 255 then C_width:=C_width - alpha else if b0 <> 0 then font_error('Out-of-bounds value for b0') ; @.error: font: Out-of-bounds |b0|@> D_width[ nf, tex_chr] := C_width ; @ We can now send stuff to declare the font. First we specify the font ID. This is a number by which the printer will refer to the font after loading it. @<Get the overall font...@>= print(chr(27), '*c', PR_dl_font:1, 'D'); {Specify printers font identifier} print(chr(27), ')s26W' ); {Start a create font command} prw(26); prw(1) ; { 8 bit chars} prw(0) ; prw(cell_top) ; prw(cell_wid) ; prw(cell_ht ) ; prw(1) ; { portrait, proportional spaced} prw(277) ; for font_i := 1 to 5 do prw(0) ; {The HP needs these parameters, but they dont serve any purpose known to me} @ Finally, we must establish the map from \TeX\ characters to printers characters in the new font. @<Make the coding scheme point to the new font@>= incr(top_code) ; {get a new coding scheme} scheme[ nf] := top_code ; alphabet(0, 33, top_code, PR_dl_font, 190); alphabet(33, 95, top_code, PR_dl_font, 33); for tex_chr := 0 to max_D_char do codes[ top_code, tex_chr].breadth := down_loaded ; @ @<Glob...@>= top_code: integer ; @ @<Set init...@>= top_code := 1 ; @* Downloading, part2: Lazy downloading. The idea is to load only those characters in each font that actually will be printed. It is obviously essential to ensure that each character gets loaded before being printed, and only once. This is done in the procedure |set_character|. The \TeX\ character is number |c_num| in font |D_font|, but the printer character is addressed by |cod|. The first job is to assemble the size parameters for the character. @<Enter a download...@>= begin dir_ptr := dir_start[D_font] + c_num * 16 ; C_pxl_w := next_half ; C_pxl_h := next_half ; C_h_off := next_half ; C_v_off := next_half ; two_comp(C_h_off) ; two_comp(C_v_off) ; pxl_ptr := next_half ; pxl_ptr := pxl_ptr * 65536 + next_half ; pxl_ptr := pxl_ptr * 4 + pxl_start[D_font] ; Tex_bytes := (C_pxl_w + 31) div 32 ; Tex_bytes := Tex_bytes * 4 ; {Bytes per row in PXL file} PR_bytes := (C_pxl_w + 7) div 8 ;{Ditto, in HP fonts} C_length := PR_bytes * C_pxl_h + 16 ; @ @<Glob...@>= pxl_ptr, Tex_bytes, PR_bytes, C_length, C_delta : integer; @ Now we must not let the character get downloaded twice, so we put the correct value into its |breadth|; we must also update the current |cod|. @<Enter a download...@>= C_width := D_width[ D_font, c_num] ; C_delta := round(C_width * h_conv) ; codes[ cur_scheme, c_num].breadth := C_delta ; cod.breadth := C_delta ; PR_mem_used := PR_mem_used + C_length + 64 ; {approximate} if PR_mem_used > PR_max_mem then warn('overflowed printer memory, will try to proceed regardless') ; @.Error: overflowed printer memory@> @ Now we send the character header. First, tell the printer which character will be downloaded. \TeX\ fonts usually have 128 characters and HP fonts have either 96 or 192. The permitted values for HP characters are 33..127 and 160..255 according to the manual but appendix B says 160 and some others are undefined. So we map \TeX\ characters 0..32 onto 190..222 . @<Enter a download...@>= print(chr(27), '*c', cod.IM_font:1, 'D'); {Specify printers font identifier} print(chr(27), '*c') ; print(cod.IM_char:1 ) ; print('E'); print(chr(27), '(s', C_length:1, 'W' ) ; prw(1024); prw(14*256 + 1); prw(0); prw(- C_h_off) ; {\TeX\ and the HP measure this in opposite directions} prw(C_v_off); prw(C_pxl_w) ; prw(C_pxl_h) ; prw(4 * C_delta) ; @ And at long last we can send the pixels!! This is the only pleasant part of the whole messy business. We need not shuffle bits because the H-P wants them in almost the exact order that they appear in the PXL file. Only difference is that H-P packs with zero bits to the next 8-bit byte, while PXL files pack to next 32 bits. That is the reason for the odd-loking calculation of |Tex_bytes| above. @<Enter a download...@>= for d_i:= 1 to C_pxl_h do begin for d_j:= 1 to PR_bytes do begin print(chr(pixels[ pxl_ptr ] )) ; incr(pxl_ptr) ; end ; pxl_ptr := pxl_ptr + Tex_bytes - PR_bytes ; end; print_ln ; end; @ Nearly all the HP's arguments come as signed 16-bit words, to be printed in two-complement notation. This procedure prints them. @<Low...@>= procedure prw( n: i_word); var nn: integer ; begin if (n>= 0) then nn := n else nn := n + 65536 ; print( zchr(nn div 256)); print( zchr(nn mod 256)); end ; @z