static void pdf_write_strike_out_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect) { fz_point quad[4], a, b; float h; pdf_obj *qp; int i, n; pdf_write_stroke_color_appearance(ctx, annot, buf); qp = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints)); n = pdf_array_len(ctx, qp); if (n > 0) { *rect = fz_empty_rect; for (i = 0; i < n; i += 8) { /* Acrobat draws the line at 3/7 of the box width from the bottom * of the box and 1/16 thick of the box width. */ h = extract_quad(ctx, quad, qp, i); a = lerp_point(quad[LL], quad[UL], 3/7.0f); b = lerp_point(quad[LR], quad[UR], 3/7.0f); fz_append_printf(ctx, buf, "%g w\n", h/16); fz_append_printf(ctx, buf, "%g %g m\n", a.x, a.y); fz_append_printf(ctx, buf, "%g %g l\n", b.x, b.y); fz_append_printf(ctx, buf, "S\n"); union_quad(rect, quad, h/16); } } }
static pdf_obj *draw_check_button(fz_context *ctx, pdf_annot *annot, fz_rect bbox, fz_matrix matrix, float w, float h, int yes) { float black[3] = { 0, 0, 0 }; pdf_obj *ap, *res = NULL; fz_buffer *buf; float b; fz_var(res); buf = fz_new_buffer(ctx, 1024); fz_try(ctx) { fz_append_string(ctx, buf, "q\n"); if (pdf_write_MK_BG_appearance(ctx, annot, buf)) fz_append_printf(ctx, buf, "0 0 %g %g re\nf\n", w, h); b = pdf_write_border_appearance(ctx, annot, buf); if (b > 0 && pdf_write_MK_BC_appearance(ctx, annot, buf)) fz_append_printf(ctx, buf, "%g %g %g %g re\nS\n", b/2, b/2, w-b, h-b); if (yes) write_variable_text(ctx, annot, buf, &res, "3", "ZaDb", h, black, 0, w, h, b+h/10, 0.8f, 1.2f, 0, 0, 0); fz_append_string(ctx, buf, "Q\n"); ap = pdf_new_xobject(ctx, annot->page->doc, bbox, matrix, res, buf); } fz_always(ctx) { pdf_drop_obj(ctx, res); fz_drop_buffer(ctx, buf); } fz_catch(ctx) fz_rethrow(ctx); return ap; }
static void write_stamp(fz_context *ctx, fz_buffer *buf, fz_font *font, const char *text, float y, float h) { float tw = measure_simple_string(ctx, font, text) * h; fz_append_string(ctx, buf, "BT\n"); fz_append_printf(ctx, buf, "/Times %g Tf\n", h); fz_append_printf(ctx, buf, "%g %g Td\n", (190-tw)/2, y); write_stamp_string(ctx, buf, font, text); fz_append_string(ctx, buf, " Tj\n"); fz_append_string(ctx, buf, "ET\n"); }
static void draw_circle(fz_context *ctx, fz_buffer *buf, const char *op, float rx, float ry, float cx, float cy) { float mx = rx * CIRCLE_MAGIC; float my = ry * CIRCLE_MAGIC; fz_append_printf(ctx, buf, "%g %g m\n", cx, cy+ry); fz_append_printf(ctx, buf, "%g %g %g %g %g %g c\n", cx+mx, cy+ry, cx+rx, cy+my, cx+rx, cy); fz_append_printf(ctx, buf, "%g %g %g %g %g %g c\n", cx+rx, cy-my, cx+mx, cy-ry, cx, cy-ry); fz_append_printf(ctx, buf, "%g %g %g %g %g %g c\n", cx-mx, cy-ry, cx-rx, cy-my, cx-rx, cy); fz_append_printf(ctx, buf, "%g %g %g %g %g %g c\n", cx-rx, cy+my, cx-mx, cy+ry, cx, cy+ry); fz_append_string(ctx, buf, op); }
static int pdf_write_MK_BC_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf) { float color[4]; int n; pdf_annot_MK_BC(ctx, annot, &n, color); switch (n) { default: return 0; case 1: fz_append_printf(ctx, buf, "%g G\n", color[0]); break; case 3: fz_append_printf(ctx, buf, "%g %g %g RG\n", color[0], color[1], color[2]); break; case 4: fz_append_printf(ctx, buf, "%g %g %g %g K\n", color[0], color[1], color[2], color[3]); break; } return 1; }
static void write_simple_string_with_quadding(fz_context *ctx, fz_buffer *buf, fz_font *font, float size, const char *a, float maxw, int q) { const char *b; float px = 0, x = 0, w; while (*a) { w = break_simple_string(ctx, font, size, a, &b, maxw); if (b > a) { if (q > 0) { if (q == 1) x = (maxw - w) / 2; else x = (maxw - w); fz_append_printf(ctx, buf, "%g %g Td ", x - px, -size); } if (b[-1] == '\n' || b[-1] == '\r') write_simple_string(ctx, buf, a, b-1); else write_simple_string(ctx, buf, a, b); a = b; px = x; fz_append_string(ctx, buf, (q > 0) ? "Tj\n" : "'\n"); } } }
static void write_comb_string(fz_context *ctx, fz_buffer *buf, const char *a, const char *b, fz_font *font, float cell_w) { float gw, pad, carry = 0; fz_append_byte(ctx, buf, '['); while (a < b) { int c, g; a += fz_chartorune(&c, a); c = fz_windows_1252_from_unicode(c); if (c < 0) c = REPLACEMENT; g = fz_encode_character(ctx, font, c); gw = fz_advance_glyph(ctx, font, g, 0) * 1000; pad = (cell_w - gw) / 2; fz_append_printf(ctx, buf, "%g", -(carry + pad)); carry = pad; fz_append_byte(ctx, buf, '('); if (c == '(' || c == ')' || c == '\\') fz_append_byte(ctx, buf, '\\'); fz_append_byte(ctx, buf, c); fz_append_byte(ctx, buf, ')'); } fz_append_string(ctx, buf, "] TJ\n"); }
static void pdf_write_squiggly_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect) { fz_point quad[4], a, b, c, v; float h, x, w; pdf_obj *qp; int i, n; *rect = fz_empty_rect; pdf_write_stroke_color_appearance(ctx, annot, buf); qp = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints)); n = pdf_array_len(ctx, qp); if (n > 0) { for (i = 0; i < n; i += 8) { int up = 1; h = extract_quad(ctx, quad, qp, i); v = fz_make_point(quad[LR].x - quad[LL].x, quad[LR].y - quad[LL].y); w = sqrtf(v.x * v.x + v.y * v.y); x = 0; fz_append_printf(ctx, buf, "%g w\n", h/16); fz_append_printf(ctx, buf, "%g %g m\n", quad[LL].x, quad[LL].y); while (x < w) { x += h/7; a = lerp_point(quad[LL], quad[LR], x/w); if (up) { b = lerp_point(quad[UL], quad[UR], x/w); c = lerp_point(a, b, 1/7.0f); fz_append_printf(ctx, buf, "%g %g l\n", c.x, c.y); } else fz_append_printf(ctx, buf, "%g %g l\n", a.x, a.y); up = !up; } fz_append_printf(ctx, buf, "S\n"); union_quad(rect, quad, h/16); } } }
static void pdf_write_sig_widget_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, fz_rect *bbox, fz_matrix *matrix, pdf_obj **res) { float x0 = rect->x0 + 1; float y0 = rect->y0 + 1; float x1 = rect->x1 - 1; float y1 = rect->y1 - 1; float w = x1 - x0; float h = y1 - y0; fz_append_printf(ctx, buf, "1 w\n0 G\n"); fz_append_printf(ctx, buf, "%g %g %g %g re\n", x0, y0, w, h); fz_append_printf(ctx, buf, "%g %g m %g %g l\n", x0, y0, x1, y1); fz_append_printf(ctx, buf, "%g %g m %g %g l\n", x1, y0, x0, y1); fz_append_printf(ctx, buf, "s\n"); *bbox = *rect; *matrix = fz_identity; }
static void pdf_write_arrow_appearance(fz_context *ctx, fz_buffer *buf, fz_rect *rect, float x, float y, float dx, float dy, float w) { float r = fz_max(1, w); float angle = atan2f(dy, dx); fz_point v, a, b; v = rotate_vector(angle, 8.8f*r, 4.5f*r); a = fz_make_point(x + v.x, y + v.y); v = rotate_vector(angle, 8.8f*r, -4.5f*r); b = fz_make_point(x + v.x, y + v.y); *rect = fz_include_point_in_rect(*rect, a); *rect = fz_include_point_in_rect(*rect, b); *rect = fz_expand_rect(*rect, w); fz_append_printf(ctx, buf, "%g %g m\n", a.x, a.y); fz_append_printf(ctx, buf, "%g %g l\n", x, y); fz_append_printf(ctx, buf, "%g %g l\n", b.x, b.y); }
static void pdf_write_free_text_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, fz_rect *bbox, fz_matrix *matrix, pdf_obj **res) { const char *font; float size, color[3]; const char *text; float w, h, t, b; int q, r; /* /Rotate is an undocumented annotation property supported by Adobe */ text = pdf_annot_contents(ctx, annot); r = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(Rotate)); q = pdf_annot_quadding(ctx, annot); pdf_annot_default_appearance(ctx, annot, &font, &size, color); w = rect->x1 - rect->x0; h = rect->y1 - rect->y0; if (r == 90 || r == 270) t = h, h = w, w = t; *matrix = fz_rotate(r); *bbox = fz_make_rect(0, 0, w, h); if (pdf_write_fill_color_appearance(ctx, annot, buf)) fz_append_printf(ctx, buf, "0 0 %g %g re\nf\n", w, h); b = pdf_write_border_appearance(ctx, annot, buf); if (b > 0) { fz_append_printf(ctx, buf, "%g %g %g RG\n", color[0], color[1], color[2]); fz_append_printf(ctx, buf, "%g %g %g %g re\nS\n", b/2, b/2, w-b, h-b); } fz_append_printf(ctx, buf, "%g %g %g %g re\nW\nn\n", b, b, w-b*2, h-b*2); write_variable_text(ctx, annot, buf, res, text, font, size, color, q, w, h, b*2, 0.8f, 1.2f, 1, 0, 0); }
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); }
static void pdf_write_polygon_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, int close) { pdf_obj *verts; fz_point p; int i, n; float lw; lw = pdf_write_border_appearance(ctx, annot, buf); pdf_write_stroke_color_appearance(ctx, annot, buf); *rect = fz_empty_rect; verts = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices)); n = pdf_array_len(ctx, verts) / 2; if (n > 0) { for (i = 0; i < n; ++i) { p.x = pdf_array_get_real(ctx, verts, i*2+0); p.y = pdf_array_get_real(ctx, verts, i*2+1); if (i == 0) { rect->x0 = rect->x1 = p.x; rect->y0 = rect->y1 = p.y; } else *rect = fz_include_point_in_rect(*rect, p); if (i == 0) fz_append_printf(ctx, buf, "%g %g m\n", p.x, p.y); else fz_append_printf(ctx, buf, "%g %g l\n", p.x, p.y); } fz_append_string(ctx, buf, close ? "s" : "S"); *rect = fz_expand_rect(*rect, lw); } }
static void pdf_write_ink_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect) { pdf_obj *ink_list, *stroke; int i, n, k, m; float lw; fz_point p; lw = pdf_write_border_appearance(ctx, annot, buf); pdf_write_stroke_color_appearance(ctx, annot, buf); *rect = fz_empty_rect; ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList)); n = pdf_array_len(ctx, ink_list); for (i = 0; i < n; ++i) { stroke = pdf_array_get(ctx, ink_list, i); m = pdf_array_len(ctx, stroke) / 2; for (k = 0; k < m; ++k) { p.x = pdf_array_get_real(ctx, stroke, k*2+0); p.y = pdf_array_get_real(ctx, stroke, k*2+1); if (i == 0 && k == 0) { rect->x0 = rect->x1 = p.x; rect->y0 = rect->y1 = p.y; } else *rect = fz_include_point_in_rect(*rect, p); fz_append_printf(ctx, buf, "%g %g %c\n", p.x, p.y, k == 0 ? 'm' : 'l'); } } fz_append_printf(ctx, buf, "S"); *rect = fz_expand_rect(*rect, lw); }
static int make_fake_doc(pdfapp_t *app) { fz_context *ctx = app->ctx; pdf_document *pdf = NULL; fz_buffer *contents = NULL; pdf_obj *page_obj = NULL; fz_var(contents); fz_var(page_obj); fz_try(ctx) { fz_rect mediabox = { 0, 0, app->winw, app->winh }; int i; pdf = pdf_create_document(ctx); contents = fz_new_buffer(ctx, 100); fz_append_printf(ctx, contents, "1 0 0 RG %g w 0 0 m %g %g l 0 %g m %g 0 l s\n", fz_min(mediabox.x1, mediabox.y1) / 20, mediabox.x1, mediabox.y1, mediabox.y1, mediabox.x1); /* Create enough copies of our blank(ish) page so that the * page number is preserved if and when a subsequent load * works. */ page_obj = pdf_add_page(ctx, pdf, &mediabox, 0, NULL, contents); for (i = 0; i < app->pagecount; i++) pdf_insert_page(ctx, pdf, -1, page_obj); } fz_always(ctx) { pdf_drop_obj(ctx, page_obj); fz_drop_buffer(ctx, contents); } fz_catch(ctx) { fz_drop_document(ctx, (fz_document *) pdf); return 1; } app->doc = (fz_document*)pdf; return 0; }
/* Helper functions */ static void pdf_dev_stroke_state(fz_context *ctx, pdf_device *pdev, const fz_stroke_state *stroke_state) { gstate *gs = CURRENT_GSTATE(pdev); if (stroke_state == gs->stroke_state) return; if (gs->stroke_state && !memcmp(stroke_state, gs->stroke_state, sizeof(*stroke_state))) return; if (!gs->stroke_state || gs->stroke_state->linewidth != stroke_state->linewidth) { fz_append_printf(ctx, gs->buf, "%g w\n", stroke_state->linewidth); } if (!gs->stroke_state || gs->stroke_state->start_cap != stroke_state->start_cap) { int cap = stroke_state->start_cap; /* FIXME: Triangle caps aren't supported in pdf */ if (cap == FZ_LINECAP_TRIANGLE) cap = FZ_LINECAP_BUTT; fz_append_printf(ctx, gs->buf, "%d J\n", cap); } if (!gs->stroke_state || gs->stroke_state->linejoin != stroke_state->linejoin) { int join = stroke_state->linejoin; if (join == FZ_LINEJOIN_MITER_XPS) join = FZ_LINEJOIN_MITER; fz_append_printf(ctx, gs->buf, "%d j\n", join); } if (!gs->stroke_state || gs->stroke_state->miterlimit != stroke_state->miterlimit) { fz_append_printf(ctx, gs->buf, "%g M\n", stroke_state->miterlimit); } if (gs->stroke_state == NULL && stroke_state->dash_len == 0) {} else if (!gs->stroke_state || gs->stroke_state->dash_phase != stroke_state->dash_phase || gs->stroke_state->dash_len != stroke_state->dash_len || memcmp(gs->stroke_state->dash_list, stroke_state->dash_list, sizeof(float)*stroke_state->dash_len)) { int i; if (stroke_state->dash_len == 0) fz_append_byte(ctx, gs->buf, '['); for (i = 0; i < stroke_state->dash_len; i++) { if (i > 0) fz_append_byte(ctx, gs->buf, ' '); fz_append_printf(ctx, gs->buf, "%g", stroke_state->dash_list[i]); } fz_append_printf(ctx, gs->buf, "]%g d\n", stroke_state->dash_phase); } fz_drop_stroke_state(ctx, gs->stroke_state); gs->stroke_state = fz_keep_stroke_state(ctx, stroke_state); }
static void pdf_write_square_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect) { float x, y, w, h; float lw; int ic; lw = pdf_write_border_appearance(ctx, annot, buf); pdf_write_stroke_color_appearance(ctx, annot, buf); ic = pdf_write_interior_fill_color_appearance(ctx, annot, buf); x = rect->x0 + lw; y = rect->y0 + lw; w = rect->x1 - x - lw; h = rect->y1 - y - lw; fz_append_printf(ctx, buf, "%g %g %g %g re\n", x, y, w, h); fz_append_string(ctx, buf, ic ? "b" : "s"); }
static void pdf_write_line_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect) { pdf_obj *line, *le; fz_point a, b; float w; int ic; w = pdf_write_border_appearance(ctx, annot, buf); pdf_write_stroke_color_appearance(ctx, annot, buf); ic = pdf_write_interior_fill_color_appearance(ctx, annot, buf); line = pdf_dict_get(ctx, annot->obj, PDF_NAME(L)); a.x = pdf_array_get_real(ctx, line, 0); a.y = pdf_array_get_real(ctx, line, 1); b.x = pdf_array_get_real(ctx, line, 2); b.y = pdf_array_get_real(ctx, line, 3); fz_append_printf(ctx, buf, "%g %g m\n%g %g l\nS\n", a.x, a.y, b.x, b.y); rect->x0 = fz_min(a.x, b.x); rect->y0 = fz_min(a.y, b.y); rect->x1 = fz_max(a.x, b.x); rect->y1 = fz_max(a.y, b.y); le = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE)); if (pdf_array_len(ctx, le) == 2) { float dx = b.x - a.x; float dy = b.y - a.y; float l = sqrtf(dx*dx + dy*dy); pdf_write_line_cap_appearance(ctx, buf, rect, a.x, a.y, dx/l, dy/l, w, ic, pdf_array_get(ctx, le, 0)); pdf_write_line_cap_appearance(ctx, buf, rect, b.x, b.y, -dx/l, -dy/l, w, ic, pdf_array_get(ctx, le, 1)); } *rect = fz_expand_rect(*rect, fz_max(1, w)); }
static void pdf_write_tx_widget_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, fz_rect *bbox, fz_matrix *matrix, pdf_obj **res, const char *text, int ff) { const char *font; float size, color[3]; float w, h, t, b; int has_bc = 0; int q, r; r = pdf_dict_get_int(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(R)); q = pdf_annot_quadding(ctx, annot); pdf_annot_default_appearance(ctx, annot, &font, &size, color); w = rect->x1 - rect->x0; h = rect->y1 - rect->y0; if (r == 90 || r == 270) t = h, h = w, w = t; *matrix = fz_rotate(r); *bbox = fz_make_rect(0, 0, w, h); fz_append_string(ctx, buf, "/Tx BMC\nq\n"); if (pdf_write_MK_BG_appearance(ctx, annot, buf)) fz_append_printf(ctx, buf, "0 0 %g %g re\nf\n", w, h); b = pdf_write_border_appearance(ctx, annot, buf); if (b > 0 && pdf_write_MK_BC_appearance(ctx, annot, buf)) { fz_append_printf(ctx, buf, "%g %g %g %g re\ns\n", b/2, b/2, w-b, h-b); has_bc = 1; } fz_append_printf(ctx, buf, "%g %g %g %g re\nW\nn\n", b, b, w-b*2, h-b*2); if (ff & PDF_TX_FIELD_IS_MULTILINE) { write_variable_text(ctx, annot, buf, res, text, font, size, color, q, w, h, b*2, 1.116f, 1.116f, 1, 0, 1); } else if (ff & PDF_TX_FIELD_IS_COMB) { int maxlen = pdf_to_int(ctx, pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(MaxLen))); if (has_bc && maxlen > 1) { float cell_w = (w - 2 * b) / maxlen; int i; for (i = 1; i < maxlen; ++i) { float x = b + cell_w * i; fz_append_printf(ctx, buf, "%g %g m %g %g l s\n", x, b, x, h-b); } } write_variable_text(ctx, annot, buf, res, text, font, size, color, q, w, h, 0, 0.8f, 1.2f, 0, maxlen, 0); } else { write_variable_text(ctx, annot, buf, res, text, font, size, color, q, w, h, b*2, 0.8f, 1.2f, 0, 0, 0); } fz_append_string(ctx, buf, "Q\nEMC\n"); }
static void pdf_dev_color(fz_context *ctx, pdf_device *pdev, fz_colorspace *colorspace, const float *color, int stroke, const fz_color_params *color_params) { int diff = 0; int i; int cspace = 0; float rgb[FZ_MAX_COLORS]; gstate *gs = CURRENT_GSTATE(pdev); if (colorspace == fz_device_gray(ctx)) cspace = 1; else if (colorspace == fz_device_rgb(ctx)) cspace = 3; else if (colorspace == fz_device_cmyk(ctx)) cspace = 4; if (cspace == 0) { /* If it's an unknown colorspace, fallback to rgb */ fz_convert_color(ctx, color_params, NULL, fz_device_rgb(ctx), rgb, colorspace, color); color = rgb; colorspace = fz_device_rgb(ctx); cspace = 3; } if (gs->colorspace[stroke] != colorspace) { gs->colorspace[stroke] = colorspace; diff = 1; } for (i=0; i < cspace; i++) if (gs->color[stroke][i] != color[i]) { gs->color[stroke][i] = color[i]; diff = 1; } if (diff == 0) return; switch (cspace + stroke*8) { case 1: fz_append_printf(ctx, gs->buf, "%g g\n", color[0]); break; case 3: fz_append_printf(ctx, gs->buf, "%g %g %g rg\n", color[0], color[1], color[2]); break; case 4: fz_append_printf(ctx, gs->buf, "%g %g %g %g k\n", color[0], color[1], color[2], color[3]); break; case 1+8: fz_append_printf(ctx, gs->buf, "%g G\n", color[0]); break; case 3+8: fz_append_printf(ctx, gs->buf, "%g %g %g RG\n", color[0], color[1], color[2]); break; case 4+8: fz_append_printf(ctx, gs->buf, "%g %g %g %g K\n", color[0], color[1], color[2], color[3]); break; } }
static pdf_obj *draw_push_button(fz_context *ctx, pdf_annot *annot, fz_rect bbox, fz_matrix matrix, float w, float h, const char *caption, const char *font, float size, float color[3], int down) { pdf_obj *ap, *res = NULL; fz_buffer *buf; float bc[3] = { 0, 0, 0 }; float bg[3] = { 0.8f, 0.8f, 0.8f }; float hi[3], sh[3]; int has_bg, has_bc; float b; int i; buf = fz_new_buffer(ctx, 1024); fz_var(res); fz_try(ctx) { b = pdf_annot_border(ctx, annot); has_bc = pdf_annot_MK_BC_rgb(ctx, annot, bc); has_bg = pdf_annot_MK_BG_rgb(ctx, annot, bg); for (i = 0; i < 3; ++i) { if (down) { sh[i] = 1 - (1 - bg[i]) / 2; hi[i] = bg[i] / 2; } else { hi[i] = 1 - (1 - bg[i]) / 2; sh[i] = bg[i] / 2; } } fz_append_string(ctx, buf, "q\n"); fz_append_printf(ctx, buf, "%g w\n", b); if (has_bg) { fz_append_printf(ctx, buf, "%g %g %g rg\n", bg[0], bg[1], bg[2]); fz_append_printf(ctx, buf, "0 0 %g %g re\nf\n", 0, 0, w, h); } if (has_bc && b > 0) { fz_append_printf(ctx, buf, "%g %g %g RG\n", bc[0], bc[1], bc[2]); fz_append_printf(ctx, buf, "%g %g %g %g re\nS\n", b/2, b/2, w-b, h-b); } if (has_bg) { fz_append_printf(ctx, buf, "%g %g %g rg\n", hi[0], hi[1], hi[2]); fz_append_printf(ctx, buf, "%g %g m %g %g l %g %g l %g %g l %g %g l %g %g l f\n", b, b, b, h-b, w-b, h-b, w-b-2, h-b-2, b+2, h-b-2, b+2, b+2); fz_append_printf(ctx, buf, "%g %g %g rg\n", sh[0], sh[1], sh[2]); fz_append_printf(ctx, buf, "%g %g m %g %g l %g %g l %g %g l %g %g l %g %g l f\n", b, b, b+2, b+2, w-b-2, b+2, w-b-2, h-b-2, w-b, h-b, w-b, b); } if (down) fz_append_string(ctx, buf, "1 0 0 1 2 -2 cm\n"); write_variable_text(ctx, annot, buf, &res, caption, font, size, color, 1, w, h, b+6, 0.8f, 1.2f, 0, 0, 0); fz_append_string(ctx, buf, "Q\n"); ap = pdf_new_xobject(ctx, annot->page->doc, bbox, matrix, res, buf); } fz_always(ctx) { pdf_drop_obj(ctx, res); fz_drop_buffer(ctx, buf); } fz_catch(ctx) fz_rethrow(ctx); return ap; }
static void pdf_dev_path_curveto(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2, float x3, float y3) { fz_buffer *buf = (fz_buffer *)arg; fz_append_printf(ctx, buf, "%g %g %g %g %g %g c\n", x1, y1, x2, y2, x3, y3); }
static void pdf_dev_path_lineto(fz_context *ctx, void *arg, float x, float y) { fz_buffer *buf = (fz_buffer *)arg; fz_append_printf(ctx, buf, "%g %g l\n", x, y); }
static void pdf_write_line_cap_appearance(fz_context *ctx, fz_buffer *buf, fz_rect *rect, float x, float y, float dx, float dy, float w, int ic, pdf_obj *cap) { if (cap == PDF_NAME(Square)) { float r = fz_max(2.5f, w * 2.5f); fz_append_printf(ctx, buf, "%g %g %g %g re\n", x-r, y-r, r*2, r*2); fz_append_string(ctx, buf, ic ? "b\n" : "s\n"); include_cap(rect, x, y, r); } else if (cap == PDF_NAME(Circle)) { float r = fz_max(2.5f, w * 2.5f); float m = r * CIRCLE_MAGIC; fz_append_printf(ctx, buf, "%g %g m\n", x, y+r); fz_append_printf(ctx, buf, "%g %g %g %g %g %g c\n", x+m, y+r, x+r, y+m, x+r, y); fz_append_printf(ctx, buf, "%g %g %g %g %g %g c\n", x+r, y-m, x+m, y-r, x, y-r); fz_append_printf(ctx, buf, "%g %g %g %g %g %g c\n", x-m, y-r, x-r, y-m, x-r, y); fz_append_printf(ctx, buf, "%g %g %g %g %g %g c\n", x-r, y+m, x-m, y+r, x, y+r); fz_append_string(ctx, buf, ic ? "b\n" : "s\n"); include_cap(rect, x, y, r); } else if (cap == PDF_NAME(Diamond)) { float r = fz_max(2.5f, w * 2.5f); fz_append_printf(ctx, buf, "%g %g m\n", x, y+r); fz_append_printf(ctx, buf, "%g %g l\n", x+r, y); fz_append_printf(ctx, buf, "%g %g l\n", x, y-r); fz_append_printf(ctx, buf, "%g %g l\n", x-r, y); fz_append_string(ctx, buf, ic ? "b\n" : "s\n"); include_cap(rect, x, y, r); } else if (cap == PDF_NAME(OpenArrow)) { pdf_write_arrow_appearance(ctx, buf, rect, x, y, dx, dy, w); fz_append_string(ctx, buf, "S\n"); } else if (cap == PDF_NAME(ClosedArrow)) { pdf_write_arrow_appearance(ctx, buf, rect, x, y, dx, dy, w); fz_append_string(ctx, buf, ic ? "b\n" : "s\n"); } /* PDF 1.5 */ else if (cap == PDF_NAME(Butt)) { float r = fz_max(3, w * 3); fz_point a = { x-dy*r, y+dx*r }; fz_point b = { x+dy*r, y-dx*r }; fz_append_printf(ctx, buf, "%g %g m\n", a.x, a.y); fz_append_printf(ctx, buf, "%g %g l\n", b.x, b.y); fz_append_string(ctx, buf, "S\n"); *rect = fz_include_point_in_rect(*rect, a); *rect = fz_include_point_in_rect(*rect, b); } /* PDF 1.6 */ else if (cap == PDF_NAME(ROpenArrow)) { pdf_write_arrow_appearance(ctx, buf, rect, x, y, -dx, -dy, w); fz_append_string(ctx, buf, "S\n"); } else if (cap == PDF_NAME(RClosedArrow)) { pdf_write_arrow_appearance(ctx, buf, rect, x, y, -dx, -dy, w); fz_append_string(ctx, buf, ic ? "b\n" : "s\n"); } else if (cap == PDF_NAME(Slash)) { float r = fz_max(5, w * 5); float angle = atan2f(dy, dx) - (30 * FZ_PI / 180); fz_point a, b, v; v = rotate_vector(angle, 0, r); a = fz_make_point(x + v.x, y + v.y); v = rotate_vector(angle, 0, -r); b = fz_make_point(x + v.x, y + v.y); fz_append_printf(ctx, buf, "%g %g m\n", a.x, a.y); fz_append_printf(ctx, buf, "%g %g l\n", b.x, b.y); fz_append_string(ctx, buf, "S\n"); *rect = fz_include_point_in_rect(*rect, a); *rect = fz_include_point_in_rect(*rect, b); } }
static void write_variable_text(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, pdf_obj **res, const char *text, const char *fontname, float size, float color[3], int q, float w, float h, float padding, float baseline, float lineheight, int multiline, int comb, int adjust_baseline) { pdf_obj *res_font; fz_font *font; w -= padding * 2; h -= padding * 2; font = fz_new_base14_font(ctx, full_font_name(&fontname)); fz_try(ctx) { if (size == 0) { if (multiline) size = 12; else { size = w / measure_simple_string(ctx, font, text); if (size > h) size = h; } } lineheight = size * lineheight; baseline = size * baseline; if (adjust_baseline) { /* Make sure baseline is inside rectangle */ if (baseline + 0.2f * size > h) baseline = h - 0.2f * size; } /* /Resources << /Font << /Helv %d 0 R >> >> */ *res = pdf_new_dict(ctx, annot->page->doc, 1); res_font = pdf_dict_put_dict(ctx, *res, PDF_NAME(Font), 1); pdf_dict_puts_drop(ctx, res_font, fontname, pdf_add_simple_font(ctx, annot->page->doc, font, 0)); fz_append_string(ctx, buf, "BT\n"); fz_append_printf(ctx, buf, "%g %g %g rg\n", color[0], color[1], color[2]); fz_append_printf(ctx, buf, "/%s %g Tf\n", fontname, size); if (multiline) { fz_append_printf(ctx, buf, "%g TL\n", lineheight); fz_append_printf(ctx, buf, "%g %g Td\n", padding, padding+h-baseline+lineheight); write_simple_string_with_quadding(ctx, buf, font, size, text, w, q); } else if (comb > 0) { float ty = (h - size) / 2; fz_append_printf(ctx, buf, "%g %g Td\n", padding, padding+h-baseline-ty); write_comb_string(ctx, buf, text, text + strlen(text), font, (w * 1000 / size) / comb); } else { float tx = 0, ty = (h - size) / 2; if (q > 0) { float tw = measure_simple_string(ctx, font, text) * size; if (q == 1) tx = (w - tw) / 2; else tx = (w - tw); } fz_append_printf(ctx, buf, "%g %g Td\n", padding+tx, padding+h-baseline-ty); write_simple_string(ctx, buf, text, text + strlen(text)); fz_append_printf(ctx, buf, " Tj\n"); } fz_append_string(ctx, buf, "ET\n"); } fz_always(ctx) fz_drop_font(ctx, font); fz_catch(ctx) fz_rethrow(ctx); }
static float pdf_write_border_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf) { float w = pdf_annot_border(ctx, annot); fz_append_printf(ctx, buf, "%g w\n", w); return w; }
static void pdf_write_stamp_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, fz_rect *bbox, pdf_obj **res) { fz_font *font; pdf_obj *res_font; pdf_obj *name; float w, h, xs, ys; fz_matrix rotate; name = pdf_dict_get(ctx, annot->obj, PDF_NAME(Name)); if (!name) name = PDF_NAME(Draft); h = rect->y1 - rect->y0; w = rect->x1 - rect->x0; xs = w / 190; ys = h / 50; font = fz_new_base14_font(ctx, "Times-Bold"); fz_try(ctx) { /* /Resources << /Font << /Times %d 0 R >> >> */ *res = pdf_new_dict(ctx, annot->page->doc, 1); res_font = pdf_dict_put_dict(ctx, *res, PDF_NAME(Font), 1); pdf_dict_put_drop(ctx, res_font, PDF_NAME(Times), pdf_add_simple_font(ctx, annot->page->doc, font, 0)); pdf_write_fill_color_appearance(ctx, annot, buf); pdf_write_stroke_color_appearance(ctx, annot, buf); rotate = fz_rotate(0.6f); fz_append_printf(ctx, buf, "%M cm\n", &rotate); fz_append_string(ctx, buf, "2 w\n2 2 186 44 re\nS\n"); if (name == PDF_NAME(Approved)) write_stamp(ctx, buf, font, "APPROVED", 13, 30); else if (name == PDF_NAME(AsIs)) write_stamp(ctx, buf, font, "AS IS", 13, 30); else if (name == PDF_NAME(Confidential)) write_stamp(ctx, buf, font, "CONFIDENTIAL", 17, 20); else if (name == PDF_NAME(Departmental)) write_stamp(ctx, buf, font, "DEPARTMENTAL", 17, 20); else if (name == PDF_NAME(Experimental)) write_stamp(ctx, buf, font, "EXPERIMENTAL", 17, 20); else if (name == PDF_NAME(Expired)) write_stamp(ctx, buf, font, "EXPIRED", 13, 30); else if (name == PDF_NAME(Final)) write_stamp(ctx, buf, font, "FINAL", 13, 30); else if (name == PDF_NAME(ForComment)) write_stamp(ctx, buf, font, "FOR COMMENT", 17, 20); else if (name == PDF_NAME(ForPublicRelease)) { write_stamp(ctx, buf, font, "FOR PUBLIC", 26, 18); write_stamp(ctx, buf, font, "RELEASE", 8.5f, 18); } else if (name == PDF_NAME(NotApproved)) write_stamp(ctx, buf, font, "NOT APPROVED", 17, 20); else if (name == PDF_NAME(NotForPublicRelease)) { write_stamp(ctx, buf, font, "NOT FOR", 26, 18); write_stamp(ctx, buf, font, "PUBLIC RELEASE", 8.5, 18); } else if (name == PDF_NAME(Sold)) write_stamp(ctx, buf, font, "SOLD", 13, 30); else if (name == PDF_NAME(TopSecret)) write_stamp(ctx, buf, font, "TOP SECRET", 14, 26); else if (name == PDF_NAME(Draft)) write_stamp(ctx, buf, font, "DRAFT", 13, 30); else write_stamp(ctx, buf, font, pdf_to_name(ctx, name), 17, 20); } fz_always(ctx) fz_drop_font(ctx, font); fz_catch(ctx) fz_rethrow(ctx); *bbox = fz_make_rect(0, 0, 190, 50); if (xs > ys) { float xc = (rect->x1+rect->x0) / 2; rect->x0 = xc - 95 * ys; rect->x1 = xc + 95 * ys; } else { float yc = (rect->y1+rect->y0) / 2; rect->y0 = yc - 25 * xs; rect->y1 = yc + 25 * xs; } }
static void pdf_write_highlight_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, pdf_obj **res) { pdf_obj *res_egs, *res_egs_h; pdf_obj *qp; fz_point quad[4], mquad[4], v; float opacity, h, m, dx, dy, vn; int i, n; *rect = fz_empty_rect; /* /Resources << /ExtGState << /H << /Type/ExtGState /BM/Multiply /CA %g >> >> >> */ *res = pdf_new_dict(ctx, annot->page->doc, 1); res_egs = pdf_dict_put_dict(ctx, *res, PDF_NAME(ExtGState), 1); res_egs_h = pdf_dict_put_dict(ctx, res_egs, PDF_NAME(H), 2); pdf_dict_put(ctx, res_egs_h, PDF_NAME(Type), PDF_NAME(ExtGState)); pdf_dict_put(ctx, res_egs_h, PDF_NAME(BM), PDF_NAME(Multiply)); opacity = pdf_annot_opacity(ctx, annot); if (opacity < 1) pdf_dict_put_real(ctx, res_egs_h, PDF_NAME(ca), opacity); pdf_write_fill_color_appearance(ctx, annot, buf); fz_append_printf(ctx, buf, "/H gs\n"); qp = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints)); n = pdf_array_len(ctx, qp); if (n > 0) { for (i = 0; i < n; i += 8) { h = extract_quad(ctx, quad, qp, i); m = h / 4.2425f; /* magic number that matches adobe's appearance */ dx = quad[LR].x - quad[LL].x; dy = quad[LR].y - quad[LL].y; vn = sqrtf(dx * dx + dy * dy); v = fz_make_point(dx * m / vn, dy * m / vn); mquad[LL].x = quad[LL].x - v.x - v.y; mquad[LL].y = quad[LL].y - v.y + v.x; mquad[UL].x = quad[UL].x - v.x + v.y; mquad[UL].y = quad[UL].y - v.y - v.x; mquad[LR].x = quad[LR].x + v.x - v.y; mquad[LR].y = quad[LR].y + v.y + v.x; mquad[UR].x = quad[UR].x + v.x + v.y; mquad[UR].y = quad[UR].y + v.y - v.x; fz_append_printf(ctx, buf, "%g %g m\n", quad[LL].x, quad[LL].y); fz_append_printf(ctx, buf, "%g %g %g %g %g %g c\n", mquad[LL].x, mquad[LL].y, mquad[UL].x, mquad[UL].y, quad[UL].x, quad[UL].y); fz_append_printf(ctx, buf, "%g %g l\n", quad[UR].x, quad[UR].y); fz_append_printf(ctx, buf, "%g %g %g %g %g %g c\n", mquad[UR].x, mquad[UR].y, mquad[LR].x, mquad[LR].y, quad[LR].x, quad[LR].y); fz_append_printf(ctx, buf, "f\n"); union_quad(rect, quad, h/16); union_quad(rect, mquad, 0); } } }