static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; int n = src->w * src->h; while (n--) { #ifdef SLOWCMYK float cmyk[4], rgb[3]; cmyk[0] = s[0] / 255.0f; cmyk[1] = s[1] / 255.0f; cmyk[2] = s[2] / 255.0f; cmyk[3] = s[3] / 255.0f; cmyk_to_rgb(ctx, NULL, cmyk, rgb); d[0] = rgb[2] * 255; d[1] = rgb[1] * 255; d[2] = rgb[0] * 255; #else d[0] = 255 - (unsigned char)fz_mini(s[2] + s[3], 255); d[1] = 255 - (unsigned char)fz_mini(s[1] + s[3], 255); d[2] = 255 - (unsigned char)fz_mini(s[0] + s[3], 255); #endif d[3] = s[4]; s += 5; d += 4; } }
static void shrinkwrap(void) { int w = fz_mini(page_tex.w + canvas_x, screen_w - SCREEN_FURNITURE_W); int h = fz_mini(page_tex.h + canvas_y, screen_h - SCREEN_FURNITURE_H); if (isfullscreen) toggle_fullscreen(); glfwSetWindowSize(window, w, h); }
static void xps_draw_linear_gradient(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area, struct stop *stops, int count, fz_xml *root, int spread) { float x0, y0, x1, y1; int i, mi, ma; float dx, dy, x, y, k; fz_point p1, p2; fz_matrix inv; fz_rect local_area = *area; char *start_point_att = fz_xml_att(root, "StartPoint"); char *end_point_att = fz_xml_att(root, "EndPoint"); x0 = y0 = 0; x1 = y1 = 1; if (start_point_att) xps_parse_point(ctx, doc, start_point_att, &x0, &y0); if (end_point_att) xps_parse_point(ctx, doc, end_point_att, &x1, &y1); p1.x = x0; p1.y = y0; p2.x = x1; p2.y = y1; fz_transform_rect(&local_area, fz_invert_matrix(&inv, ctm)); x = p2.x - p1.x; y = p2.y - p1.y; k = ((local_area.x0 - p1.x) * x + (local_area.y0 - p1.y) * y) / (x * x + y * y); mi = floorf(k); ma = ceilf(k); k = ((local_area.x1 - p1.x) * x + (local_area.y0 - p1.y) * y) / (x * x + y * y); mi = fz_mini(mi, floorf(k)); ma = fz_maxi(ma, ceilf(k)); k = ((local_area.x0 - p1.x) * x + (local_area.y1 - p1.y) * y) / (x * x + y * y); mi = fz_mini(mi, floorf(k)); ma = fz_maxi(ma, ceilf(k)); k = ((local_area.x1 - p1.x) * x + (local_area.y1 - p1.y) * y) / (x * x + y * y); mi = fz_mini(mi, floorf(k)); ma = fz_maxi(ma, ceilf(k)); dx = x1 - x0; dy = y1 - y0; if (spread == SPREAD_REPEAT) { for (i = mi; i < ma; i++) xps_draw_one_linear_gradient(ctx, doc, ctm, stops, count, 0, x0 + i * dx, y0 + i * dy, x1 + i * dx, y1 + i * dy); } else if (spread == SPREAD_REFLECT) { if ((mi % 2) != 0) mi--; for (i = mi; i < ma; i += 2) { xps_draw_one_linear_gradient(ctx, doc, ctm, stops, count, 0, x0 + i * dx, y0 + i * dy, x1 + i * dx, y1 + i * dy); xps_draw_one_linear_gradient(ctx, doc, ctm, stops, count, 0, x0 + (i + 2) * dx, y0 + (i + 2) * dy, x1 + i * dx, y1 + i * dy); } } else { xps_draw_one_linear_gradient(ctx, doc, ctm, stops, count, 1, x0, y0, x1, y1); } }
fz_bbox fz_union_bbox(fz_bbox a, fz_bbox b) { fz_bbox r; /* Check for empty box before infinite box */ if (fz_is_empty_rect(a)) return b; if (fz_is_empty_rect(b)) return a; if (fz_is_infinite_rect(a)) return a; if (fz_is_infinite_rect(b)) return b; r.x0 = fz_mini(a.x0, b.x0); r.y0 = fz_mini(a.y0, b.y0); r.x1 = fz_maxi(a.x1, b.x1); r.y1 = fz_maxi(a.y1, b.y1); return r; }
fz_bbox fz_intersect_bbox(fz_bbox a, fz_bbox b) { fz_bbox r; /* Check for empty box before infinite box */ if (fz_is_empty_rect(a)) return fz_empty_bbox; if (fz_is_empty_rect(b)) return fz_empty_bbox; if (fz_is_infinite_rect(a)) return b; if (fz_is_infinite_rect(b)) return a; r.x0 = fz_maxi(a.x0, b.x0); r.y0 = fz_maxi(a.y0, b.y0); r.x1 = fz_mini(a.x1, b.x1); r.y1 = fz_mini(a.y1, b.y1); return (r.x1 < r.x0 || r.y1 < r.y0) ? fz_empty_bbox : r; }
static inline void jxr_unpack_sample(fz_context *ctx, struct info *info, jxr_image_t image, int *sp, unsigned char *dp) { int k, bpc, comps, alpha; float v; if (info->format == JXRC_FMT_32bppRGBE) { dp[0] = sRGB_from_scRGB(ldexpf(sp[0], sp[3] - 128 - 8)) * 255 + 0.5f; dp[1] = sRGB_from_scRGB(ldexpf(sp[1], sp[3] - 128 - 8)) * 255 + 0.5f; dp[2] = sRGB_from_scRGB(ldexpf(sp[2], sp[3] - 128 - 8)) * 255 + 0.5f; return; } if (info->format == JXRC_FMT_16bppBGR565) { dp[0] = sp[0] << 3; dp[1] = sp[1] << 2; dp[2] = sp[2] << 3; return; } comps = fz_mini(fz_colorspace_n(ctx, info->cspace), jxr_get_IMAGE_CHANNELS(image)); alpha = jxr_get_ALPHACHANNEL_FLAG(image); bpc = jxr_get_CONTAINER_BPC(image); for (k = 0; k < comps + alpha; k++) { switch (bpc) { default: fz_throw(ctx, FZ_ERROR_GENERIC, "unknown sample type: %d", bpc); case JXR_BD1WHITE1: dp[k] = sp[k] ? 255 : 0; break; case JXR_BD1BLACK1: dp[k] = sp[k] ? 0 : 255; break; case JXR_BD5: dp[k] = sp[k] << 3; break; case JXR_BD8: dp[k] = sp[k]; break; case JXR_BD10: dp[k] = sp[k] >> 2; break; case JXR_BD16: dp[k] = sp[k] >> 8; break; case JXR_BD16S: v = sp[k] * (1.0f / (1 << 13)); goto decode_float32; case JXR_BD32S: v = sp[k] * (1.0f / (1 << 24)); goto decode_float32; case JXR_BD16F: v = float32_from_float16(sp[k]); goto decode_float32; case JXR_BD32F: v = float32_from_int32_bits(sp[k]); goto decode_float32; decode_float32: if (k < comps) dp[k] = sRGB_from_scRGB(fz_clamp(v, 0, 1)) * 255 + 0.5f; else dp[k] = fz_clamp(v, 0, 1) * 255 + 0.5f; break; } } }
static const unsigned char * bmp_read_color_table(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end) { int i, colors, readcolors; if (info->bitcount > 8) return p; if (info->colors == 0) colors = 1 << info->bitcount; else colors = info->colors; colors = fz_mini(colors, 1 << info->bitcount); if (info->palettetype == 0) { readcolors = fz_mini(colors, (end - p) / 3); for (i = 0; i < readcolors; i++) { info->palette[3 * i + 0] = read8(p + i * 3 + 2); info->palette[3 * i + 1] = read8(p + i * 3 + 1); info->palette[3 * i + 2] = read8(p + i * 3 + 0); } if (readcolors < colors) bmp_load_default_palette(ctx, info, readcolors); return p + readcolors * 3; } else { readcolors = fz_mini(colors, (end - p) / 4); for (i = 0; i < readcolors; i++) { /* ignore alpha channel */ info->palette[3 * i + 0] = read8(p + i * 4 + 2); info->palette[3 * i + 1] = read8(p + i * 4 + 1); info->palette[3 * i + 2] = read8(p + i * 4 + 0); } if (readcolors < colors) bmp_load_default_palette(ctx, info, readcolors); return p + readcolors * 4; } return p; }
static void fast_bgr_to_cmyk(fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; int n = src->w * src->h; while (n--) { unsigned char c = 255 - s[2]; unsigned char m = 255 - s[1]; unsigned char y = 255 - s[0]; unsigned char k = (unsigned char)fz_mini(c, fz_mini(m, y)); d[0] = c - k; d[1] = m - k; d[2] = y - k; d[3] = k; d[4] = s[3]; s += 4; d += 5; } }
static int read_null(fz_stream *stm, unsigned char *buf, int len) { struct null_filter *state = stm->state; int amount = fz_mini(len, state->remain); int n; fz_seek(state->chain, state->pos, 0); n = fz_read(state->chain, buf, amount); state->remain -= n; state->pos += n; return n; }
static void fast_cmyk_to_gray(fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; int n = src->w * src->h; while (n--) { unsigned char c = fz_mul255(s[0], 77); unsigned char m = fz_mul255(s[1], 150); unsigned char y = fz_mul255(s[2], 28); d[0] = 255 - (unsigned char)fz_mini(c + m + y + s[3], 255); d[1] = s[4]; s += 5; d += 2; } }
fz_pixmap * pdf_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src) { struct indexed *idx; fz_pixmap *dst; unsigned char *s, *d; int y, x, k, n, high; unsigned char *lookup; fz_irect bbox; assert(src->colorspace->to_rgb == indexed_to_rgb); assert(src->n == 2); idx = src->colorspace->data; high = idx->high; lookup = idx->lookup; n = idx->base->n; dst = fz_new_pixmap_with_bbox(ctx, idx->base, fz_pixmap_bbox(ctx, src, &bbox)); s = src->samples; d = dst->samples; for (y = 0; y < src->h; y++) { for (x = 0; x < src->w; x++) { int v = *s++; int a = *s++; v = fz_mini(v, high); for (k = 0; k < n; k++) *d++ = fz_mul255(lookup[v * n + k], a); *d++ = a; } } dst->interpolate = src->interpolate; return dst; }
static pdf_font_desc * load_cid_font(pdf_document *xref, pdf_obj *dict, pdf_obj *encoding, pdf_obj *to_unicode) { pdf_obj *widths; pdf_obj *descriptor; pdf_font_desc *fontdesc = NULL; FT_Face face; int kind; char collection[256]; char *basefont; int i, k, fterr; pdf_obj *obj; int dw; fz_context *ctx = xref->ctx; fz_var(fontdesc); fz_try(ctx) { /* Get font name and CID collection */ basefont = pdf_to_name(pdf_dict_gets(dict, "BaseFont")); { pdf_obj *cidinfo; char tmpstr[64]; int tmplen; cidinfo = pdf_dict_gets(dict, "CIDSystemInfo"); if (!cidinfo) fz_throw(ctx, "cid font is missing info"); obj = pdf_dict_gets(cidinfo, "Registry"); tmplen = fz_mini(sizeof tmpstr - 1, pdf_to_str_len(obj)); memcpy(tmpstr, pdf_to_str_buf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcpy(collection, tmpstr, sizeof collection); fz_strlcat(collection, "-", sizeof collection); obj = pdf_dict_gets(cidinfo, "Ordering"); tmplen = fz_mini(sizeof tmpstr - 1, pdf_to_str_len(obj)); memcpy(tmpstr, pdf_to_str_buf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcat(collection, tmpstr, sizeof collection); } /* Load font file */ fontdesc = pdf_new_font_desc(ctx); descriptor = pdf_dict_gets(dict, "FontDescriptor"); if (!descriptor) fz_throw(ctx, "syntaxerror: missing font descriptor"); pdf_load_font_descriptor(fontdesc, xref, descriptor, collection, basefont); face = fontdesc->font->ft_face; kind = ft_kind(face); /* Encoding */ if (pdf_is_name(encoding)) { if (!strcmp(pdf_to_name(encoding), "Identity-H")) fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 2); else if (!strcmp(pdf_to_name(encoding), "Identity-V")) fontdesc->encoding = pdf_new_identity_cmap(ctx, 1, 2); else fontdesc->encoding = pdf_load_system_cmap(ctx, pdf_to_name(encoding)); } else if (pdf_is_indirect(encoding)) { fontdesc->encoding = pdf_load_embedded_cmap(xref, encoding); } else { fz_throw(ctx, "syntaxerror: font missing encoding"); } fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); pdf_set_font_wmode(ctx, fontdesc, pdf_cmap_wmode(ctx, fontdesc->encoding)); if (kind == TRUETYPE) { pdf_obj *cidtogidmap; cidtogidmap = pdf_dict_gets(dict, "CIDToGIDMap"); if (pdf_is_indirect(cidtogidmap)) { fz_buffer *buf; buf = pdf_load_stream(xref, pdf_to_num(cidtogidmap), pdf_to_gen(cidtogidmap)); fontdesc->cid_to_gid_len = (buf->len) / 2; fontdesc->cid_to_gid = fz_malloc_array(ctx, fontdesc->cid_to_gid_len, sizeof(unsigned short)); fontdesc->size += fontdesc->cid_to_gid_len * sizeof(unsigned short); for (i = 0; i < fontdesc->cid_to_gid_len; i++) fontdesc->cid_to_gid[i] = (buf->data[i * 2] << 8) + buf->data[i * 2 + 1]; fz_drop_buffer(ctx, buf); } /* if truetype font is external, cidtogidmap should not be identity */ /* so we map from cid to unicode and then map that through the (3 1) */ /* unicode cmap to get a glyph id */ else if (fontdesc->font->ft_substitute) { fterr = FT_Select_Charmap(face, ft_encoding_unicode); if (fterr) { fz_throw(ctx, "fonterror: no unicode cmap when emulating CID font: %s", ft_error_string(fterr)); } if (!strcmp(collection, "Adobe-CNS1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-CNS1-UCS2"); else if (!strcmp(collection, "Adobe-GB1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-GB1-UCS2"); else if (!strcmp(collection, "Adobe-Japan1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-Japan1-UCS2"); else if (!strcmp(collection, "Adobe-Japan2")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-Japan2-UCS2"); else if (!strcmp(collection, "Adobe-Korea1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-Korea1-UCS2"); } } pdf_load_to_unicode(xref, fontdesc, NULL, collection, to_unicode); /* Horizontal */ dw = 1000; obj = pdf_dict_gets(dict, "DW"); if (obj) dw = pdf_to_int(obj); pdf_set_default_hmtx(ctx, fontdesc, dw); widths = pdf_dict_gets(dict, "W"); if (widths) { int c0, c1, w, n, m; n = pdf_array_len(widths); for (i = 0; i < n; ) { c0 = pdf_to_int(pdf_array_get(widths, i)); obj = pdf_array_get(widths, i + 1); if (pdf_is_array(obj)) { m = pdf_array_len(obj); for (k = 0; k < m; k++) { w = pdf_to_int(pdf_array_get(obj, k)); pdf_add_hmtx(ctx, fontdesc, c0 + k, c0 + k, w); } i += 2; } else { c1 = pdf_to_int(obj); w = pdf_to_int(pdf_array_get(widths, i + 2)); pdf_add_hmtx(ctx, fontdesc, c0, c1, w); i += 3; } } } pdf_end_hmtx(ctx, fontdesc); /* Vertical */ if (pdf_cmap_wmode(ctx, fontdesc->encoding) == 1) { int dw2y = 880; int dw2w = -1000; obj = pdf_dict_gets(dict, "DW2"); if (obj) { dw2y = pdf_to_int(pdf_array_get(obj, 0)); dw2w = pdf_to_int(pdf_array_get(obj, 1)); } pdf_set_default_vmtx(ctx, fontdesc, dw2y, dw2w); widths = pdf_dict_gets(dict, "W2"); if (widths) { int c0, c1, w, x, y, n; n = pdf_array_len(widths); for (i = 0; i < n; ) { c0 = pdf_to_int(pdf_array_get(widths, i)); obj = pdf_array_get(widths, i + 1); if (pdf_is_array(obj)) { int m = pdf_array_len(obj); for (k = 0; k * 3 < m; k ++) { w = pdf_to_int(pdf_array_get(obj, k * 3 + 0)); x = pdf_to_int(pdf_array_get(obj, k * 3 + 1)); y = pdf_to_int(pdf_array_get(obj, k * 3 + 2)); pdf_add_vmtx(ctx, fontdesc, c0 + k, c0 + k, x, y, w); } i += 2; } else { c1 = pdf_to_int(obj); w = pdf_to_int(pdf_array_get(widths, i + 2)); x = pdf_to_int(pdf_array_get(widths, i + 3)); y = pdf_to_int(pdf_array_get(widths, i + 4)); pdf_add_vmtx(ctx, fontdesc, c0, c1, x, y, w); i += 5; } } } pdf_end_vmtx(ctx, fontdesc); } } fz_catch(ctx) { pdf_drop_font(ctx, fontdesc); fz_throw(ctx, "cannot load cid font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } return fontdesc; }
static void pdf_load_mesh_params(fz_context *ctx, pdf_document *doc, fz_shade *shade, pdf_obj *dict) { pdf_obj *obj; int i, n; shade->u.m.x0 = shade->u.m.y0 = 0; shade->u.m.x1 = shade->u.m.y1 = 1; for (i = 0; i < FZ_MAX_COLORS; i++) { shade->u.m.c0[i] = 0; shade->u.m.c1[i] = 1; } shade->u.m.vprow = pdf_dict_get_int(ctx, dict, PDF_NAME(VerticesPerRow)); shade->u.m.bpflag = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerFlag)); shade->u.m.bpcoord = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerCoordinate)); shade->u.m.bpcomp = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerComponent)); obj = pdf_dict_get(ctx, dict, PDF_NAME(Decode)); if (pdf_array_len(ctx, obj) >= 6) { n = fz_mini(FZ_MAX_COLORS, (pdf_array_len(ctx, obj) - 4) / 2); shade->u.m.x0 = pdf_array_get_real(ctx, obj, 0); shade->u.m.x1 = pdf_array_get_real(ctx, obj, 1); shade->u.m.y0 = pdf_array_get_real(ctx, obj, 2); shade->u.m.y1 = pdf_array_get_real(ctx, obj, 3); for (i = 0; i < n; i++) { shade->u.m.c0[i] = pdf_array_get_real(ctx, obj, 4 + i * 2); shade->u.m.c1[i] = pdf_array_get_real(ctx, obj, 5 + i * 2); } } if (shade->u.m.vprow < 2 && shade->type == 5) { fz_warn(ctx, "Too few vertices per row (%d)", shade->u.m.vprow); shade->u.m.vprow = 2; } if (shade->u.m.bpflag != 2 && shade->u.m.bpflag != 4 && shade->u.m.bpflag != 8 && shade->type != 5) { fz_warn(ctx, "Invalid number of bits per flag (%d)", shade->u.m.bpflag); shade->u.m.bpflag = 8; } if (shade->u.m.bpcoord != 1 && shade->u.m.bpcoord != 2 && shade->u.m.bpcoord != 4 && shade->u.m.bpcoord != 8 && shade->u.m.bpcoord != 12 && shade->u.m.bpcoord != 16 && shade->u.m.bpcoord != 24 && shade->u.m.bpcoord != 32) { fz_warn(ctx, "Invalid number of bits per coordinate (%d)", shade->u.m.bpcoord); shade->u.m.bpcoord = 8; } if (shade->u.m.bpcomp != 1 && shade->u.m.bpcomp != 2 && shade->u.m.bpcomp != 4 && shade->u.m.bpcomp != 8 && shade->u.m.bpcomp != 12 && shade->u.m.bpcomp != 16) { fz_warn(ctx, "Invalid number of bits per component (%d)", shade->u.m.bpcomp); shade->u.m.bpcomp = 8; } }
static pdf_font_desc * load_cid_font(pdf_document *doc, pdf_obj *dict, pdf_obj *encoding, pdf_obj *to_unicode) { pdf_obj *widths; pdf_obj *descriptor; pdf_font_desc *fontdesc = NULL; FT_Face face; int kind; char collection[256]; char *basefont; int i, k, fterr; pdf_obj *obj; int dw; fz_context *ctx = doc->ctx; fz_var(fontdesc); fz_try(ctx) { /* Get font name and CID collection */ basefont = pdf_to_name(pdf_dict_gets(dict, "BaseFont")); { pdf_obj *cidinfo; char tmpstr[64]; int tmplen; cidinfo = pdf_dict_gets(dict, "CIDSystemInfo"); if (!cidinfo) fz_throw(ctx, FZ_ERROR_GENERIC, "cid font is missing info"); obj = pdf_dict_gets(cidinfo, "Registry"); tmplen = fz_mini(sizeof tmpstr - 1, pdf_to_str_len(obj)); memcpy(tmpstr, pdf_to_str_buf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcpy(collection, tmpstr, sizeof collection); fz_strlcat(collection, "-", sizeof collection); obj = pdf_dict_gets(cidinfo, "Ordering"); tmplen = fz_mini(sizeof tmpstr - 1, pdf_to_str_len(obj)); memcpy(tmpstr, pdf_to_str_buf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcat(collection, tmpstr, sizeof collection); } /* Load font file */ fontdesc = pdf_new_font_desc(ctx); descriptor = pdf_dict_gets(dict, "FontDescriptor"); if (!descriptor) fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: missing font descriptor"); pdf_load_font_descriptor(fontdesc, doc, descriptor, collection, basefont, 1, 1); face = fontdesc->font->ft_face; kind = ft_kind(face); /* Encoding */ if (pdf_is_name(encoding)) { if (!strcmp(pdf_to_name(encoding), "Identity-H")) fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 2); else if (!strcmp(pdf_to_name(encoding), "Identity-V")) fontdesc->encoding = pdf_new_identity_cmap(ctx, 1, 2); else fontdesc->encoding = pdf_load_system_cmap(ctx, pdf_to_name(encoding)); } else if (pdf_is_indirect(encoding)) { fontdesc->encoding = pdf_load_embedded_cmap(doc, encoding); } else { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: font missing encoding"); } fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); pdf_set_font_wmode(ctx, fontdesc, pdf_cmap_wmode(ctx, fontdesc->encoding)); if (kind == TRUETYPE || /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1565 */ !strcmp(pdf_to_name(pdf_dict_gets(dict, "Subtype")), "CIDFontType2") || /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1997 */ pdf_is_indirect(pdf_dict_gets(dict, "CIDToGIDMap"))) { pdf_obj *cidtogidmap; cidtogidmap = pdf_dict_gets(dict, "CIDToGIDMap"); if (pdf_is_indirect(cidtogidmap)) { fz_buffer *buf; buf = pdf_load_stream(doc, pdf_to_num(cidtogidmap), pdf_to_gen(cidtogidmap)); fontdesc->cid_to_gid_len = (buf->len) / 2; fontdesc->cid_to_gid = fz_malloc_array(ctx, fontdesc->cid_to_gid_len, sizeof(unsigned short)); fontdesc->size += fontdesc->cid_to_gid_len * sizeof(unsigned short); for (i = 0; i < fontdesc->cid_to_gid_len; i++) fontdesc->cid_to_gid[i] = (buf->data[i * 2] << 8) + buf->data[i * 2 + 1]; fz_drop_buffer(ctx, buf); } /* if truetype font is external, cidtogidmap should not be identity */ /* so we map from cid to unicode and then map that through the (3 1) */ /* unicode cmap to get a glyph id */ else if (fontdesc->font->ft_substitute) { fterr = FT_Select_Charmap(face, ft_encoding_unicode); if (fterr) { fz_throw(ctx, FZ_ERROR_GENERIC, "fonterror: no unicode cmap when emulating CID font: %s", ft_error_string(fterr)); } if (!strcmp(collection, "Adobe-CNS1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-CNS1-UCS2"); else if (!strcmp(collection, "Adobe-GB1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-GB1-UCS2"); else if (!strcmp(collection, "Adobe-Japan1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-Japan1-UCS2"); else if (!strcmp(collection, "Adobe-Japan2")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-Japan2-UCS2"); else if (!strcmp(collection, "Adobe-Korea1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-Korea1-UCS2"); /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=2318 */ else if (!strcmp(collection, "Adobe-Identity") && fontdesc->font->ft_file) fontdesc->font->ft_substitute = 0; } } /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1961 */ fz_try(ctx) { pdf_load_to_unicode(doc, fontdesc, NULL, collection, to_unicode); } fz_catch(ctx) { fz_warn(ctx, "cannot load ToUnicode CMap"); } /* If we have an identity encoding, we're supposed to use the glyph ids directly. * If we only have a substitute font, that won't work. * Make a last ditch attempt by using * the ToUnicode table if it exists to map via the substitute font's cmap. */ if (strstr(fontdesc->encoding->cmap_name, "Identity-") && fontdesc->font->ft_substitute) { fz_warn(ctx, "non-embedded font using identity encoding: %s", basefont); if (fontdesc->to_unicode && !fontdesc->to_ttf_cmap) fontdesc->to_ttf_cmap = pdf_keep_cmap(ctx, fontdesc->to_unicode); } /* Horizontal */ dw = 1000; obj = pdf_dict_gets(dict, "DW"); if (obj) dw = pdf_to_int(obj); pdf_set_default_hmtx(ctx, fontdesc, dw); widths = pdf_dict_gets(dict, "W"); if (widths) { int c0, c1, w, n, m; n = pdf_array_len(widths); for (i = 0; i < n; ) { c0 = pdf_to_int(pdf_array_get(widths, i)); obj = pdf_array_get(widths, i + 1); if (pdf_is_array(obj)) { m = pdf_array_len(obj); for (k = 0; k < m; k++) { w = pdf_to_int(pdf_array_get(obj, k)); pdf_add_hmtx(ctx, fontdesc, c0 + k, c0 + k, w); } i += 2; } else { c1 = pdf_to_int(obj); w = pdf_to_int(pdf_array_get(widths, i + 2)); pdf_add_hmtx(ctx, fontdesc, c0, c1, w); i += 3; } } } pdf_end_hmtx(ctx, fontdesc); /* Vertical */ if (pdf_cmap_wmode(ctx, fontdesc->encoding) == 1) { int dw2y = 880; int dw2w = -1000; obj = pdf_dict_gets(dict, "DW2"); if (obj) { dw2y = pdf_to_int(pdf_array_get(obj, 0)); dw2w = pdf_to_int(pdf_array_get(obj, 1)); } pdf_set_default_vmtx(ctx, fontdesc, dw2y, dw2w); widths = pdf_dict_gets(dict, "W2"); if (widths) { int c0, c1, w, x, y, n; n = pdf_array_len(widths); for (i = 0; i < n; ) { c0 = pdf_to_int(pdf_array_get(widths, i)); obj = pdf_array_get(widths, i + 1); if (pdf_is_array(obj)) { int m = pdf_array_len(obj); for (k = 0; k * 3 < m; k ++) { w = pdf_to_int(pdf_array_get(obj, k * 3 + 0)); x = pdf_to_int(pdf_array_get(obj, k * 3 + 1)); y = pdf_to_int(pdf_array_get(obj, k * 3 + 2)); pdf_add_vmtx(ctx, fontdesc, c0 + k, c0 + k, x, y, w); } i += 2; } else { c1 = pdf_to_int(obj); w = pdf_to_int(pdf_array_get(widths, i + 2)); x = pdf_to_int(pdf_array_get(widths, i + 3)); y = pdf_to_int(pdf_array_get(widths, i + 4)); pdf_add_vmtx(ctx, fontdesc, c0, c1, x, y, w); i += 5; } } } pdf_end_vmtx(ctx, fontdesc); } } fz_catch(ctx) { pdf_drop_font(ctx, fontdesc); fz_rethrow_message(ctx, "cannot load cid font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } return fontdesc; }