7 #define ALLOWED_TEXT_POS_ERROR (0.001f)
9 typedef struct pdf_device_s pdf_device;
11 typedef struct gstate_s gstate;
15 /* The first few entries aren't really graphics state things, but
16 * they are recorded here as they are fundamentally intertwined with
17 * the push/pulling of the gstates. */
19 void (*on_pop)(pdf_device*,void *);
21 /* The graphics state proper */
22 fz_colorspace *colorspace[2];
25 fz_stroke_state *stroke_state;
31 float horizontal_scaling;
33 int text_rendering_mode;
39 typedef struct image_entry_s image_entry;
47 typedef struct alpha_entry_s alpha_entry;
55 typedef struct font_entry_s font_entry;
62 typedef struct group_entry_s group_entry;
69 fz_colorspace *colorspace;
106 #define CURRENT_GSTATE(pdev) (&(pdev)->gstates[(pdev)->num_gstates-1])
108 /* Helper functions */
111 send_image(pdf_device *pdev, fz_image *image, int mask, int smask)
113 fz_context *ctx = pdev->ctx;
114 fz_pixmap *pixmap = NULL;
115 pdf_obj *imobj = NULL;
116 pdf_obj *imref = NULL;
117 fz_compressed_buffer *cbuffer = NULL;
118 fz_compression_params *cp = NULL;
119 fz_buffer *buffer = NULL;
122 unsigned char digest[16];
123 fz_colorspace *colorspace = image->colorspace;
124 pdf_document *doc = pdev->doc;
126 /* If we can maintain compression, do so */
127 cbuffer = image->buffer;
136 if (cbuffer != NULL && cbuffer->params.type != FZ_IMAGE_PNG && cbuffer->params.type != FZ_IMAGE_TIFF)
138 buffer = fz_keep_buffer(ctx, cbuffer->buffer);
139 cp = &cbuffer->params;
145 /* Currently, set to maintain resolution; should we consider
146 * subsampling here according to desired output res? */
147 pixmap = image->get_pixmap(ctx, image, image->w, image->h);
148 colorspace = pixmap->colorspace; /* May be different to image->colorspace! */
149 n = (pixmap->n == 1 ? 1 : pixmap->n-1);
150 size = image->w * image->h * n;
151 buffer = fz_new_buffer(ctx, size);
155 memcpy(buffer->data, pixmap->samples, size);
159 /* Need to remove the alpha plane */
160 unsigned char *d = buffer->data;
161 unsigned char *s = pixmap->samples;
174 fz_md5_update(&state, buffer->data, buffer->len);
175 fz_md5_final(&state, digest);
176 for(i=0; i < pdev->num_imgs; i++)
178 if (!memcmp(&digest, pdev->images[i].digest, sizeof(16)))
185 if (i < pdev->num_imgs)
188 if (pdev->num_imgs == pdev->max_imgs)
190 int newmax = pdev->max_imgs * 2;
193 pdev->images = fz_resize_array(ctx, pdev->images, newmax, sizeof(*pdev->images));
194 pdev->max_imgs = newmax;
196 num = pdev->num_imgs++;
197 memcpy(pdev->images[num].digest,digest,16);
198 pdev->images[num].ref = NULL; /* Will be filled in later */
200 imobj = pdf_new_dict(doc, 3);
201 pdf_dict_puts_drop(imobj, "Type", pdf_new_name(doc, "XObject"));
202 pdf_dict_puts_drop(imobj, "Subtype", pdf_new_name(doc, "Image"));
203 pdf_dict_puts_drop(imobj, "Width", pdf_new_int(doc, image->w));
204 pdf_dict_puts_drop(imobj, "Height", pdf_new_int(doc, image->h));
207 else if (!colorspace || colorspace->n == 1)
208 pdf_dict_puts_drop(imobj, "ColorSpace", pdf_new_name(doc, "DeviceGray"));
209 else if (colorspace->n == 3)
210 pdf_dict_puts_drop(imobj, "ColorSpace", pdf_new_name(doc, "DeviceRGB"));
211 else if (colorspace->n == 4)
212 pdf_dict_puts_drop(imobj, "ColorSpace", pdf_new_name(doc, "DeviceCMYK"));
214 pdf_dict_puts_drop(imobj, "BitsPerComponent", pdf_new_int(doc, image->bpc));
215 switch (cp ? cp->type : FZ_IMAGE_UNKNOWN)
217 case FZ_IMAGE_UNKNOWN: /* Unknown also means raw */
221 if (cp->u.jpeg.color_transform != -1)
222 pdf_dict_puts_drop(imobj, "ColorTransform", pdf_new_int(doc, cp->u.jpeg.color_transform));
223 pdf_dict_puts_drop(imobj, "Filter", pdf_new_name(doc, "DCTDecode"));
226 if (cp->u.jpx.smask_in_data)
227 pdf_dict_puts_drop(imobj, "SMaskInData", pdf_new_int(doc, cp->u.jpx.smask_in_data));
228 pdf_dict_puts_drop(imobj, "Filter", pdf_new_name(doc, "JPXDecode"));
231 if (cp->u.fax.columns)
232 pdf_dict_puts_drop(imobj, "Columns", pdf_new_int(doc, cp->u.fax.columns));
234 pdf_dict_puts_drop(imobj, "Rows", pdf_new_int(doc, cp->u.fax.rows));
236 pdf_dict_puts_drop(imobj, "K", pdf_new_int(doc, cp->u.fax.k));
237 if (cp->u.fax.end_of_line)
238 pdf_dict_puts_drop(imobj, "EndOfLine", pdf_new_int(doc, cp->u.fax.end_of_line));
239 if (cp->u.fax.encoded_byte_align)
240 pdf_dict_puts_drop(imobj, "EncodedByteAlign", pdf_new_int(doc, cp->u.fax.encoded_byte_align));
241 if (cp->u.fax.end_of_block)
242 pdf_dict_puts_drop(imobj, "EndOfBlock", pdf_new_int(doc, cp->u.fax.end_of_block));
243 if (cp->u.fax.black_is_1)
244 pdf_dict_puts_drop(imobj, "BlackIs1", pdf_new_int(doc, cp->u.fax.black_is_1));
245 if (cp->u.fax.damaged_rows_before_error)
246 pdf_dict_puts_drop(imobj, "DamagedRowsBeforeError", pdf_new_int(doc, cp->u.fax.damaged_rows_before_error));
247 pdf_dict_puts_drop(imobj, "Filter", pdf_new_name(doc, "CCITTFaxDecode"));
250 /* FIXME - jbig2globals */
251 cp->type = FZ_IMAGE_UNKNOWN;
254 if (cp->u.flate.columns)
255 pdf_dict_puts_drop(imobj, "Columns", pdf_new_int(doc, cp->u.flate.columns));
256 if (cp->u.flate.colors)
257 pdf_dict_puts_drop(imobj, "Colors", pdf_new_int(doc, cp->u.flate.colors));
258 if (cp->u.flate.predictor)
259 pdf_dict_puts_drop(imobj, "Predictor", pdf_new_int(doc, cp->u.flate.predictor));
260 pdf_dict_puts_drop(imobj, "Filter", pdf_new_name(doc, "FlateDecode"));
261 pdf_dict_puts_drop(imobj, "BitsPerComponent", pdf_new_int(doc, image->bpc));
264 if (cp->u.lzw.columns)
265 pdf_dict_puts_drop(imobj, "Columns", pdf_new_int(doc, cp->u.lzw.columns));
266 if (cp->u.lzw.colors)
267 pdf_dict_puts_drop(imobj, "Colors", pdf_new_int(doc, cp->u.lzw.colors));
268 if (cp->u.lzw.predictor)
269 pdf_dict_puts_drop(imobj, "Predictor", pdf_new_int(doc, cp->u.lzw.predictor));
270 if (cp->u.lzw.early_change)
271 pdf_dict_puts_drop(imobj, "EarlyChange", pdf_new_int(doc, cp->u.lzw.early_change));
272 pdf_dict_puts_drop(imobj, "Filter", pdf_new_name(doc, "LZWDecode"));
275 pdf_dict_puts_drop(imobj, "Filter", pdf_new_name(doc, "RunLengthDecode"));
280 pdf_dict_puts_drop(imobj, "ImageMask", pdf_new_bool(doc, 1));
284 int smasknum = send_image(pdev, image->mask, 0, 1);
285 pdf_dict_puts(imobj, "SMask", pdev->images[smasknum].ref);
288 imref = pdf_new_ref(doc, imobj);
289 pdf_update_stream(doc, pdf_to_num(imref), buffer);
290 pdf_dict_puts_drop(imobj, "Length", pdf_new_int(doc, buffer->len));
294 snprintf(text, sizeof(text), "XObject/Img%d", num);
295 pdf_dict_putp(pdev->resources, text, imref);
297 pdev->images[num].ref = imref;
301 fz_drop_buffer(ctx, buffer);
303 fz_drop_pixmap(ctx, pixmap);
314 pdf_dev_stroke_state(pdf_device *pdev, fz_stroke_state *stroke_state)
316 fz_context *ctx = pdev->ctx;
317 gstate *gs = CURRENT_GSTATE(pdev);
319 if (stroke_state == gs->stroke_state)
321 if (gs->stroke_state && !memcmp(stroke_state, gs->stroke_state, sizeof(*stroke_state)))
323 if (!gs->stroke_state || gs->stroke_state->linewidth != stroke_state->linewidth)
325 fz_buffer_printf(ctx, gs->buf, "%f w\n", stroke_state->linewidth);
327 if (!gs->stroke_state || gs->stroke_state->start_cap != stroke_state->start_cap)
329 int cap = stroke_state->start_cap;
330 /* FIXME: Triangle caps aren't supported in pdf */
331 if (cap == FZ_LINECAP_TRIANGLE)
332 cap = FZ_LINECAP_BUTT;
333 fz_buffer_printf(ctx, gs->buf, "%d J\n", cap);
335 if (!gs->stroke_state || gs->stroke_state->linejoin != stroke_state->linejoin)
337 int join = stroke_state->linejoin;
338 if (join == FZ_LINEJOIN_MITER_XPS)
339 join = FZ_LINEJOIN_MITER;
340 fz_buffer_printf(ctx, gs->buf, "%d j\n", join);
342 if (!gs->stroke_state || gs->stroke_state->miterlimit != stroke_state->miterlimit)
344 fz_buffer_printf(ctx, gs->buf, "%f M\n", stroke_state->miterlimit);
346 if (gs->stroke_state == NULL && stroke_state->dash_len == 0)
348 else if (!gs->stroke_state || gs->stroke_state->dash_phase != stroke_state->dash_phase || gs->stroke_state->dash_len != stroke_state->dash_len ||
349 memcmp(gs->stroke_state->dash_list, stroke_state->dash_list, sizeof(float)*stroke_state->dash_len))
352 if (stroke_state->dash_len == 0)
353 fz_buffer_printf(ctx, gs->buf, "[");
354 for (i = 0; i < stroke_state->dash_len; i++)
355 fz_buffer_printf(ctx, gs->buf, "%c%f", (i == 0 ? '[' : ' '), stroke_state->dash_list[i]);
356 fz_buffer_printf(ctx, gs->buf, "]%f d\n", stroke_state->dash_phase);
359 fz_drop_stroke_state(ctx, gs->stroke_state);
360 gs->stroke_state = fz_keep_stroke_state(ctx, stroke_state);
364 pdf_dev_path(pdf_device *pdev, fz_path *path)
366 fz_context *ctx = pdev->ctx;
367 gstate *gs = CURRENT_GSTATE(pdev);
370 while (i < path->cmd_len)
372 switch (path->cmds[i++])
375 x = path->coords[k++];
376 y = path->coords[k++];
377 fz_buffer_printf(ctx, gs->buf, "%f %f m\n", x, y);
380 x = path->coords[k++];
381 y = path->coords[k++];
382 fz_buffer_printf(ctx, gs->buf, "%f %f l\n", x, y);
385 x = path->coords[k++];
386 y = path->coords[k++];
387 fz_buffer_printf(ctx, gs->buf, "%f %f ", x, y);
388 x = path->coords[k++];
389 y = path->coords[k++];
390 fz_buffer_printf(ctx, gs->buf, "%f %f ", x, y);
391 x = path->coords[k++];
392 y = path->coords[k++];
393 fz_buffer_printf(ctx, gs->buf, "%f %f c\n", x, y);
396 fz_buffer_printf(ctx, gs->buf, "h\n");
403 pdf_dev_ctm(pdf_device *pdev, const fz_matrix *ctm)
406 gstate *gs = CURRENT_GSTATE(pdev);
408 if (memcmp(&gs->ctm, ctm, sizeof(*ctm)) == 0)
410 fz_invert_matrix(&inverse, &gs->ctm);
411 fz_concat(&inverse, ctm, &inverse);
412 memcpy(&gs->ctm, ctm, sizeof(*ctm));
413 fz_buffer_printf(pdev->ctx, gs->buf, "%f %f %f %f %f %f cm\n", inverse.a, inverse.b, inverse.c, inverse.d, inverse.e, inverse.f);
417 pdf_dev_color(pdf_device *pdev, fz_colorspace *colorspace, float *color, int stroke)
422 fz_context *ctx = pdev->ctx;
423 float rgb[FZ_MAX_COLORS];
424 gstate *gs = CURRENT_GSTATE(pdev);
426 if (colorspace == fz_device_gray(ctx))
428 else if (colorspace == fz_device_rgb(ctx))
430 else if (colorspace == fz_device_cmyk(ctx))
435 /* If it's an unknown colorspace, fallback to rgb */
436 colorspace->to_rgb(ctx, colorspace, color, rgb);
438 colorspace = fz_device_rgb(ctx);
441 if (gs->colorspace[stroke] != colorspace)
443 gs->colorspace[stroke] = colorspace;
447 for (i=0; i < colorspace->n; i++)
448 if (gs->color[stroke][i] != color[i])
450 gs->color[stroke][i] = color[i];
457 switch (cspace + stroke*8)
460 fz_buffer_printf(ctx, gs->buf, "%f g\n", color[0]);
463 fz_buffer_printf(ctx, gs->buf, "%f %f %f rg\n", color[0], color[1], color[2]);
466 fz_buffer_printf(ctx, gs->buf, "%f %f %f %f k\n", color[0], color[1], color[2], color[3]);
469 fz_buffer_printf(ctx, gs->buf, "%f G\n", color[0]);
472 fz_buffer_printf(ctx, gs->buf, "%f %f %f RG\n", color[0], color[1], color[2]);
475 fz_buffer_printf(ctx, gs->buf, "%f %f %f %f K\n", color[0], color[1], color[2], color[3]);
481 pdf_dev_alpha(pdf_device *pdev, float alpha, int stroke)
484 fz_context *ctx = pdev->ctx;
485 pdf_document *doc = pdev->doc;
486 gstate *gs = CURRENT_GSTATE(pdev);
488 /* If the alpha is unchanged, nothing to do */
489 if (gs->alpha[stroke] == alpha)
492 /* Have we sent such an alpha before? */
493 for (i = 0; i < pdev->num_alphas; i++)
494 if (pdev->alphas[i].alpha == alpha && pdev->alphas[i].stroke == stroke)
497 if (i == pdev->num_alphas)
504 /* No. Need to make a new one */
505 if (pdev->num_alphas == pdev->max_alphas)
507 int newmax = pdev->max_alphas * 2;
510 pdev->alphas = fz_resize_array(ctx, pdev->alphas, newmax, sizeof(*pdev->alphas));
511 pdev->max_alphas = newmax;
513 pdev->alphas[i].alpha = alpha;
514 pdev->alphas[i].stroke = stroke;
516 o = pdf_new_dict(doc, 1);
520 pdf_dict_puts_drop(o, (stroke ? "CA" : "ca"), pdf_new_real(doc, alpha));
521 ref = pdf_new_ref(doc, o);
522 snprintf(text, sizeof(text), "ExtGState/Alp%d", i);
523 pdf_dict_putp(pdev->resources, text, ref);
536 fz_buffer_printf(ctx, gs->buf, "/Alp%d gs\n", i);
540 pdf_dev_font(pdf_device *pdev, fz_font *font, float size)
543 pdf_document *doc = pdev->doc;
544 fz_context *ctx = pdev->ctx;
545 gstate *gs = CURRENT_GSTATE(pdev);
547 /* If the font is unchanged, nothing to do */
548 if (gs->font >= 0 && pdev->fonts[gs->font].font == font)
551 if (font->ft_buffer != NULL || font->ft_substitute)
552 fz_throw(pdev->ctx, FZ_ERROR_GENERIC, "pdf device supports only base 14 fonts currently");
554 /* Have we sent such a font before? */
555 for (i = 0; i < pdev->num_fonts; i++)
556 if (pdev->fonts[i].font == font)
559 if (i == pdev->num_fonts)
566 /* No. Need to make a new one */
567 if (pdev->num_fonts == pdev->max_fonts)
569 int newmax = pdev->max_fonts * 2;
572 pdev->fonts = fz_resize_array(ctx, pdev->fonts, newmax, sizeof(*pdev->fonts));
573 pdev->max_fonts = newmax;
575 pdev->fonts[i].font = fz_keep_font(ctx, font);
577 o = pdf_new_dict(doc, 3);
581 pdf_dict_puts_drop(o, "Type", pdf_new_name(doc, "Font"));
582 pdf_dict_puts_drop(o, "Subtype", pdf_new_name(doc, "Type1"));
583 pdf_dict_puts_drop(o, "BaseFont", pdf_new_name(doc, font->name));
584 pdf_dict_puts_drop(o, "Encoding", pdf_new_name(doc, "WinAnsiEncoding"));
585 ref = pdf_new_ref(doc, o);
586 snprintf(text, sizeof(text), "Font/F%d", i);
587 pdf_dict_putp(pdev->resources, text, ref);
600 fz_buffer_printf(ctx, gs->buf, "/F%d %f Tf\n", i, size);
604 pdf_dev_tm(pdf_device *pdev, const fz_matrix *tm)
606 gstate *gs = CURRENT_GSTATE(pdev);
608 if (memcmp(&gs->tm, tm, sizeof(*tm)) == 0)
610 fz_buffer_printf(pdev->ctx, gs->buf, "%f %f %f %f %f %f Tm\n", tm->a, tm->b, tm->c, tm->d, tm->e, tm->f);
615 pdf_dev_push_new_buf(pdf_device *pdev, fz_buffer *buf, void (*on_pop)(pdf_device*,void *), void *on_pop_arg)
617 fz_context *ctx = pdev->ctx;
619 if (pdev->num_gstates == pdev->max_gstates)
621 int newmax = pdev->max_gstates*2;
623 pdev->gstates = fz_resize_array(ctx, pdev->gstates, newmax, sizeof(*pdev->gstates));
624 pdev->max_gstates = newmax;
626 memcpy(&pdev->gstates[pdev->num_gstates], &pdev->gstates[pdev->num_gstates-1], sizeof(*pdev->gstates));
627 fz_keep_stroke_state(ctx, pdev->gstates[pdev->num_gstates].stroke_state);
629 pdev->gstates[pdev->num_gstates].buf = buf;
631 fz_keep_buffer(ctx, pdev->gstates[pdev->num_gstates].buf);
632 pdev->gstates[pdev->num_gstates].on_pop = on_pop;
633 pdev->gstates[pdev->num_gstates].on_pop_arg = on_pop_arg;
634 fz_buffer_printf(ctx, pdev->gstates[pdev->num_gstates].buf, "q\n");
639 pdf_dev_push(pdf_device *pdev)
641 pdf_dev_push_new_buf(pdev, NULL, NULL, NULL);
645 pdf_dev_pop(pdf_device *pdev)
647 fz_context *ctx = pdev->ctx;
648 gstate *gs = CURRENT_GSTATE(pdev);
649 void *arg = gs->on_pop_arg;
651 fz_buffer_printf(pdev->ctx, gs->buf, "Q\n");
653 gs->on_pop(pdev, arg);
655 fz_drop_stroke_state(ctx, pdev->gstates[pdev->num_gstates].stroke_state);
656 fz_drop_buffer(ctx, pdev->gstates[pdev->num_gstates].buf);
661 pdf_dev_text(pdf_device *pdev, fz_text *text, float size)
663 int mask = FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
667 gstate *gs = CURRENT_GSTATE(pdev);
677 fz_invert_matrix(&inverse, &trunc_trm);
680 while (i < text->len)
682 fz_text_item *it = &text->items[i];
687 delta.x = it->x - trm.e;
688 delta.y = it->y - trm.f;
689 fz_transform_point(&delta, &inverse);
690 if (delta.x != 0 || delta.y != 0)
692 fz_buffer_printf(pdev->ctx, gs->buf, "%f %f Td ", delta.x, delta.y);
698 if (text->font->ft_face)
700 /* Find prefix of text for which the advance of each character accounts
701 * for the position offset */
703 while (j < text->len)
706 FT_Get_Advance(text->font->ft_face, text->items[j-1].gid, mask, &adv);
707 x += (float)adv * size /((FT_Face)text->font->ft_face)->units_per_EM;
708 if (fabs(x - text->items[j].x) > ALLOWED_TEXT_POS_ERROR || fabs(it->y - text->items[j].y) > ALLOWED_TEXT_POS_ERROR)
714 fz_buffer_printf(pdev->ctx, gs->buf, "<");
715 for (/* i from its current value */; i < j; i++)
717 /* FIXME: should use it->gid, rather than it->ucs, and convert
718 * to the correct encoding */
719 fz_buffer_printf(pdev->ctx, gs->buf, "%02x", text->items[i].ucs);
721 fz_buffer_printf(pdev->ctx, gs->buf, "> Tj\n");
728 pdf_dev_trm(pdf_device *pdev, int trm)
730 gstate *gs = CURRENT_GSTATE(pdev);
732 if (gs->text_rendering_mode == trm)
734 gs->text_rendering_mode = trm;
735 fz_buffer_printf(pdev->ctx, gs->buf, "%d Tr\n", trm);
739 pdf_dev_begin_text(pdf_device *pdev, const fz_matrix *tm, int trm)
741 pdf_dev_trm(pdev, trm);
744 gstate *gs = CURRENT_GSTATE(pdev);
745 fz_buffer_printf(pdev->ctx, gs->buf, "BT\n");
754 pdf_dev_tm(pdev, tm);
758 pdf_dev_end_text(pdf_device *pdev)
760 gstate *gs = CURRENT_GSTATE(pdev);
765 fz_buffer_printf(pdev->ctx, gs->buf, "ET\n");
769 pdf_dev_new_form(pdf_obj **form_ref, pdf_device *pdev, const fz_rect *bbox, int isolated, int knockout, float alpha, fz_colorspace *colorspace)
771 fz_context *ctx = pdev->ctx;
772 pdf_document *doc = pdev->doc;
780 /* Find (or make) a new group with the required options. */
781 for(num = 0; num < pdev->num_groups; num++)
783 group_entry *g = &pdev->groups[num];
784 if (g->isolated == isolated && g->knockout == knockout && g->alpha == alpha && g->colorspace == colorspace)
786 group_ref = pdev->groups[num].ref;
791 /* If we didn't find one, make one */
792 if (num == pdev->num_groups)
794 if (pdev->num_groups == pdev->max_groups)
796 int newmax = pdev->max_groups * 2;
799 pdev->groups = fz_resize_array(ctx, pdev->groups, newmax, sizeof(*pdev->groups));
800 pdev->max_groups = newmax;
803 pdev->groups[num].isolated = isolated;
804 pdev->groups[num].knockout = knockout;
805 pdev->groups[num].alpha = alpha;
806 pdev->groups[num].colorspace = fz_keep_colorspace(ctx, colorspace);
807 pdev->groups[num].ref = NULL;
808 group = pdf_new_dict(doc, 5);
811 pdf_dict_puts_drop(group, "Type", pdf_new_name(doc, "Group"));
812 pdf_dict_puts_drop(group, "S", pdf_new_name(doc, "Transparency"));
813 pdf_dict_puts_drop(group, "K", pdf_new_bool(doc, knockout));
814 pdf_dict_puts_drop(group, "I", pdf_new_bool(doc, isolated));
817 else if (colorspace->n == 1)
818 pdf_dict_puts_drop(group, "CS", pdf_new_name(doc, "DeviceGray"));
819 else if (colorspace->n == 4)
820 pdf_dict_puts_drop(group, "CS", pdf_new_name(doc, "DeviceCMYK"));
822 pdf_dict_puts_drop(group, "CS", pdf_new_name(doc, "DeviceRGB"));
823 group_ref = pdev->groups[num].ref = pdf_new_ref(doc, group);
835 /* Make us a new Forms object that points to that group, and change
836 * to writing into the buffer for that Forms object. */
837 form = pdf_new_dict(doc, 4);
840 pdf_dict_puts_drop(form, "Subtype", pdf_new_name(doc, "Form"));
841 pdf_dict_puts(form, "Group", group_ref);
842 pdf_dict_puts_drop(form, "FormType", pdf_new_int(doc, 1));
843 pdf_dict_puts_drop(form, "BBox", pdf_new_rect(doc, bbox));
844 *form_ref = pdf_new_ref(doc, form);
852 /* Insert the new form object into the resources */
855 num = pdev->num_forms++;
856 snprintf(text, sizeof(text), "XObject/Fm%d", num);
857 pdf_dict_putp(pdev->resources, text, *form_ref);
866 pdf_dev_fill_path(fz_device *dev, fz_path *path, int even_odd, const fz_matrix *ctm,
867 fz_colorspace *colorspace, float *color, float alpha)
869 pdf_device *pdev = dev->user;
870 gstate *gs = CURRENT_GSTATE(pdev);
872 pdf_dev_end_text(pdev);
873 pdf_dev_alpha(pdev, alpha, 0);
874 pdf_dev_color(pdev, colorspace, color, 0);
875 pdf_dev_ctm(pdev, ctm);
876 pdf_dev_path(pdev, path);
877 fz_buffer_printf(dev->ctx, gs->buf, (even_odd ? "f*\n" : "f\n"));
881 pdf_dev_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, const fz_matrix *ctm,
882 fz_colorspace *colorspace, float *color, float alpha)
884 pdf_device *pdev = dev->user;
885 gstate *gs = CURRENT_GSTATE(pdev);
887 pdf_dev_end_text(pdev);
888 pdf_dev_alpha(pdev, alpha, 1);
889 pdf_dev_color(pdev, colorspace, color, 1);
890 pdf_dev_ctm(pdev, ctm);
891 pdf_dev_stroke_state(pdev, stroke);
892 pdf_dev_path(pdev, path);
893 fz_buffer_printf(dev->ctx, gs->buf, "S\n");
897 pdf_dev_clip_path(fz_device *dev, fz_path *path, const fz_rect *rect, int even_odd, const fz_matrix *ctm)
899 pdf_device *pdev = dev->user;
902 pdf_dev_end_text(pdev);
904 pdf_dev_ctm(pdev, ctm);
905 pdf_dev_path(pdev, path);
906 gs = CURRENT_GSTATE(pdev);
907 fz_buffer_printf(dev->ctx, gs->buf, (even_odd ? "W* n\n" : "W n\n"));
911 pdf_dev_clip_stroke_path(fz_device *dev, fz_path *path, const fz_rect *rect, fz_stroke_state *stroke, const fz_matrix *ctm)
913 pdf_device *pdev = dev->user;
916 pdf_dev_end_text(pdev);
918 /* FIXME: Need to push a group, select a pattern (or shading) here,
919 * stroke with the pattern/shading. Then move to defining that pattern
920 * with the next calls to the device interface until the next pop
921 * when we pop the group. */
922 pdf_dev_ctm(pdev, ctm);
923 pdf_dev_path(pdev, path);
924 gs = CURRENT_GSTATE(pdev);
925 fz_buffer_printf(dev->ctx, gs->buf, "W n\n");
929 pdf_dev_fill_text(fz_device *dev, fz_text *text, const fz_matrix *ctm,
930 fz_colorspace *colorspace, float *color, float alpha)
932 pdf_device *pdev = dev->user;
933 fz_matrix trm = text->trm;
934 float size = fz_matrix_expansion(&trm);
936 fz_pre_scale(&trm, 1/size, 1/size);
938 pdf_dev_begin_text(pdev, &trm, 0);
939 pdf_dev_font(pdev, text->font, size);
940 pdf_dev_ctm(pdev, ctm);
941 pdf_dev_alpha(pdev, alpha, 0);
942 pdf_dev_color(pdev, colorspace, color, 0);
943 pdf_dev_text(pdev, text, size);
947 pdf_dev_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm,
948 fz_colorspace *colorspace, float *color, float alpha)
950 pdf_device *pdev = dev->user;
951 fz_matrix trm = text->trm;
952 float size = fz_matrix_expansion(&trm);
954 fz_pre_scale(&trm, 1/size, 1/size);
956 pdf_dev_begin_text(pdev, &text->trm, 1);
957 pdf_dev_font(pdev, text->font, 1);
958 pdf_dev_ctm(pdev, ctm);
959 pdf_dev_alpha(pdev, alpha, 1);
960 pdf_dev_color(pdev, colorspace, color, 1);
961 pdf_dev_text(pdev, text, size);
965 pdf_dev_clip_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, int accumulate)
967 pdf_device *pdev = dev->user;
968 fz_matrix trm = text->trm;
969 float size = fz_matrix_expansion(&trm);
971 fz_pre_scale(&trm, 1/size, 1/size);
973 pdf_dev_begin_text(pdev, &text->trm, 0);
974 pdf_dev_ctm(pdev, ctm);
975 pdf_dev_font(pdev, text->font, 7);
976 pdf_dev_text(pdev, text, size);
980 pdf_dev_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm)
982 pdf_device *pdev = dev->user;
983 fz_matrix trm = text->trm;
984 float size = fz_matrix_expansion(&trm);
986 fz_pre_scale(&trm, 1/size, 1/size);
988 pdf_dev_begin_text(pdev, &text->trm, 0);
989 pdf_dev_font(pdev, text->font, 5);
990 pdf_dev_ctm(pdev, ctm);
991 pdf_dev_text(pdev, text, size);
995 pdf_dev_ignore_text(fz_device *dev, fz_text *text, const fz_matrix *ctm)
997 pdf_device *pdev = dev->user;
998 fz_matrix trm = text->trm;
999 float size = fz_matrix_expansion(&trm);
1001 fz_pre_scale(&trm, 1/size, 1/size);
1003 pdf_dev_begin_text(pdev, &text->trm, 0);
1004 pdf_dev_ctm(pdev, ctm);
1005 pdf_dev_font(pdev, text->font, 3);
1006 pdf_dev_text(pdev, text, size);
1010 pdf_dev_fill_image(fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha)
1012 pdf_device *pdev = (pdf_device *)dev->user;
1014 gstate *gs = CURRENT_GSTATE(pdev);
1015 fz_matrix local_ctm = *ctm;
1017 pdf_dev_end_text(pdev);
1018 num = send_image(pdev, image, 0, 0);
1019 pdf_dev_alpha(pdev, alpha, 0);
1020 /* PDF images are upside down, so fiddle the ctm */
1021 fz_pre_scale(&local_ctm, 1, -1);
1022 fz_pre_translate(&local_ctm, 0, -1);
1023 pdf_dev_ctm(pdev, &local_ctm);
1024 fz_buffer_printf(dev->ctx, gs->buf, "/Img%d Do\n", num);
1028 pdf_dev_fill_shade(fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha)
1030 pdf_device *pdev = (pdf_device *)dev->user;
1033 pdf_dev_end_text(pdev);
1037 pdf_dev_fill_image_mask(fz_device *dev, fz_image *image, const fz_matrix *ctm,
1038 fz_colorspace *colorspace, float *color, float alpha)
1040 pdf_device *pdev = (pdf_device *)dev->user;
1041 gstate *gs = CURRENT_GSTATE(pdev);
1043 fz_matrix local_ctm = *ctm;
1045 pdf_dev_end_text(pdev);
1046 num = send_image(pdev, image, 1, 0);
1047 fz_buffer_printf(dev->ctx, gs->buf, "q\n");
1048 pdf_dev_alpha(pdev, alpha, 0);
1049 pdf_dev_color(pdev, colorspace, color, 0);
1050 /* PDF images are upside down, so fiddle the ctm */
1051 fz_pre_scale(&local_ctm, 1, -1);
1052 fz_pre_translate(&local_ctm, 0, -1);
1053 pdf_dev_ctm(pdev, &local_ctm);
1054 fz_buffer_printf(dev->ctx, gs->buf, "/Img%d Do Q\n", num);
1058 pdf_dev_clip_image_mask(fz_device *dev, fz_image *image, const fz_rect *rect, const fz_matrix *ctm)
1060 pdf_device *pdev = (pdf_device *)dev->user;
1063 pdf_dev_end_text(pdev);
1068 pdf_dev_pop_clip(fz_device *dev)
1070 pdf_device *pdev = (pdf_device *)dev->user;
1073 pdf_dev_end_text(pdev);
1078 pdf_dev_begin_mask(fz_device *dev, const fz_rect *bbox, int luminosity, fz_colorspace *colorspace, float *color)
1080 pdf_device *pdev = (pdf_device *)dev->user;
1081 pdf_document *doc = pdev->doc;
1082 fz_context *ctx = pdev->ctx;
1084 pdf_obj *smask = NULL;
1085 pdf_obj *egs = NULL;
1088 pdf_obj *color_obj = NULL;
1095 pdf_dev_end_text(pdev);
1097 /* Make a new form to contain the contents of the softmask */
1098 pdf_dev_new_form(&form_ref, pdev, bbox, 0, 0, 1, colorspace);
1102 smask = pdf_new_dict(doc, 4);
1103 pdf_dict_puts_drop(smask, "Type", pdf_new_name(doc, "Mask"));
1104 pdf_dict_puts_drop(smask, "S", pdf_new_name(doc, (luminosity ? "Luminosity" : "Alpha")));
1105 pdf_dict_puts(smask, "G", form_ref);
1106 color_obj = pdf_new_array(doc, colorspace->n);
1107 for (i = 0; i < colorspace->n; i++)
1108 pdf_array_push(color_obj, pdf_new_real(doc, color[i]));
1109 pdf_dict_puts_drop(smask, "BC", color_obj);
1112 egs = pdf_new_dict(doc, 5);
1113 pdf_dict_puts_drop(egs, "Type", pdf_new_name(doc, "ExtGState"));
1114 pdf_dict_puts_drop(egs, "SMask", pdf_new_ref(doc, smask));
1115 egs_ref = pdf_new_ref(doc, egs);
1119 snprintf(text, sizeof(text), "ExtGState/SM%d", pdev->num_smasks++);
1120 pdf_dict_putp(pdev->resources, text, egs_ref);
1121 pdf_drop_obj(egs_ref);
1123 gs = CURRENT_GSTATE(pdev);
1124 fz_buffer_printf(dev->ctx, gs->buf, "/SM%d gs\n", pdev->num_smasks-1);
1128 pdf_drop_obj(smask);
1132 pdf_drop_obj(form_ref);
1133 pdf_drop_obj(color_obj);
1137 /* Now, everything we get until the end_mask needs to go into a
1138 * new buffer, which will be the stream contents for the form. */
1139 pdf_dev_push_new_buf(pdev, fz_new_buffer(ctx, 1024), NULL, form_ref);
1143 pdf_dev_end_mask(fz_device *dev)
1145 pdf_device *pdev = (pdf_device *)dev->user;
1146 pdf_document *doc = pdev->doc;
1147 fz_context *ctx = pdev->ctx;
1148 gstate *gs = CURRENT_GSTATE(pdev);
1149 fz_buffer *buf = fz_keep_buffer(ctx, gs->buf);
1150 pdf_obj *form_ref = (pdf_obj *)gs->on_pop_arg;
1152 /* Here we do part of the pop, but not all of it. */
1153 pdf_dev_end_text(pdev);
1154 fz_buffer_printf(ctx, buf, "Q\n");
1155 pdf_dict_puts_drop(form_ref, "Length", pdf_new_int(doc, buf->len));
1156 pdf_update_stream(doc, pdf_to_num(form_ref), buf);
1157 fz_drop_buffer(ctx, buf);
1158 gs->buf = fz_keep_buffer(ctx, gs[-1].buf);
1159 gs->on_pop_arg = NULL;
1160 pdf_drop_obj(form_ref);
1161 fz_buffer_printf(ctx, gs->buf, "q\n");
1165 pdf_dev_begin_group(fz_device *dev, const fz_rect *bbox, int isolated, int knockout, int blendmode, float alpha)
1167 pdf_device *pdev = (pdf_device *)dev->user;
1168 fz_context *ctx = pdev->ctx;
1169 pdf_document *doc = pdev->doc;
1174 pdf_dev_end_text(pdev);
1176 num = pdf_dev_new_form(&form_ref, pdev, bbox, isolated, knockout, alpha, NULL);
1178 /* Do we have an appropriate blending extgstate already? */
1182 snprintf(text, sizeof(text), "ExtGState/BlendMode%d", blendmode);
1183 obj = pdf_dict_getp(pdev->resources, text);
1186 /* No, better make one */
1187 obj = pdf_new_dict(pdev->doc, 2);
1188 pdf_dict_puts_drop(obj, "Type", pdf_new_name(doc, "ExtGState"));
1189 pdf_dict_puts_drop(obj, "BM", pdf_new_name(doc, fz_blendmode_name(blendmode)));
1190 pdf_dict_putp_drop(pdev->resources, text, obj);
1194 /* Add the call to this group */
1195 gs = CURRENT_GSTATE(pdev);
1196 fz_buffer_printf(dev->ctx, gs->buf, "/BlendMode%d gs /Fm%d Do\n", blendmode, num);
1198 /* Now, everything we get until the end of group needs to go into a
1199 * new buffer, which will be the stream contents for the form. */
1200 pdf_dev_push_new_buf(pdev, fz_new_buffer(ctx, 1024), NULL, form_ref);
1204 pdf_dev_end_group(fz_device *dev)
1206 pdf_device *pdev = (pdf_device *)dev->user;
1207 pdf_document *doc = pdev->doc;
1208 gstate *gs = CURRENT_GSTATE(pdev);
1209 fz_context *ctx = pdev->ctx;
1210 fz_buffer *buf = fz_keep_buffer(ctx, gs->buf);
1213 pdf_dev_end_text(pdev);
1214 form_ref = (pdf_obj *)pdf_dev_pop(pdev);
1215 pdf_dict_puts_drop(form_ref, "Length", pdf_new_int(doc, gs->buf->len));
1216 pdf_update_stream(doc, pdf_to_num(form_ref), buf);
1217 fz_drop_buffer(ctx, buf);
1218 pdf_drop_obj(form_ref);
1222 pdf_dev_begin_tile(fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id)
1224 pdf_device *pdev = (pdf_device *)dev->user;
1227 pdf_dev_end_text(pdev);
1232 pdf_dev_end_tile(fz_device *dev)
1234 pdf_device *pdev = (pdf_device *)dev->user;
1237 pdf_dev_end_text(pdev);
1241 pdf_dev_free_user(fz_device *dev)
1243 pdf_device *pdev = dev->user;
1244 pdf_document *doc = pdev->doc;
1245 fz_context *ctx = pdev->ctx;
1246 gstate *gs = CURRENT_GSTATE(pdev);
1249 pdf_dev_end_text(pdev);
1251 pdf_dict_puts_drop(pdev->contents, "Length", pdf_new_int(doc, gs->buf->len));
1253 for (i = pdev->num_gstates-1; i >= 0; i--)
1255 fz_drop_stroke_state(ctx, pdev->gstates[i].stroke_state);
1258 for (i = pdev->num_fonts-1; i >= 0; i--)
1260 fz_drop_font(ctx, pdev->fonts[i].font);
1263 for (i = pdev->num_imgs-1; i >= 0; i--)
1265 pdf_drop_obj(pdev->images[i].ref);
1268 pdf_update_stream(doc, pdf_to_num(pdev->contents), pdev->gstates[0].buf);
1269 fz_drop_buffer(ctx, pdev->gstates[0].buf);
1271 pdf_drop_obj(pdev->contents);
1272 pdf_drop_obj(pdev->resources);
1274 fz_free(ctx, pdev->images);
1275 fz_free(ctx, pdev->alphas);
1276 fz_free(ctx, pdev->gstates);
1281 pdf_dev_rebind(fz_device *dev)
1283 pdf_device *pdev = dev->user;
1285 fz_rebind_document((fz_document *)pdev->doc, dev->ctx);
1288 fz_device *pdf_new_pdf_device(pdf_document *doc, pdf_obj *contents, pdf_obj *resources, const fz_matrix *ctm)
1290 fz_context *ctx = doc->ctx;
1291 pdf_device *pdev = fz_malloc_struct(ctx, pdf_device);
1298 pdev->contents = pdf_keep_obj(contents);
1299 pdev->resources = pdf_keep_obj(resources);
1300 pdev->gstates = fz_malloc_struct(ctx, gstate);
1301 pdev->gstates[0].buf = fz_new_buffer(ctx, 256);
1302 pdev->gstates[0].ctm = *ctm;
1303 pdev->gstates[0].colorspace[0] = fz_device_gray(ctx);
1304 pdev->gstates[0].colorspace[1] = fz_device_gray(ctx);
1305 pdev->gstates[0].color[0][0] = 1;
1306 pdev->gstates[0].color[1][0] = 1;
1307 pdev->gstates[0].alpha[0] = 1.0;
1308 pdev->gstates[0].alpha[1] = 1.0;
1309 pdev->gstates[0].font = -1;
1310 pdev->gstates[0].horizontal_scaling = 100;
1311 pdev->num_gstates = 1;
1312 pdev->max_gstates = 1;
1314 dev = fz_new_device(ctx, pdev);
1319 fz_drop_buffer(ctx, pdev->gstates[0].buf);
1324 dev->rebind = pdf_dev_rebind;
1325 dev->free_user = pdf_dev_free_user;
1327 dev->fill_path = pdf_dev_fill_path;
1328 dev->stroke_path = pdf_dev_stroke_path;
1329 dev->clip_path = pdf_dev_clip_path;
1330 dev->clip_stroke_path = pdf_dev_clip_stroke_path;
1332 dev->fill_text = pdf_dev_fill_text;
1333 dev->stroke_text = pdf_dev_stroke_text;
1334 dev->clip_text = pdf_dev_clip_text;
1335 dev->clip_stroke_text = pdf_dev_clip_stroke_text;
1336 dev->ignore_text = pdf_dev_ignore_text;
1338 dev->fill_shade = pdf_dev_fill_shade;
1339 dev->fill_image = pdf_dev_fill_image;
1340 dev->fill_image_mask = pdf_dev_fill_image_mask;
1341 dev->clip_image_mask = pdf_dev_clip_image_mask;
1343 dev->pop_clip = pdf_dev_pop_clip;
1345 dev->begin_mask = pdf_dev_begin_mask;
1346 dev->end_mask = pdf_dev_end_mask;
1347 dev->begin_group = pdf_dev_begin_group;
1348 dev->end_group = pdf_dev_end_group;
1350 dev->begin_tile = pdf_dev_begin_tile;
1351 dev->end_tile = pdf_dev_end_tile;
1356 fz_device *pdf_page_write(pdf_document *doc, pdf_page *page)
1358 fz_context *ctx = doc->ctx;
1359 pdf_obj *resources = pdf_dict_gets(page->me, "Resources");
1361 fz_pre_translate(fz_scale(&ctm, 1, -1), 0, page->mediabox.y0-page->mediabox.y1);
1363 if (resources == NULL)
1365 resources = pdf_new_dict(doc, 0);
1366 pdf_dict_puts_drop(page->me, "Resources", resources);
1369 if (page->contents == NULL)
1371 pdf_obj *obj = pdf_new_dict(doc, 0);
1374 page->contents = pdf_new_ref(doc, obj);
1375 pdf_dict_puts(page->me, "Contents", page->contents);
1387 return pdf_new_pdf_device(doc, page->contents, resources, &ctm);