diff options
Diffstat (limited to 'Build/source/texk/xdvipdfmx/src/epdf.c')
-rw-r--r-- | Build/source/texk/xdvipdfmx/src/epdf.c | 760 |
1 files changed, 574 insertions, 186 deletions
diff --git a/Build/source/texk/xdvipdfmx/src/epdf.c b/Build/source/texk/xdvipdfmx/src/epdf.c index c041bb1e7b5..d01421d7635 100644 --- a/Build/source/texk/xdvipdfmx/src/epdf.c +++ b/Build/source/texk/xdvipdfmx/src/epdf.c @@ -1,28 +1,27 @@ -/* $Header: /home/cvsroot/dvipdfmx/src/epdf.c,v 1.14 2004/09/12 11:57:49 hirata Exp $ +/* $Header: /home/cvsroot/dvipdfmx/src/epdf.c,v 1.18 2008/02/13 20:22:21 matthias Exp $ - This is dvipdfm, a DVI to PDF translator. - Copyright (C) 1998, 1999 by Mark A. Wicks + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2007 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team <dvipdfmx@project.ktug.or.kr> + + Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - The author may be contacted via the e-mail address - - mwicks@kettering.edu + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ - /* * Concatinating content streams are only supported for streams that only uses * single FlateDecode filter, i.e., @@ -49,6 +48,8 @@ #include "pdfdev.h" #include "pdfximage.h" +#include "pdfdraw.h" +#include "pdfparse.h" #include "epdf.h" @@ -60,44 +61,55 @@ static void print_bbox_info (pdf_obj *rect, const char *type, pdf_obj *crop_box static int rect_equal (pdf_obj *rect1, pdf_obj *rect2); /* - * From PDF Reference 4th ed. + * From PDFReference15_v6.pdf (p.119 and p.834) * - * MediaBox rectangle (Required; inheritable) + * MediaBox rectangle (Required; inheritable) * - * A rectangle, expressed in default user space units, defining the boundaries of the - * physical medium on which the page is intended to be displayed or printed. + * The media box defines the boundaries of the physical medium on which the + * page is to be printed. It may include any extended area surrounding the + * finished page for bleed, printing marks, or other such purposes. It may + * also include areas close to the edges of the medium that cannot be marked + * because of physical limitations of the output device. Content falling + * outside this boundary can safely be discarded without affecting the + * meaning of the PDF file. * - * CropBox rectangle (Optional; inheritable) + * CropBox rectangle (Optional; inheritable) * - * A rectangle, expressed in default user space units, defining the visible region of - * default user space. When the page is displayed or printed, its contents are to be - * clipped (cropped) to this rectangle and then imposed on the output medium in some - * implementation-defined manner. - * Default value: the value of MediaBox. + * The crop box defines the region to which the contents of the page are to be + * clipped (cropped) when displayed or printed. Unlike the other boxes, the + * crop box has no defined meaning in terms of physical page geometry or + * intended use; it merely imposes clipping on the page contents. However, + * in the absence of additional information (such as imposition instructions + * specified in a JDF or PJTF job ticket), the crop box will determine how + * the page’s contents are to be positioned on the output medium. The default + * value is the page’s media box. * - * BleedBox rectangle (Optional; PDF 1.3) + * BleedBox rectangle (Optional; PDF 1.3) * - * A rectangle, expressed in default user space units, defining the region to which the - * contents of the page should be clipped when output in a production environment. - * Default value: the value of CropBox. + * The bleed box (PDF 1.3) defines the region to which the contents of the + * page should be clipped when output in a production environment. This may + * include any extra “bleed area” needed to accommodate the physical + * limitations of cutting, folding, and trimming equipment. The actual printed + * page may include printing marks that fall outside the bleed box. + * The default value is the page’s crop box. * - * TrimBox rectangle (Optional; PDF 1.3) + * TrimBox rectangle (Optional; PDF 1.3) * - * A rectangle, expressed in default user space units, defining the intended dimensions - * of the finished page after trimming. - * Default value: the value of CropBox. + * The trim box (PDF 1.3) defines the intended dimensions of the finished page + * after trimming. It may be smaller than the media box, to allow for + * production-related content such as printing instructions, cut marks, or + * color bars. The default value is the page’s crop box. * - * ArtBox rectangle (Optional; PDF 1.3) + * ArtBox rectangle (Optional; PDF 1.3) * - * A rectangle, expressed in default user space units, defining the extent of the page's - * meaningful content (including potential white space) as intended by the page's creator - * Default value: the value of CropBox. + * The art box (PDF 1.3) defines the extent of the page’s meaningful content + * (including potential white space) as intended by the page’s creator. + * The default value is the page’s crop box. * - * Rotate integer (Optional; inheritable) + * Rotate integer (Optional; inheritable) * - * The number of degrees by which the page should be rotated clockwise when displayed or - * printed. The value must be a multiple of 90. - * Default value: 0. + * The number of degrees by which the page should be rotated clockwise when + * displayed or printed. The value must be a multiple of 90. Default value: 0. */ static int @@ -132,16 +144,12 @@ print_bbox_info (pdf_obj *rect, const char *type, pdf_obj *crop_box) pdf_number_value(pdf_get_array(crop_box, 3))); } -int -pdf_include_page (pdf_ximage *ximage, FILE *image_file, int page_index, int pdf_box) +static pdf_obj* +pdf_get_page_obj (FILE *image_file, long page_no, pdf_obj **ret_bbox, pdf_obj **ret_resources) { - xform_info info; - pdf_obj *contents, *contents_ref, *contents_dict; - pdf_obj *page_tree; - pdf_obj *bbox, *resources, *rotate, *matrix; - int page_count; + pdf_obj *page_tree, *resources = NULL, *rotate = NULL, *bbox = NULL; + long page_count, page_idx; - pdf_ximage_init_form_info(&info); /* * Get Page Tree. */ @@ -153,22 +161,22 @@ pdf_include_page (pdf_ximage *ximage, FILE *image_file, int page_index, int pdf_ trailer = pdf_open(image_file); if (!trailer) { WARN("Trailer not found! Corrupt PDF file?"); - pdf_close(); - return -1; + return NULL; } if (pdf_lookup_dict(trailer, "Encrypt")) { WARN("This PDF document is encrypted."); pdf_release_obj(trailer); - pdf_close(); - return -1; + return NULL; } catalog = pdf_deref_obj(pdf_lookup_dict(trailer, "Root")); - if (!catalog) { - WARN("Catalog isn't where I expect it."); - pdf_close(); - return -1; + if (!PDF_OBJ_DICTTYPE(catalog)) { + WARN("Can't read document catalog."); + pdf_release_obj(trailer); + if (catalog) + pdf_release_obj(catalog); + return NULL; } pdf_release_obj(trailer); @@ -179,8 +187,7 @@ pdf_include_page (pdf_ximage *ximage, FILE *image_file, int page_index, int pdf_ if (tmp && pdf_boolean_value(tmp)) { WARN("Tagged PDF not supported."); pdf_release_obj(catalog); - pdf_close(); - return -1; + return NULL; } } @@ -189,70 +196,63 @@ pdf_include_page (pdf_ximage *ximage, FILE *image_file, int page_index, int pdf_ } if (!page_tree) { WARN("Page tree not found."); - pdf_close(); - return -1; + return NULL; } - page_count = (int)pdf_number_value(pdf_lookup_dict(page_tree, "Count")); - if (page_index >= page_count) - page_index = page_count - 1; - else if (page_index < 0) { - page_index = page_count + page_index; - if (page_index < 0) - page_index = 0; + /* + * Negative page numbers are counted from the back. + */ + { + long count = pdf_number_value(pdf_lookup_dict(page_tree, "Count")); + page_idx = page_no + (page_no >= 0 ? -1 : count); + if (page_idx < 0 || page_idx >= count) { + WARN("Page %ld does not exist.", page_no); + page_idx = page_idx < 0 ? 0 : count - 1; + } + page_no = page_idx + 1; } /* - * Seek required page. Get Media/Crop Box. + * Seek correct page. Get Media/Crop Box. * Media box and resources can be inherited. */ { pdf_obj *kids_ref, *kids; - pdf_obj *crop_box; + pdf_obj *crop_box = NULL; pdf_obj *tmp; - tmp = pdf_lookup_dict(page_tree, "MediaBox"); - bbox = tmp ? pdf_deref_obj(tmp) : NULL; - tmp = pdf_lookup_dict(page_tree, "CropBox"); - crop_box = tmp ? pdf_deref_obj(tmp) : NULL; - tmp = pdf_lookup_dict(page_tree, "Rotate"); - rotate = tmp ? pdf_deref_obj(tmp) : NULL; - tmp = pdf_lookup_dict(page_tree, "Resources"); resources = tmp ? pdf_deref_obj(tmp) : pdf_new_dict(); - while ((kids_ref = pdf_lookup_dict(page_tree, "Kids")) != NULL) { - /* page_tree is a Pages object: figure out which of its Kids we need */ - int kid_index; - kids = pdf_deref_obj(kids_ref); - for (kid_index = 0; ; ++kid_index) { - pdf_release_obj(page_tree); - page_tree = pdf_deref_obj(pdf_get_array(kids, kid_index)); - /* page_tree might be a Page or another Pages node */ - tmp = pdf_lookup_dict(page_tree, "Count"); - if (tmp) { - /* it's a subtree: check if the required page is within this tree */ - page_count = (int)pdf_number_value(tmp); - if (page_index < page_count) - break; - else - page_index -= page_count; - } - else { - /* it's a page: break if it's the one we want */ - if (page_index == 0) - break; - else - --page_index; - } - } - pdf_release_obj(kids); - + while (1) { + long kids_length, i; + if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "MediaBox")))) { if (bbox) pdf_release_obj(bbox); bbox = tmp; } + if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "BleedBox")))) { + if (!rect_equal(tmp, bbox)) { + if (bbox) + pdf_release_obj(bbox); + bbox = tmp; + } + } + if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "TrimBox")))) { + if (!rect_equal(tmp, bbox)) { + if (bbox) + pdf_release_obj(bbox); + bbox = tmp; + } + } + if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "ArtBox")))) { + if (!rect_equal(tmp, bbox)) { + if (bbox) + pdf_release_obj(bbox); + bbox = tmp; + } + } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "CropBox")))) { if (crop_box) pdf_release_obj(crop_box); @@ -271,116 +271,192 @@ pdf_include_page (pdf_ximage *ximage, FILE *image_file, int page_index, int pdf_ pdf_release_obj(resources); resources = tmp; } + + kids_ref = pdf_lookup_dict(page_tree, "Kids"); + if (!kids_ref) + break; + kids = pdf_deref_obj(kids_ref); + kids_length = pdf_array_length(kids); + + for (i = 0; i < kids_length; i++) { + long count; + + pdf_release_obj(page_tree); + page_tree = pdf_deref_obj(pdf_get_array(kids, i)); + + tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Count")); + if (tmp) { + /* Pages object */ + count = pdf_number_value(tmp); + pdf_release_obj(tmp); + } else + /* Page object */ + count = 1; + + if (page_idx < count) + break; + + page_idx -= count; + } + + pdf_release_obj(kids); + + if (i == kids_length) { + WARN("Page %ld not found! Broken PDF file?", page_no); + if (bbox) + pdf_release_obj(bbox); + if (crop_box) + pdf_release_obj(crop_box); + if (rotate) + pdf_release_obj(rotate); + pdf_release_obj(resources); + pdf_release_obj(page_tree); + return NULL; + } } if (crop_box) { pdf_release_obj(bbox); bbox = crop_box; } } + if (!bbox) { WARN("No BoundingBox information available."); pdf_release_obj(page_tree); pdf_release_obj(resources); if (rotate) pdf_release_obj(rotate); - pdf_close(); - return -1; + return NULL; + } + + if (rotate) { + if (pdf_number_value(rotate) != 0.0) + WARN("<< /Rotate %d >> found. (Not supported yet)", (int)pdf_number_value(rotate)); + pdf_release_obj(rotate); + rotate = NULL; } - /* - * BleedBox, TrimBox, and ArtBox are not inheritable. - */ - { - pdf_obj *tmp; + if (ret_bbox != NULL) + *ret_bbox = bbox; + if (ret_resources != NULL) + *ret_resources = resources; - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "TrimBox")))) { - if (!rect_equal(tmp, bbox)) { - print_bbox_info(tmp, "TrimBox", bbox); - if (bbox) - pdf_release_obj(bbox); - bbox = tmp; - } - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "BleedBox")))) { - if (!rect_equal(tmp, bbox)) { - print_bbox_info(tmp, "BleedBox", bbox); - if (bbox) - pdf_release_obj(bbox); - bbox = tmp; + return page_tree; +} + +static pdf_obj* +pdf_get_page_content (pdf_obj* page) +{ + pdf_obj *contents, *content_new; + + contents = pdf_deref_obj(pdf_lookup_dict(page, "Contents")); + if (!contents) + return NULL; + + if (pdf_obj_typeof(contents) == PDF_NULL) { + /* empty page */ + pdf_release_obj(contents); + /* TODO: better don't include anything if the page is empty */ + contents = pdf_new_stream(0); + } else if (PDF_OBJ_ARRAYTYPE(contents)) { + /* + * Concatenate all content streams. + */ + pdf_obj *content_seg, *content_new; + int idx = 0; + content_new = pdf_new_stream(STREAM_COMPRESS); + for (;;) { + content_seg = pdf_deref_obj(pdf_get_array(contents, idx)); + if (!content_seg) + break; + else if (PDF_OBJ_NULLTYPE(content_seg)) { + /* Silently ignore. */ + } else if (!PDF_OBJ_STREAMTYPE(content_seg)) { + WARN("Page content not a stream object. Broken PDF file?"); + pdf_release_obj(content_seg); + pdf_release_obj(content_new); + pdf_release_obj(contents); + return NULL; + } else if (concat_stream(content_new, content_seg) < 0) { + WARN("Could not handle content stream with multiple segments."); + pdf_release_obj(content_seg); + pdf_release_obj(content_new); + pdf_release_obj(contents); + return NULL; } + pdf_release_obj(content_seg); + idx++; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "ArtBox")))) { - if (!rect_equal(tmp, bbox)) { - print_bbox_info(tmp, "ArtBox", bbox); - if (bbox) - pdf_release_obj(bbox); - bbox = tmp; - } + pdf_release_obj(contents); + contents = content_new; + } else { + if (!PDF_OBJ_STREAMTYPE(contents)) { + WARN("Page content not a stream object. Broken PDF file?"); + pdf_release_obj(contents); + return NULL; } - if (rotate) { - if (pdf_number_value(rotate) != 0.0) - WARN("<< /Rotate %d >> found. (Not supported yet)", (int)pdf_number_value(rotate)); - pdf_release_obj(rotate); - rotate = NULL; + /* Flate the contents if necessary. */ + content_new = pdf_new_stream(STREAM_COMPRESS); + if (concat_stream(content_new, contents) < 0) { + WARN("Could not handle a content stream."); + pdf_release_obj(contents); + pdf_release_obj(content_new); + return NULL; } - - info.bbox.llx = pdf_number_value(pdf_get_array(bbox, 0)); - info.bbox.lly = pdf_number_value(pdf_get_array(bbox, 1)); - info.bbox.urx = pdf_number_value(pdf_get_array(bbox, 2)); - info.bbox.ury = pdf_number_value(pdf_get_array(bbox, 3)); + pdf_release_obj(contents); + contents = content_new; } + return contents; +} + +int +pdf_include_page (pdf_ximage *ximage, FILE *image_file) +{ + xform_info info; + pdf_obj *contents, *contents_dict; + pdf_obj *page_tree; + pdf_obj *matrix; + pdf_obj *bbox = NULL, *resources = NULL; + long page_no, page_idx; + + pdf_ximage_init_form_info(&info); + /* - * Handle page content stream. - * page_tree is now set to the first page. + * Get Page Tree. */ - contents_ref = contents = NULL; - { - contents = pdf_deref_obj(pdf_lookup_dict(page_tree, "Contents")); - pdf_release_obj(page_tree); - if (!contents) { - pdf_release_obj(bbox); - pdf_close(); - return -1; - } + page_no = pdf_ximage_get_page(ximage); + if (page_no == 0) + page_no = 1; - /* - * Concatinate all content streams. - */ - if (PDF_OBJ_ARRAYTYPE(contents)) { - pdf_obj *content_seg, *content_new; - int idx = 0; - content_new = pdf_new_stream(STREAM_COMPRESS); - for (;;) { - content_seg = pdf_deref_obj(pdf_get_array(contents, idx)); - if (!content_seg) - break; - else if (PDF_OBJ_NULLTYPE(content_seg)) { - /* Silently ignore. */ - } else if (!PDF_OBJ_STREAMTYPE(content_seg)) { - WARN("Page content not a stream object. Broken PDF file?"); - pdf_release_obj(content_new); - pdf_release_obj(bbox); - pdf_close(); - return -1; - } else if (concat_stream(content_new, content_seg) < 0) { - WARN("Could not handle content stream with multiple segment."); - pdf_release_obj(content_new); - pdf_release_obj(bbox); - pdf_close(); - return -1; - } - pdf_release_obj(content_seg); - idx++; - } - pdf_release_obj(contents); - contents = content_new; - } - if (!contents) { - pdf_release_obj(bbox); - pdf_close(); - return -1; - } + page_tree = pdf_get_page_obj(image_file, page_no, &bbox, &resources); + if (page_tree == NULL) { + pdf_close(); + return -1; + } + + if (bbox != NULL) { + pdf_obj *tmp; + + tmp = pdf_deref_obj(pdf_get_array(bbox, 0)); + info.bbox.llx = pdf_number_value(tmp); + pdf_release_obj(tmp); + tmp = pdf_deref_obj(pdf_get_array(bbox, 1)); + info.bbox.lly = pdf_number_value(tmp); + pdf_release_obj(tmp); + tmp = pdf_deref_obj(pdf_get_array(bbox, 2)); + info.bbox.urx = pdf_number_value(tmp); + pdf_release_obj(tmp); + tmp = pdf_deref_obj(pdf_get_array(bbox, 3)); + info.bbox.ury = pdf_number_value(tmp); + pdf_release_obj(tmp); + } + + contents = pdf_get_page_content(page_tree); + pdf_release_obj(page_tree); + if (contents == NULL) { + pdf_close(); + return -1; } { @@ -389,6 +465,9 @@ pdf_include_page (pdf_ximage *ximage, FILE *image_file, int page_index, int pdf_ tmp = pdf_import_object(resources); pdf_release_obj(resources); resources = tmp; + tmp = pdf_import_object(bbox); + pdf_release_obj(bbox); + bbox = tmp; } pdf_close(); @@ -423,6 +502,315 @@ pdf_include_page (pdf_ximage *ximage, FILE *image_file, int page_index, int pdf_ return 0; } +typedef enum { + OP_SETCOLOR = 1, + OP_CLOSEandCLIP = 2, + OP_CLIP = 3, + OP_CONCATMATRIX = 4, + OP_SETCOLORSPACE = 5, + OP_RECTANGLE = 6, + OP_CURVETO = 7, + OP_CLOSEPATH = 8, + OP_LINETO = 9, + OP_MOVETO = 10, + OP_NOOP = 11, + OP_GSAVE = 12, + OP_GRESTORE = 13, + OP_CURVETO1 = 14, + OP_CURVETO2 = 15, + OP_UNKNOWN = 16 +} pdf_opcode; + +static struct operator +{ + const char *token; + int opcode; +} pdf_operators[] = { + {"SCN", OP_SETCOLOR}, + {"b*", OP_CLOSEandCLIP}, + {"B*", OP_CLIP}, + {"cm", OP_CONCATMATRIX}, + {"CS", OP_SETCOLORSPACE}, + {"f*", 0}, + {"gs", -1}, + {"re", OP_RECTANGLE}, + {"rg", -3}, + {"RG", -3}, + {"sc", OP_SETCOLOR}, + {"SC", OP_SETCOLOR}, + {"W*", OP_CLIP}, + {"b", OP_CLOSEandCLIP}, + {"B", OP_CLIP}, + {"c", OP_CURVETO}, + {"d", -2}, + {"f", 0}, + {"F", 0}, + {"g", -1}, + {"G", -1}, + {"h", OP_CLOSEPATH}, + {"i", -1}, + {"j", -1}, + {"J", -1}, + {"k", -4}, + {"K", -4}, + {"l", OP_LINETO}, + {"m", OP_MOVETO}, + {"M", -1}, + {"n", OP_NOOP}, + {"q", OP_GSAVE}, + {"Q", OP_GRESTORE}, + {"s", OP_CLOSEandCLIP}, + {"S", OP_CLIP}, + {"v", OP_CURVETO1}, + {"w", -1}, + {"W", OP_CLIP}, + {"y", OP_CURVETO2} +}; + + +int +pdf_copy_clip (FILE *image_file, int pageNo, double x_user, double y_user) +{ + pdf_obj *page_tree, *contents; + int depth = 0, top = -1; + char *clip_path, *temp, *end_path; + pdf_tmatrix M; + double stack[6]; + pdf_coord p0, p1, p2; + pdf_rect bbox; + + pdf_dev_currentmatrix(&M); + pdf_invertmatrix(&M); + M.e += x_user; M.f += y_user; + page_tree = pdf_get_page_obj (image_file, pageNo, NULL, NULL); + if (!page_tree) { + pdf_close(); + return -1; + } + + contents = pdf_get_page_content(page_tree); + pdf_release_obj(page_tree); + if (!contents) { + pdf_close(); + return -1; + } + + pdf_doc_add_page_content(" ", 1); + + clip_path = malloc(pdf_stream_length(contents) + 1); + strncpy(clip_path, (char*)pdf_stream_dataptr(contents), pdf_stream_length(contents)); + end_path = clip_path + pdf_stream_length(contents); + depth = 0; + + for (; clip_path < end_path; clip_path++) { + int color_dimen; + char *token; + skip_white(&clip_path, end_path); + if (clip_path == end_path) + break; + if (depth > 1) { + if (*clip_path == 'q') + depth++; + if (*clip_path == 'Q') + depth--; + parse_ident(&clip_path, end_path); + continue; + } else if (*clip_path == '-' + || *clip_path == '+' + || *clip_path == '.' + || isdigit(*clip_path)) { + stack[++top] = strtod(clip_path, &temp); + clip_path = temp; + } else if (*clip_path == '[') { + /* Ignore, but put a dummy value on the stack (in case of d operator) */ + parse_pdf_array(&clip_path, end_path); + stack[++top] = 0; + } else if (*clip_path == '/') { + if (strncmp("/DeviceGray", clip_path, 11) == 0 + || strncmp("/Indexed", clip_path, 8) == 0 + || strncmp("/CalGray", clip_path, 8) == 0) { + color_dimen = 1; + continue; + } + else if (strncmp("/DeviceRGB", clip_path, 10) == 0 + || strncmp("/CalRGB", clip_path, 7) == 0 + || strncmp("/Lab", clip_path, 4) == 0) { + color_dimen = 3; + continue; + } + else if (strncmp("/DeviceCMYK", clip_path, 11) == 0) { + color_dimen = 4; + continue; + } + else { + clip_path++; + parse_ident(&clip_path, end_path); + skip_white(&clip_path, end_path); + token = parse_ident(&clip_path, end_path); + if (strcmp(token, "gs") == 0) { + continue; + } + return -1; + } + } else { + int j; + pdf_tmatrix T; + pdf_coord p0, p1, p2, p3; + + token = parse_ident(&clip_path, end_path); + for (j = 0; j < sizeof(pdf_operators) / sizeof(pdf_operators[0]); j++) + if (strcmp(token, pdf_operators[j].token) == 0) + break; + if (j == sizeof(pdf_operators) / sizeof(pdf_operators[0])) { + return -1; + } + switch (pdf_operators[j].opcode) { + case 0: + case -1: + case -2: + case -3: + case -4: + /* Just pop the stack and do nothing. */ + top += pdf_operators[j].opcode; + if (top < -1) + return -1; + break; + case OP_SETCOLOR: + top -= color_dimen; + if (top < -1) + return -1; + break; + case OP_CLOSEandCLIP: + pdf_dev_closepath(); + case OP_CLIP: +#if 0 + pdf_dev_clip(); +#else + pdf_dev_flushpath('W', PDF_FILL_RULE_NONZERO); +#endif + break; + case OP_CONCATMATRIX: + if (top < 5) + return -1; + T.f = stack[top--]; + T.e = stack[top--]; + T.d = stack[top--]; + T.c = stack[top--]; + T.b = stack[top--]; + T.a = stack[top--]; + pdf_concatmatrix(&M, &T); + break; + case OP_SETCOLORSPACE: + /* Do nothing. */ + break; + case OP_RECTANGLE: + if (top < 3) + return -1; + p1.y = stack[top--]; + p1.x = stack[top--]; + p0.y = stack[top--]; + p0.x = stack[top--]; + if (M.b == 0 && M.c == 0) { + pdf_tmatrix M0; + M0.a = M.a; M0.b = M.b; M0.c = M.c; M0.d = M.d; + M0.e = 0; M0.f = 0; + pdf_dev_transform(&p0, &M); + pdf_dev_transform(&p1, &M0); + pdf_dev_rectadd(p0.x, p0.y, p1.x, p1.y); + } else { + p2.x = p0.x + p1.x; p2.y = p0.y + p1.y; + p3.x = p0.x; p3.y = p0.y + p1.y; + p1.x += p0.x; p1.y = p0.y; + pdf_dev_transform(&p0, &M); + pdf_dev_transform(&p1, &M); + pdf_dev_transform(&p2, &M); + pdf_dev_transform(&p3, &M); + pdf_dev_moveto(p0.x, p0.y); + pdf_dev_lineto(p1.x, p1.y); + pdf_dev_lineto(p2.x, p2.y); + pdf_dev_lineto(p3.x, p3.y); + pdf_dev_closepath(); + } + break; + case OP_CURVETO: + if (top < 5) + return -1; + p0.y = stack[top--]; + p0.x = stack[top--]; + pdf_dev_transform(&p0, &M); + p1.y = stack[top--]; + p1.x = stack[top--]; + pdf_dev_transform(&p1, &M); + p2.y = stack[top--]; + p2.x = stack[top--]; + pdf_dev_transform(&p2, &M); + pdf_dev_curveto(p2.x, p2.y, p1.x, p1.y, p0.x, p0.y); + break; + case OP_CLOSEPATH: + pdf_dev_closepath(); + break; + case OP_LINETO: + if (top < 1) + return -1; + p0.y = stack[top--]; + p0.x = stack[top--]; + pdf_dev_transform(&p0, &M); + pdf_dev_lineto(p0.x, p0.y); + break; + case OP_MOVETO: + if (top < 1) + return -1; + p0.y = stack[top--]; + p0.x = stack[top--]; + pdf_dev_transform(&p0, &M); + pdf_dev_moveto(p0.x, p0.y); + break; + case OP_NOOP: + pdf_doc_add_page_content(" n", 2); + break; + case OP_GSAVE: + depth++; + break; + case OP_GRESTORE: + depth--; + break; + case OP_CURVETO1: + if (top < 3) + return -1; + p0.y = stack[top--]; + p0.x = stack[top--]; + pdf_dev_transform(&p0, &M); + p1.y = stack[top--]; + p1.x = stack[top--]; + pdf_dev_transform(&p1, &M); + pdf_dev_vcurveto(p1.x, p1.y, p0.x, p0.y); + break; + case OP_CURVETO2: + if (top < 3) + return -1; + p0.y = stack[top--]; + p0.x = stack[top--]; + pdf_dev_transform(&p0, &M); + p1.y = stack[top--]; + p1.x = stack[top--]; + pdf_dev_transform(&p1, &M); + pdf_dev_ycurveto(p1.x, p1.y, p0.x, p0.y); + break; + default: + return -1; + } + } + } + clip_path = end_path; + clip_path -= pdf_stream_length(contents); + free(clip_path); + + pdf_release_obj(contents); + pdf_close(); + + return 0; +} + #define WBUF_SIZE 4096 #if HAVE_ZLIB static int |