void pdf_add_annot_quad_point(fz_context *ctx, pdf_annot *annot, fz_rect bbox) { pdf_document *doc = annot->page->doc; fz_matrix page_ctm, inv_page_ctm; pdf_obj *quad_points; check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes); pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); quad_points = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints)); if (!pdf_is_array(ctx, quad_points)) { quad_points = pdf_new_array(ctx, doc, 8); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(QuadPoints), quad_points); } /* Contrary to the specification, the points within a QuadPoint are NOT ordered * in a counterclockwise fashion. Experiments with Adobe's implementation * indicates a cross-wise ordering is intended: ul, ur, ll, lr. */ fz_transform_rect(&bbox, &inv_page_ctm); pdf_array_push_real(ctx, quad_points, bbox.x0); /* ul */ pdf_array_push_real(ctx, quad_points, bbox.y1); pdf_array_push_real(ctx, quad_points, bbox.x1); /* ur */ pdf_array_push_real(ctx, quad_points, bbox.y1); pdf_array_push_real(ctx, quad_points, bbox.x0); /* ll */ pdf_array_push_real(ctx, quad_points, bbox.y0); pdf_array_push_real(ctx, quad_points, bbox.x1); /* lr */ pdf_array_push_real(ctx, quad_points, bbox.y0); pdf_dirty_annot(ctx, annot); }
void pdf_set_annot_ink_list(fz_context *ctx, pdf_annot *annot, int n, const int *count, const float *v) { pdf_document *doc = annot->page->doc; fz_matrix page_ctm, inv_page_ctm; pdf_obj *ink_list, *stroke; fz_point point; int i, k; if (pdf_annot_type(ctx, annot) != PDF_ANNOT_INK) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot set InkList on non-ink annotations"); pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); // TODO: update Rect (in update appearance perhaps?) ink_list = pdf_new_array(ctx, doc, n); for (i = 0; i < n; ++i) { stroke = pdf_new_array(ctx, doc, count[i]); for (k = 0; k < count[i]; ++k) { point.x = *v++; point.y = *v++; fz_transform_point(&point, &inv_page_ctm); pdf_array_push_drop(ctx, stroke, pdf_new_real(ctx, doc, point.x)); pdf_array_push_drop(ctx, stroke, pdf_new_real(ctx, doc, point.y)); } pdf_array_push_drop(ctx, ink_list, stroke); } pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_InkList, ink_list); annot->changed = 1; }
void render_page(void) { fz_annot *annot; fz_pixmap *pix; fz_scale(&page_ctm, currentzoom / 72, currentzoom / 72); fz_pre_rotate(&page_ctm, -currentrotate); fz_invert_matrix(&page_inv_ctm, &page_ctm); fz_drop_page(ctx, page); page = fz_load_page(ctx, doc, currentpage); fz_drop_link(ctx, links); links = NULL; links = fz_load_links(ctx, page); pix = fz_new_pixmap_from_page_contents(ctx, page, &page_ctm, fz_device_rgb(ctx), 0); texture_from_pixmap(&page_tex, pix); fz_drop_pixmap(ctx, pix); annot_count = 0; for (annot = fz_first_annot(ctx, page); annot; annot = fz_next_annot(ctx, annot)) { pix = fz_new_pixmap_from_annot(ctx, annot, &page_ctm, fz_device_rgb(ctx), 1); texture_from_pixmap(&annot_tex[annot_count++], pix); fz_drop_pixmap(ctx, pix); if (annot_count >= nelem(annot_tex)) { fz_warn(ctx, "too many annotations to display!"); break; } } }
void pdf_set_annot_ink_list(fz_context *ctx, pdf_annot *annot, int n, const int *count, const float *v) { pdf_document *doc = annot->page->doc; fz_matrix page_ctm, inv_page_ctm; pdf_obj *ink_list, *stroke; fz_point point; int i, k; check_allowed_subtypes(ctx, annot, PDF_NAME_InkList, ink_list_subtypes); pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); // TODO: update Rect (in update appearance perhaps?) ink_list = pdf_new_array(ctx, doc, n); for (i = 0; i < n; ++i) { stroke = pdf_new_array(ctx, doc, count[i]); for (k = 0; k < count[i]; ++k) { point.x = *v++; point.y = *v++; fz_transform_point(&point, &inv_page_ctm); pdf_array_push_drop(ctx, stroke, pdf_new_real(ctx, doc, point.x)); pdf_array_push_drop(ctx, stroke, pdf_new_real(ctx, doc, point.y)); } pdf_array_push_drop(ctx, ink_list, stroke); } pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_InkList, ink_list); annot->changed = 1; }
void pdf_set_annot_vertices(fz_context *ctx, pdf_annot *annot, int n, const float *v) { pdf_document *doc = annot->page->doc; fz_matrix page_ctm, inv_page_ctm; pdf_obj *vertices; fz_point point; int i; check_allowed_subtypes(ctx, annot, PDF_NAME_Vertices, vertices_subtypes); if (n <= 0 || !v) fz_throw(ctx, FZ_ERROR_GENERIC, "invalid number of vertices"); pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); vertices = pdf_new_array(ctx, doc, n * 2); for (i = 0; i < n; ++i) { point.x = v[i * 2]; point.y = v[i * 2 + 1]; fz_transform_point(&point, &inv_page_ctm); pdf_array_push_drop(ctx, vertices, pdf_new_real(ctx, doc, point.x)); pdf_array_push_drop(ctx, vertices, pdf_new_real(ctx, doc, point.y)); } pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_Vertices, vertices); annot->changed = 1; }
void pdf_set_annot_quad_points(fz_context *ctx, pdf_annot *annot, int n, const float *v) { pdf_document *doc = annot->page->doc; fz_matrix page_ctm, inv_page_ctm; pdf_obj *quad_points; fz_point point; int i, k; check_allowed_subtypes(ctx, annot, PDF_NAME_QuadPoints, quad_point_subtypes); if (n <= 0 || !v) fz_throw(ctx, FZ_ERROR_GENERIC, "invalid number of quadrilaterals"); pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); quad_points = pdf_new_array(ctx, doc, n * 8); for (i = 0; i < n; ++i) { for (k = 0; k < 4; ++k) { point.x = v[i * 8 + k * 2 + 0]; point.y = v[i * 8 + k * 2 + 1]; fz_transform_point(&point, &inv_page_ctm); pdf_array_push_drop(ctx, quad_points, pdf_new_real(ctx, doc, point.x)); pdf_array_push_drop(ctx, quad_points, pdf_new_real(ctx, doc, point.y)); } } pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_QuadPoints, quad_points); annot->changed = 1; }
void pdf_set_annot_quad_points(fz_context *ctx, pdf_annot *annot, int n, const float *v) { pdf_document *doc = annot->page->doc; fz_matrix page_ctm, inv_page_ctm; pdf_obj *quad_points; fz_point point; int i, k; // TODO: check annot type pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); quad_points = pdf_new_array(ctx, doc, n * 8); for (i = 0; i < n; ++i) { for (k = 0; k < 4; ++k) { point.x = v[i * 8 + k * 2 + 0]; point.y = v[i * 8 + k * 2 + 1]; fz_transform_point(&point, &inv_page_ctm); pdf_array_push_drop(ctx, quad_points, pdf_new_real(ctx, doc, point.x)); pdf_array_push_drop(ctx, quad_points, pdf_new_real(ctx, doc, point.y)); } } pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_QuadPoints, quad_points); annot->changed = 1; }
static void svg_dev_text(svg_device *sdev, const fz_matrix *ctm, fz_text *text) { fz_output *out = sdev->out; int i; fz_matrix inverse; fz_matrix local_trm; float size; /* Rely on the fact that trm.{e,f} == 0 */ size = fz_matrix_expansion(&text->trm); local_trm.a = text->trm.a / size; local_trm.b = text->trm.b / size; local_trm.c = -text->trm.c / size; local_trm.d = -text->trm.d / size; local_trm.e = 0; local_trm.f = 0; fz_invert_matrix(&inverse, &local_trm); fz_concat(&local_trm, &local_trm, ctm); fz_printf(out, " transform=\"matrix(%g,%g,%g,%g,%g,%g)\"", local_trm.a, local_trm.b, local_trm.c, local_trm.d, local_trm.e, local_trm.f); fz_printf(out, " font-size=\"%g\"", size); fz_printf(out, " font-family=\"%s\"", text->font->name); fz_printf(out, " x="); for (i=0; i < text->len; i++) { fz_text_item *it = &text->items[i]; fz_point p; p.x = it->x; p.y = it->y; fz_transform_point(&p, &inverse); fz_printf(out, "%c%g", i == 0 ? '\"' : ' ', p.x); } fz_printf(out, "\" y="); for (i=0; i < text->len; i++) { fz_text_item *it = &text->items[i]; fz_point p; p.x = it->x; p.y = it->y; fz_transform_point(&p, &inverse); fz_printf(out, "%c%g", i == 0 ? '\"' : ' ', p.y); } fz_printf(out, "\">\n"); for (i=0; i < text->len; i++) { fz_text_item *it = &text->items[i]; int c = it->ucs; if (c >= 32 && c <= 127 && c != '<' && c != '&') fz_printf(out, "%c", c); else fz_printf(out, "&#x%04x;", c); } fz_printf(out, "\n</text>\n"); }
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); } }
static void pdf_dev_ctm(fz_context *ctx, pdf_device *pdev, fz_matrix ctm) { fz_matrix inverse; gstate *gs = CURRENT_GSTATE(pdev); if (memcmp(&gs->ctm, &ctm, sizeof(ctm)) == 0) return; inverse = fz_invert_matrix(gs->ctm); inverse = fz_concat(ctm, inverse); gs->ctm = ctm; fz_append_printf(ctx, gs->buf, "%M cm\n", &inverse); }
void pdf_set_annot_rect(fz_context *ctx, pdf_annot *annot, const fz_rect *rect) { fz_rect trect = *rect; fz_matrix page_ctm, inv_page_ctm; pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); fz_transform_rect(&trect, &inv_page_ctm); pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(Rect), &trect); pdf_dirty_annot(ctx, annot); }
static void pdf_dev_ctm(fz_context *ctx, pdf_device *pdev, const fz_matrix *ctm) { fz_matrix inverse; gstate *gs = CURRENT_GSTATE(pdev); if (memcmp(&gs->ctm, ctm, sizeof(*ctm)) == 0) return; fz_invert_matrix(&inverse, &gs->ctm); fz_concat(&inverse, ctm, &inverse); gs->ctm = *ctm; fz_buffer_printf(ctx, gs->buf, "%M cm\n", &inverse); }
static int svg_dev_begin_tile(fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id) { svg_device *sdev = (svg_device *)dev->user; fz_output *out = sdev->out; fz_context *ctx = dev->ctx; fz_matrix inverse; int num; tile *t; if (sdev->num_tiles == sdev->max_tiles) { int n = (sdev->num_tiles == 0 ? 4 : sdev->num_tiles * 2); sdev->tiles = fz_resize_array(ctx, sdev->tiles, n, sizeof(tile)); sdev->max_tiles = n; } num = sdev->num_tiles++; t = &sdev->tiles[num]; t->area = *area; t->view = *view; t->ctm = *ctm; t->pattern = sdev->id++; t->step.x = xstep; t->step.y = ystep; /* view = area of our reference tile in pattern space. * area = area to tile into in pattern space. * xstep/ystep = pattern repeat step in pattern space. * All of these need to be transformed by ctm to get to device space. * SVG only allows us to specify pattern tiles as axis aligned * rectangles, so we send these through as is, and ensure that the * correct matrix is used on the fill. */ /* In svg, the reference tile is taken from (x,y) to (x+width,y+height) * and is repeated at (x+n*width,y+m*height) for all integer n and m. * This means that width and height correspond to xstep and ystep. */ fz_printf(out, "<pattern id=\"pa%d\" patternUnits=\"userSpaceOnUse\" patternContentUnits=\"userSpaceOnUse\"", t->pattern); fz_printf(out, " x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\">\n", view->x0, view->y0, xstep, ystep); /* All the pattern contents will have their own ctm applied. Let's * undo the current one to allow for this */ fz_invert_matrix(&inverse, ctm); fz_printf(out, "<g"); svg_dev_ctm(sdev, &inverse); fz_printf(out, ">\n"); return 0; }
JNIEXPORT int JNICALL Java_com_artifex_mupdf_MuPDFCore_passClickEventInternal(JNIEnv * env, jobject thiz, int pageNumber, float x, float y) { fz_matrix ctm; fz_interactive *idoc = fz_interact(doc); float zoom; fz_point p; fz_ui_event event; int changed = 0; page_cache *pc; if (idoc == NULL) return 0; Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(env, thiz, pageNumber); pc = &pages[current]; if (pc->number != pageNumber || pc->page == NULL) return 0; p.x = x; p.y = y; /* Ultimately we should probably return a pointer to a java structure * with the link details in, but for now, page number will suffice. */ zoom = resolution / 72; ctm = fz_scale(zoom, zoom); ctm = fz_invert_matrix(ctm); p = fz_transform_point(ctm, p); fz_try(ctx) { event.etype = FZ_EVENT_TYPE_POINTER; event.event.pointer.pt = p; event.event.pointer.ptype = FZ_POINTER_DOWN; changed = fz_pass_event(idoc, pc->page, &event); event.event.pointer.ptype = FZ_POINTER_UP; changed |= fz_pass_event(idoc, pc->page, &event); if (changed) { dump_annotation_display_lists(); } } fz_catch(ctx) { LOGE("passClickEvent: %s", ctx->error->message); } return changed; }
void pdf_set_annot_rect(fz_context *ctx, pdf_annot *annot, const fz_rect *rect) { pdf_document *doc = annot->page->doc; fz_rect trect = *rect; fz_matrix page_ctm, inv_page_ctm; pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); fz_transform_rect(&trect, &inv_page_ctm); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_Rect, pdf_new_rect(ctx, doc, &trect)); annot->changed = 1; }
void pdf_set_annot_vertex(fz_context *ctx, pdf_annot *annot, int i, fz_point p) { fz_matrix page_ctm, inv_page_ctm; pdf_obj *vertices; check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes); pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); fz_transform_point(&p, &inv_page_ctm); vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices)); pdf_array_put_drop(ctx, vertices, i * 2 + 0, pdf_new_real(ctx, p.x)); pdf_array_put_drop(ctx, vertices, i * 2 + 1, pdf_new_real(ctx, p.y)); }
JNIEXPORT int JNICALL Java_com_artifex_mupdf_MuPDFCore_getPageLink(JNIEnv * env, jobject thiz, int pageNumber, float x, float y) { fz_matrix ctm; float zoom; fz_link *link; fz_point p; page_cache *pc; Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(env, thiz, pageNumber); pc = &pages[current]; if (pc->number != pageNumber || pc->page == NULL) return -1; p.x = x; p.y = y; /* Ultimately we should probably return a pointer to a java structure * with the link details in, but for now, page number will suffice. */ zoom = resolution / 72; ctm = fz_scale(zoom, zoom); ctm = fz_invert_matrix(ctm); p = fz_transform_point(ctm, p); for (link = fz_load_links(doc, pc->page); link; link = link->next) { if (p.x >= link->rect.x0 && p.x <= link->rect.x1) if (p.y >= link->rect.y0 && p.y <= link->rect.y1) break; } if (link == NULL) return -1; if (link->dest.kind == FZ_LINK_URI) { //gotouri(link->dest.ld.uri.uri); return -1; } else if (link->dest.kind == FZ_LINK_GOTO) return link->dest.ld.gotor.page; return -1; }
void pdf_add_annot_ink_list(fz_context *ctx, pdf_annot *annot, int n, fz_point p[]) { pdf_document *doc = annot->page->doc; fz_matrix page_ctm, inv_page_ctm; pdf_obj *ink_list, *stroke; int i; check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes); pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList)); if (!pdf_is_array(ctx, ink_list)) { ink_list = pdf_new_array(ctx, doc, 10); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(InkList), ink_list); } stroke = pdf_new_array(ctx, doc, n * 2); fz_try(ctx) { for (i = 0; i < n; ++i) { fz_point tp = p[i]; fz_transform_point(&tp, &inv_page_ctm); pdf_array_push_real(ctx, stroke, tp.x); pdf_array_push_real(ctx, stroke, tp.y); } } fz_catch(ctx) { pdf_drop_obj(ctx, stroke); fz_rethrow(ctx); } pdf_array_push_drop(ctx, ink_list, stroke); pdf_dirty_annot(ctx, annot); }
void pdf_set_text_annot_position(fz_context *ctx, pdf_document *doc, pdf_annot *annot, fz_point pt) { fz_matrix ctm; fz_rect rect; int flags; fz_invert_matrix(&ctm, &annot->page->ctm); rect.x0 = pt.x; rect.x1 = pt.x + TEXT_ANNOT_SIZE; rect.y0 = pt.y; rect.y1 = pt.y + TEXT_ANNOT_SIZE; fz_transform_rect(&rect, &ctm); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_Rect, pdf_new_rect(ctx, doc, &rect)); flags = pdf_to_int(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME_F)); flags |= (F_NoZoom|F_NoRotate); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_F, pdf_new_int(ctx, doc, flags)); update_rect(ctx, annot); }
void pdf_set_text_annot_position(fz_context *ctx, pdf_annot *annot, fz_point pt) { fz_matrix page_ctm, inv_page_ctm; fz_rect rect; int flags; pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); rect.x0 = pt.x; rect.x1 = pt.x + TEXT_ANNOT_SIZE; rect.y0 = pt.y; rect.y1 = pt.y + TEXT_ANNOT_SIZE; fz_transform_rect(&rect, &inv_page_ctm); pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(Rect), &rect); flags = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F)); flags |= (PDF_ANNOT_IS_NO_ZOOM|PDF_ANNOT_IS_NO_ROTATE); pdf_dict_put_int(ctx, annot->obj, PDF_NAME(F), flags); }
void pdf_set_text_annot_position(fz_context *ctx, pdf_annot *annot, fz_point pt) { pdf_document *doc = annot->page->doc; fz_matrix page_ctm, inv_page_ctm; fz_rect rect; int flags; pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); rect.x0 = pt.x; rect.x1 = pt.x + TEXT_ANNOT_SIZE; rect.y0 = pt.y; rect.y1 = pt.y + TEXT_ANNOT_SIZE; fz_transform_rect(&rect, &inv_page_ctm); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_Rect, pdf_new_rect(ctx, doc, &rect)); flags = pdf_to_int(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME_F)); flags |= (PDF_ANNOT_IS_NO_ZOOM|PDF_ANNOT_IS_NO_ROTATE); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_F, pdf_new_int(ctx, doc, flags)); }
void pdf_set_annot_line(fz_context *ctx, pdf_annot *annot, fz_point a, fz_point b) { fz_matrix page_ctm, inv_page_ctm; pdf_obj *line; check_allowed_subtypes(ctx, annot, PDF_NAME(L), line_subtypes); pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); fz_transform_point(&a, &inv_page_ctm); fz_transform_point(&b, &inv_page_ctm); line = pdf_new_array(ctx, annot->page->doc, 4); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(L), line); pdf_array_push_real(ctx, line, a.x); pdf_array_push_real(ctx, line, a.y); pdf_array_push_real(ctx, line, b.x); pdf_array_push_real(ctx, line, b.y); pdf_dirty_annot(ctx, annot); }
void pdf_set_markup_annot_quadpoints(fz_context *ctx, pdf_document *doc, pdf_annot *annot, fz_point *qp, int n) { fz_matrix ctm; pdf_obj *arr = pdf_new_array(ctx, doc, n*2); int i; fz_invert_matrix(&ctm, &annot->page->ctm); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_QuadPoints, arr); for (i = 0; i < n; i++) { fz_point pt = qp[i]; pdf_obj *r; fz_transform_point(&pt, &ctm); r = pdf_new_real(ctx, doc, pt.x); pdf_array_push_drop(ctx, arr, r); r = pdf_new_real(ctx, doc, pt.y); pdf_array_push_drop(ctx, arr, r); } }
void pdf_add_annot_vertex(fz_context *ctx, pdf_annot *annot, fz_point p) { pdf_document *doc = annot->page->doc; fz_matrix page_ctm, inv_page_ctm; pdf_obj *vertices; check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes); pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices)); if (!pdf_is_array(ctx, vertices)) { vertices = pdf_new_array(ctx, doc, 32); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(Vertices), vertices); } fz_transform_point(&p, &inv_page_ctm); pdf_array_push_real(ctx, vertices, p.x); pdf_array_push_real(ctx, vertices, p.y); pdf_dirty_annot(ctx, annot); }
void pdf_set_ink_annot_list(fz_context *ctx, pdf_document *doc, pdf_annot *annot, fz_point *pts, int *counts, int ncount, float color[3], float thickness) { fz_matrix ctm; pdf_obj *list = pdf_new_array(ctx, doc, ncount); pdf_obj *bs, *col; fz_rect rect; int i, k = 0; fz_invert_matrix(&ctm, &annot->page->ctm); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_InkList, list); for (i = 0; i < ncount; i++) { int j; pdf_obj *arc = pdf_new_array(ctx, doc, counts[i]); pdf_array_push_drop(ctx, list, arc); for (j = 0; j < counts[i]; j++) { fz_point pt = pts[k]; fz_transform_point(&pt, &ctm); if (i == 0 && j == 0) { rect.x0 = rect.x1 = pt.x; rect.y0 = rect.y1 = pt.y; } else { fz_include_point_in_rect(&rect, &pt); } pdf_array_push_drop(ctx, arc, pdf_new_real(ctx, doc, pt.x)); pdf_array_push_drop(ctx, arc, pdf_new_real(ctx, doc, pt.y)); k++; } } /* Expand the rectangle by thickness all around. We cannot use fz_expand_rect because the rectangle might be empty in the single point case */ if (k > 0) { rect.x0 -= thickness; rect.y0 -= thickness; rect.x1 += thickness; rect.y1 += thickness; } pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_Rect, pdf_new_rect(ctx, doc, &rect)); update_rect(ctx, annot); bs = pdf_new_dict(ctx, doc, 1); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_BS, bs); pdf_dict_put_drop(ctx, bs, PDF_NAME_W, pdf_new_real(ctx, doc, thickness)); col = pdf_new_array(ctx, doc, 3); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_C, col); for (i = 0; i < 3; i++) pdf_array_push_drop(ctx, col, pdf_new_real(ctx, doc, color[i])); }
static void xps_draw_radial_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, r0; float x1, y1, r1; float xrad = 1; float yrad = 1; float invscale; int i, ma = 1; fz_matrix local_ctm = *ctm; fz_matrix inv; fz_rect local_area = *area; char *center_att = fz_xml_att(root, "Center"); char *origin_att = fz_xml_att(root, "GradientOrigin"); char *radius_x_att = fz_xml_att(root, "RadiusX"); char *radius_y_att = fz_xml_att(root, "RadiusY"); x0 = y0 = 0.0; x1 = y1 = 1.0; xrad = 1.0; yrad = 1.0; if (origin_att) xps_parse_point(ctx, doc, origin_att, &x0, &y0); if (center_att) xps_parse_point(ctx, doc, center_att, &x1, &y1); if (radius_x_att) xrad = fz_atof(radius_x_att); if (radius_y_att) yrad = fz_atof(radius_y_att); xrad = fz_max(0.01f, xrad); yrad = fz_max(0.01f, yrad); /* scale the ctm to make ellipses */ if (fz_abs(xrad) > FLT_EPSILON) { fz_pre_scale(&local_ctm, 1, yrad/xrad); } if (yrad != 0.0) { invscale = xrad / yrad; y0 = y0 * invscale; y1 = y1 * invscale; } r0 = 0; r1 = xrad; fz_transform_rect(&local_area, fz_invert_matrix(&inv, &local_ctm)); ma = fz_maxi(ma, ceilf(hypotf(local_area.x0 - x0, local_area.y0 - y0) / xrad)); ma = fz_maxi(ma, ceilf(hypotf(local_area.x1 - x0, local_area.y0 - y0) / xrad)); ma = fz_maxi(ma, ceilf(hypotf(local_area.x0 - x0, local_area.y1 - y0) / xrad)); ma = fz_maxi(ma, ceilf(hypotf(local_area.x1 - x0, local_area.y1 - y0) / xrad)); if (spread == SPREAD_REPEAT) { for (i = ma - 1; i >= 0; i--) xps_draw_one_radial_gradient(ctx, doc, &local_ctm, stops, count, 0, x0, y0, r0 + i * xrad, x1, y1, r1 + i * xrad); } else if (spread == SPREAD_REFLECT) { if ((ma % 2) != 0) ma++; for (i = ma - 2; i >= 0; i -= 2) { xps_draw_one_radial_gradient(ctx, doc, &local_ctm, stops, count, 0, x0, y0, r0 + i * xrad, x1, y1, r1 + i * xrad); xps_draw_one_radial_gradient(ctx, doc, &local_ctm, stops, count, 0, x0, y0, r0 + (i + 2) * xrad, x1, y1, r1 + i * xrad); } } else { xps_draw_one_radial_gradient(ctx, doc, &local_ctm, stops, count, 1, x0, y0, r0, x1, y1, r1); } }
void xps_parse_tiling_brush(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area, char *base_uri, xps_resource *dict, fz_xml *root, void (*func)(fz_context *ctx, xps_document*, const fz_matrix*, const fz_rect*, char*, xps_resource*, fz_xml*, void*), void *user) { fz_device *dev = doc->dev; fz_xml *node; struct closure c; char *opacity_att; char *transform_att; char *viewbox_att; char *viewport_att; char *tile_mode_att; fz_xml *transform_tag = NULL; fz_matrix transform; fz_rect viewbox; fz_rect viewport; float xstep, ystep; float xscale, yscale; int tile_mode; opacity_att = fz_xml_att(root, "Opacity"); transform_att = fz_xml_att(root, "Transform"); viewbox_att = fz_xml_att(root, "Viewbox"); viewport_att = fz_xml_att(root, "Viewport"); tile_mode_att = fz_xml_att(root, "TileMode"); c.base_uri = base_uri; c.dict = dict; c.root = root; c.user = user; c.func = func; for (node = fz_xml_down(root); node; node = fz_xml_next(node)) { if (fz_xml_is_tag(node, "ImageBrush.Transform")) transform_tag = fz_xml_down(node); if (fz_xml_is_tag(node, "VisualBrush.Transform")) transform_tag = fz_xml_down(node); } xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL); transform = fz_identity; if (transform_att) xps_parse_render_transform(ctx, doc, transform_att, &transform); if (transform_tag) xps_parse_matrix_transform(ctx, doc, transform_tag, &transform); fz_concat(&transform, &transform, ctm); viewbox = fz_unit_rect; if (viewbox_att) xps_parse_rectangle(ctx, doc, viewbox_att, &viewbox); viewport = fz_unit_rect; if (viewport_att) xps_parse_rectangle(ctx, doc, viewport_att, &viewport); if (fabsf(viewport.x1 - viewport.x0) < 0.01f || fabsf(viewport.y1 - viewport.y0) < 0.01f) fz_warn(ctx, "not drawing tile for viewport size %.4f x %.4f", viewport.x1 - viewport.x0, viewport.y1 - viewport.y0); else if (fabsf(viewbox.x1 - viewbox.x0) < 0.01f || fabsf(viewbox.y1 - viewbox.y0) < 0.01f) fz_warn(ctx, "not drawing tile for viewbox size %.4f x %.4f", viewbox.x1 - viewbox.x0, viewbox.y1 - viewbox.y0); /* some sanity checks on the viewport/viewbox size */ if (fabsf(viewport.x1 - viewport.x0) < 0.01f) return; if (fabsf(viewport.y1 - viewport.y0) < 0.01f) return; if (fabsf(viewbox.x1 - viewbox.x0) < 0.01f) return; if (fabsf(viewbox.y1 - viewbox.y0) < 0.01f) return; xstep = viewbox.x1 - viewbox.x0; ystep = viewbox.y1 - viewbox.y0; xscale = (viewport.x1 - viewport.x0) / xstep; yscale = (viewport.y1 - viewport.y0) / ystep; tile_mode = TILE_NONE; if (tile_mode_att) { if (!strcmp(tile_mode_att, "None")) tile_mode = TILE_NONE; if (!strcmp(tile_mode_att, "Tile")) tile_mode = TILE_TILE; if (!strcmp(tile_mode_att, "FlipX")) tile_mode = TILE_FLIP_X; if (!strcmp(tile_mode_att, "FlipY")) tile_mode = TILE_FLIP_Y; if (!strcmp(tile_mode_att, "FlipXY")) tile_mode = TILE_FLIP_X_Y; } if (tile_mode == TILE_FLIP_X || tile_mode == TILE_FLIP_X_Y) xstep *= 2; if (tile_mode == TILE_FLIP_Y || tile_mode == TILE_FLIP_X_Y) ystep *= 2; xps_begin_opacity(ctx, doc, &transform, area, base_uri, dict, opacity_att, NULL); fz_pre_translate(&transform, viewport.x0, viewport.y0); fz_pre_scale(&transform, xscale, yscale); fz_pre_translate(&transform, -viewbox.x0, -viewbox.y0); if (tile_mode != TILE_NONE) { int x0, y0, x1, y1; fz_matrix invctm; fz_rect local_area = *area; fz_transform_rect(&local_area, fz_invert_matrix(&invctm, &transform)); x0 = floorf(local_area.x0 / xstep); y0 = floorf(local_area.y0 / ystep); x1 = ceilf(local_area.x1 / xstep); y1 = ceilf(local_area.y1 / ystep); #ifdef TILE if ((x1 - x0) * (y1 - y0) > 1) #else if (0) #endif { fz_rect bigview = viewbox; bigview.x1 = bigview.x0 + xstep; bigview.y1 = bigview.y0 + ystep; fz_begin_tile(ctx, dev, &local_area, &bigview, xstep, ystep, &transform); xps_paint_tiling_brush(ctx, doc, &transform, &viewbox, tile_mode, &c); fz_end_tile(ctx, dev); } else { int x, y; for (y = y0; y < y1; y++) { for (x = x0; x < x1; x++) { fz_matrix ttm = transform; fz_pre_translate(&ttm, xstep * x, ystep * y); xps_paint_tiling_brush(ctx, doc, &ttm, &viewbox, tile_mode, &c); } } } } else { xps_paint_tiling_brush(ctx, doc, &transform, &viewbox, tile_mode, &c); } xps_end_opacity(ctx, doc, base_uri, dict, opacity_att, NULL); }
void pdf_set_free_text_details(fz_context *ctx, pdf_annot *annot, fz_point *pos, char *text, char *font_name, float font_size, float color[3]) { pdf_document *doc = annot->page->doc; char nbuf[32]; pdf_obj *dr; pdf_obj *form_fonts; pdf_obj *font = NULL; pdf_obj *ref; pdf_font_desc *font_desc = NULL; fz_matrix page_ctm, inv_page_ctm; pdf_da_info da_info; fz_buffer *fzbuf = NULL; fz_point page_pos; pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); dr = pdf_dict_get(ctx, annot->page->obj, PDF_NAME_Resources); if (!dr) { dr = pdf_new_dict(ctx, doc, 1); pdf_dict_put_drop(ctx, annot->page->obj, PDF_NAME_Resources, dr); } /* Ensure the resource dictionary includes a font dict */ form_fonts = pdf_dict_get(ctx, dr, PDF_NAME_Font); if (!form_fonts) { form_fonts = pdf_new_dict(ctx, doc, 1); pdf_dict_put_drop(ctx, dr, PDF_NAME_Font, form_fonts); /* form_fonts is still valid if execution continues past the above call */ } fz_var(fzbuf); fz_var(font); fz_try(ctx) { unsigned char *da_str; size_t da_len; fz_rect bounds; find_free_font_name(ctx, form_fonts, nbuf, sizeof(nbuf)); font = pdf_new_dict(ctx, doc, 5); ref = pdf_add_object(ctx, doc, font); pdf_dict_puts_drop(ctx, form_fonts, nbuf, ref); pdf_dict_put_drop(ctx, font, PDF_NAME_Type, PDF_NAME_Font); pdf_dict_put_drop(ctx, font, PDF_NAME_Subtype, PDF_NAME_Type1); pdf_dict_put_drop(ctx, font, PDF_NAME_BaseFont, pdf_new_name(ctx, doc, font_name)); pdf_dict_put_drop(ctx, font, PDF_NAME_Encoding, PDF_NAME_WinAnsiEncoding); memcpy(da_info.col, color, sizeof(float)*3); da_info.col_size = 3; da_info.font_name = nbuf; da_info.font_size = font_size; fzbuf = fz_new_buffer(ctx, 0); pdf_fzbuf_print_da(ctx, fzbuf, &da_info); da_len = fz_buffer_storage(ctx, fzbuf, &da_str); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_DA, pdf_new_string(ctx, doc, (char *)da_str, da_len)); /* FIXME: should convert to WinAnsiEncoding */ pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_Contents, pdf_new_string(ctx, doc, text, strlen(text))); font_desc = pdf_load_font(ctx, doc, NULL, font, 0); pdf_measure_text(ctx, font_desc, (unsigned char *)text, strlen(text), &bounds); page_pos = *pos; fz_transform_point(&page_pos, &inv_page_ctm); bounds.x0 *= font_size; bounds.x1 *= font_size; bounds.y0 *= font_size; bounds.y1 *= font_size; bounds.x0 += page_pos.x; bounds.x1 += page_pos.x; bounds.y0 += page_pos.y; bounds.y1 += page_pos.y; pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_Rect, pdf_new_rect(ctx, doc, &bounds)); } fz_always(ctx) { pdf_drop_obj(ctx, font); fz_drop_buffer(ctx, fzbuf); pdf_drop_font(ctx, font_desc); } fz_catch(ctx) { fz_rethrow(ctx); } }
static void svg_dev_end_tile(fz_context *ctx, fz_device *dev) { svg_device *sdev = (svg_device*)dev; fz_output *out = sdev->out; int num, cp = -1; tile *t; fz_matrix inverse; float x, y, w, h; if (sdev->num_tiles == 0) return; num = --sdev->num_tiles; t = &sdev->tiles[num]; fz_printf(ctx, out, "</symbol>\n"); /* In svg, the reference tile is taken from (x,y) to (x+width,y+height) * and is repeated at (x+n*width,y+m*height) for all integer n and m. * This means that width and height generally correspond to xstep and * ystep. There are exceptional cases where we have to break this * though; when xstep/ystep are smaller than the width/height of the * pattern tile, we need to render the pattern contents several times * to ensure that the pattern tile contains everything. */ fz_printf(ctx, out, "<pattern id=\"pa%d\" patternUnits=\"userSpaceOnUse\" patternContentUnits=\"userSpaceOnUse\"", t->pattern); fz_printf(ctx, out, " x=\"0\" y=\"0\" width=\"%g\" height=\"%g\">\n", t->step.x, t->step.y); if (t->view.x0 > 0 || t->step.x < t->view.x1 || t->view.y0 > 0 || t->step.y < t->view.y1) { cp = sdev->id++; fz_printf(ctx, out, "<clipPath id=\"cp%d\">\n", cp); fz_printf(ctx, out, "<path d=\"M %g %g L %g %g L %g %g L %g %g Z\"/>", t->view.x0, t->view.y0, t->view.x1, t->view.y0, t->view.x1, t->view.y1, t->view.x0, t->view.y1); fz_printf(ctx, out, "</clipPath>\n"); fz_printf(ctx, out, "<g clip-path=\"url(#cp%d)\">\n", cp); } /* All the pattern contents will have their own ctm applied. Let's * undo the current one to allow for this */ fz_invert_matrix(&inverse, &t->ctm); fz_printf(ctx, out, "<g"); svg_dev_ctm(ctx, sdev, &inverse); fz_printf(ctx, out, ">\n"); w = t->view.x1 - t->view.x0; h = t->view.y1 - t->view.y0; for (x = 0; x > -w; x -= t->step.x) for (y = 0; y > -h; y -= t->step.y) fz_printf(ctx, out, "<use x=\"%g\" y=\"%g\" xlink:href=\"#pac%d\"/>", x, y, t->pattern); fz_printf(ctx, out, "</g>\n"); if (cp != -1) fz_printf(ctx, out, "</g>\n"); fz_printf(ctx, out, "</pattern>\n"); out = end_def(ctx, sdev); /* Finally, fill a rectangle with the pattern. */ fz_printf(ctx, out, "<rect"); svg_dev_ctm(ctx, sdev, &t->ctm); fz_printf(ctx, out, " fill=\"url(#pa%d)\" x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n", t->pattern, t->area.x0, t->area.y0, t->area.x1 - t->area.x0, t->area.y1 - t->area.y0); }
static void svg_dev_text(fz_context *ctx, svg_device *sdev, const fz_matrix *ctm, fz_text *text) { fz_output *out = sdev->out; int i; fz_matrix inverse; fz_matrix local_trm; float size; int start, is_wspace, was_wspace; fz_text_span *span; for (span = text->head; text; span = span->next) { /* Rely on the fact that trm.{e,f} == 0 */ size = fz_matrix_expansion(&span->trm); local_trm.a = span->trm.a / size; local_trm.b = span->trm.b / size; local_trm.c = -span->trm.c / size; local_trm.d = -span->trm.d / size; local_trm.e = 0; local_trm.f = 0; fz_invert_matrix(&inverse, &local_trm); fz_concat(&local_trm, &local_trm, ctm); fz_printf(ctx, out, " transform=\"matrix(%g,%g,%g,%g,%g,%g)\"", local_trm.a, local_trm.b, local_trm.c, local_trm.d, local_trm.e, local_trm.f); fz_printf(ctx, out, " font-size=\"%g\"", size); fz_printf(ctx, out, " font-family=\"%s\"", span->font->name); /* Leading (and repeated) whitespace presents a problem for SVG * text, so elide it here. */ for (start=0; start < span->len; start++) { fz_text_item *it = &span->items[start]; if (!is_xml_wspace(it->ucs)) break; } fz_printf(ctx, out, " x="); was_wspace = 0; for (i=start; i < span->len; i++) { fz_text_item *it = &span->items[i]; fz_point p; is_wspace = is_xml_wspace(it->ucs); if (is_wspace && was_wspace) continue; was_wspace = is_wspace; p.x = it->x; p.y = it->y; fz_transform_point(&p, &inverse); fz_printf(ctx, out, "%c%g", i == start ? '\"' : ' ', p.x); } fz_printf(ctx, out, "\" y="); was_wspace = 0; for (i=start; i < span->len; i++) { fz_text_item *it = &span->items[i]; fz_point p; is_wspace = is_xml_wspace(it->ucs); if (is_wspace && was_wspace) continue; was_wspace = is_wspace; p.x = it->x; p.y = it->y; fz_transform_point(&p, &inverse); fz_printf(ctx, out, "%c%g", i == start ? '\"' : ' ', p.y); } fz_printf(ctx, out, "\">\n"); was_wspace = 0; for (i=start; i < span->len; i++) { fz_text_item *it = &span->items[i]; int c = it->ucs; is_wspace = is_xml_wspace(c); if (is_wspace && was_wspace) continue; was_wspace = is_wspace; if (c >= 32 && c <= 127 && c != '<' && c != '&') fz_printf(ctx, out, "%c", c); else fz_printf(ctx, out, "&#x%04x;", c); } fz_printf(ctx, out, "\n</text>\n"); } }