|
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: 25659 (0x643b) Types: TextFile Names: »hpgf.ch«
└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89 └─⟦this⟧ »./DVIware/lpr-viewers/crudetype/hpgf.ch« └─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12 └─⟦af5ba6c8e⟧ »unix3.0/DVIWARE.tar.Z« └─⟦ca79c7339⟧ └─⟦this⟧ »DVIware/lpr-viewers/crudetype/hpgf.ch«
% HPGF.CH Provisional change file for the HP Laserjet... % NOTE the system change file must normally be inserted above this point. % SEE HPGF.DOC for users document--which must be rewritten for any new % system. % % [43] @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 % [59] % 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 % [175] @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 % [213] @x @<Const...@>= device_ID = 'Lineprinter'; @y @<Const...@>= device_ID = 'Laserjet +'; @z % [214] @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 % [215] @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 % [216] @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 % [221] @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 and 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 % [236] @x @<Assign char...@>= @<Assign Lineprinter coding schemes@> @<Define Lineprinter code tables@> @<Set rule characters@> @y @<Assign char...@>= do_nothing @z % [238...] @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, 1: reading the font file. The simplest and crudest way this could possibly be done is: read the raster 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 raster file into an array. Then download each character before trying to print it. This `lazy downloading' makes the program run much faster, at the price of a large use of memory. @^\.{TUG}boat@> @<Download a whole font@>= begin @<Prepare to read the |raster_file|@> repeat @<Get \.{GF} command |GF_com|, and do it@> until GF_com = 248; close_binary( raster_file) ; @<Establish the new font in memory@> end @ First we have to determine the file name. @<Prepare to read...@>= raster_mag := round(300 * 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; @ 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 read the file; a horrible mess. @<Get \.{GF} command...@>= GF_com := get_byte( raster) ; if GF_com <= 63 then paint( GF_com) else if ( GF_com >= 74) and ( GF_com <= 238) then new_row( GF_com - 74 ) else @ Then we have the usual messy |case| statement: @d three_cases(#)== #,#+1,#+2 : begin GF_par := get_integer( raster)( GF_com - # + 1 ); four_case_end @<Get \.{GF} command...@>= case GF_com of three_cases( 64)( paint( GF_par)); 67, 68: boc; 69: eoc; 70: miss_row( 0); three_cases( 71)( miss_row( GF_par)); three_cases( 239)( skip( raster)( GF_par)); 242: skip( raster)( get_integer( raster)( -4)) ; 243: skip( raster)( 4); 244:; 247: preamble; 248: postamble ; 245,246,249,250,251,252,253,254,255: warn( 'illegal GF command, will try to continue'); end; @.illegal GF command@> @ Now there follow lots of procedures to deal with the commands. @<Lowest...@>= procedure preamble; var p: byte; begin p:=get_byte( raster); p:=get_byte( raster); skip( raster)( p) ; {the introductory comment} with Font_box do begin L := pixel_R ; R := pixel_L ; T := pixel_B ; B := pixel_T ; end; end; @# procedure postamble; var GF_check: integer ; begin skip( raster)( 8); GF_check := get_integer( raster)( -4) ; if (D_check<>0)and(GF_check<>0)and(D_check<>GF_check) then begin warn('check sums do not agree!'); @.error: check sums...@> display_ln('DVI check was: ', D_check, ' GF check was: ', GF_check); display(' '); end; end; @# procedure boc; var q : byte; mm, nn: i_word; begin if GF_com = 67 then begin GF_char := get_integer( raster)( 4) mod 256 ; skip( raster) ( 4); Boc_box.L:=get_integer( raster)( -4); Boc_box.R:=get_integer( raster)( -4); Boc_box.B:=get_integer( raster)( -4); Boc_box.T:=get_integer( raster)( -4); end else begin GF_char:=get_byte( raster); q:=get_byte( raster); Boc_box.R:=get_byte( raster); Boc_box.L:=Boc_box.R-q; q:=get_byte( raster); Boc_box.T:=get_byte( raster); Boc_box.B:=Boc_box.T-q; end; @<Clear the image@> end; @ Now lets assign names to variables. In order to try to clear up the muddle of boundaries for character cells, I introduce a concept of a ``box'', not the same as a \TeX\ box. The fields represent the boundaries that must contain all the black pixels of any character. @<Const...@>= pixel_L = -300; pixel_R = 700; pixel_B = -300; pixel_T = 700; @ @<Types...@>= @!x_coord=pixel_L..pixel_R; @!y_coord=pixel_B..pixel_T; box = packed record L,R: x_coord; T,B: y_coord; end; dir_entry = packed record point: integer; h_offset, v_offset, wid, ht : i_word; end; @ @<Glob...@>= Boc_box, {Limits of char. cell declared in |BOC| command} char_box, {actual boundaries of char. cell} Font_box: box; {The font cell. This is the smallest cell that contains the reference point and any char. cell in the font} GF_com, GF_par, GF_char : byte; glyphs: packed array[1..max_glyph] of byte ; glyph_ptr: integer; raster_mag: integer; directory : array[D_font_ptr, D_char_ptr ] of dir_entry ; C_width : integer; @ @<Set init...@>= glyph_ptr := 1 ; for in_i := 0 to max_D_fonts do for in_j := 0 to max_D_char do directory[ in_i, in_j].point := sentry ; {Mark everything as unprintable} @ The definition of \.{GF} files refers to two registers, $(G_m,G_n)$, which hold row and column numbers. We also need to remember |paint_switch|, which is either |black| or |white|. @<Glob...@>= @!pixels: packed array [y_coord,x_coord] of pixel; @!G_m: x_coord; @!G_n: y_coord; {current state values} @!paint_switch: pixel; @ We'll need a big array of pixels to hold the character image. Each pixel should be represented as a single bit in order to save space. Different systems may prefer the following definitions, while others may do better using the |boolean| type and constants. @^system dependencies@> @d white==false @d black==true @d swop == paint_switch:=not paint_switch {could also be |if paint_switch=black then paint_switch:=white else paint_switch:=black|} @<Types...@>= @!pixel=boolean ; {could also be |white..black|} @ Maybe there's a faster way to do this on your system. Note that the only part of the |image_array| that we clear is the part that the current character may use. Thus, the rest of this program may not look outside the area delimited by |Boc_box| and expect to see anything but junk. @^system dependencies@> @<Clear the image@>= begin for nn := Boc_box.B to Boc_box.T do for mm := Boc_box.L to Boc_box.R do pixels[nn,mm] := white; G_n := Boc_box.T ; G_m := Boc_box.L ; char_box.L := pixel_R ; char_box.R := pixel_L ; char_box.B := pixel_T ; char_box.T := pixel_B ; directory[ nf, GF_char].point := 0 ; {Indicates a blank character} end @ @<Lowest...@>= procedure paint( p: integer); var m, k: integer; begin if G_m+p> pixel_R then warn('character extends too far to the right') @.character extends...@> else if paint_switch = white then else begin m := G_m + p -1 ; if char_box.T < G_n then char_box.T := G_n ; if char_box.B > G_n then char_box.B := G_n ; if char_box.L > G_m then char_box.L := G_m ; for k:= G_m to m do pixels[G_n, k] := black ; if char_box.R < m then char_box.R := m ; end; swop; G_m := G_m +p ; end; @# procedure new_row( p:integer); begin decr(G_n); G_m:=Boc_box.L + p; paint_switch:=black; end; @# procedure miss_row( p: integer); begin G_n:=G_n - p ; G_m:= Boc_box.L; paint_switch:=white; end; @* Downloading, 2: Transfer characters into memory. After we have read the character, we must transfer it into memory. First, stretch the Font box to include the current characters box. @<Lowest...@>= procedure eoc; var x, y : integer; cur_byt: byte ; q: i_word ; begin if char_box.R >= char_box.L {If not, the character is unprintable} then begin if char_box.L < Font_box.L then Font_box.L := char_box.L ; if char_box.B < Font_box.B then Font_box.B := char_box.B ; if char_box.R > Font_box.R then Font_box.R := char_box.R ; if char_box.T > Font_box.T then Font_box.T := char_box.T ; @<Transfer the dimensions of the character@> @<Transfer the |pixels| into |glyphs|@> end; end; @ In landscape mode, the character must be rotated. The |directory| will contain the dimensions to be downloaded; these do depend on orientation. |char_box| describes the logical character which does not depend on orientation. @<Transfer the dimensions...@>= with directory[nf, GF_char] do begin point := glyph_ptr; if land then begin h_offset := - char_box.T ; v_offset := char_box.R ; ht := char_box.R - char_box.L +1 ; wid := char_box.T - char_box.B +1 ; end else begin h_offset := char_box.L ; {\TeX\ and the HP measure this in opposite directions} v_offset := char_box.T ; wid := char_box.R - char_box.L +1 ; ht := char_box.T - char_box.B +1 ; end; end; @ Likewise the |glyphs| array will contain the pixels to be downloaded; these also depend on orientation. Looking at the logical character, |x| is the horizontal coordinate and |y| the vertical. In portrait mode the pixels must be sent starting at the top left corner and going left to right along the top row. In Landscape mode you must start at the top right corner and go down the right hand column. Each row or column must be padded to |8n| bits. @<Transfer the |pixels|...@>= if land then begin for x := char_box.R downto char_box.L do begin cur_byt := 0 ; q := 0 ; for y := char_box.T downto char_box.B do begin if pixels[ y, x] then cur_byt := cur_byt + powers[q] ; if q < 7 then incr( q) else begin glyphs[glyph_ptr] := cur_byt ; incr( glyph_ptr) ; cur_byt := 0; q := 0 ; end; end; if q > 0 then begin glyphs[glyph_ptr] := cur_byt ; incr( glyph_ptr) ; cur_byt := 0; end; end; end else @ @<Transfer the |pixels|...@>= begin for y := char_box.T downto char_box.B do begin cur_byt := 0 ; q := 0 ; for x := char_box.L to char_box.R do begin if pixels[ y, x] then cur_byt := cur_byt + powers[q] ; if q < 7 then incr( q) else begin glyphs[glyph_ptr] := cur_byt ; incr( glyph_ptr) ; cur_byt := 0; q := 0 ; end; end; if q > 0 then begin glyphs[glyph_ptr] := cur_byt ; incr( glyph_ptr) ; cur_byt := 0; end; end; end ; @ @<Set init...@>= powers[0] := 128 ; for in_i := 1 to 7 do powers[in_i] := powers[in_i-1] div 2 ; @ @<Glob...@>= powers: array[0..7] of byte ; @ @<Const...@>= max_glyph = 1000000 ; @ @<Clean...@>= display_ln ('Used ', glyph_ptr:1, ' bytes of font memory out of ', max_glyph:1); @ 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. @<Establish...@>= incr(PR_dl_font ) ; if PR_dl_font > max_dl_font then font_error('tried to load too many fonts') ; @.Error: tried to load@> @ @<Set init...@>= PR_dl_font := min_dl_font ; PR_mem_used := 0 ; PR_max_mem := 395000; set_string( font_start, '$*c&DD', '$', 27) ; @ @<Glob...@>= PR_dl_font, PR_max_mem, PR_mem_used: integer ; font_start: var_string ; @ 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. First we specify the font ID. This is a number by which the printer will refer to the font after loading it. @<Establish...@>= print_command( font_start, PR_dl_font) ; print(chr(27), ')s26W' ); {A create font command} prw(26); prw(1) ; { 8 bit chars} prw(0) ; with Font_box do begin if L > 0 then L := 0 ; if B > 0 then B := 0 ; if R < 0 then R := 0 ; if T < 0 then T := 0 ; {Stretch the Font box to include the ref. point} prw( T) ; prw( R - L + 1) ; {width} prw( T - B + 1) ; {height} end; if land then prw( 257) else prw(1) ; {proportional spaced} prw(277) ; for font_i := 1 to 5 do prw(0) ; {The HP needs these parameters, but they serve no purpose known to me} @ Finally, we must establish the map from \TeX\ characters to printers characters in the new font. @<Establish...@>= 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 ; @ @<|font_def| vars@>= tex_chr, font_i: integer; @ @<Set init...@>= top_code := 1 ; @* Downloading, 3: 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 update the directory info. for the character, and assemble its size parameters. @<Enter a download...@>= with directory [ D_font, c_num] do begin if point < 0 then begin warn( 'tried to print a non-existent character, number: ' , c_num:1) ; codes[ cur_scheme, c_num].breadth := bad_char ; end else begin C_length := ht * (( wid + 7) div 8) ; {length of data} 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@> @.Error: tried to print...@> @ @<Clean...@>= display_ln ('Used ', PR_mem_used:1, ' bytes of printers memory out of ', PR_max_mem:1) ; @ @<Glob...@>= C_length, C_delta : integer; char_start, char_head: var_string ; @ @<Set init...@>= set_string( char_start, '$*c&DE', '$', 27) ; set_string( char_head, '$(s&DW', '$', 27) ; @ 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|. @ 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...@>= { N.B. still |with directory [ D_font, c_num]| } print_command( font_start, cod.IM_font ) ; {Specify printers font identifier} print_command( char_start, cod.IM_char) ; print_command( char_head, (C_length + 16) ) ; {and the character} prw(1024); prw(14*256 + 1); if land then prw( 256 ) else prw(0); prw(h_offset) ; prw(v_offset); prw(wid) ; prw(ht) ; prw(4 * C_delta) ; @ And at long last we can send the pixels!! @<Enter a download...@>= for d_i := point to point+C_length-1 do print(chr(glyphs[ d_i] )) ; print_ln ; end; 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