fz_gel * fz_new_gel(fz_context *ctx) { fz_gel *gel; gel = fz_malloc_struct(ctx, fz_gel); fz_try(ctx) { gel->edges = NULL; gel->cap = 512; gel->len = 0; gel->edges = fz_malloc_array(ctx, gel->cap, sizeof(fz_edge)); gel->clip.x0 = gel->clip.y0 = BBOX_MIN; gel->clip.x1 = gel->clip.y1 = BBOX_MAX; gel->bbox.x0 = gel->bbox.y0 = BBOX_MAX; gel->bbox.x1 = gel->bbox.y1 = BBOX_MIN; gel->acap = 64; gel->alen = 0; gel->active = fz_malloc_array(ctx, gel->acap, sizeof(fz_edge*)); } fz_catch(ctx) { if (gel) fz_free(ctx, gel->edges); fz_free(ctx, gel); fz_rethrow(ctx); } return gel; }
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->cmd_len = old->cmd_len; path->cmd_cap = old->cmd_len; path->cmds = fz_malloc_array(ctx, path->cmd_cap, sizeof(unsigned char)); memcpy(path->cmds, old->cmds, sizeof(unsigned char) * path->cmd_len); path->coord_len = old->coord_len; path->coord_cap = old->coord_len; path->coords = fz_malloc_array(ctx, path->coord_cap, sizeof(float)); memcpy(path->coords, old->coords, sizeof(float) * path->coord_len); } fz_catch(ctx) { fz_free(ctx, path->cmds); fz_free(ctx, path->coords); fz_free(ctx, path); fz_rethrow(ctx); } return path; }
/* Convert Unicode/PdfDocEncoding string into ucs-2 */ unsigned short * pdf_to_ucs2(fz_context *ctx, pdf_obj *src) { unsigned char *srcptr = (unsigned char *) pdf_to_str_buf(src); unsigned short *dstptr, *dst; int srclen = pdf_to_str_len(src); int i; if (srclen >= 2 && srcptr[0] == 254 && srcptr[1] == 255) { dstptr = dst = fz_malloc_array(ctx, (srclen - 2) / 2 + 1, sizeof(short)); for (i = 2; i + 1 < srclen; i += 2) *dstptr++ = srcptr[i] << 8 | srcptr[i+1]; } else if (srclen >= 2 && srcptr[0] == 255 && srcptr[1] == 254) { dstptr = dst = fz_malloc_array(ctx, (srclen - 2) / 2 + 1, sizeof(short)); for (i = 2; i + 1 < srclen; i += 2) *dstptr++ = srcptr[i] | srcptr[i+1] << 8; } else { dstptr = dst = fz_malloc_array(ctx, srclen + 1, sizeof(short)); for (i = 0; i < srclen; i++) *dstptr++ = pdf_doc_encoding[srcptr[i]]; } *dstptr = '\0'; return dst; }
static void fz_process_mesh_type5(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_mesh_processor *painter) { fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer); fz_vertex *buf = NULL; fz_vertex *ref = NULL; int first; int ncomp = painter->ncomp; int i, k; int vprow = shade->u.m.vprow; int bpcoord = shade->u.m.bpcoord; int bpcomp = shade->u.m.bpcomp; float x0 = shade->u.m.x0; float x1 = shade->u.m.x1; float y0 = shade->u.m.y0; float y1 = shade->u.m.y1; float *c0 = shade->u.m.c0; float *c1 = shade->u.m.c1; float x, y, c[FZ_MAX_COLORS]; fz_var(buf); fz_var(ref); fz_try(ctx) { ref = fz_malloc_array(ctx, vprow, sizeof(fz_vertex)); buf = fz_malloc_array(ctx, vprow, sizeof(fz_vertex)); first = 1; while (!fz_is_eof_bits(ctx, stream)) { for (i = 0; i < vprow; i++) { x = read_sample(ctx, stream, bpcoord, x0, x1); y = read_sample(ctx, stream, bpcoord, y0, y1); for (k = 0; k < ncomp; k++) c[k] = read_sample(ctx, stream, bpcomp, c0[k], c1[k]); fz_prepare_vertex(ctx, painter, &buf[i], ctm, x, y, c); } if (!first) for (i = 0; i < vprow - 1; i++) paint_quad(ctx, painter, &ref[i], &ref[i+1], &buf[i+1], &buf[i]); SWAP(ref,buf); first = 0; } } fz_always(ctx) { fz_free(ctx, ref); fz_free(ctx, buf); fz_drop_stream(ctx, stream); } fz_catch(ctx) { fz_rethrow(ctx); } }
static void fz_mesh_type5_process(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_mesh_processor *painter) { fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer); fz_vertex *buf = NULL; fz_vertex *ref = NULL; int first; int ncomp; int i, k; int vprow = shade->u.m.vprow; int bpcoord = shade->u.m.bpcoord; int bpcomp = shade->u.m.bpcomp; float x0 = shade->u.m.x0; float x1 = shade->u.m.x1; float y0 = shade->u.m.y0; float y1 = shade->u.m.y1; float *c0 = shade->u.m.c0; float *c1 = shade->u.m.c1; fz_var(buf); fz_var(ref); fz_try(ctx) { ref = fz_malloc_array(ctx, vprow, sizeof(fz_vertex)); buf = fz_malloc_array(ctx, vprow, sizeof(fz_vertex)); first = 1; ncomp = (shade->use_function > 0 ? 1 : shade->colorspace->n); while (!fz_is_eof_bits(stream)) { for (i = 0; i < vprow; i++) { buf[i].p.x = read_sample(stream, bpcoord, x0, x1); buf[i].p.y = read_sample(stream, bpcoord, y0, y1); fz_transform_point(&buf[i].p, ctm); for (k = 0; k < ncomp; k++) buf[i].c[k] = read_sample(stream, bpcomp, c0[k], c1[k]); } if (!first) for (i = 0; i < vprow - 1; i++) paint_quad(painter, &ref[i], &ref[i+1], &buf[i+1], &buf[i]); SWAP(ref,buf); first = 0; } } fz_always(ctx) { fz_free(ctx, ref); fz_free(ctx, buf); fz_close(stream); } fz_catch(ctx) { fz_rethrow(ctx); } }
static void pdf_load_type5_shade(fz_shade *shade, pdf_document *xref, pdf_obj *dict, int funcs, pdf_function **func) { fz_context *ctx = xref->ctx; struct mesh_params p; struct vertex *buf, *ref; int first; int ncomp; int i, k; fz_stream *stream; pdf_load_mesh_params(xref, dict, &p); if (funcs > 0) { ncomp = 1; pdf_sample_shade_function(ctx, shade, funcs, func, p.c0[0], p.c1[0]); } else ncomp = shade->colorspace->n; ref = fz_malloc_array(ctx, p.vprow, sizeof(struct vertex)); buf = fz_malloc_array(ctx, p.vprow, sizeof(struct vertex)); first = 1; stream = pdf_open_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); while (!fz_is_eof_bits(stream)) { for (i = 0; i < p.vprow; i++) { buf[i].x = read_sample(stream, p.bpcoord, p.x0, p.x1); buf[i].y = read_sample(stream, p.bpcoord, p.y0, p.y1); for (k = 0; k < ncomp; k++) buf[i].c[k] = read_sample(stream, p.bpcomp, p.c0[k], p.c1[k]); } if (!first) for (i = 0; i < p.vprow - 1; i++) pdf_add_quad(ctx, shade, &ref[i], &ref[i+1], &buf[i+1], &buf[i]); memcpy(ref, buf, p.vprow * sizeof(struct vertex)); first = 0; } fz_free(ctx, ref); fz_free(ctx, buf); fz_close(stream); }
/* SumatraPDF: provide a bullet fallback font */ static pdf_font_desc * pdf_load_bullet_font(fz_context *ctx) { pdf_font_desc *fontdesc = pdf_new_font_desc(ctx); int gid, i; fz_try(ctx) { pdf_load_builtin_font(ctx, fontdesc, "Symbol"); fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); fontdesc->cid_to_gid_len = 256; fontdesc->cid_to_gid = fz_malloc_array(ctx, 256, sizeof(unsigned short)); gid = FT_Get_Name_Index(fontdesc->font->ft_face, "bullet"); for (i = 0; i < 256; i++) fontdesc->cid_to_gid[i] = gid; pdf_set_default_hmtx(ctx, fontdesc, ft_width(ctx, fontdesc, 0)); } fz_catch(ctx) { pdf_drop_font(ctx, fontdesc); fz_rethrow(ctx); } return fontdesc; }
pdf_obj * pdf_new_array(fz_context *ctx, int initialcap) { pdf_obj *obj; int i; obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj)), "pdf_obj(array)"); obj->ctx = ctx; obj->refs = 1; obj->kind = PDF_ARRAY; obj->u.a.len = 0; obj->u.a.cap = initialcap > 1 ? initialcap : 6; fz_try(ctx) { obj->u.a.items = Memento_label(fz_malloc_array(ctx, obj->u.a.cap, sizeof(pdf_obj*)), "pdf_obj(array items)"); } fz_catch(ctx) { fz_free(ctx, obj); fz_rethrow(ctx); } for (i = 0; i < obj->u.a.cap; i++) obj->u.a.items[i] = NULL; return obj; }
pdf_obj * pdf_new_dict(fz_context *ctx, pdf_document *doc, int initialcap) { pdf_obj_dict *obj; int i; obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj_dict)), "pdf_obj(dict)"); obj->super.refs = 1; obj->super.kind = PDF_DICT; obj->super.flags = 0; obj->doc = doc; obj->parent_num = 0; obj->len = 0; obj->cap = initialcap > 1 ? initialcap : 10; fz_try(ctx) { DICT(obj)->items = Memento_label(fz_malloc_array(ctx, DICT(obj)->cap, sizeof(struct keyval)), "pdf_obj(dict items)"); } fz_catch(ctx) { fz_free(ctx, obj); fz_rethrow(ctx); } for (i = 0; i < DICT(obj)->cap; i++) { DICT(obj)->items[i].k = NULL; DICT(obj)->items[i].v = NULL; } return &obj->super; }
static void split_block(fz_context *ctx, fz_text_page *page, int blocknum, int linenum) { int split_len; if (page->len == page->cap) { int new_cap = fz_maxi(16, page->cap * 2); page->blocks = fz_resize_array(ctx, page->blocks, new_cap, sizeof(*page->blocks)); page->cap = new_cap; } memmove(page->blocks+blocknum+1, page->blocks+blocknum, (page->len - blocknum)*sizeof(*page->blocks)); page->len++; split_len = page->blocks[blocknum].len - linenum; page->blocks[blocknum+1].bbox = page->blocks[blocknum].bbox; /* FIXME! */ page->blocks[blocknum+1].cap = 0; page->blocks[blocknum+1].len = 0; page->blocks[blocknum+1].lines = NULL; page->blocks[blocknum+1].lines = fz_malloc_array(ctx, split_len, sizeof(fz_text_line)); page->blocks[blocknum+1].cap = page->blocks[blocknum+1].len; page->blocks[blocknum+1].len = split_len; page->blocks[blocknum].len = linenum; memcpy(page->blocks[blocknum+1].lines, page->blocks[blocknum].lines + linenum, split_len * sizeof(fz_text_line)); }
pdf_obj * pdf_new_dict(fz_context *ctx, int initialcap) { pdf_obj *obj; int i; obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj)), "pdf_obj(dict)"); obj->ctx = ctx; obj->refs = 1; obj->kind = PDF_DICT; obj->u.d.sorted = 0; obj->u.d.marked = 0; obj->u.d.len = 0; obj->u.d.cap = initialcap > 1 ? initialcap : 10; fz_try(ctx) { obj->u.d.items = Memento_label(fz_malloc_array(ctx, obj->u.d.cap, sizeof(struct keyval)), "pdf_obj(dict items)"); } fz_catch(ctx) { fz_free(ctx, obj); fz_rethrow(ctx); } for (i = 0; i < obj->u.d.cap; i++) { obj->u.d.items[i].k = NULL; obj->u.d.items[i].v = NULL; } return obj; }
pdf_obj * pdf_new_array(fz_context *ctx, pdf_document *doc, int initialcap) { pdf_obj_array *obj; int i; obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj_array)), "pdf_obj(array)"); obj->super.refs = 1; obj->super.kind = PDF_ARRAY; obj->super.flags = 0; obj->doc = doc; obj->parent_num = 0; obj->len = 0; obj->cap = initialcap > 1 ? initialcap : 6; fz_try(ctx) { obj->items = Memento_label(fz_malloc_array(ctx, obj->cap, sizeof(pdf_obj*)), "pdf_obj(array items)"); } fz_catch(ctx) { fz_free(ctx, obj); fz_rethrow(ctx); } for (i = 0; i < obj->cap; i++) obj->items[i] = NULL; return &obj->super; }
static void cbz_create_page_list(fz_context *ctx, cbz_document *doc) { fz_archive *arch = doc->arch; int i, k, count; count = fz_count_archive_entries(ctx, arch); doc->page_count = 0; doc->page = fz_malloc_array(ctx, count, sizeof *doc->page); for (i = 0; i < count; i++) { const char *name = fz_list_archive_entry(ctx, arch, i); const char *ext = name ? strrchr(name, '.') : NULL; for (k = 0; cbz_ext_list[k]; k++) { if (ext && !fz_strcasecmp(ext, cbz_ext_list[k])) { doc->page[doc->page_count++] = name; break; } } } qsort((char **)doc->page, doc->page_count, sizeof *doc->page, cbz_compare_page_names); }
static void cbz_create_page_list(cbz_document *doc) { fz_context *ctx = doc->ctx; fz_archive *zip = doc->zip; int i, k, count; count = fz_count_archive_entries(ctx, zip); doc->page_count = 0; doc->page = fz_malloc_array(ctx, count, sizeof *doc->page); for (i = 0; i < count; i++) { for (k = 0; cbz_ext_list[k]; k++) { const char *name = fz_list_archive_entry(ctx, zip, i); if (strstr(name, cbz_ext_list[k])) { doc->page[doc->page_count++] = name; printf("found page %d = '%s'\n", i, name); break; } } } qsort((char **)doc->page, doc->page_count, sizeof *doc->page, cbz_compare_page_names); for (i = 0; i < doc->page_count; ++i) printf(" %d = %s\n", i, doc->page[i]); }
static void split_block(fz_context *ctx, fz_text_page *page, int block_num, int linenum) { int split_len; fz_text_block *block, *block2; if (page->len == page->cap) { int new_cap = fz_maxi(16, page->cap * 2); page->blocks = fz_resize_array(ctx, page->blocks, new_cap, sizeof(*page->blocks)); page->cap = new_cap; } memmove(page->blocks+block_num+1, page->blocks+block_num, (page->len - block_num)*sizeof(*page->blocks)); page->len++; block2 = fz_malloc_struct(ctx, fz_text_block); block = page->blocks[block_num].u.text; page->blocks[block_num+1].type = FZ_PAGE_BLOCK_TEXT; page->blocks[block_num+1].u.text = block2; split_len = block->len - linenum; block2->bbox = block->bbox; /* FIXME! */ block2->cap = 0; block2->len = 0; block2->lines = NULL; block2->lines = fz_malloc_array(ctx, split_len, sizeof(fz_text_line)); block2->cap = block2->len; block2->len = split_len; block->len = linenum; memcpy(block2->lines, block->lines + linenum, split_len * sizeof(fz_text_line)); block2->lines[0].distance = 0; }
static fz_font * fz_new_font(fz_context *ctx, char *name, int use_glyph_bbox, int glyph_count) { fz_font *font; int i; font = fz_malloc_struct(ctx, fz_font); font->refs = 1; if (name) fz_strlcpy(font->name, name, sizeof font->name); else fz_strlcpy(font->name, "(null)", sizeof font->name); font->ft_face = NULL; font->ft_substitute = 0; font->ft_bold = 0; font->ft_italic = 0; font->ft_hint = 0; font->ft_file = NULL; font->ft_data = NULL; font->ft_size = 0; font->t3matrix = fz_identity; font->t3resources = NULL; font->t3procs = NULL; font->t3lists = NULL; font->t3widths = NULL; font->t3flags = NULL; font->t3doc = NULL; font->t3run = NULL; font->bbox.x0 = 0; font->bbox.y0 = 0; font->bbox.x1 = 1; font->bbox.y1 = 1; font->use_glyph_bbox = use_glyph_bbox; if (use_glyph_bbox && glyph_count <= MAX_BBOX_TABLE_SIZE) { font->bbox_count = glyph_count; font->bbox_table = fz_malloc_array(ctx, glyph_count, sizeof(fz_rect)); for (i = 0; i < glyph_count; i++) font->bbox_table[i] = fz_infinite_rect; } else { if (use_glyph_bbox) fz_warn(ctx, "not building glyph bbox table for font '%s' with %d glyphs", font->name, glyph_count); font->bbox_count = 0; font->bbox_table = NULL; } font->width_count = 0; font->width_table = NULL; return font; }
static fz_colorspace * load_indexed(pdf_document *doc, pdf_obj *array) { fz_context *ctx = doc->ctx; pdf_obj *baseobj = pdf_array_get(array, 1); pdf_obj *highobj = pdf_array_get(array, 2); pdf_obj *lookupobj = pdf_array_get(array, 3); fz_colorspace *base = NULL; fz_colorspace *cs; int i, n, high; unsigned char *lookup = NULL; fz_var(base); fz_var(lookup); fz_try(ctx) { base = pdf_load_colorspace(doc, baseobj); high = pdf_to_int(highobj); high = fz_clampi(high, 0, 255); n = base->n * (high + 1); lookup = fz_malloc_array(ctx, 1, n); if (pdf_is_string(lookupobj) && pdf_to_str_len(lookupobj) >= n) { unsigned char *buf = (unsigned char *) pdf_to_str_buf(lookupobj); for (i = 0; i < n; i++) lookup[i] = buf[i]; } else if (pdf_is_indirect(lookupobj)) { fz_stream *file = NULL; fz_var(file); fz_try(ctx) { file = pdf_open_stream(doc, pdf_to_num(lookupobj), pdf_to_gen(lookupobj)); i = fz_read(file, lookup, n); if (i < n) memset(lookup+i, 0, n-i); } fz_always(ctx) { fz_close(file); } fz_catch(ctx) { fz_rethrow_message(ctx, "cannot open colorspace lookup table (%d 0 R)", pdf_to_num(lookupobj)); } } else { fz_rethrow_message(ctx, "cannot parse colorspace lookup table"); } cs = fz_new_indexed_colorspace(ctx, base, high, lookup); }
int fz_pack_path(fz_context *ctx, uint8_t *pack_, int max, const fz_path *path) { uint8_t *ptr; int size; if (path->packed) fz_throw(ctx, FZ_ERROR_GENERIC, "Can't repack a packed path"); size = sizeof(fz_packed_path) + sizeof(float) * path->coord_len + sizeof(uint8_t) * path->cmd_len; /* If the path can't be packed flat, then pack it open */ if (path->cmd_len > 255 || path->coord_len > 255 || size > max) { fz_path *pack = (fz_path *)pack_; if (sizeof(fz_path) > max) fz_throw(ctx, FZ_ERROR_GENERIC, "Can't pack a path that small!"); if (pack != NULL) { pack->refs = 1; pack->packed = FZ_PATH_PACKED_OPEN; pack->current.x = 0; pack->current.y = 0; pack->begin.x = 0; pack->begin.y = 0; pack->coord_cap = path->coord_len; pack->coord_len = path->coord_len; pack->cmd_cap = path->cmd_len; pack->cmd_len = path->cmd_len; pack->coords = fz_malloc_array(ctx, path->coord_len, sizeof(float)); fz_try(ctx) { pack->cmds = fz_malloc_array(ctx, path->cmd_len, sizeof(uint8_t)); } fz_catch(ctx) { fz_free(ctx, pack->coords); fz_rethrow(ctx); } memcpy(pack->coords, path->coords, sizeof(float) * path->coord_len); memcpy(pack->cmds, path->cmds, sizeof(uint8_t) * path->cmd_len); }
static void renumberobjs(void) { pdf_xref_entry *oldxref; int newlen; int num; /* Apply renumber map to indirect references in all objects in xref */ renumberobj(xref->trailer); for (num = 0; num < xref->len; num++) { fz_obj *obj = xref->table[num].obj; if (fz_is_indirect(obj)) { obj = fz_new_indirect(ctx, renumbermap[fz_to_num(obj)], 0, xref); pdf_update_object(xref, num, 0, obj); fz_drop_obj(obj); } else { renumberobj(obj); } } /* Create new table for the reordered, compacted xref */ oldxref = xref->table; xref->table = fz_malloc_array(xref->ctx, xref->len, sizeof(pdf_xref_entry)); xref->table[0] = oldxref[0]; /* Move used objects into the new compacted xref */ newlen = 0; for (num = 1; num < xref->len; num++) { if (uselist[num]) { if (newlen < renumbermap[num]) newlen = renumbermap[num]; xref->table[renumbermap[num]] = oldxref[num]; } else { if (oldxref[num].obj) fz_drop_obj(oldxref[num].obj); } } fz_free(xref->ctx, oldxref); /* Update the used objects count in compacted xref */ xref->len = newlen + 1; /* Update list of used objects to fit with compacted xref */ for (num = 1; num < xref->len; num++) uselist[num] = 1; }
static void *alloc(void *ud, void *ptr, unsigned int n) { fz_context *ctx = ud; if (n == 0) { fz_free(ctx, ptr); return NULL; } if (ptr) return fz_resize_array(ctx, ptr, n, 1); return fz_malloc_array(ctx, n, 1); }
fz_pixmap * fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, unsigned char *samples) { fz_pixmap *pix; pix = fz_malloc_struct(ctx, fz_pixmap); FZ_INIT_STORABLE(pix, 1, fz_free_pixmap_imp); pix->x = 0; pix->y = 0; pix->w = w; pix->h = h; pix->interpolate = 1; pix->xres = 96; pix->yres = 96; pix->colorspace = NULL; pix->n = 1; pix->has_alpha = 1; /* SumatraPDF: allow optimizing non-alpha pixmaps */ pix->single_bit = 0; /* SumatraPDF: allow optimizing 1-bit pixmaps */ if (colorspace) { pix->colorspace = fz_keep_colorspace(ctx, colorspace); pix->n = 1 + colorspace->n; } pix->samples = samples; if (samples) { pix->free_samples = 0; } else { fz_try(ctx) { if (pix->w + pix->n - 1 > INT_MAX / pix->n) fz_throw(ctx, "overly wide image"); pix->samples = fz_malloc_array(ctx, pix->h, pix->w * pix->n); } fz_catch(ctx) { if (colorspace) fz_drop_colorspace(ctx, colorspace); fz_free(ctx, pix); fz_rethrow(ctx); } pix->free_samples = 1; } return pix; }
static void ch_dialog(void) { const char *label; const char *value; const char **options; int n, choice; int label_h; label = pdf_field_label(ctx, ch_widget->obj); label_h = ui_break_lines((char*)label, NULL, 20, 394, NULL); n = pdf_choice_widget_options(ctx, ch_widget->page->doc, ch_widget, 0, NULL); options = fz_malloc_array(ctx, n, sizeof(char*)); pdf_choice_widget_options(ctx, ch_widget->page->doc, ch_widget, 0, options); value = pdf_field_value(ctx, ch_widget->obj); ui_dialog_begin(400, (ui.gridsize+4)*3 + ui.lineheight*(label_h-1)); { ui_layout(T, X, NW, 2, 2); ui_label("%s", label); choice = ui_select("Widget/Ch", value, options, n); if (choice >= 0) pdf_set_choice_field_value(ctx, ch_widget, options[choice]); ui_layout(B, X, NW, 2, 2); ui_panel_begin(0, ui.gridsize, 0, 0, 0); { ui_layout(R, NONE, S, 0, 0); if (ui_button("Cancel") || (!ui.focus && ui.key == KEY_ESCAPE)) ui.dialog = NULL; ui_spacer(); if (ui_button("Okay")) { if (pdf_update_page(ctx, ch_widget->page)) render_page(); ui.dialog = NULL; } } ui_panel_end(); } ui_dialog_end(); fz_free(ctx, options); }
fz_bitmap * fz_new_bitmap(fz_context *ctx, int w, int h, int n, int xres, int yres) { fz_bitmap *bit; bit = fz_malloc_struct(ctx, fz_bitmap); bit->refs = 1; bit->w = w; bit->h = h; bit->n = n; bit->xres = xres; bit->yres = yres; /* Span is 32 bit aligned. We may want to make this 64 bit if we * use SSE2 etc. */ bit->stride = ((n * w + 31) & ~31) >> 3; bit->samples = fz_malloc_array(ctx, h, bit->stride); return bit; }
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_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; }
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 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; }
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->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) */ /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1980 */ if (in_line && 0) { 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->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->bpc) - 1); conv = pdf_expand_indexed_pixmap(ctx, tile); fz_drop_pixmap(ctx, tile); tile = conv; } else { fz_decode_tile(tile, image->decode); } }
static fz_colorspace * load_indexed(pdf_document *xref, pdf_obj *array) { struct indexed *idx = NULL; fz_context *ctx = xref->ctx; pdf_obj *baseobj = pdf_array_get(array, 1); pdf_obj *highobj = pdf_array_get(array, 2); pdf_obj *lookup = pdf_array_get(array, 3); fz_colorspace *base = NULL; fz_colorspace *cs = NULL; int i, n; fz_var(idx); fz_var(base); fz_var(cs); fz_try(ctx) { base = pdf_load_colorspace(xref, baseobj); /* "cannot load base colorspace (%d %d R)", pdf_to_num(baseobj), pdf_to_gen(baseobj) */ idx = fz_malloc_struct(ctx, struct indexed); idx->lookup = NULL; idx->base = base; idx->high = pdf_to_int(highobj); idx->high = CLAMP(idx->high, 0, 255); n = base->n * (idx->high + 1); idx->lookup = fz_malloc_array(ctx, 1, n); cs = fz_new_colorspace(ctx, "Indexed", 1); cs->to_rgb = indexed_to_rgb; cs->free_data = free_indexed; cs->data = idx; cs->size += sizeof(*idx) + n + (base ? base->size : 0); if (pdf_is_string(lookup) && pdf_to_str_len(lookup) == n) { unsigned char *buf = (unsigned char *) pdf_to_str_buf(lookup); for (i = 0; i < n; i++) idx->lookup[i] = buf[i]; } else if (pdf_is_indirect(lookup)) { fz_stream *file = NULL; fz_try(ctx) { file = pdf_open_stream(xref, pdf_to_num(lookup), pdf_to_gen(lookup)); } fz_catch(ctx) { fz_throw(ctx, "cannot open colorspace lookup table (%d 0 R)", pdf_to_num(lookup)); } i = fz_read(file, idx->lookup, n); if (i < 0) { fz_close(file); fz_throw(ctx, "cannot read colorspace lookup table (%d 0 R)", pdf_to_num(lookup)); } fz_close(file); } else { fz_throw(ctx, "cannot parse colorspace lookup table"); } }