static void res_table_free(fz_context *ctx, pdf_res_table *table) { int i, n; pdf_obj *res; if (table == NULL) return; if (table->hash != NULL) { n = fz_hash_len(ctx, table->hash); for (i = 0; i < n; i++) { res = fz_hash_get_val(ctx, table->hash, i); if (res) pdf_drop_obj(ctx, res); } fz_drop_hash(ctx, table->hash); } fz_free(ctx, table); }
static void drawimage(HDC hdc, pdfmoz_t *moz, fz_pixmap *image, int yofs) { int bmpstride = ((image->w * 3 + 3) / 4) * 4; unsigned char *bmpdata = fz_malloc(image->h * bmpstride); int x, y; if (!bmpdata) return; for (y = 0; y < image->h; y++) { unsigned char *p = bmpdata + y * bmpstride; unsigned char *s = image->samples + y * image->w * 4; for (x = 0; x < image->w; x++) { p[x * 3 + 0] = s[x * 4 + 3]; p[x * 3 + 1] = s[x * 4 + 2]; p[x * 3 + 2] = s[x * 4 + 1]; } } moz->dibinf->bmiHeader.biWidth = image->w; moz->dibinf->bmiHeader.biHeight = -image->h; moz->dibinf->bmiHeader.biSizeImage = image->h * bmpstride; SetDIBitsToDevice(hdc, 0, /* destx */ yofs, /* desty */ image->w, /* destw */ image->h, /* desth */ 0, /* srcx */ 0, /* srcy */ 0, /* startscan */ image->h, /* numscans */ bmpdata, /* pBits */ moz->dibinf, /* pInfo */ DIB_RGB_COLORS /* color use flag */ ); fz_free(bmpdata); }
fz_error * fz_newpredict(fz_filter **fp, fz_obj *params, int encode) { fz_obj *obj; FZ_NEWFILTER(fz_predict, p, predict); p->encode = encode; p->predictor = 1; p->columns = 1; p->colors = 1; p->bpc = 8; obj = fz_dictgets(params, "Predictor"); if (obj) p->predictor = fz_toint(obj); obj = fz_dictgets(params, "Columns"); if (obj) p->columns = fz_toint(obj); obj = fz_dictgets(params, "Colors"); if (obj) p->colors = fz_toint(obj); obj = fz_dictgets(params, "BitsPerComponent"); if (obj) p->bpc = fz_toint(obj); p->stride = (p->bpc * p->colors * p->columns + 7) / 8; p->bpp = (p->bpc * p->colors + 7) / 8; if (p->predictor >= 10) { p->ref = fz_malloc(p->stride); if (!p->ref) { fz_free(p); return fz_throw("outofmem: predictor reference buffer"); } memset(p->ref, 0, p->stride); } else { p->ref = nil; } return fz_okay; }
fz_path * fz_clone_path(fz_context *ctx, fz_path *old) { fz_path *path; assert(old); path = fz_malloc_struct(ctx, fz_path); fz_try(ctx) { path->len = old->len; path->cap = old->len; path->items = fz_malloc_array(ctx, path->cap, sizeof(fz_path_item)); memcpy(path->items, old->items, sizeof(fz_path_item) * path->len); } fz_catch(ctx) { fz_free(ctx, path); fz_rethrow(ctx); } return path; }
fz_stream * fz_open_fd(fz_context *ctx, int fd) { fz_stream *stm; int *state; state = fz_malloc_struct(ctx, int); *state = fd; fz_try(ctx) { stm = fz_new_stream(ctx, state, read_file, close_file); } fz_catch(ctx) { fz_free(ctx, state); fz_rethrow(ctx); } stm->seek = seek_file; return stm; }
fz_stream * fz_open_file(fz_context *ctx, const char *name) { #ifdef _WIN32 char *s = (char*)name; wchar_t *wname, *d; int c, fd; d = wname = fz_malloc(ctx, (strlen(name)+1) * sizeof(wchar_t)); while (*s) { s += fz_chartorune(&c, s); *d++ = c; } *d = 0; fd = _wopen(wname, O_BINARY | O_RDONLY, 0); fz_free(ctx, wname); #else int fd = open(name, O_BINARY | O_RDONLY, 0); #endif if (fd == -1) fz_throw(ctx, "cannot open %s", name); return fz_open_fd(ctx, fd); }
fz_error * pdf_newstore(pdf_store **storep) { fz_error *error; pdf_store *store; store = fz_malloc(sizeof(pdf_store)); if (!store) return fz_outofmem; error = fz_newhash(&store->hash, 4096, sizeof(struct refkey)); if (error) { fz_free(store); return error; } store->root = nil; *storep = store; return nil; }
fz_error fz_openrfilter(fz_stream **stmp, fz_filter *flt, fz_stream *src) { fz_error error; fz_stream *stm; stm = newstm(FZ_SFILTER); if (!stm) return fz_rethrow(-1, "out of memory: stream struct"); error = fz_newbuffer(&stm->buffer, FZ_BUFSIZE); if (error) { fz_free(stm); return fz_rethrow(error, "cannot create buffer"); } stm->chain = fz_keepstream(src); stm->filter = fz_keepfilter(flt); *stmp = stm; return fz_okay; }
static void execute_action(fz_context *ctx, pdf_document *doc, pdf_obj *obj, pdf_obj *a) { if (a) { pdf_obj *type = pdf_dict_get(ctx, a, PDF_NAME_S); if (pdf_name_eq(ctx, type, PDF_NAME_JavaScript)) { pdf_obj *js = pdf_dict_get(ctx, a, PDF_NAME_JS); if (js) { char *code = pdf_to_utf8(ctx, doc, js); fz_try(ctx) { pdf_js_execute(doc->js, code); } fz_always(ctx) { fz_free(ctx, code); } fz_catch(ctx) { fz_rethrow(ctx); } } } else if (pdf_name_eq(ctx, type, PDF_NAME_ResetForm)) { reset_form(ctx, doc, pdf_dict_get(ctx, a, PDF_NAME_Fields), pdf_to_int(ctx, pdf_dict_get(ctx, a, PDF_NAME_Flags)) & 1); } else if (pdf_name_eq(ctx, type, PDF_NAME_Named)) { pdf_obj *name = pdf_dict_get(ctx, a, PDF_NAME_N); if (pdf_name_eq(ctx, name, PDF_NAME_Print)) pdf_event_issue_print(ctx, doc); } }
static tiff_page * tiff_load_page(fz_context *ctx, tiff_document *doc, int number) { fz_pixmap *pixmap = NULL; fz_image *image = NULL; tiff_page *page = NULL; if (number < 0 || number >= doc->page_count) return NULL; fz_var(pixmap); fz_var(image); fz_var(page); fz_try(ctx) { pixmap = fz_load_tiff_subimage(ctx, doc->buffer->data, doc->buffer->len, number); image = fz_new_image_from_pixmap(ctx, pixmap, NULL); page = fz_new_page(ctx, sizeof *page); page->super.bound_page = (fz_page_bound_page_fn *)tiff_bound_page; page->super.run_page_contents = (fz_page_run_page_contents_fn *)tiff_run_page; page->super.drop_page_imp = (fz_page_drop_page_imp_fn *)tiff_drop_page_imp; page->image = fz_keep_image(ctx, image); } fz_always(ctx) { fz_drop_image(ctx, image); fz_drop_pixmap(ctx, pixmap); } fz_catch(ctx) { fz_free(ctx, page); fz_rethrow(ctx); } return page; }
void fz_dropstream(fz_stream *stm) { stm->refs --; if (stm->refs == 0) { if (stm->error) { fflush(stdout); fz_printerror(stm->error); fz_droperror(stm->error); fflush(stderr); fz_warn("dropped unhandled ioerror"); } if (stm->mode == FZ_SWRITE) { stm->buffer->eof = 1; fz_flush(stm); } switch (stm->kind) { case FZ_SFILE: close(stm->file); break; case FZ_SFILTER: fz_dropfilter(stm->filter); fz_dropstream(stm->chain); break; case FZ_SBUFFER: break; } fz_dropbuffer(stm->buffer); fz_free(stm); } }
/* Convert UCS-2 string into PdfDocEncoding for authentication */ char * pdf_from_ucs2(pdf_document *doc, unsigned short *src) { fz_context *ctx = doc->ctx; int i, j, len; char *docstr; len = 0; while (src[len]) len++; docstr = fz_malloc(ctx, len + 1); for (i = 0; i < len; i++) { /* shortcut: check if the character has the same code point in both encodings */ if (0 < src[i] && src[i] < 256 && pdf_doc_encoding[src[i]] == src[i]) { docstr[i] = src[i]; continue; } /* search through pdf_docencoding for the character's code point */ for (j = 0; j < 256; j++) if (pdf_doc_encoding[j] == src[i]) break; docstr[i] = j; /* fail, if a character can't be encoded */ if (!docstr[i]) { fz_free(ctx, docstr); return NULL; } } docstr[len] = '\0'; return docstr; }
fz_error fz_newfontfromfile(fz_font **fontp, char *path, int index) { fz_error error; fz_font *font; int fterr; error = fz_initfreetype(); if (error) return fz_rethrow(error, "cannot init freetype library"); font = fz_newfont(); fterr = FT_New_Face(fz_ftlib, path, index, (FT_Face*)&font->ftface); if (fterr) { fz_free(font); return fz_throw("freetype: cannot load font: %s", ft_errorstring(fterr)); } *fontp = font; return fz_okay; }
static fz_error * openfilter(fz_stream **stmp, fz_filter *flt, fz_stream *src, int mode) { fz_error *error; fz_stream *stm; stm = newstm(FZ_SFILTER, mode); if (!stm) return fz_throw("outofmem: stream struct"); error = fz_newbuffer(&stm->buffer, FZ_BUFSIZE); if (error) { fz_free(stm); return fz_rethrow(error, "cannot create buffer"); } stm->chain = fz_keepstream(src); stm->filter = fz_keepfilter(flt); *stmp = stm; return fz_okay; }
fz_stream * fz_open_file(fz_context *ctx, const char *name) { FILE *f; #if defined(_WIN32) || defined(_WIN64) char *s = (char*)name; wchar_t *wname, *d; int c; d = wname = fz_malloc(ctx, (strlen(name)+1) * sizeof(wchar_t)); while (*s) { s += fz_chartorune(&c, s); *d++ = c; } *d = 0; f = _wfopen(wname, L"rb"); fz_free(ctx, wname); #else f = fz_fopen(name, "rb"); #endif if (f == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open %s: %s", name, strerror(errno)); return fz_open_file_ptr(ctx, f); }
void pdf_free_page(pdf_document *doc, pdf_page *page) { if (page == NULL) return; pdf_drop_obj(page->resources); pdf_drop_obj(page->contents); if (page->links) fz_drop_link(doc->ctx, page->links); if (page->annots) pdf_free_annot(doc->ctx, page->annots); if (page->deleted_annots) pdf_free_annot(doc->ctx, page->deleted_annots); if (page->tmp_annots) pdf_free_annot(doc->ctx, page->tmp_annots); /* doc->focus, when not NULL, refers to one of * the annotations and must be NULLed when the * annotations are destroyed. doc->focus_obj * keeps track of the actual annotation object. */ doc->focus = NULL; pdf_drop_obj(page->me); fz_free(doc->ctx, page); }
fz_error fz_newfontfrombuffer(fz_font **fontp, unsigned char *data, int len, int index) { fz_error error; fz_font *font; int fterr; error = fz_initfreetype(); if (error) return fz_rethrow(error, "cannot init freetype library"); font = fz_newfont(); fterr = FT_New_Memory_Face(fz_ftlib, data, len, index, (FT_Face*)&font->ftface); if (fterr) { fz_free(font); return fz_throw("freetype: cannot load font: %s", ft_errorstring(fterr)); } *fontp = font; return fz_okay; }
fz_error * fz_newpixmap(fz_pixmap **pixp, int x, int y, int w, int h, int n) { fz_pixmap *pix; pix = *pixp = fz_malloc(sizeof(fz_pixmap)); if (!pix) return fz_outofmem; pix->x = x; pix->y = y; pix->w = w; pix->h = h; pix->n = n; pix->samples = fz_malloc(pix->w * pix->h * pix->n * sizeof(fz_sample)); if (!pix->samples) { fz_free(pix); return fz_outofmem; } return nil; }
fz_buffer * fz_new_buffer(fz_context *ctx, int size) { fz_buffer *b; size = size > 1 ? size : 16; b = (fz_buffer*)fz_malloc_struct(ctx, fz_buffer); b->refs = 1; try { b->data = (unsigned char*)fz_malloc(ctx, size); } catch(...) { fz_free(ctx, b); throw(ctx); } b->cap = size; b->len = 0; return b; }
fz_text * fz_clone_text(fz_context *ctx, fz_text *old) { fz_text *text; text = fz_malloc_struct(ctx, fz_text); text->len = old->len; fz_try(ctx) { text->items = fz_malloc_array(ctx, text->len, sizeof(fz_text_item)); } fz_catch(ctx) { fz_free(ctx, text); fz_rethrow(ctx); } memcpy(text->items, old->items, text->len * sizeof(fz_text_item)); text->font = fz_keep_font(ctx, old->font); text->trm = old->trm; text->wmode = old->wmode; text->cap = text->len; return text; }
void fz_drop_output_context(fz_context *ctx) { if (!ctx) return; if (fz_drop_imp(ctx, ctx->output, &ctx->output->refs)) { fz_try(ctx) fz_flush_output(ctx, ctx->output->out); fz_catch(ctx) fz_warn(ctx, "cannot flush stdout"); fz_drop_output(ctx, ctx->output->out); fz_try(ctx) fz_flush_output(ctx, ctx->output->err); fz_catch(ctx) fz_warn(ctx, "cannot flush stderr"); fz_drop_output(ctx, ctx->output->err); fz_free(ctx, ctx->output); ctx->output = NULL; } }
fz_document_writer * fz_new_cbz_writer(fz_context *ctx, const char *path, const char *options) { fz_cbz_writer *wri; wri = fz_malloc_struct(ctx, fz_cbz_writer); wri->super.begin_page = cbz_begin_page; wri->super.end_page = cbz_end_page; wri->super.close_writer = cbz_close_writer; wri->super.drop_writer = cbz_drop_writer; fz_try(ctx) { fz_parse_draw_options(ctx, &wri->options, options); wri->zip = fz_new_zip_writer(ctx, path ? path : "out.cbz"); } fz_catch(ctx) { fz_free(ctx, wri); fz_rethrow(ctx); } return (fz_document_writer*)wri; }
struct element * xml_parse_document(fz_context *ctx, unsigned char *s, int n) { struct parser parser; struct element root; char *p, *error; /* s is already null-terminated (see xps_new_part) */ memset(&root, 0, sizeof(root)); parser.head = &root; parser.ctx = ctx; p = convert_to_utf8(ctx, s, n); error = xml_parse_document_imp(&parser, p); if (error) fz_throw(ctx, "%s", error); if (p != (char*)s) fz_free(ctx, p); return root.down; }
fz_buffer * fz_new_buffer(fz_context *ctx, int size) { fz_buffer *b; size = size > 1 ? size : 16; b = fz_malloc_struct(ctx, fz_buffer); b->refs = 1; fz_try(ctx) { b->data = fz_malloc(ctx, size); } fz_catch(ctx) { fz_free(ctx, b); fz_rethrow(ctx); } b->cap = size; b->len = 0; b->unused_bits = 0; return b; }
static void drop_glyph_cache_entry(fz_context *ctx, fz_glyph_cache_entry *entry) { fz_glyph_cache *cache = ctx->glyph_cache; if (entry->lru_next) entry->lru_next->lru_prev = entry->lru_prev; else cache->lru_tail = entry->lru_prev; if (entry->lru_prev) entry->lru_prev->lru_next = entry->lru_next; else cache->lru_head = entry->lru_next; cache->total -= fz_glyph_size(ctx, entry->val); if (entry->bucket_next) entry->bucket_next->bucket_prev = entry->bucket_prev; if (entry->bucket_prev) entry->bucket_prev->bucket_next = entry->bucket_next; else cache->entry[entry->hash] = entry->bucket_next; fz_drop_font(ctx, entry->key.font); fz_drop_glyph(ctx, entry->val); fz_free(ctx, entry); }
void winconvert(pdfapp_t *app, fz_pixmap *image) { int y, x; if (bmpdata) fz_free(bmpdata); bmpstride = ((image->w * 3 + 3) / 4) * 4; bmpdata = fz_malloc(image->h * bmpstride); if (!bmpdata) return; for (y = 0; y < image->h; y++) { unsigned char *p = bmpdata + y * bmpstride; unsigned char *s = image->samples + y * image->w * 4; for (x = 0; x < image->w; x++) { p[x * 3 + 0] = s[x * 4 + 3]; p[x * 3 + 1] = s[x * 4 + 2]; p[x * 3 + 2] = s[x * 4 + 1]; } } }
void pdf_dropfont(pdf_fontdesc *fontdesc) { if (fontdesc && --fontdesc->refs == 0) { if (fontdesc->font) fz_dropfont(fontdesc->font); if (fontdesc->buffer) fz_free(fontdesc->buffer); if (fontdesc->encoding) pdf_dropcmap(fontdesc->encoding); if (fontdesc->tottfcmap) pdf_dropcmap(fontdesc->tottfcmap); if (fontdesc->tounicode) pdf_dropcmap(fontdesc->tounicode); fz_free(fontdesc->cidtogid); fz_free(fontdesc->cidtoucs); fz_free(fontdesc->hmtx); fz_free(fontdesc->vmtx); fz_free(fontdesc); } }
static void drawbmp(fz_context *ctx, fz_document *doc, fz_page *page, fz_display_list *list, int pagenum, fz_cookie *cookie) { float zoom; fz_matrix ctm; fz_irect ibounds; fz_rect bounds, tbounds; int w, h; fz_device *dev; HDC dc, dc_main; RECT rc; HBRUSH bg_brush; HBITMAP hbmp; BITMAPINFO bmi = { 0 }; int bmp_data_len; unsigned char *bmp_data; fz_bound_page(doc, page, &bounds); zoom = resolution / 72; fz_pre_scale(fz_rotate(&ctm, rotation), zoom, zoom); tbounds = bounds; fz_round_rect(&ibounds, fz_transform_rect(&tbounds, &ctm)); w = width; h = height; if (res_specified) { fz_round_rect(&ibounds, &tbounds); if (w && ibounds.x1 - ibounds.x0 <= w) w = 0; if (h && ibounds.y1 - ibounds.y0 <= h) h = 0; } if (w || h) { float scalex = w / (tbounds.x1 - tbounds.x0); float scaley = h / (tbounds.y1 - tbounds.y0); fz_matrix scale_mat; if (w == 0) scalex = fit ? 1.0f : scaley; if (h == 0) scaley = fit ? 1.0f : scalex; if (!fit) scalex = scaley = min(scalex, scaley); fz_concat(&ctm, &ctm, fz_scale(&scale_mat, scalex, scaley)); tbounds = bounds; fz_transform_rect(&tbounds, &ctm); } fz_round_rect(&ibounds, &tbounds); fz_rect_from_irect(&tbounds, &ibounds); w = ibounds.x1 - ibounds.x0; h = ibounds.y1 - ibounds.y0; dc_main = GetDC(NULL); dc = CreateCompatibleDC(dc_main); hbmp = CreateCompatibleBitmap(dc_main, w, h); DeleteObject(SelectObject(dc, hbmp)); SetRect(&rc, 0, 0, w, h); bg_brush = CreateSolidBrush(RGB(0xFF,0xFF,0xFF)); FillRect(dc, &rc, bg_brush); DeleteObject(bg_brush); dev = fz_new_gdiplus_device(ctx, dc, &tbounds); if (list) fz_run_display_list(list, dev, &ctm, &tbounds, cookie); else fz_run_page(doc, page, dev, &ctm, cookie); fz_free_device(dev); bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = w; bmi.bmiHeader.biHeight = output_format == OUT_TGA ? -h : h; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = output_format == OUT_TGA ? 32 : 24; bmi.bmiHeader.biCompression = BI_RGB; bmp_data_len = output_format == OUT_TGA ? w * h * 4 : ((w * 3 + 3) / 4) * 4 * h; bmp_data = fz_malloc(ctx, bmp_data_len); if (!GetDIBits(dc, hbmp, 0, h, bmp_data, &bmi, DIB_RGB_COLORS)) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot draw page %d in PDF file '%s'", pagenum, filename); DeleteDC(dc); ReleaseDC(NULL, dc_main); DeleteObject(hbmp); if (output) { char buf[512]; FILE *f; sprintf(buf, output, pagenum); f = fopen(buf, "wb"); if (!f) fz_throw(ctx, FZ_ERROR_GENERIC, "could not create raster file '%s'", buf); if (output_format == OUT_TGA) { fz_pixmap *pix = fz_new_pixmap_with_data(ctx, fz_device_bgr(ctx), w, h, bmp_data); fz_write_tga(ctx, pix, buf, 0); fz_drop_pixmap(ctx, pix); } else { BITMAPFILEHEADER bmpfh = { 0 }; static const int one = 1; if (!*(char *)&one) fz_throw(ctx, FZ_ERROR_GENERIC, "rendering to BMP is not supported on big-endian architectures"); bmpfh.bfType = MAKEWORD('B', 'M'); bmpfh.bfOffBits = sizeof(bmpfh) + sizeof(bmi); bmpfh.bfSize = bmpfh.bfOffBits + bmp_data_len; fwrite(&bmpfh, sizeof(bmpfh), 1, f); fwrite(&bmi, sizeof(bmi), 1, f); fwrite(bmp_data, 1, bmp_data_len, f); } fclose(f); } if (showmd5) { fz_pixmap *pix = fz_new_pixmap_with_data(ctx, fz_device_bgr(ctx), bmp_data_len / 4 / h, h, bmp_data); unsigned char digest[16]; int i; fz_md5_pixmap(pix, digest); printf(" "); for (i = 0; i < 16; i++) printf("%02x", digest[i]); fz_drop_pixmap(ctx, pix); } fz_free(ctx, bmp_data); }
static pdf_font_desc * pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) { pdf_obj *descriptor; pdf_obj *encoding; pdf_obj *widths; unsigned short *etable = NULL; pdf_font_desc *fontdesc = NULL; char *subtype; FT_Face face; FT_CharMap cmap; int symbolic; int kind; char *basefont; char *estrings[256]; char ebuffer[256][32]; int i, k, n; int fterr; fz_context *ctx = xref->ctx; fz_var(fontdesc); fz_var(etable); basefont = pdf_to_name(pdf_dict_gets(dict, "BaseFont")); /* Load font file */ fz_try(ctx) { fontdesc = pdf_new_font_desc(ctx); descriptor = pdf_dict_gets(dict, "FontDescriptor"); if (descriptor) pdf_load_font_descriptor(fontdesc, xref, descriptor, NULL, basefont); else pdf_load_builtin_font(ctx, fontdesc, basefont); /* Some chinese documents mistakenly consider WinAnsiEncoding to be codepage 936 */ if (descriptor && pdf_is_string(pdf_dict_gets(descriptor, "FontName")) && !pdf_dict_gets(dict, "ToUnicode") && !strcmp(pdf_to_name(pdf_dict_gets(dict, "Encoding")), "WinAnsiEncoding") && pdf_to_int(pdf_dict_gets(descriptor, "Flags")) == 4) { char *cp936fonts[] = { "\xCB\xCE\xCC\xE5", "SimSun,Regular", "\xBA\xDA\xCC\xE5", "SimHei,Regular", "\xBF\xAC\xCC\xE5_GB2312", "SimKai,Regular", "\xB7\xC2\xCB\xCE_GB2312", "SimFang,Regular", "\xC1\xA5\xCA\xE9", "SimLi,Regular", NULL }; for (i = 0; cp936fonts[i]; i += 2) if (!strcmp(basefont, cp936fonts[i])) break; if (cp936fonts[i]) { fz_warn(ctx, "workaround for S22PDF lying about chinese font encodings"); pdf_drop_font(ctx, fontdesc); fontdesc = pdf_new_font_desc(ctx); pdf_load_font_descriptor(fontdesc, xref, descriptor, "Adobe-GB1", cp936fonts[i+1]); fontdesc->encoding = pdf_load_system_cmap(ctx, "GBK-EUC-H"); fontdesc->to_unicode = pdf_load_system_cmap(ctx, "Adobe-GB1-UCS2"); fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-GB1-UCS2"); face = fontdesc->font->ft_face; kind = ft_kind(face); goto skip_encoding; } } face = fontdesc->font->ft_face; kind = ft_kind(face); /* Encoding */ symbolic = fontdesc->flags & 4; if (face->num_charmaps > 0) cmap = face->charmaps[0]; else cmap = NULL; for (i = 0; i < face->num_charmaps; i++) { FT_CharMap test = face->charmaps[i]; if (kind == TYPE1) { if (test->platform_id == 7) cmap = test; } if (kind == TRUETYPE) { if (test->platform_id == 1 && test->encoding_id == 0) cmap = test; if (test->platform_id == 3 && test->encoding_id == 1) cmap = test; if (symbolic && test->platform_id == 3 && test->encoding_id == 0) cmap = test; } } if (cmap) { fterr = FT_Set_Charmap(face, cmap); if (fterr) fz_warn(ctx, "freetype could not set cmap: %s", ft_error_string(fterr)); } else fz_warn(ctx, "freetype could not find any cmaps"); etable = fz_malloc_array(ctx, 256, sizeof(unsigned short)); fontdesc->size += 256 * sizeof(unsigned short); for (i = 0; i < 256; i++) { estrings[i] = NULL; etable[i] = 0; } encoding = pdf_dict_gets(dict, "Encoding"); if (encoding) { if (pdf_is_name(encoding)) pdf_load_encoding(estrings, pdf_to_name(encoding)); if (pdf_is_dict(encoding)) { pdf_obj *base, *diff, *item; base = pdf_dict_gets(encoding, "BaseEncoding"); if (pdf_is_name(base)) pdf_load_encoding(estrings, pdf_to_name(base)); else if (!fontdesc->is_embedded && !symbolic) pdf_load_encoding(estrings, "StandardEncoding"); diff = pdf_dict_gets(encoding, "Differences"); if (pdf_is_array(diff)) { n = pdf_array_len(diff); k = 0; for (i = 0; i < n; i++) { item = pdf_array_get(diff, i); if (pdf_is_int(item)) k = pdf_to_int(item); if (pdf_is_name(item) && k >= 0 && k < nelem(estrings)) estrings[k++] = pdf_to_name(item); } } } } /* start with the builtin encoding */ for (i = 0; i < 256; i++) etable[i] = ft_char_index(face, i); fz_lock(ctx, FZ_LOCK_FREETYPE); /* built-in and substitute fonts may be a different type than what the document expects */ subtype = pdf_to_name(pdf_dict_gets(dict, "Subtype")); if (!strcmp(subtype, "Type1")) kind = TYPE1; else if (!strcmp(subtype, "MMType1")) kind = TYPE1; else if (!strcmp(subtype, "TrueType")) kind = TRUETYPE; else if (!strcmp(subtype, "CIDFontType0")) kind = TYPE1; else if (!strcmp(subtype, "CIDFontType2")) kind = TRUETYPE; /* encode by glyph name where we can */ if (kind == TYPE1) { for (i = 0; i < 256; i++) { if (estrings[i]) { etable[i] = FT_Get_Name_Index(face, estrings[i]); if (etable[i] == 0) { int aglcode = pdf_lookup_agl(estrings[i]); const char **dupnames = pdf_lookup_agl_duplicates(aglcode); while (*dupnames) { etable[i] = FT_Get_Name_Index(face, (char*)*dupnames); if (etable[i]) break; dupnames++; } } } } } /* encode by glyph name where we can */ if (kind == TRUETYPE) { /* Unicode cmap */ if (!symbolic && face->charmap && face->charmap->platform_id == 3) { for (i = 0; i < 256; i++) { if (estrings[i]) { int aglcode = pdf_lookup_agl(estrings[i]); if (!aglcode) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ft_char_index(face, aglcode); } } } /* MacRoman cmap */ else if (!symbolic && face->charmap && face->charmap->platform_id == 1) { for (i = 0; i < 256; i++) { if (estrings[i]) { k = lookup_mre_code(estrings[i]); if (k <= 0) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ft_char_index(face, k); } } } /* Symbolic cmap */ else if (!face->charmap || face->charmap->encoding != FT_ENCODING_MS_SYMBOL) { for (i = 0; i < 256; i++) { if (estrings[i]) { etable[i] = FT_Get_Name_Index(face, estrings[i]); if (etable[i] == 0) etable[i] = ft_char_index(face, i); } } } } /* try to reverse the glyph names from the builtin encoding */ for (i = 0; i < 256; i++) { if (etable[i] && !estrings[i]) { if (FT_HAS_GLYPH_NAMES(face)) { fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32); if (fterr) fz_warn(ctx, "freetype get glyph name (gid %d): %s", etable[i], ft_error_string(fterr)); if (ebuffer[i][0]) estrings[i] = ebuffer[i]; } else { estrings[i] = (char*) pdf_win_ansi[i]; /* discard const */ } } } /* symbolic Type 1 fonts with an implicit encoding and non-standard glyph names */ if (kind == TYPE1 && symbolic) { for (i = 0; i < 256; i++) if (etable[i] && estrings[i] && !pdf_lookup_agl(estrings[i])) estrings[i] = (char*) pdf_standard[i]; } fz_unlock(ctx, FZ_LOCK_FREETYPE); fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); fontdesc->cid_to_gid_len = 256; fontdesc->cid_to_gid = etable; fz_try(ctx) { pdf_load_to_unicode(xref, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode")); } fz_catch(ctx) { fz_warn(ctx, "cannot load ToUnicode CMap"); } skip_encoding: /* Widths */ pdf_set_default_hmtx(ctx, fontdesc, fontdesc->missing_width); widths = pdf_dict_gets(dict, "Widths"); if (widths) { int first, last; first = pdf_to_int(pdf_dict_gets(dict, "FirstChar")); last = pdf_to_int(pdf_dict_gets(dict, "LastChar")); if (first < 0 || last > 255 || first > last) first = last = 0; for (i = 0; i < last - first + 1; i++) { int wid = pdf_to_int(pdf_array_get(widths, i)); pdf_add_hmtx(ctx, fontdesc, i + first, i + first, wid); } } else { fz_lock(ctx, FZ_LOCK_FREETYPE); fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72); if (fterr) fz_warn(ctx, "freetype set character size: %s", ft_error_string(fterr)); for (i = 0; i < 256; i++) { pdf_add_hmtx(ctx, fontdesc, i, i, ft_width(ctx, fontdesc, i)); } fz_unlock(ctx, FZ_LOCK_FREETYPE); } pdf_end_hmtx(ctx, fontdesc); } fz_catch(ctx) { if (fontdesc && etable != fontdesc->cid_to_gid) fz_free(ctx, etable); pdf_drop_font(ctx, fontdesc); fz_throw(ctx, "cannot load simple font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } return fontdesc; }
static fz_pixmap * decomp_image_from_stream(fz_context *ctx, fz_stream *stm, pdf_image *image, int in_line, int indexed, int l2factor, int native_l2factor, int cache) { fz_pixmap *tile = NULL; fz_pixmap *existing_tile; int stride, len, i; unsigned char *samples = NULL; int f = 1<<native_l2factor; int w = (image->base.w + f-1) >> native_l2factor; int h = (image->base.h + f-1) >> native_l2factor; pdf_image_key *key = NULL; fz_var(tile); fz_var(samples); fz_var(key); fz_try(ctx) { tile = fz_new_pixmap(ctx, image->base.colorspace, w, h); tile->interpolate = image->interpolate; stride = (w * image->n * image->base.bpc + 7) / 8; samples = fz_malloc_array(ctx, h, stride); len = fz_read(stm, samples, h * stride); if (len < 0) { fz_throw(ctx, "cannot read image data"); } /* Make sure we read the EOF marker (for inline images only) */ if (in_line) { unsigned char tbuf[512]; fz_try(ctx) { int tlen = fz_read(stm, tbuf, sizeof tbuf); if (tlen > 0) fz_warn(ctx, "ignoring garbage at end of image"); } fz_catch(ctx) { fz_warn(ctx, "ignoring error at end of image"); } } /* Pad truncated images */ if (len < stride * h) { fz_warn(ctx, "padding truncated image"); memset(samples + len, 0, stride * h - len); } /* Invert 1-bit image masks */ if (image->imagemask) { /* 0=opaque and 1=transparent so we need to invert */ unsigned char *p = samples; len = h * stride; for (i = 0; i < len; i++) p[i] = ~p[i]; } fz_unpack_tile(tile, samples, image->n, image->base.bpc, stride, indexed); fz_free(ctx, samples); samples = NULL; if (image->usecolorkey) pdf_mask_color_key(tile, image->n, image->colorkey); if (indexed) { fz_pixmap *conv; fz_decode_indexed_tile(tile, image->decode, (1 << image->base.bpc) - 1); conv = pdf_expand_indexed_pixmap(ctx, tile); fz_drop_pixmap(ctx, tile); tile = conv; } else { fz_decode_tile(tile, image->decode); } } fz_always(ctx) { fz_close(stm); } fz_catch(ctx) { if (tile) fz_drop_pixmap(ctx, tile); fz_free(ctx, samples); fz_rethrow(ctx); } /* Now apply any extra subsampling required */ if (l2factor - native_l2factor > 0) { if (l2factor - native_l2factor > 8) l2factor = native_l2factor + 8; fz_subsample_pixmap(ctx, tile, l2factor - native_l2factor); } if (!cache) return tile; /* Now we try to cache the pixmap. Any failure here will just result * in us not caching. */ fz_try(ctx) { key = fz_malloc_struct(ctx, pdf_image_key); key->refs = 1; key->image = fz_keep_image(ctx, &image->base); key->l2factor = l2factor; existing_tile = fz_store_item(ctx, key, tile, fz_pixmap_size(ctx, tile), &pdf_image_store_type); if (existing_tile) { /* We already have a tile. This must have been produced by a * racing thread. We'll throw away ours and use that one. */ fz_drop_pixmap(ctx, tile); tile = existing_tile; } } fz_always(ctx) { pdf_drop_image_key(ctx, key); } fz_catch(ctx) { /* Do nothing */ } return tile; }