1 /*
2 * pklib.c
3 *
4 * This file is part of the ttf2pk package.
5 *
6 * Copyright 1997-1999, 2000 by
7 * Frederic Loyer <loyer@ensta.fr>
8 * Werner Lemberg <wl@gnu.org>
9 */
10
11 /*
12 * This code has been derived from the program gsftopk.
13 * Here the original copyright.
14 */
15
16 /*
17 * Copyright (c) 1994 Paul Vojta. All rights reserved.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <stddef.h> /* for size_t */
49 #include <string.h>
50 #include <errno.h>
51 #include <ctype.h>
52
53 #include "newobj.h"
54 #include "pklib.h"
55 #include "errormsg.h"
56 #include "filesrch.h"
57
58 #ifndef MAXPATHLEN
59 #define MAXPATHLEN 256
60 #endif
61
62 #define PK_PRE (char)247
63 #define PK_ID 89
64 #define PK_POST (char)245
65 #define PK_NOP (char)246
66
67 extern int dpi;
68
69 FILE *pk_file;
70
71
72 /*
73 * Information from the .tfm file.
74 */
75
76 int tfm_lengths[12];
77
78 #define lh tfm_lengths[1]
79 #define bc tfm_lengths[2]
80 #define ec tfm_lengths[3]
81 #define nw tfm_lengths[4]
82
83 long checksum;
84 long design;
85 byte width_index[256];
86 long tfm_widths[256];
87
88 /*
89 * Information on the bitmap currently being worked on.
90 */
91
92 byte *bitmap;
93 int width;
94 int skip;
95 int height;
96 int hoff;
97 int voff;
98 int bytes_wide;
99 size_t bm_size;
100 byte *bitmap_end;
101 int pk_len;
102
103 /*
104 * Here's the path searching stuff. First the typedefs and variables.
105 */
106
107 static char searchpath[MAXPATHLEN + 1];
108
109 #define HUNKSIZE (MAXPATHLEN + 2)
110
111 struct spacenode /* used for storage of directory names */
112 {
113 struct spacenode *next;
114 char *sp_end; /* end of data for this chunk */
115 char sp[HUNKSIZE];
116 } firstnode;
117
118
119
120 static FILE *
search_tfm(char ** name)121 search_tfm(char **name)
122 {
123 char *p;
124 FILE *f;
125
126
127 p = TeX_search_tfm(name);
128 if (p == NULL)
129 return NULL;
130 strcpy(searchpath, p);
131 f = fopen(searchpath, "rb");
132 return f;
133 }
134
135
136 static long
getlong(FILE * f)137 getlong(FILE *f)
138 {
139 unsigned long value;
140
141
142 value = (unsigned long)getc(f) << 24;
143 value |= (unsigned long)getc(f) << 16;
144 value |= (unsigned long)getc(f) << 8;
145 value |= (unsigned long)getc(f);
146 return value;
147 }
148
149
150 char line[82];
151
152
153 static byte masks[] = {0, 1, 3, 7, 017, 037, 077, 0177, 0377};
154
155 byte flag;
156 int pk_dyn_f;
157 int pk_dyn_g;
158 int base; /* cost of this character if pk_dyn_f = 0 */
159 int deltas[13]; /* cost of increasing pk_dyn_f from i to i+1 */
160
161
162 /*
163 * Add up statistics for putting out the given shift count.
164 */
165
166 static void
tallyup(int n)167 tallyup(int n)
168 {
169 int m;
170
171
172 if (n > 208)
173 {
174 ++base;
175 n -= 192;
176 for (m = 0x100; m != 0 && m < n; m <<= 4)
177 base += 2;
178 if (m != 0 && (m = (m - n) / 15) < 13)
179 deltas[m] += 2;
180 }
181 else if (n > 13)
182 ++deltas[(208 - n) / 15];
183 else
184 --deltas[n - 1];
185 }
186
187
188 /*
189 * Routines for storing the shift counts.
190 */
191
192 static Boolean odd = False;
193 static byte part;
194
195
196 static void
pk_put_nyb(int n)197 pk_put_nyb(int n)
198 {
199 if (odd)
200 {
201 *bitmap_end++ = (part << 4) | n;
202 odd = False;
203 }
204 else
205 {
206 part = n;
207 odd = True;
208 }
209 }
210
211
212 static void
pk_put_long(int n)213 pk_put_long(int n)
214 {
215 if (n >= 16)
216 {
217 pk_put_nyb(0);
218 pk_put_long(n / 16);
219 }
220 pk_put_nyb(n % 16);
221 }
222
223
224 static void
pk_put_count(int n)225 pk_put_count(int n)
226 {
227 if (n > pk_dyn_f)
228 {
229 if (n > pk_dyn_g)
230 pk_put_long(n - pk_dyn_g + 15);
231 else
232 {
233 pk_put_nyb(pk_dyn_f + (n - pk_dyn_f + 15) / 16);
234 pk_put_nyb((n - pk_dyn_f - 1) % 16);
235 }
236 }
237 else
238 pk_put_nyb(n);
239 }
240
241
242 static void
trim_bitmap(void)243 trim_bitmap(void)
244 {
245 byte *p;
246 byte mask;
247
248
249 /* clear out garbage bits in bitmap */
250
251 if (width % 8 != 0)
252 {
253 mask = ~masks[8 - width % 8];
254 for (p = bitmap + bytes_wide - 1; p < bitmap_end; p += bytes_wide)
255 *p &= mask;
256 }
257
258 /* Find the bounding box of the bitmap. */
259
260 /* trim top */
261
262 skip = 0;
263 mask = 0;
264
265 for (;;)
266 {
267 if (bitmap >= bitmap_end) /* if bitmap is empty */
268 {
269 width = height = hoff = voff = 0;
270 return;
271 }
272
273 p = bitmap + bytes_wide;
274 while (p > bitmap)
275 mask |= *--p;
276 if (mask)
277 break;
278 ++skip;
279 bitmap += bytes_wide;
280 }
281
282 height -= skip;
283 voff -= skip;
284
285 #ifdef DEBUG
286 if (skip < 2 || skip > 3)
287 printf("Character has %d empty rows at top\n", skip);
288 #endif
289
290 /* trim bottom */
291
292 skip = 0;
293 mask = 0;
294
295 for (;;)
296 {
297 p = bitmap_end - bytes_wide;
298 while (p < bitmap_end)
299 mask |= *p++;
300 if (mask)
301 break;
302 ++skip;
303 bitmap_end -= bytes_wide;
304 }
305
306 height -= skip;
307
308 #ifdef DEBUG
309 if (skip < 2 || skip > 3)
310 printf("Character has %d empty rows at bottom\n", skip);
311 #endif
312
313 /* trim right */
314
315 skip = 0;
316 --width;
317
318 for (;;)
319 {
320 mask = 0;
321 for (p = bitmap + width / 8; p < bitmap_end; p += bytes_wide)
322 mask |= *p;
323 if (mask & (0x80 >> (width % 8)))
324 break;
325
326 --width;
327 ++skip;
328 }
329
330 ++width;
331
332 #ifdef DEBUG
333 if (skip < 2 || skip > 3)
334 printf("Character has %d empty columns at right\n", skip);
335 #endif
336
337 /* trim left */
338
339 skip = 0;
340
341 for (;;)
342 {
343 mask = 0;
344 for (p = bitmap + skip / 8; p < bitmap_end; p += bytes_wide)
345 mask |= *p;
346 if (mask & (0x80 >> (skip % 8)))
347 break;
348
349 ++skip;
350 }
351
352 width -= skip;
353 hoff -= skip;
354
355 #ifdef DEBUG
356 if (skip < 2 || skip > 3)
357 printf("Character has %d empty columns at left\n", skip);
358 #endif
359
360 bitmap += skip / 8;
361 skip = skip % 8;
362 }
363
364
365 /*
366 * Pack the bitmap using the rll method. (Return false if it's better
367 * to just pack the bits.)
368 */
369
370 static Boolean
pk_rll_cvt(void)371 pk_rll_cvt(void)
372 {
373 static int *counts = NULL; /* area for saving bit counts */
374 static int maxcounts = 0; /* size of this area */
375 unsigned int ncounts; /* max to allow this time */
376 int *nextcount; /* next count value */
377
378 int *counts_end; /* pointer to end */
379 byte *rowptr;
380 byte *p;
381 byte mask;
382 byte *rowdup; /* last row checked for dup */
383 byte paint_switch; /* 0 or 0xff */
384 int bits_left; /* bits left in row */
385 int cost;
386 int i;
387
388
389 /* Allocate space for bit counts. */
390
391 ncounts = (width * height + 3) / 4;
392 if (ncounts > maxcounts)
393 {
394 if (counts != NULL)
395 free(counts);
396 counts = (int *)mymalloc((ncounts + 2) * sizeof (int));
397 maxcounts = ncounts;
398 }
399 counts_end = counts + ncounts;
400
401 /* Form bit counts and collect statistics */
402
403 base = 0;
404 memset(deltas, 0, sizeof (deltas));
405 rowdup = NULL; /* last row checked for duplicates */
406 p = rowptr = bitmap;
407 mask = 0x80 >> skip;
408 flag = 0;
409 paint_switch = 0;
410
411 if (*p & mask)
412 {
413 flag = 8;
414 paint_switch = 0xff;
415 }
416
417 bits_left = width;
418 nextcount = counts;
419
420 while (rowptr < bitmap_end) /* loop over shift counts */
421 {
422 int shift_count = bits_left;
423
424
425 for (;;)
426 {
427 if (bits_left == 0)
428 {
429 if ((p = rowptr += bytes_wide) >= bitmap_end)
430 break;
431 mask = 0x80 >> skip;
432 bits_left = width;
433 shift_count += width;
434 }
435 if (((*p ^ paint_switch) & mask) != 0)
436 break;
437 --bits_left;
438 mask >>= 1;
439 if (mask == 0)
440 {
441 ++p;
442 while (*p == paint_switch && bits_left >= 8)
443 {
444 ++p;
445 bits_left -= 8;
446 }
447 mask = 0x80;
448 }
449 }
450
451 if (nextcount >= counts_end)
452 return False;
453 shift_count -= bits_left;
454 *nextcount++ = shift_count;
455 tallyup(shift_count);
456
457 /* check for duplicate rows */
458 if (rowptr != rowdup && bits_left != width)
459 {
460 byte *p1 = rowptr;
461 byte *q = rowptr + bytes_wide;
462 int repeat_count;
463
464
465 while (q < bitmap_end && *p1 == *q)
466 {
467 ++p1;
468 ++q;
469 }
470 repeat_count = (p1 - rowptr) / bytes_wide;
471 if (repeat_count > 0)
472 {
473 *nextcount++ = -repeat_count;
474 if (repeat_count == 1)
475 --base;
476 else
477 {
478 ++base;
479 tallyup(repeat_count);
480 }
481 rowptr += repeat_count * bytes_wide;
482 }
483 rowdup = rowptr;
484 }
485 paint_switch = ~paint_switch;
486 }
487
488 #ifdef DEBUG
489 /*
490 * Dump the bitmap
491 */
492
493 for (p = bitmap; p < bitmap_end; p += bytes_wide)
494 {
495 byte *p1 = p;
496 int j;
497
498
499 mask = 0x80 >> skip;
500 for (j = 0; j < width; ++j)
501 {
502 putchar(*p1 & mask ? '@' : '.');
503 if ((mask >>= 1) == 0)
504 {
505 mask = 0x80;
506 ++p1;
507 }
508 }
509 putchar('\n');
510 }
511 putchar('\n');
512 #endif
513
514 /* Determine the best pk_dyn_f */
515
516 pk_dyn_f = 0;
517 cost = base += 2 * (nextcount - counts);
518
519 for (i = 1; i < 14; ++i)
520 {
521 base += deltas[i - 1];
522 if (base < cost)
523 {
524 pk_dyn_f = i;
525 cost = base;
526 }
527 }
528
529 /* last chance to bail out */
530
531 if (cost * 4 > width * height)
532 return False;
533
534 /* Pack the bit counts */
535
536 pk_dyn_g = 208 - 15 * pk_dyn_f;
537 flag |= pk_dyn_f << 4;
538 bitmap_end = bitmap;
539 *nextcount = 0;
540 nextcount = counts;
541
542 while (*nextcount != 0)
543 {
544 if (*nextcount > 0)
545 pk_put_count(*nextcount);
546 else
547 if (*nextcount == -1)
548 pk_put_nyb(15);
549 else
550 {
551 pk_put_nyb(14);
552 pk_put_count(-*nextcount);
553 }
554 ++nextcount;
555 }
556
557 if (odd)
558 {
559 pk_put_nyb(0);
560 ++cost;
561 }
562
563 if (cost != 2 * (bitmap_end - bitmap))
564 printf("Cost miscalculation: expected %d, got %ld\n",
565 cost, (long)(2 * (bitmap_end - bitmap)));
566 pk_len = bitmap_end - bitmap;
567 return True;
568 }
569
570
571 static void
pk_bm_cvt(void)572 pk_bm_cvt(void)
573 {
574 byte *rowptr;
575 byte *p;
576 int blib1; /* bits left in byte */
577 int bits_left; /* bits left in row */
578 byte *q;
579 int blib2;
580 byte nextbyte;
581
582
583 flag = 14 << 4;
584 q = bitmap;
585 blib2 = 8;
586 nextbyte = 0;
587
588 for (rowptr = bitmap; rowptr < bitmap_end; rowptr += bytes_wide)
589 {
590 p = rowptr;
591 blib1 = 8 - skip;
592 bits_left = width;
593
594 if (blib2 != 8)
595 {
596 int n;
597
598
599 if (blib1 < blib2)
600 {
601 nextbyte |= *p << (blib2 - blib1);
602 n = blib1;
603 }
604 else
605 {
606 nextbyte |= *p >> (blib1 - blib2);
607 n = blib2;
608 }
609 blib2 -= n;
610 if ((bits_left -= n) < 0)
611 {
612 blib2 -= bits_left;
613 continue;
614 }
615 if ((blib1 -= n) == 0)
616 {
617 blib1 = 8;
618 ++p;
619 if (blib2 > 0)
620 {
621 nextbyte |= *p >> (8 - blib2);
622 blib1 -= blib2;
623 bits_left -= blib2;
624 if (bits_left < 0)
625 {
626 blib2 = -bits_left;
627 continue;
628 }
629 }
630 }
631 *q++ = nextbyte;
632 }
633
634 /* fill up whole (destination) bytes */
635
636 while (bits_left >= 8)
637 {
638 nextbyte = *p++ << (8 - blib1);
639 *q++ = nextbyte | (*p >> blib1);
640 bits_left -= 8;
641 }
642
643 /* now do the remainder */
644
645 nextbyte = *p << (8 - blib1);
646 if (bits_left > blib1)
647 nextbyte |= p[1] >> blib1;
648 blib2 = 8 - bits_left;
649 }
650
651 if (blib2 != 8)
652 *q++ = nextbyte;
653
654 pk_len = q - bitmap;
655 }
656
657
658 static void
putshort(int w)659 putshort(int w)
660 {
661 putc(w >> 8, pk_file);
662 putc(w, pk_file);
663 }
664
665
666 static void
putmed(long w)667 putmed(long w)
668 {
669 putc(w >> 16, pk_file);
670 putc(w >> 8, pk_file);
671 putc(w, pk_file);
672 }
673
674
675 static void
putlong(long w)676 putlong(long w)
677 {
678 putc(w >> 24, pk_file);
679 putc(w >> 16, pk_file);
680 putc(w >> 8, pk_file);
681 putc(w, pk_file);
682 }
683
684
685 static char
xgetc(FILE * f)686 xgetc(FILE *f)
687 {
688 int c;
689
690
691 c = getc(f);
692 if (c == EOF)
693 oops("Premature end of file.");
694 return (byte)c;
695 }
696
697
698 /*
699 * Open and read the tfm file.
700 */
701
702 void
TFMopen(char ** filename)703 TFMopen(char **filename)
704 {
705 FILE *tfm_file;
706 int i;
707 int cc;
708
709
710 tfm_file = search_tfm(filename);
711 if (tfm_file == NULL)
712 oops("Cannot find tfm file.");
713
714 for (i = 0; i < 12; i++)
715 {
716 int j;
717
718
719 j = (int)((byte)getc(tfm_file)) << 8;
720 tfm_lengths[i] = j | (int)((byte)xgetc(tfm_file));
721 }
722
723 checksum = getlong(tfm_file);
724 design = getlong(tfm_file);
725 fseek(tfm_file, 4 * (lh + 6), 0);
726
727 for (cc = bc; cc <= ec; ++cc)
728 {
729 width_index[cc] = (byte)xgetc(tfm_file);
730
731 (void)xgetc(tfm_file);
732 (void)xgetc(tfm_file);
733 (void)xgetc(tfm_file);
734 }
735
736 for (i = 0; i < nw; ++i)
737 tfm_widths[i] = getlong(tfm_file);
738
739 fclose(tfm_file);
740 }
741
742
743 /*
744 * Create pk file and write preamble.
745 */
746
747 void
PKopen(char * filename,char * ident,int resolution)748 PKopen(char *filename,
749 char *ident,
750 int resolution)
751 {
752 int ppp;
753 int i;
754
755
756 dpi = resolution;
757
758 if ((pk_file = fopen(filename, "wb")) == NULL)
759 {
760 perror(filename);
761 exit(1);
762 }
763
764 putc(PK_PRE, pk_file);
765 putc(PK_ID, pk_file);
766
767 i = strlen(ident);
768
769 putc(i, pk_file);
770 fwrite(ident, 1, i, pk_file);
771 putlong(design);
772 putlong(checksum);
773 ppp = dpi / 72.27 * 65536.0 + 0.5;
774 putlong(ppp); /* hppp */
775 putlong(ppp); /* vppp */
776 }
777
778
779 void
PKputglyph(int cc,int llx,int lly,int urx,int ury,int w,int h,byte * b)780 PKputglyph(int cc,
781 int llx, int lly, int urx, int ury,
782 int w, int h,
783 byte *b)
784 {
785 float char_width;
786
787 long dm;
788 long tfm_wid;
789
790
791 bitmap = b;
792 width = w;
793 height = h;
794
795 hoff = -llx;
796 voff = ury - 2; /* Don't ask me why `-2' */
797 /* Fred */
798
799 if (width != urx - llx || height != ury - lly)
800 oops("Dimensions do not match: (%d - %d) (%d - %d) <=> %d %d",
801 llx, lly, urx, ury, width, height);
802
803 bytes_wide = (width + 7) / 8;
804 bm_size = bytes_wide * height;
805 bitmap_end = bitmap + bm_size;
806
807 trim_bitmap();
808
809 if (height == 0 || !pk_rll_cvt())
810 pk_bm_cvt();
811
812 if (!width_index[cc])
813 return;
814
815 tfm_wid = tfm_widths[width_index[cc]];
816 char_width = tfm_wid / 1048576.0 * design / 1048576.0 * dpi / 72.27;
817 dm = (long)(char_width + 0.5) - (char_width < -0.5);
818
819 if (pk_len + 8 < 4 * 256 && tfm_wid < (1<<24) &&
820 dm >= 0 && dm < 256 && width < 256 && height < 256 &&
821 hoff >= -128 && hoff < 128 && voff >= -128 && voff < 128)
822 {
823 putc(flag | ((pk_len + 8) >> 8), pk_file);
824 putc(pk_len + 8, pk_file);
825 putc(cc, pk_file);
826 putmed(tfm_wid);
827 putc(dm, pk_file);
828 putc(width, pk_file);
829 putc(height, pk_file);
830 putc(hoff, pk_file);
831 putc(voff, pk_file);
832 }
833 else if (pk_len + 13 < 3 * 65536L && tfm_wid < (1<<24) &&
834 dm >= 0 && dm < 65536L && width < 65536L && height < 65536L &&
835 hoff >= -65536L && hoff < 65536L &&
836 voff >= -65536L && voff < 65536L)
837 {
838 putc(flag | 4 | ((pk_len + 13) >> 16), pk_file);
839 putshort(pk_len + 13);
840 putc(cc, pk_file);
841 putmed(tfm_wid);
842 putshort(dm);
843 putshort(width);
844 putshort(height);
845 putshort(hoff);
846 putshort(voff);
847 }
848 else
849 {
850 putc(flag | 7, pk_file);
851 putlong(pk_len + 28);
852 putlong(cc);
853 putlong(tfm_wid);
854 putlong((long)(char_width * 65536.0 + 0.5) - (char_width < -0.5));
855 putlong(0);
856 putlong(width);
857 putlong(height);
858 putlong(hoff);
859 putlong(voff);
860 }
861 fwrite(bitmap, 1, pk_len, pk_file);
862 }
863
864
865 void
PKclose(void)866 PKclose(void)
867 {
868 putc(PK_POST, pk_file);
869 while (ftell(pk_file) % 4 != 0)
870 putc(PK_NOP, pk_file);
871
872 fclose(pk_file);
873 }
874
875
876 /* end */
877