[go: up one dir, main page]

File: pkfont.ml

package info (click to toggle)
advi 1.10.2-3
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 15,008 kB
  • sloc: ml: 12,279; sh: 1,032; ansic: 1,016; makefile: 705; perl: 55
file content (298 lines) | stat: -rw-r--r-- 9,083 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
(***********************************************************************)
(*                                                                     *)
(*                             Active-DVI                              *)
(*                                                                     *)
(*                   Projet Cristal, INRIA Rocquencourt                *)
(*                                                                     *)
(*  Copyright 2002 Institut National de Recherche en Informatique et   *)
(*  en Automatique.  All rights reserved.  This file is distributed    *)
(*  under the terms of the GNU Lesser General Public License.          *)
(*                                                                     *)
(*  Jun Furuse, Didier Rmy and Pierre Weis.                           *)
(*  Contributions by Roberto Di Cosmo, Didier Le Botlan,               *)
(*  Xavier Leroy, and Alan Schmitt.                                    *)
(*                                                                     *)
(*  Based on Mldvi by Alexandre Miquel.                                *)
(***********************************************************************)

(* $Id: pkfont.ml,v 1.1 2007/01/18 14:14:36 rousse Exp $ *)

open Input;;

(*** Public types ***)

type bitmap =
  | Packed of int * string
  | Unpacked of string ;;

type char_def = {
    code : int ;
    tfm_width : int ;
    dx : int ;
    dy : int ;
    width : int ;
    height : int ;
    hoffset : int ;
    voffset : int ;
    (* The following field is declared as mutable for
       allowing in-place unpacking of the bitmap. *)
    mutable bitmap : bitmap
  } ;;

type t = {
    text : string ;
    design_size : int ;
    checksum : string ;
    hppp : int ;
    vppp : int ;
    defs : char_def list
  } ;;

(*** Reading a character definition ***)

let input_char_def ch flag =
  (* Loading the character parameters *)
  let (len, cdef) =
    match flag land 0x7 with
    | 0|1|2|3 ->
        (* Short format *)
	let pl = ((flag land 0x3) lsl 8) + input_uint8 ch in
	let cc = input_uint8 ch in
	let tfm = input_uint24 ch in
	let dm = input_uint8 ch in
	let w = input_uint8 ch in
	let h = input_uint8 ch in
	let hoff = input_int8 ch in
	let voff = input_int8 ch in
	let cdef =
	  { code = cc ; tfm_width = tfm ;
	    dx = dm lsl 16 ; dy = 0 ;
	    width = w ; height = h ;
	    hoffset = hoff ; voffset = voff ;
	    bitmap = Unpacked "" } in
	(pl - 8, cdef)
    | 4|5|6 ->
	(* Extended short format *)
	let pl = ((flag land 0x3) lsl 16) + input_uint16 ch in
	let cc = input_uint8 ch in
	let tfm = input_uint24 ch in
	let dm = input_uint16 ch in
	let w = input_uint16 ch in
	let h = input_uint16 ch in
	let hoff = input_int16 ch in
	let voff = input_int16 ch in
	let cdef =
	  { code = cc ; tfm_width = tfm ;
	    dx = dm lsl 16 ; dy = 0 ;
	    width = w ; height = h ;
	    hoffset = hoff ; voffset = voff ;
	    bitmap = Unpacked "" } in
	(pl - 13, cdef)
    | 7 ->
	(* Long format *)
	let pl = input_int32 ch in
	let cc = input_int32 ch in
	let tfm = input_int32 ch in
	let dx = input_int32 ch in
	let dy = input_int32 ch in
	let w = input_int32 ch in
	let h = input_int32 ch in
	let hoff = input_int32 ch in
	let voff = input_int32 ch in
	let cdef =
	  { code = cc ; tfm_width = tfm ;
	    dx = dx ; dy = dy ;
	    width = w ; height = h ;
	    hoffset = hoff ; voffset = voff ;
	    bitmap = Unpacked "" } in
	(pl - 28, cdef)
    | _ -> assert false in
  (* Loading the charater bitmap *)
  if flag lsr 4 = 14 then begin
    (* This is an unpacked bitmap *)
    if len <> (cdef.width * cdef.height + 7) lsr 3 then
      raise (Error "bad raster bitmap size") ;
    cdef.bitmap <- Unpacked(input_string ch len)
  end else begin
    (* This is a packed bitmap *)
    cdef.bitmap <- Packed(flag, input_string ch len)
  end ;
  cdef ;;

(*** Loading the body of the file ***)

let rec input_body ch =
  let flag = input_byte ch in
  if flag < 240 then begin
    let cdef = input_char_def ch flag in
    cdef :: input_body ch
  end else begin
    match flag with
    (* `pk_xxx' commands (specials).  We simply ignore them *)
    | 240 -> skip_bytes ch (input_uint8 ch) ; input_body ch
    | 241 -> skip_bytes ch (input_uint16 ch) ; input_body ch
    | 242 -> skip_bytes ch (input_uint24 ch) ; input_body ch
    | 243 -> skip_bytes ch (input_int32 ch) ; input_body ch
    (* `pk_yyy' command. Idem *)
    | 244 -> skip_bytes ch 4 ; input_body ch
    (* `pk_post' command (postamble).  This is the end *)
    | 245 ->
	begin
	  try
	    while input_byte ch = 246 do () done ;
	    raise (Error "invalid byte in the postamble")
	  with End_of_file -> []
	end
    (* `pk_no_op' command.  Nothing to do *)
    | 246 -> input_body ch
    (* `pk_pre' command (preamble).  This should not happen... *)
    | 247 -> raise (Error "preamble command found while reading the body")
    | _ -> raise (Error "unknown command")
  end ;;

(*** Loading a PK file ***)

let pk_pre = 247 ;;
let pk_id = 89 ;;

let input_font ch =
  let b = input_byte ch in
  let i = input_byte ch in
  if b <> pk_pre || i <> pk_id then
    raise (Error "not a PK file") ;
  let k = input_uint8 ch in
  let txt = input_string ch k in
  let ds = input_int32 ch in
  let cs = input_string ch 4 in
  let hppp = input_int32 ch in
  let vppp = input_int32 ch in
  let defs = input_body ch in
  { text = txt ;
    design_size = ds ;
    checksum = cs ;
    hppp = hppp ;
    vppp = vppp ;
    defs = defs } ;;

let load filename =
  let ch = open_in_bin filename in
  try
    let font = input_font ch in
    close_in ch ; font
  with e ->
    close_in ch ; raise e ;;

let find_char_def font code =
  let rec search = function
    | [] -> raise Not_found
    | cdef :: rest -> if cdef.code = code then cdef else search rest in
  search font.defs ;;

(*** Unpacking a character bitmap ***)

let unpack cdef =
  match cdef.bitmap with
  | Unpacked _ -> ()
  | Packed(flag, str) ->
      let dyn_f = flag lsr 4
      and len = String.length str
      and pos = ref 0
      and byte = ref (-1) in
      (* Reading a nybble (i.e. a 4-bit integer) *)
      let read_nyb () =
	if !byte >= 0 then begin
	  let lo = !byte land 0xf in
	  byte := -1 ; lo
	end else begin
	  if !pos = len then
	    raise (Error "nybble stream exhausted") ;
	  byte := Char.code str.[!pos] ;
	  incr pos ;
	  !byte lsr 4
	end in
      (* Reading a packed number *)
      let finish_big_pnum () =
	let j = ref 0 and k = ref 1 in
	while j := read_nyb () ; !j = 0 do incr k done ;
	while !k > 0 do j := (!j lsl 4) + read_nyb () ; decr k done ;
	!j - 15 + ((13 - dyn_f) lsl 4) + dyn_f in
      let read_pnum () =
	match read_nyb () with
	| 0 -> finish_big_pnum ()
	| 14 ->
	    let pnum =
	      match read_nyb () with
	      |	0 -> finish_big_pnum ()
	      |	14|15 -> raise (Error "two repeat counts in the same row")
	      |	i ->
		  if i <= dyn_f then i else
		  ((i - dyn_f - 1) lsl 4) + read_nyb () + dyn_f + 1 in
	    -pnum
	| 15 -> -1
	| i ->
	    if i <= dyn_f then i else
	    ((i - dyn_f - 1) lsl 4) + read_nyb () + dyn_f + 1 in
      (* The bitmap structure *)
      let w = cdef.width
      and h = cdef.height in
      let size = w * h in
      let datalen = (size + 7) lsr 3 in
      let data = String.make datalen '\000'
      (* Index into the bitmap *)
      and i = ref 0 and imask = ref 0x80
      (* Index into the bitmap, [w] bits before *)
      and j = ref ((-w) asr 3)
      and jmask = ref (0x80 lsr ((-w) land 7)) in
      (* Sending a bit to the bitmap *)
      let send_bit b =
	if b then
	  data.[!i] <- Char.chr (Char.code data.[!i] lor !imask) ;
	imask := !imask lsr 1 ;
	if !imask = 0 then begin imask := 0x80 ; incr i end ;
	jmask := !jmask lsr 1 ;
	if !jmask = 0 then begin jmask := 0x80 ; incr j end in
      (* Resending n times the last line to the bitmap *)
      let resend_last_line n =
	for p = 1 to n * w do
	  if Char.code data.[!j] land !jmask <> 0 then
	    data.[!i] <- Char.chr (Char.code data.[!i] lor !imask) ;
	  imask := !imask lsr 1 ;
	  if !imask = 0 then begin imask := 0x80 ; incr i end ;
	  jmask := !jmask lsr 1 ;
	  if !jmask = 0 then begin jmask := 0x80 ; incr j end
	done in
      (* Current coordinates into the bitmap *)
      let x = ref 0 and y = ref 0
      and black = ref ((flag land 8) = 8)
      and repeat_count = ref 0 in
      (* Filling the bitmap *)
      while !y < h do
	let pnum = read_pnum () in
	if pnum < 0 then begin
	  (* This is a repeat count *)
	  if !repeat_count > 0 then
	    raise (Error "two repeat counts in the same row") ;
	  repeat_count := -pnum
	end else begin
	  (* This is a run-length *)
	  for k = 1 to pnum do
	    if !i = datalen then
	      raise (Error "bitmap overflow") ;
	    send_bit !black ;
	    incr x ;
	    if !x = w then begin
	      x := 0 ;
	      incr y ;
	      if !repeat_count > 0 then begin
		y := !y + !repeat_count ;
		if !y > h then
		  raise (Error "bitmap overflow") ;
		resend_last_line !repeat_count ;
		repeat_count := 0
	      end
	    end
	  done ;
	  black := not !black
	end
      done ;
      cdef.bitmap <- Unpacked data ;;