3 This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5 Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6 the dvipdfmx project team.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 * PostScript Language Reference Manual, 3rd. ed. (Adobe Systems Inc.)
27 * 5.11.4 CMap Dictionaries
28 * 5.11.5 FMapType 9 Composite Fonts
29 * Building CMap Files for CID-Keyed Fonts, Adobe Technical Note #5099
30 * CID-Keyed Font Technology Overview, Adobe Technical Note #5092
31 * Adobe CMap and CIDFont Files Specification, Adobe Technical Specification #5014
33 * Undefined Character Handling:
34 * PLRM 3rd. ed., sec. 5.11.5., "Handling Undefined Characters"
50 #include "pdfresource.h"
55 #include "cmap_write.h"
63 static int write_map (mapDef *mtab, int count,
64 unsigned char *codestr, int depth,
65 struct sbuf *wbuf, pdf_obj *stream);
67 /* Not completed yet */
70 * This is for collecting only used CIDs.
71 * add_inverse_map never supports code-to-code of
72 * cid-to-code mapping.
74 static int add_inverse_map (CMap *icmap, mapDef *mtab,
75 unsigned char *codestr, int depth,
76 unsigned char *used_slot);
77 static int add_map (CMap *cmap, mapDef *mtab,
78 unsigned char *codestr, int depth);
79 static CMap *invert_cmap (CMap *cmap, unsigned char *used_slot);
80 static CMap *flatten_cmap (CMap *cmap);
84 block_count (mapDef *mtab, int c)
90 for (; c < 256; c++) {
91 if (LOOKUP_CONTINUE(mtab[c].flag) ||
92 !MAP_DEFINED(mtab[c].flag) ||
93 (MAP_TYPE(mtab[c].flag) != MAP_IS_CID &&
94 MAP_TYPE(mtab[c].flag) != MAP_IS_CODE) ||
95 mtab[c-1].len != mtab[c].len)
97 else if (!memcmp(mtab[c-1].code, mtab[c].code, n) &&
98 mtab[c-1].code[n] < 255 &&
99 mtab[c-1].code[n] + 1 == mtab[c].code[n])
110 write_map (mapDef *mtab, int count,
111 unsigned char *codestr, int depth,
112 struct sbuf *wbuf, pdf_obj *stream)
114 int c, i, block_length;
116 /* Must be greater than 1 */
117 #define BLOCK_LEN_MIN 2
120 } blocks[256/BLOCK_LEN_MIN+1];
123 for (c = 0; c < 256; c++) {
124 codestr[depth] = (unsigned char) (c & 0xff);
125 if (LOOKUP_CONTINUE(mtab[c].flag)) {
126 mtab1 = mtab[c].next;
127 count = write_map(mtab1, count,
128 codestr, depth + 1, wbuf, stream);
130 if (MAP_DEFINED(mtab[c].flag)) {
131 switch (MAP_TYPE(mtab[c].flag)) {
132 case MAP_IS_CID: case MAP_IS_CODE:
133 block_length = block_count(mtab, c);
134 if (block_length >= BLOCK_LEN_MIN) {
135 blocks[num_blocks].start = c;
136 blocks[num_blocks].count = block_length;
140 *(wbuf->curptr)++ = '<';
141 for (i = 0; i <= depth; i++)
142 sputx(codestr[i], &(wbuf->curptr), wbuf->limptr);
143 *(wbuf->curptr)++ = '>';
144 *(wbuf->curptr)++ = ' ';
145 *(wbuf->curptr)++ = '<';
146 for (i = 0; i < mtab[c].len; i++)
147 sputx(mtab[c].code[i], &(wbuf->curptr), wbuf->limptr);
148 *(wbuf->curptr)++ = '>';
149 *(wbuf->curptr)++ = '\n';
154 ERROR("%s: Unexpected error...", CMAP_DEBUG_STR);
159 ERROR("%s: Unknown mapping type: %d",
160 CMAP_DEBUG_STR, MAP_TYPE(mtab[c].flag));
165 /* Flush if necessary */
167 wbuf->curptr >= wbuf->limptr ) {
170 ERROR("Unexpected error....: %d", count);
171 sprintf(fmt_buf, "%d beginbfchar\n", count);
172 pdf_add_stream(stream, fmt_buf, strlen(fmt_buf));
173 pdf_add_stream(stream,
174 wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
175 wbuf->curptr = wbuf->buf;
176 pdf_add_stream(stream,
177 "endbfchar\n", strlen("endbfchar\n"));
182 if (num_blocks > 0) {
186 sprintf(fmt_buf, "%d beginbfchar\n", count);
187 pdf_add_stream(stream, fmt_buf, strlen(fmt_buf));
188 pdf_add_stream(stream,
189 wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
190 wbuf->curptr = wbuf->buf;
191 pdf_add_stream(stream,
192 "endbfchar\n", strlen("endbfchar\n"));
195 sprintf(fmt_buf, "%d beginbfrange\n", num_blocks);
196 pdf_add_stream(stream, fmt_buf, strlen(fmt_buf));
197 for (i = 0; i < num_blocks; i++) {
201 *(wbuf->curptr)++ = '<';
202 for (j = 0; j < depth; j++)
203 sputx(codestr[j], &(wbuf->curptr), wbuf->limptr);
204 sputx((unsigned char)c, &(wbuf->curptr), wbuf->limptr);
205 *(wbuf->curptr)++ = '>';
206 *(wbuf->curptr)++ = ' ';
207 *(wbuf->curptr)++ = '<';
208 for (j = 0; j < depth; j++)
209 sputx(codestr[j], &(wbuf->curptr), wbuf->limptr);
210 sputx((unsigned char)(c + blocks[i].count), &(wbuf->curptr), wbuf->limptr);
211 *(wbuf->curptr)++ = '>';
212 *(wbuf->curptr)++ = ' ';
213 *(wbuf->curptr)++ = '<';
214 for (j = 0; j < mtab[c].len; j++)
215 sputx(mtab[c].code[j], &(wbuf->curptr), wbuf->limptr);
216 *(wbuf->curptr)++ = '>';
217 *(wbuf->curptr)++ = '\n';
219 pdf_add_stream(stream,
220 wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
221 wbuf->curptr = wbuf->buf;
222 pdf_add_stream(stream,
223 "endbfrange\n", strlen("endbfrange\n"));
229 #define CMAP_BEGIN "\
230 /CIDInit /ProcSet findresource begin\n\
237 CMapName currentdict /CMap defineresource pop\n\
243 CMap_create_stream (CMap *cmap, int flags) /* flags unused */
246 pdf_obj *stream_dict;
249 struct rangeDef *ranges;
250 unsigned char *codestr;
253 if (!cmap || !CMap_is_valid(cmap)) {
254 WARN("Invalid CMap");
258 if (cmap->type == CMAP_TYPE_IDENTITY)
261 stream = pdf_new_stream(STREAM_COMPRESS);
262 stream_dict = pdf_stream_dict(stream);
264 csi = CMap_get_CIDSysInfo(cmap);
266 csi = (cmap->type != CMAP_TYPE_TO_UNICODE) ?
267 &CSI_IDENTITY : &CSI_UNICODE;
270 if (cmap->type != CMAP_TYPE_TO_UNICODE) {
273 csi_dict = pdf_new_dict();
274 pdf_add_dict(csi_dict,
275 pdf_new_name("Registry"),
276 pdf_new_string(csi->registry, strlen(csi->registry)));
277 pdf_add_dict(csi_dict,
278 pdf_new_name("Ordering"),
279 pdf_new_string(csi->ordering, strlen(csi->ordering)));
280 pdf_add_dict(csi_dict,
281 pdf_new_name("Supplement"),
282 pdf_new_number(csi->supplement));
284 pdf_add_dict(stream_dict,
285 pdf_new_name("Type"),
286 pdf_new_name("CMap"));
287 pdf_add_dict(stream_dict,
288 pdf_new_name("CMapName"),
289 pdf_new_name(cmap->name));
290 pdf_add_dict(stream_dict,
291 pdf_new_name("CIDSystemInfo"), csi_dict);
292 if (cmap->wmode != 0)
293 pdf_add_dict(stream_dict,
294 pdf_new_name("WMode"),
295 pdf_new_number(cmap->wmode));
299 * Predefined CMaps need not to be embedded.
302 ERROR("UseCMap found (not supported yet)...");
303 if (CMap_is_Identity(cmap->useCMap)) { /* not sure */
304 if (CMap_get_wmode(cmap) == 1) {
305 pdf_add_dict(stream_dict,
306 pdf_new_name("UseCMap"),
307 pdf_new_name("Identity-V"));
309 pdf_add_dict(stream_dict,
310 pdf_new_name("UseCMap"),
311 pdf_new_name("Identity-H"));
317 res_id = pdf_findresource("CMap", CMap_get_name(cmap->useCMap));
319 ucmap_ref = pdf_get_resource_reference(res_id);
323 ucmap_obj = CMap_create_stream(cmap->useCMap, 0);
325 ERROR("Uh ah. I cannot continue...");
328 res_id = pdf_defineresource("CMap",
329 CMap_get_name(cmap->useCMap),
330 ucmap_obj, PDF_RES_FLUSH_IMMEDIATE);
331 ucmap_ref = pdf_get_resource_reference(res_id);
333 pdf_add_dict(stream_dict, pdf_new_name("UseCMap"), ucmap_ref);
337 #define WBUF_SIZE 4096
338 wbuf.buf = NEW(WBUF_SIZE, char);
339 codestr = NEW(cmap->profile.maxBytesIn, unsigned char);
340 memset(codestr, 0, cmap->profile.maxBytesIn);
342 wbuf.curptr = wbuf.buf;
343 wbuf.limptr = wbuf.buf + WBUF_SIZE -
344 2 * (cmap->profile.maxBytesIn + cmap->profile.maxBytesOut) + 16;
347 pdf_add_stream(stream, (const void *) CMAP_BEGIN, strlen(CMAP_BEGIN));
349 wbuf.curptr += sprintf(wbuf.curptr, "/CMapName /%s def\n", cmap->name);
350 wbuf.curptr += sprintf(wbuf.curptr, "/CMapType %d def\n" , cmap->type);
351 if (cmap->wmode != 0 &&
352 cmap->type != CMAP_TYPE_TO_UNICODE)
353 wbuf.curptr += sprintf(wbuf.curptr, "/WMode %d def\n", cmap->wmode);
355 #define CMAP_CSI_FMT "/CIDSystemInfo <<\n\
360 wbuf.curptr += sprintf(wbuf.curptr, CMAP_CSI_FMT,
361 csi->registry, csi->ordering, csi->supplement);
362 pdf_add_stream(stream, wbuf.buf, (long)(wbuf.curptr - wbuf.buf));
363 wbuf.curptr = wbuf.buf;
366 ranges = cmap->codespace.ranges;
367 wbuf.curptr += sprintf(wbuf.curptr,
368 "%d begincodespacerange\n", cmap->codespace.num);
369 for (i = 0; i < cmap->codespace.num; i++) {
370 *(wbuf.curptr)++ = '<';
371 for (j = 0; j < ranges[i].dim; j++) {
372 sputx(ranges[i].codeLo[j], &(wbuf.curptr), wbuf.limptr);
374 *(wbuf.curptr)++ = '>';
375 *(wbuf.curptr)++ = ' ';
376 *(wbuf.curptr)++ = '<';
377 for (j = 0; j < ranges[i].dim; j++) {
378 sputx(ranges[i].codeHi[j], &(wbuf.curptr), wbuf.limptr);
380 *(wbuf.curptr)++ = '>';
381 *(wbuf.curptr)++ = '\n';
383 pdf_add_stream(stream, wbuf.buf, (long)(wbuf.curptr - wbuf.buf));
384 wbuf.curptr = wbuf.buf;
385 pdf_add_stream(stream,
386 "endcodespacerange\n", strlen("endcodespacerange\n"));
390 count = write_map(cmap->mapTbl,
391 0, codestr, 0, &wbuf, stream); /* Top node */
392 if (count > 0) { /* Flush */
395 ERROR("Unexpected error....: %d", count);
396 sprintf(fmt_buf, "%d beginbfchar\n", count);
397 pdf_add_stream(stream, fmt_buf, strlen(fmt_buf));
398 pdf_add_stream(stream,
399 wbuf.buf, (long) (wbuf.curptr - wbuf.buf));
400 pdf_add_stream(stream,
401 "endbfchar\n", strlen("endbfchar\n"));
403 wbuf.curptr = wbuf.buf;
407 pdf_add_stream(stream, CMAP_END, strlen(CMAP_END));
416 /* Not completed yet */
419 add_inverse_map (CMap *icmap, mapDef *mtab,
420 unsigned char *codestr, int depth,
421 unsigned char *used_slot)
427 for (c = 0; c < 256; c++) {
428 codestr[depth] = (unsigned char) (c & 0xff);
429 if (LOOKUP_CONTINUE(mtab[c].flag)) {
430 mtab1 = mtab[c].next;
431 add_inverse_map(icmap, mtab1, codestr, depth + 1, used_slot);
433 if (MAP_DEFINED(mtab[c].flag)) {
434 switch (MAP_TYPE(mtab[c].flag)) {
435 /* We should restrict it to to-CID mapping.
438 case MAP_IS_CID: case MAP_IS_CODE:
439 if (mtab[c].len == 2) {
440 cid = (mtab[c].code[0] << 8)|mtab[c].code[1];
441 #ifndef is_used_char2
442 #define is_used_char2(b,c) (((b)[(c)/8]) & (1 << (7-((c)%8))))
445 is_used_char2(used_slot, cid)) {
446 CMap_add_bfchar(icmap,
447 mtab[c].code, mtab[c].len,
453 ERROR("%s: Unexpected error...", CMAP_DEBUG_STR);
458 ERROR("%s: Unknown mapping type: %d",
459 CMAP_DEBUG_STR, MAP_TYPE(mtab[c].flag));
469 add_map (CMap *cmap, mapDef *mtab,
470 unsigned char *codestr, int depth)
475 for (c = 0; c < 256; c++) {
476 codestr[depth] = (unsigned char) (c & 0xff);
477 if (LOOKUP_CONTINUE(mtab[c].flag)) {
478 mtab1 = mtab[c].next;
479 add_map(cmap, mtab1, codestr, depth + 1);
481 if (MAP_DEFINED(mtab[c].flag)) {
482 switch (MAP_TYPE(mtab[c].flag)) {
483 case MAP_IS_CID: case MAP_IS_CODE:
484 CMap_add_bfchar(cmap,
486 mtab[c].code, mtab[c].len);
489 ERROR("%s: Unexpected error...", CMAP_DEBUG_STR);
494 ERROR("%s: Unknown mapping type: %d",
495 CMAP_DEBUG_STR, MAP_TYPE(mtab[c].flag));
506 invert_cmap (CMap *cmap, unsigned char *used_slot)
509 unsigned char *codestr;
510 unsigned char range_min[2] = {0x00, 0x00}; /* CID */
511 unsigned char range_max[2] = {0xff, 0xfe}; /* CID */
513 cmap = flatten_cmap(cmap);
517 CMap_set_type(icmap, CMAP_TYPE_CID_TO_CODE);
518 CMap_add_codespacerange(icmap, range_min, range_max, 2);
521 codestr = NEW(cmap->profile.maxBytesIn, unsigned char);
522 memset(codestr, 0, cmap->profile.maxBytesIn);
523 add_inverse_map(icmap, cmap->mapTbl,
524 codestr, 0, used_slot); /* top node */
534 flatten_cmap (CMap *cmap)
544 for (i = 0; i < cmap->codespace.num; i++) {
545 range = &(cmap->codespace.ranges[i]);
546 CMap_add_codespacerange(fcmap, range->codeLo, range->codeHi, range->dim);
548 CMap_set_CIDSysInfo(fcmap, cmap->CSI);
549 CMap_set_type (fcmap, cmap->type );
550 CMap_set_wmode(fcmap, cmap->wmode);
552 fcmap->flags = cmap->flags;
553 fcmap->version = cmap->version;
557 unsigned char *codestr;
559 codestr = NEW(cmap->profile.maxBytesIn, unsigned char);
560 memset(codestr, 0, cmap->profile.maxBytesIn);
561 add_map(fcmap, cmap->mapTbl, codestr, 0); /* top node */
564 cmap = cmap->useCMap;
571 CMap_ToCode_stream (CMap *cmap, const char *cmap_name,
572 CIDSysInfo *csi, int cmap_type,
573 unsigned char *used_slot, int flags)
575 pdf_obj *stream = NULL;
578 ASSERT(cmap && cmap_name);
581 CMAP_TYPE_CODE_TO_CID)
584 icmap = invert_cmap(cmap, used_slot);
586 CMap_set_name(icmap, cmap_name);
588 CMap_set_CIDSysInfo(icmap, csi);
590 CMap_set_CIDSysInfo(icmap, &(CSI_IDENTITY));
592 CMap_set_type(icmap, cmap_type);
594 stream = CMap_create_stream(icmap, flags);