1% writet3.w
2%
3% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
4% Copyright 2006-2011 Taco Hoekwater <taco@@luatex.org>
5%
6% This file is part of LuaTeX.
7%
8% LuaTeX is free software; you can redistribute it and/or modify it under
9% the terms of the GNU General Public License as published by the Free
10% Software Foundation; either version 2 of the License, or (at your
11% option) any later version.
12%
13% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
14% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16% License for more details.
17%
18% You should have received a copy of the GNU General Public License along
19% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
20
21@ @c
22
23
24#include "ptexlib.h"
25#include <kpathsea/tex-glyph.h>
26#include <kpathsea/magstep.h>
27#include <string.h>
28
29#define T3_BUF_SIZE   1024
30
31typedef char t3_line_entry;
32define_array(t3_line);
33
34FILE *t3_file;
35static boolean t3_image_used;
36
37static int t3_char_procs[256];
38static float t3_char_widths[256];
39static int t3_glyph_num;
40static float t3_font_scale;
41static int t3_b0, t3_b1, t3_b2, t3_b3;
42static boolean is_pk_font;
43
44/* not static because used by pkin.c  */
45unsigned char *t3_buffer = NULL;
46int t3_size = 0;
47int t3_curbyte = 0;
48
49#define t3_check_eof()                                     \
50    if (t3_eof())                                          \
51        luatex_fail("unexpected end of file");
52
53@
54@c
55static void update_bbox(int llx, int lly, int urx, int ury,
56                        boolean is_first_glyph)
57{
58    if (is_first_glyph) {
59        t3_b0 = llx;
60        t3_b1 = lly;
61        t3_b2 = urx;
62        t3_b3 = ury;
63    } else {
64        if (llx < t3_b0)
65            t3_b0 = llx;
66        if (lly < t3_b1)
67            t3_b1 = lly;
68        if (urx > t3_b2)
69            t3_b2 = urx;
70        if (ury > t3_b3)
71            t3_b3 = ury;
72    }
73}
74
75static int get_pk_font_scale(internal_font_number f, int precision,
76                             int scale_factor)
77{
78    return
79        divide_scaled(scale_factor,
80                      divide_scaled(font_size(f), one_hundred_bp,
81                                    precision + 2), 0);
82}
83
84static int pk_char_width(internal_font_number f, scaled w, int precision,
85                         int scale_factor)
86{
87    return
88        divide_scaled(divide_scaled(w, font_size(f), 7),
89                      get_pk_font_scale(f, precision, scale_factor), 0);
90}
91
92@
93@c
94static boolean writepk(PDF pdf, internal_font_number f)
95{
96    kpse_glyph_file_type font_ret;
97    int llx, lly, urx, ury;
98    int cw, rw, i, j;
99    pdffloat pf;
100    halfword *row;
101    char *name;
102    char *ftemp = NULL;
103    chardesc cd;
104    boolean is_null_glyph, check_preamble;
105    int dpi;
106    int callback_id = 0;
107    int file_opened = 0;
108    unsigned mallocsize = 0;
109    xfree(t3_buffer);
110    t3_curbyte = 0;
111    t3_size = 0;
112
113    callback_id = callback_defined(find_pk_file_callback);
114
115    if (callback_id > 0) {
116        dpi = round((float) pdf->pk_resolution *
117                    (((float) font_size(f)) / (float) font_dsize(f)));
118        /* <base>.dpi/<fontname>.<tdpi>pk */
119        cur_file_name = font_name(f);
120        mallocsize = (unsigned) (strlen(cur_file_name) + 24 + 9);
121        name = xmalloc(mallocsize);
122        snprintf(name, (size_t) mallocsize, "%ddpi/%s.%dpk",
123                 (int) pdf->pk_resolution, cur_file_name, (int) dpi);
124        if (run_callback(callback_id, "S->S", name, &ftemp)) {
125            if (ftemp != NULL && strlen(ftemp)) {
126                free(name);
127                name = xstrdup(ftemp);
128                free(ftemp);
129            }
130        }
131    } else {
132        dpi = (int)
133            kpse_magstep_fix((unsigned) round
134                             ((float) pdf->pk_resolution *
135                              ((float) font_size(f) / (float) font_dsize(f))),
136                             (unsigned) pdf->pk_resolution, NULL);
137        cur_file_name = font_name(f);
138        name = kpse_find_pk(cur_file_name, (unsigned) dpi, &font_ret);
139        if (name == NULL ||
140            !FILESTRCASEEQ(cur_file_name, font_ret.name) ||
141            !kpse_bitmap_tolerance((float) font_ret.dpi, (float) dpi)) {
142            luatex_fail("Font %s at %i not found", cur_file_name, (int) dpi);
143        }
144    }
145    callback_id = callback_defined(read_pk_file_callback);
146    if (callback_id > 0) {
147        if (!
148            (run_callback
149             (callback_id, "S->bSd", name, &file_opened, &t3_buffer, &t3_size)
150             && file_opened && t3_size > 0)) {
151            luatex_warn("Font %s at %i not found", cur_file_name, (int) dpi);
152            cur_file_name = NULL;
153            return false;
154        }
155    } else {
156        t3_file = xfopen(name, FOPEN_RBIN_MODE);
157        recorder_record_input(name);
158        t3_read_file();
159        t3_close();
160    }
161    t3_image_used = true;
162    is_pk_font = true;
163    report_start_file(filetype_font,(char *) name);
164    cd.rastersize = 256;
165    cd.raster = xtalloc((unsigned long) cd.rastersize, halfword);
166    check_preamble = true;
167    while (readchar(check_preamble, &cd) != 0) {
168        check_preamble = false;
169        if (!pdf_char_marked(f, cd.charcode))
170            continue;
171        t3_char_widths[cd.charcode] = (float)
172            pk_char_width(f, get_charwidth(f, cd.charcode),
173                          pdf->decimal_digits, pdf->pk_scale_factor);
174        if (cd.cwidth < 1 || cd.cheight < 1) {
175            cd.xescape = cd.cwidth = round(t3_char_widths[cd.charcode] / 100.0);
176            cd.cheight = 1;
177            cd.xoff = 0;
178            cd.yoff = 0;
179            is_null_glyph = true;
180        } else
181            is_null_glyph = false;
182        llx = -cd.xoff;
183        lly = cd.yoff - cd.cheight + 1;
184        urx = cd.cwidth + llx + 1;
185        ury = cd.cheight + lly;
186        update_bbox(llx, lly, urx, ury, t3_glyph_num == 0);
187        t3_glyph_num++;
188        t3_char_procs[cd.charcode] = pdf_create_obj(pdf, obj_type_others, 0);
189        pdf_begin_obj(pdf, t3_char_procs[cd.charcode], OBJSTM_NEVER);
190        pdf_begin_dict(pdf);
191        pdf_dict_add_streaminfo(pdf);
192        pdf_end_dict(pdf);
193        pdf_begin_stream(pdf);
194        setpdffloat(pf, (int64_t) t3_char_widths[cd.charcode], 2);
195        print_pdffloat(pdf, pf);
196        pdf_printf(pdf, " 0 %i %i %i %i d1\n",
197                   (int) llx, (int) lly, (int) urx, (int) ury);
198        if (is_null_glyph)
199            goto end_stream;
200        pdf_printf(pdf, "q\n%i 0 0 %i %i %i cm\nBI\n", (int) cd.cwidth,
201                   (int) cd.cheight, (int) llx, (int) lly);
202        pdf_printf(pdf, "/W %i\n/H %i\n", (int) cd.cwidth, (int) cd.cheight);
203        pdf_puts(pdf, "/IM true\n/BPC 1\n/D [1 0]\nID ");
204        cw = (cd.cwidth + 7) / 8;
205        rw = (cd.cwidth + 15) / 16;
206        row = cd.raster;
207        for (i = 0; i < cd.cheight; i++) {
208            for (j = 0; j < rw - 1; j++) {
209                pdf_out(pdf, (unsigned char) (*row / 256));
210                pdf_out(pdf, (unsigned char) (*row % 256));
211                row++;
212            }
213            pdf_out(pdf, (unsigned char) (*row / 256));
214            if (2 * rw == cw)
215                pdf_out(pdf, (unsigned char) (*row % 256));
216            row++;
217        }
218        pdf_puts(pdf, "\nEI\nQ\n");
219      end_stream:
220        pdf_end_stream(pdf);
221        pdf_end_obj(pdf);
222    }
223    xfree(cd.raster);
224    cur_file_name = NULL;
225    return true;
226}
227
228@
229@c
230void writet3(PDF pdf, internal_font_number f)
231{
232    int i;
233    char s[32];
234    int wptr, eptr, cptr;
235    int first_char, last_char;
236    int pk_font_scale;
237    pdffloat pf;
238    boolean is_notdef;
239
240    t3_glyph_num = 0;
241    t3_image_used = false;
242    for (i = 0; i < 256; i++) {
243        t3_char_procs[i] = 0;
244        t3_char_widths[i] = 0;
245    }
246    is_pk_font = false;
247
248    xfree(t3_buffer);
249    t3_curbyte = 0;
250    t3_size = 0;
251    if (!writepk(pdf, f))
252        return;
253    for (i = font_bc(f); i <= font_ec(f); i++)
254        if (pdf_char_marked(f, i))
255            break;
256    first_char = i;
257    for (i = font_ec(f); i > first_char; i--)
258        if (pdf_char_marked(f, i))
259            break;
260    last_char = i;
261
262    /* Type 3 font dictionary */
263    pdf_begin_obj(pdf, pdf_font_num(f), OBJSTM_ALWAYS);
264    pdf_begin_dict(pdf);
265    pdf_dict_add_name(pdf, "Type", "Font");
266    pdf_dict_add_name(pdf, "Subtype", "Type3");
267    snprintf(s, 31, "F%i", (int) f);
268    pdf_dict_add_name(pdf, "Name", s);
269    if (pdf_font_attr(f) != get_nullstr() && pdf_font_attr(f) != 0) {
270        pdf_out(pdf, '\n');
271        pdf_print(pdf, pdf_font_attr(f));
272        pdf_out(pdf, '\n');
273    }
274    if (is_pk_font) {
275        pk_font_scale =
276            get_pk_font_scale(f, pdf->decimal_digits, pdf->pk_scale_factor);
277        pdf_add_name(pdf, "FontMatrix");
278        pdf_begin_array(pdf);
279        setpdffloat(pf, (int64_t) pk_font_scale, 5);
280        print_pdffloat(pdf, pf);
281        pdf_puts(pdf, " 0 0 ");
282        print_pdffloat(pdf, pf);
283        pdf_puts(pdf, " 0 0");
284        pdf_end_array(pdf);
285    } else {
286        pdf_add_name(pdf, "FontMatrix");
287        pdf_begin_array(pdf);
288        pdf_printf(pdf, "%g 0 0 %g 0 0",
289                   (double) t3_font_scale, (double) t3_font_scale);
290        pdf_end_array(pdf);
291    }
292    pdf_add_name(pdf, font_key[FONTBBOX1_CODE].pdfname);
293    pdf_begin_array(pdf);
294    pdf_add_int(pdf, (int) t3_b0);
295    pdf_add_int(pdf, (int) t3_b1);
296    pdf_add_int(pdf, (int) t3_b2);
297    pdf_add_int(pdf, (int) t3_b3);
298    pdf_end_array(pdf);
299    pdf_add_name(pdf, "Resources");
300    pdf_begin_dict(pdf);
301    pdf_add_name(pdf, "ProcSet");
302    pdf_begin_array(pdf);
303    pdf_add_name(pdf, "PDF");
304    if (t3_image_used)
305        pdf_add_name(pdf, "ImageB");
306    pdf_end_array(pdf);
307    pdf_end_dict(pdf);
308    pdf_dict_add_int(pdf, "FirstChar", first_char);
309    pdf_dict_add_int(pdf, "LastChar", last_char);
310    wptr = pdf_create_obj(pdf, obj_type_others, 0);
311    eptr = pdf_create_obj(pdf, obj_type_others, 0);
312    cptr = pdf_create_obj(pdf, obj_type_others, 0);
313    pdf_dict_add_ref(pdf, "Widths", (int) wptr);
314    pdf_dict_add_ref(pdf, "Encoding", (int) eptr);
315    pdf_dict_add_ref(pdf, "CharProcs", (int) cptr);
316    pdf_end_dict(pdf);
317    pdf_end_obj(pdf);
318
319    /* chars width array */
320    pdf_begin_obj(pdf, wptr, OBJSTM_ALWAYS);
321    pdf_begin_array(pdf);
322    if (is_pk_font)
323        for (i = first_char; i <= last_char; i++) {
324            setpdffloat(pf, (int64_t) t3_char_widths[i], 2);
325            print_pdffloat(pdf, pf);
326            pdf_out(pdf, ' ');
327    } else
328        for (i = first_char; i <= last_char; i++)
329            pdf_add_int(pdf, (int) t3_char_widths[i]);
330    pdf_end_array(pdf);
331    pdf_end_obj(pdf);
332
333    /* encoding dictionary */
334    pdf_begin_obj(pdf, eptr, OBJSTM_ALWAYS);
335    pdf_begin_dict(pdf);
336    pdf_dict_add_name(pdf, "Type", "Encoding");
337    pdf_add_name(pdf, "Differences");
338    pdf_begin_array(pdf);
339    pdf_add_int(pdf, first_char);
340    if (t3_char_procs[first_char] == 0) {
341        pdf_add_name(pdf, notdef);
342        is_notdef = true;
343    } else {
344        snprintf(s, 31, "a%i", first_char);
345        pdf_add_name(pdf, s);
346        is_notdef = false;
347    }
348    for (i = first_char + 1; i <= last_char; i++) {
349        if (t3_char_procs[i] == 0) {
350            if (!is_notdef) {
351                pdf_add_int(pdf, i);
352                pdf_add_name(pdf, notdef);
353                is_notdef = true;
354            }
355        } else {
356            if (is_notdef) {
357                pdf_add_int(pdf, i);
358                is_notdef = false;
359            }
360            snprintf(s, 31, "a%i", i);
361            pdf_add_name(pdf, s);
362        }
363    }
364    pdf_end_array(pdf);
365    pdf_end_dict(pdf);
366    pdf_end_obj(pdf);
367
368    /* CharProcs dictionary */
369    pdf_begin_obj(pdf, cptr, OBJSTM_ALWAYS);
370    pdf_begin_dict(pdf);
371    for (i = first_char; i <= last_char; i++)
372        if (t3_char_procs[i] != 0) {
373            snprintf(s, 31, "a%i", (int) i);
374            pdf_dict_add_ref(pdf, s, (int) t3_char_procs[i]);
375        }
376    pdf_end_dict(pdf);
377    pdf_end_obj(pdf);
378    report_stop_file(filetype_font);
379    cur_file_name = NULL;
380}
381