static void info_update(fz_context *ctx,pdf_document *xref,char *producer) { char moddate[64]; time_t now; struct tm date; pdf_obj *info; int newinfo; if (xref->trailer==NULL) return; time(&now); date=(*localtime(&now)); sprintf(moddate,"D:%04d%02d%02d%02d%02d%02d%s", date.tm_year+1900,date.tm_mon+1,date.tm_mday, date.tm_hour,date.tm_min,date.tm_sec, wsys_utc_string()); info=pdf_dict_gets(xref->trailer,"Info"); if (info==NULL) { newinfo=1; info=pdf_new_dict(ctx,2); } else newinfo=0; dict_put_string(ctx,info,"Producer",producer); dict_put_string(ctx,info,"ModDate",moddate); if (newinfo) { pdf_dict_puts(xref->trailer,"Info",info); pdf_drop_obj(info); } }
static pdf_obj *start_new_destpage(fz_context *ctx,double width_pts,double height_pts) { pdf_obj *pageobj; pdf_obj *mbox; pageobj=pdf_new_dict(ctx,2); pdf_dict_puts(pageobj,"Type",pdf_new_name(ctx,"Page")); mbox=pdf_new_array(ctx,4); pdf_array_push(mbox,pdf_new_real(ctx,0.)); pdf_array_push(mbox,pdf_new_real(ctx,0.)); pdf_array_push(mbox,pdf_new_real(ctx,width_pts)); pdf_array_push(mbox,pdf_new_real(ctx,height_pts)); pdf_dict_puts(pageobj,"MediaBox",mbox); return(pageobj); }
static void update_field_value(pdf_document *doc, pdf_obj *obj, char *text) { fz_context *ctx = doc->ctx; pdf_obj *sobj = NULL; pdf_obj *grp; if (!text) text = ""; /* All fields of the same name should be updated, so * set the value at the head of the group */ grp = find_head_of_field_group(obj); if (grp) obj = grp; fz_var(sobj); fz_try(ctx) { sobj = pdf_new_string(doc, text, strlen(text)); pdf_dict_puts(obj, "V", sobj); } fz_always(ctx) { pdf_drop_obj(sobj); } fz_catch(ctx) { fz_rethrow(ctx); } pdf_field_mark_dirty(doc, obj); }
static ErrorCode juggler_impose_create_sheet(fz_context *ctx, pdf_document *dest_doc, int width, int height) { /* create and insert page to dest_doc */ fz_rect rect = { 0, 0, width, height };// { 0, 0, 1390, 1684 }; pdf_page *sheet = pdf_create_page(ctx, dest_doc, rect, 0, 0); sheet->resources = pdf_new_dict(ctx, dest_doc, 16); pdf_dict_puts(ctx, sheet->me, "Resources", sheet->resources); /* will be droped when freeing the page */ sheet->contents = pdf_new_array(ctx, dest_doc, 8); pdf_dict_puts(ctx, sheet->me, "Contents", sheet->contents); /* will be droped when freeing the page */ pdf_insert_page(ctx, dest_doc, sheet, INT_MAX); pdf_drop_page(ctx, sheet); return(NoError); }
static void dict_put_string(fz_context *ctx,pdf_obj *dict,char *key,char *string) { pdf_obj *value; value=pdf_new_string(ctx,string,strlen(string)); pdf_dict_puts(dict,key,value); pdf_drop_obj(value); }
void pdf_insert_page(pdf_document *doc, pdf_page *page, int at) { fz_context *ctx = doc->ctx; int count = pdf_count_pages(doc); pdf_obj *parent, *kids; pdf_obj *page_ref; int i; page_ref = pdf_new_ref(doc, page->me); fz_try(ctx) { if (count == 0) { /* TODO: create new page tree? */ fz_throw(ctx, FZ_ERROR_GENERIC, "empty page tree, cannot insert page"); } else if (at >= count) { if (at > count) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot insert page beyond end of page tree"); /* append after last page */ pdf_lookup_page_loc(doc, count - 1, &parent, &i); kids = pdf_dict_gets(parent, "Kids"); pdf_array_insert(kids, page_ref, i + 1); } else { /* insert before found page */ pdf_lookup_page_loc(doc, at, &parent, &i); kids = pdf_dict_gets(parent, "Kids"); pdf_array_insert(kids, page_ref, i); } pdf_dict_puts(page->me, "Parent", parent); /* Adjust page counts */ while (parent) { int count = pdf_to_int(pdf_dict_gets(parent, "Count")); pdf_dict_puts_drop(parent, "Count", pdf_new_int(doc, count + 1)); parent = pdf_dict_gets(parent, "Parent"); } } fz_always(ctx) { pdf_drop_obj(page_ref); } fz_catch(ctx) { fz_rethrow(ctx); } }
/* ** From MuPDF pdfclean.c */ static void wmupdf_preserve_old_dests(pdf_obj *olddests,fz_context *ctx,pdf_document *xref, pdf_obj *pages) { int i; pdf_obj *names = pdf_new_dict(ctx,1); pdf_obj *dests = pdf_new_dict(ctx,1); pdf_obj *names_list = pdf_new_array(ctx,32); int len = pdf_dict_len(olddests); pdf_obj *root; for (i=0;i<len;i++) { pdf_obj *key = pdf_dict_get_key(olddests,i); pdf_obj *val = pdf_dict_get_val(olddests,i); pdf_obj *key_str = pdf_new_string(ctx,pdf_to_name(key),strlen(pdf_to_name(key))); pdf_obj *dest = pdf_dict_gets(val,"D"); dest = pdf_array_get(dest ? dest : val, 0); if (pdf_array_contains(pdf_dict_gets(pages,"Kids"),dest)) { pdf_array_push(names_list, key_str); pdf_array_push(names_list, val); } pdf_drop_obj(key_str); } root = pdf_dict_gets(xref->trailer,"Root"); pdf_dict_puts(dests,"Names",names_list); pdf_dict_puts(names,"Dests",dests); pdf_dict_puts(root,"Names",names); pdf_drop_obj(names); pdf_drop_obj(dests); pdf_drop_obj(names_list); pdf_drop_obj(olddests); }
static int new_stream_object(pdf_document *xref,fz_context *ctx,char *buf) { int ref; pdf_obj *obj,*len; fz_buffer *fzbuf; ref = pdf_create_object(xref); obj = pdf_new_dict(ctx,1); len=pdf_new_int(ctx,strlen(buf)); pdf_dict_puts(obj,"Length",len); pdf_drop_obj(len); pdf_update_object(xref,ref,obj); pdf_drop_obj(obj); fzbuf=fz_new_buffer(ctx,strlen(buf)); fz_write_buffer(ctx,fzbuf,(unsigned char *)buf,strlen(buf)); pdf_update_stream(xref,ref,fzbuf); fz_drop_buffer(ctx,fzbuf); return(ref); }
void pdf_update_xobject_contents(pdf_document *xref, pdf_xobject *form, fz_buffer *buffer) { fz_context *ctx = xref->ctx; pdf_obj *len = NULL; fz_var(len); fz_try(ctx) { len = pdf_new_int(ctx, buffer->len); pdf_dict_dels(form->contents, "Filter"); pdf_dict_puts(form->contents, "Length", len); pdf_update_stream(xref, pdf_to_num(form->contents), buffer); } fz_always(ctx) { pdf_drop_obj(len); } fz_catch(ctx) { fz_rethrow(ctx); } }
static void reset_field(pdf_document *doc, pdf_obj *field) { fz_context *ctx = doc->ctx; /* Set V to DV whereever DV is present, and delete V where DV is not. * FIXME: we assume for now that V has not been set unequal * to DV higher in the hierarchy than "field". * * At the bottom of the hierarchy we may find widget annotations * that aren't also fields, but DV and V will not be present in their * dictionaries, and attempts to remove V will be harmless. */ pdf_obj *dv = pdf_dict_gets(field, "DV"); pdf_obj *kids = pdf_dict_gets(field, "Kids"); if (dv) pdf_dict_puts(field, "V", dv); else pdf_dict_dels(field, "V"); if (kids == NULL) { /* The leaves of the tree are widget annotations * In some cases we need to update the appearance state; * in others we need to mark the field as dirty so that * the appearance stream will be regenerated. */ switch (pdf_field_type(doc, field)) { case PDF_WIDGET_TYPE_RADIOBUTTON: case PDF_WIDGET_TYPE_CHECKBOX: { pdf_obj *leafv = pdf_get_inheritable(doc, field, "V"); if (leafv) pdf_keep_obj(leafv); else leafv = pdf_new_name(doc, "Off"); fz_try(ctx) { pdf_dict_puts(field, "AS", leafv); } fz_always(ctx) { pdf_drop_obj(leafv); } fz_catch(ctx) { fz_rethrow(ctx); } } break; case PDF_WIDGET_TYPE_PUSHBUTTON: break; default: pdf_field_mark_dirty(doc, field); break; } } doc->dirty = 1; }
void pdf_insert_page(pdf_document *doc, pdf_page *page, int at) { fz_context *ctx = doc->ctx; int count = pdf_count_pages(doc); pdf_obj *parent, *kids; pdf_obj *page_ref; int i; page_ref = pdf_new_ref(doc, page->me); fz_try(ctx) { if (count == 0) { pdf_obj *root = pdf_dict_gets(pdf_trailer(doc), "Root"); parent = pdf_dict_gets(root, "Pages"); if (!parent) fz_throw(doc->ctx, FZ_ERROR_GENERIC, "cannot find page tree"); kids = pdf_dict_gets(parent, "Kids"); if (!kids) fz_throw(doc->ctx, FZ_ERROR_GENERIC, "malformed page tree"); pdf_array_insert(kids, page_ref, 0); } else if (at >= count) { if (at == INT_MAX) at = count; if (at > count) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot insert page beyond end of page tree"); /* append after last page */ pdf_lookup_page_loc(doc, count - 1, &parent, &i); kids = pdf_dict_gets(parent, "Kids"); pdf_array_insert(kids, page_ref, i + 1); } else { /* insert before found page */ pdf_lookup_page_loc(doc, at, &parent, &i); kids = pdf_dict_gets(parent, "Kids"); pdf_array_insert(kids, page_ref, i); } pdf_dict_puts(page->me, "Parent", parent); /* Adjust page counts */ while (parent) { int count = pdf_to_int(pdf_dict_gets(parent, "Count")); pdf_dict_puts_drop(parent, "Count", pdf_new_int(doc, count + 1)); parent = pdf_dict_gets(parent, "Parent"); } } fz_always(ctx) { pdf_drop_obj(page_ref); } fz_catch(ctx) { fz_rethrow(ctx); } doc->page_count = 0; /* invalidate cached value */ }
static int wmupdf_pdfdoc_newpages(pdf_document *xref,fz_context *ctx,WPDFPAGEINFO *pageinfo, int use_forms,FILE *out) { static char *funcname="wmupdf_pdfdoc_newpages"; pdf_obj *root,*oldroot,*pages,*kids,*countobj,*parent,*olddests; pdf_obj *srcpageobj,*srcpagecontents; pdf_obj *destpageobj,*destpagecontents,*destpageresources; double srcx0,srcy0; int qref,i,i0,pagecount,srccount,destpageref,nbb; int *srcpageused; char *bigbuf; double srcpagerot; /* Avoid compiler warning */ destpageref = 0; destpageobj = NULL; srcx0=srcy0=0.; /* Keep only pages/type and (reduced) dest entries to avoid references to unretained pages */ pagecount = pdf_count_pages(xref); if (use_forms) { willus_mem_alloc_warn((void **)&srcpageused,sizeof(int)*(pagecount+1),funcname,10); /* Mark all source pages as "not done" */ for (i=0;i<=pagecount;i++) srcpageused[i]=0; nbb=4096; willus_mem_alloc_warn((void **)&bigbuf,nbb,funcname,10); bigbuf[0]='\0'; } oldroot = pdf_dict_gets(xref->trailer,"Root"); /* ** pages points to /Pages object in PDF file. ** Has: /Type /Pages, /Count <numpages>, /Kids [ obj obj obj obj ] */ pages = pdf_dict_gets(oldroot,"Pages"); olddests = pdf_load_name_tree(xref,"Dests"); /* ** Create new root object with only /Pages and /Type (and reduced dest entries) ** to avoid references to unretained pages. */ root = pdf_new_dict(ctx,4); pdf_dict_puts(root,"Type",pdf_dict_gets(oldroot,"Type")); pdf_dict_puts(root,"Pages",pages); pdf_update_object(xref,pdf_to_num(oldroot),root); pdf_drop_obj(root); /* Parent indirectly references the /Pages object in the file */ /* (Each new page we create has to point to this.) */ parent = pdf_new_indirect(ctx, pdf_to_num(pages), pdf_to_gen(pages), xref); /* Create a new kids array with only the pages we want to keep */ kids = pdf_new_array(ctx, 1); qref=0; /* Avoid compiler warnings */ destpageresources=NULL; destpagecontents=NULL; srcpagecontents=NULL; srcpagerot=0.; for (i=0;i<=pageinfo->boxes.n;i++) if (pageinfo->boxes.box[i].dstpage>0) break; if (i>0) { if (i<pageinfo->boxes.n) memmove(&pageinfo->boxes.box[0],&pageinfo->boxes.box[i],sizeof(WPDFBOX)*pageinfo->boxes.n-i); pageinfo->boxes.n -= i; } /* Walk through PFDBOXES array */ for (i=srccount=i0=0;i<=pageinfo->boxes.n;i++) { WPDFBOX *box; int j,k,newsrc; static char buf[512]; pdf_obj *s1indirect,*qindirect,*rotobj; static double cpm[3][3],m[3][3],m1[3][3]; static double xclip[4],yclip[4]; /* printf("box[%d]\n",i); if (i<pageinfo->boxes.n) { box=&pageinfo->boxes.box[i]; printf(" srcpage=%d, dstpage=%d\n",box->srcbox.pageno,box->dstpage); printf(" x0=%g, y0=%g\n",box->x0,box->y0); printf(" w=%g, h=%g\n",box->w,box->h); printf(" x1=%g, y1=%g\n",box->x1,box->y1); printf(" sr=%g, dr=%g\n",box->srcrot_deg,box->dstrot_deg); printf(" scale=%g\n",box->scale); } */ /* Check to see if we are done with an output page */ if (srccount>0 && (i==pageinfo->boxes.n || (i>0 && pageinfo->boxes.box[i].dstpage!=pageinfo->boxes.box[i-1].dstpage))) { pdf_obj *newpageref; /* ** Store destination page into document structure */ /* printf(" ADDING NEW PAGE. (srccount=%d)\n",srccount); */ if (use_forms) { pdf_obj *dest_stream; /* Create new object in document for destination page stream */ dest_stream = pdf_new_indirect(ctx,new_stream_object(xref,ctx,bigbuf), 0,(void *)xref); /* Store this into the destination page contents array */ pdf_array_push(destpagecontents,dest_stream); pdf_drop_obj(dest_stream); } newpageref=pdf_new_indirect(ctx,destpageref,0,(void *)xref); /* Reference parent list of pages */ pdf_dict_puts(destpageobj,"Parent",parent); pdf_dict_puts(destpageobj,"Contents",destpagecontents); pdf_dict_puts(destpageobj,"Resources",destpageresources); /* Store page object in document's kids array */ pdf_array_push(kids,newpageref); /* Update document with new page */ pdf_update_object(xref,destpageref,destpageobj); /* Clean up */ pdf_drop_obj(newpageref); pdf_drop_obj(destpageresources); pdf_drop_obj(destpagecontents); pdf_drop_obj(destpageobj); /* Reset source page and index to start of new destination page */ i0=i; srccount=0; } /* Quit loop if beyond last box */ if (i>=pageinfo->boxes.n) break; box=&pageinfo->boxes.box[i]; if (box->srcbox.pageno<1 || box->srcbox.pageno>pagecount) continue; /* Is this a source page we haven't processed yet (for this destination page)? */ for (newsrc=1,j=i0;j<i;j++) { if (pageinfo->boxes.box[j].srcbox.pageno==box->srcbox.pageno) { newsrc=0; break; } } if (newsrc) { double v[4]; srccount++; if (use_forms) srcpageused[box->srcbox.pageno]=1; /* printf(" NEW SOURCE PAGE (srccount=%d)\n",srccount); */ if (srccount==1) { /* ** Start a new destination page. ** ** Each new page object is a dict type with: ** /Type /Page ** /Contents (array of objects) ** /Resources (dict) ** /MediaBox [0 0 612 792] ** /Parent <PagesObj> ** [Can have /Rotate 90, for example.] ** */ /* printf(" (STARTING NEW DEST. PAGE)\n"); */ destpageobj=start_new_destpage(ctx,box->dst_width_pts,box->dst_height_pts); destpageresources=pdf_new_dict(ctx,1); if (use_forms) pdf_dict_puts(destpageresources,"XObject",pdf_new_dict(ctx,1)); destpageref=pdf_create_object(xref); destpagecontents=pdf_new_array(ctx,1); /* Init the destination page stream for forms */ if (use_forms) bigbuf[0]='\0'; } /* New source page, so get the source page objects */ srcpageobj = xref->page_objs[box->srcbox.pageno-1]; wmupdf_page_bbox(srcpageobj,v); srcx0=v[0]; srcy0=v[1]; /* printf("SRCX0=%g, SRCY0=%g\n",srcx0,srcy0); */ rotobj=pdf_dict_gets(srcpageobj,"Rotate"); srcpagerot = rotobj!=NULL ? pdf_to_real(rotobj) : 0.; /* printf("Page rotation = %g\n",srcpagerot); */ srcpagecontents=pdf_dict_gets(srcpageobj,"Contents"); /* if (pdf_is_array(srcpagecontents)) { int k; printf(" source page contents = array.\n"); for (k=0;k<pdf_array_len(srcpagecontents);k++) { pdf_obj *obj; obj=pdf_array_get(srcpagecontents,k); if (pdf_is_indirect(obj)) { printf(" contents[%d] = indirect (%d)\n",k,pdf_to_num(obj)); pdf_resolve_indirect(obj); } } } */ if (use_forms) { pdf_obj *xobjdict; int pageno; xobjdict=pdf_dict_gets(destpageresources,"XObject"); pageno=box->srcbox.pageno; pdf_dict_puts(xobjdict,xobject_name(pageno),xref->page_refs[pageno-1]); pdf_dict_puts(destpageresources,"XObject",xobjdict); } else { pdf_obj *srcpageresources; /* Merge source page resources into destination page resources */ srcpageresources=pdf_dict_gets(srcpageobj,"Resources"); /* printf("box->dstpage=%d, srcpage=%d (ind.#=%d)\n",box->dstpage,box->srcbox.pageno,pdf_to_num(xref->page_refs[box->srcbox.pageno-1])); */ wmupdf_dict_merge(ctx,"Resources",destpageresources,srcpageresources); } } /* ** Process this source box: ** ** Create a tranformation matrix and clipping path to only show the ** desired part of the source page at the appropriate place on the ** destination page. ** ** How the tranformation matrix works: ** - Translations shall be specified as [ 1 0 0 1 tx ty ], where tx and ty ** shall be the distances to translate the origin of the coordinate system ** in the horizontal and vertical dimensions, respectively. ** ** - Scaling shall be obtained by [ sx 0 0 sy 0 0 ]. This scales the coordinates ** so that 1 unit in the horizontal and vertical dimensions of the new coordinate ** system is the same size as sx and sy units, respectively, in the previous ** coordinate system. ** ** - Rotations shall be produced by [ cos q sin q -sin q cos q 0 0 ], which has the ** effect of rotating the coordinate system axes by an angle q counter-clockwise. ** ** - Skew shall be specified by [ 1 tan a tan b 1 0 0 ], which skews the x axis by ** an angle a and the y axis by an angle b. ** */ wpdfbox_determine_original_source_position(box); /* printf("Before unrotate.\n"); printf("box->srcrot=%g\n",box->srcrot_deg); printf("box->x0=%g, box->y0=%g\n",box->x0,box->y0); printf("box->w=%g, box->h=%g\n",box->w,box->h); printf("box->pw=%g, box->ph=%g\n",box->src_width_pts,box->src_height_pts); */ if (fabs(srcpagerot) > 1.0e-4) wpdfbox_unrotate(box,srcpagerot); /* printf("box->srcrot=%g\n",box->srcrot_deg); printf("box->x0=%g, box->y0=%g\n",box->x0,box->y0); printf("box->w=%g, box->h=%g\n",box->w,box->h); printf("box->pw=%g, box->ph=%g\n",box->src_width_pts,box->src_height_pts); */ matrix_unity(m,1.); /* printf("xfmatrix = [ %9.6f %9.6f %9.6f ]\n" " [ %9.6f %9.6f %9.6f ]\n" " [ %9.6f %9.6f %9.6f ]\n", m[0][0],m[0][1],m[0][2], m[1][0],m[1][1],m[1][2], m[2][0],m[2][1],m[2][2]); */ matrix_translate(m1,-box->x0-srcx0,-box->y0-srcy0); matrix_mul(m,m1); matrix_rotate(m1,-box->srcrot_deg+box->dstrot_deg); matrix_mul(m,m1); matrix_unity(m1,box->scale); matrix_mul(m,m1); matrix_translate(m1,box->x1,box->y1); matrix_mul(m,m1); matrix_zero_round(m); matrix_rotate(cpm,box->srcrot_deg); matrix_translate(m1,box->x0+srcx0,box->y0+srcy0); matrix_mul(cpm,m1); /* printf("Clip matrix:\n"); printf("xfmatrix = [ %9.6f %9.6f %9.6f ]\n" " [ %9.6f %9.6f %9.6f ]\n" " [ %9.6f %9.6f %9.6f ]\n", cpm[0][0],cpm[0][1],cpm[0][2], cpm[1][0],cpm[1][1],cpm[1][2], cpm[2][0],cpm[2][1],cpm[2][2]); */ set_clip_array(xclip,yclip,box->srcrot_deg,box->w,box->h); for (k=0;k<4;k++) matrix_xymul(cpm,&xclip[k],&yclip[k]); /* printf("Clip path:\n %7.2f %7.2f\n %7.2f,%7.2f\n %7.2f,%7.2f\n" " %7.2f %7.2f\n %7.2f,%7.2f\n", xclip[0],yclip[0],xclip[1],yclip[1],xclip[2],yclip[2], xclip[3],yclip[3],xclip[0],yclip[0]); */ strcpy(buf,"q"); for (k=0;k<=2;k++) { cat_pdf_double(buf,m[k][0]); cat_pdf_double(buf,m[k][1]); } strcat(buf," cm"); for (k=0;k<=4;k++) { cat_pdf_double(buf,xclip[k&3]); cat_pdf_double(buf,yclip[k&3]); strcat(buf,k==0 ? " m" : " l"); } strcat(buf," W n"); if (use_forms) { /* FORM METHOD */ sprintf(&buf[strlen(buf)]," /%s Do Q\n",xobject_name(box->srcbox.pageno)); if (strlen(bigbuf)+strlen(buf) > nbb) { int newsize; newsize=nbb*2; willus_mem_realloc_robust_warn((void **)&bigbuf,newsize,nbb,funcname,10); nbb=newsize; } strcat(bigbuf,buf); } else { /* NO-FORMS METHOD */ strcat(buf,"\n"); /* Create new objects in document for tx matrix and restore matrix */ s1indirect = pdf_new_indirect(ctx,new_stream_object(xref,ctx,buf),0,(void *)xref); if (qref==0) qref=new_stream_object(xref,ctx,"Q\n"); qindirect = pdf_new_indirect(ctx,qref,0,(void *)xref); /* Store this region into the destination page contents array */ pdf_array_push(destpagecontents,s1indirect); if (pdf_is_array(srcpagecontents)) { int k; for (k=0;k<pdf_array_len(srcpagecontents);k++) pdf_array_push(destpagecontents,pdf_array_get(srcpagecontents,k)); } else pdf_array_push(destpagecontents,srcpagecontents); pdf_array_push(destpagecontents,qindirect); pdf_drop_obj(s1indirect); pdf_drop_obj(qindirect); } } pdf_drop_obj(parent); /* For forms, convert all original source pages to XObject Forms */ if (use_forms) wmupdf_convert_pages_to_forms(xref,ctx,srcpageused); /* Update page count and kids array */ countobj = pdf_new_int(ctx, pdf_array_len(kids)); pdf_dict_puts(pages, "Count", countobj); pdf_drop_obj(countobj); pdf_dict_puts(pages, "Kids", kids); pdf_drop_obj(kids); /* Also preserve the (partial) Dests name tree */ if (olddests) wmupdf_preserve_old_dests(olddests,ctx,xref,pages); if (use_forms) { /* Free memory */ willus_mem_free((double **)&bigbuf,funcname); willus_mem_free((double **)&srcpageused,funcname); } return(0); }
pdf_page * pdf_create_page(pdf_document *doc, fz_rect mediabox, int res, int rotate) { pdf_page *page = NULL; pdf_obj *pageobj, *obj; float userunit = 1; fz_context *ctx = doc->ctx; fz_matrix ctm, tmp; fz_rect realbox; page = fz_malloc_struct(ctx, pdf_page); obj = NULL; fz_var(obj); fz_try(ctx) { page->resources = NULL; page->contents = NULL; page->transparency = 0; page->links = NULL; page->annots = NULL; page->me = pageobj = pdf_new_dict(doc, 4); pdf_dict_puts_drop(pageobj, "Type", pdf_new_name(doc, "Page")); page->mediabox.x0 = fz_min(mediabox.x0, mediabox.x1) * userunit; page->mediabox.y0 = fz_min(mediabox.y0, mediabox.y1) * userunit; page->mediabox.x1 = fz_max(mediabox.x0, mediabox.x1) * userunit; page->mediabox.y1 = fz_max(mediabox.y0, mediabox.y1) * userunit; pdf_dict_puts_drop(pageobj, "MediaBox", pdf_new_rect(doc, &page->mediabox)); /* Snap page->rotate to 0, 90, 180 or 270 */ if (page->rotate < 0) page->rotate = 360 - ((-page->rotate) % 360); if (page->rotate >= 360) page->rotate = page->rotate % 360; page->rotate = 90*((page->rotate + 45)/90); if (page->rotate > 360) page->rotate = 0; pdf_dict_puts_drop(pageobj, "Rotate", pdf_new_int(doc, page->rotate)); fz_pre_rotate(fz_scale(&ctm, 1, -1), -page->rotate); realbox = page->mediabox; fz_transform_rect(&realbox, &ctm); fz_pre_scale(fz_translate(&tmp, -realbox.x0, -realbox.y0), userunit, userunit); fz_concat(&ctm, &ctm, &tmp); page->ctm = ctm; obj = pdf_new_dict(doc, 4); page->contents = pdf_new_ref(doc, obj); pdf_drop_obj(obj); obj = NULL; pdf_dict_puts(pageobj, "Contents", page->contents); } fz_catch(ctx) { pdf_drop_obj(page->me); pdf_drop_obj(obj); fz_free(ctx, page); fz_rethrow_message(ctx, "Failed to create page"); } return page; }
static void decimatepages(pdf_document *xref) { pdf_obj *oldroot, *root, *pages, *kids, *parent; fz_context *ctx = xref->ctx; int num_pages = pdf_count_pages(xref); int page, kidcount; /* Keep only pages/type and (reduced) dest entries to avoid * references to unretained pages */ oldroot = pdf_dict_gets(pdf_trailer(xref), "Root"); pages = pdf_dict_gets(oldroot, "Pages"); root = pdf_new_dict(ctx, 2); pdf_dict_puts(root, "Type", pdf_dict_gets(oldroot, "Type")); pdf_dict_puts(root, "Pages", pdf_dict_gets(oldroot, "Pages")); pdf_update_object(xref, pdf_to_num(oldroot), root); pdf_drop_obj(root); /* Create a new kids array with only the pages we want to keep */ parent = pdf_new_indirect(ctx, pdf_to_num(pages), pdf_to_gen(pages), xref); kids = pdf_new_array(ctx, 1); kidcount = 0; for (page=0; page < num_pages; page++) { pdf_page *page_details = pdf_load_page(xref, page); int xf = x_factor, yf = y_factor; int x, y; float w = page_details->mediabox.x1 - page_details->mediabox.x0; float h = page_details->mediabox.y1 - page_details->mediabox.y0; if (xf == 0 && yf == 0) { /* Nothing specified, so split along the long edge */ if (w > h) xf = 2, yf = 1; else xf = 1, yf = 2; } else if (xf == 0) xf = 1; else if (yf == 0) yf = 1; for (y = yf-1; y >= 0; y--) { for (x = 0; x < xf; x++) { pdf_obj *newpageobj, *newpageref, *newmediabox; fz_rect mb; int num; newpageobj = pdf_copy_dict(ctx, xref->page_objs[page]); num = pdf_create_object(xref); pdf_update_object(xref, num, newpageobj); newpageref = pdf_new_indirect(ctx, num, 0, xref); newmediabox = pdf_new_array(ctx, 4); mb.x0 = page_details->mediabox.x0 + (w/xf)*x; if (x == xf-1) mb.x1 = page_details->mediabox.x1; else mb.x1 = page_details->mediabox.x0 + (w/xf)*(x+1); mb.y0 = page_details->mediabox.y0 + (h/yf)*y; if (y == yf-1) mb.y1 = page_details->mediabox.y1; else mb.y1 = page_details->mediabox.y0 + (h/yf)*(y+1); pdf_array_push(newmediabox, pdf_new_real(ctx, mb.x0)); pdf_array_push(newmediabox, pdf_new_real(ctx, mb.y0)); pdf_array_push(newmediabox, pdf_new_real(ctx, mb.x1)); pdf_array_push(newmediabox, pdf_new_real(ctx, mb.y1)); pdf_dict_puts(newpageobj, "Parent", parent); pdf_dict_puts(newpageobj, "MediaBox", newmediabox); /* Store page object in new kids array */ pdf_array_push(kids, newpageref); kidcount++; } } } pdf_drop_obj(parent); /* Update page count and kids array */ pdf_dict_puts(pages, "Count", pdf_new_int(ctx, kidcount)); pdf_dict_puts(pages, "Kids", kids); pdf_drop_obj(kids); }
static void retainpages(int argc, char **argv) { pdf_obj *oldroot, *root, *pages, *kids, *countobj, *parent, *olddests; /* Keep only pages/type and (reduced) dest entries to avoid * references to unretained pages */ oldroot = pdf_dict_gets(xref->trailer, "Root"); pages = pdf_dict_gets(oldroot, "Pages"); olddests = pdf_load_name_tree(xref, "Dests"); root = pdf_new_dict(ctx, 2); pdf_dict_puts(root, "Type", pdf_dict_gets(oldroot, "Type")); pdf_dict_puts(root, "Pages", pdf_dict_gets(oldroot, "Pages")); pdf_update_object(xref, pdf_to_num(oldroot), root); pdf_drop_obj(root); /* Create a new kids array with only the pages we want to keep */ parent = pdf_new_indirect(ctx, pdf_to_num(pages), pdf_to_gen(pages), xref); kids = pdf_new_array(ctx, 1); /* Retain pages specified */ while (argc - fz_optind) { int page, spage, epage, pagecount; char *spec, *dash; char *pagelist = argv[fz_optind]; pagecount = pdf_count_pages(xref); spec = fz_strsep(&pagelist, ","); while (spec) { dash = strchr(spec, '-'); if (dash == spec) spage = epage = pagecount; else spage = epage = atoi(spec); if (dash) { if (strlen(dash) > 1) epage = atoi(dash + 1); else epage = pagecount; } if (spage > epage) page = spage, spage = epage, epage = page; spage = fz_clampi(spage, 1, pagecount); epage = fz_clampi(epage, 1, pagecount); for (page = spage; page <= epage; page++) { pdf_obj *pageobj = xref->page_objs[page-1]; pdf_obj *pageref = xref->page_refs[page-1]; pdf_dict_puts(pageobj, "Parent", parent); /* Store page object in new kids array */ pdf_array_push(kids, pageref); } spec = fz_strsep(&pagelist, ","); } fz_optind++; } pdf_drop_obj(parent); /* Update page count and kids array */ countobj = pdf_new_int(ctx, pdf_array_len(kids)); pdf_dict_puts(pages, "Count", countobj); pdf_drop_obj(countobj); pdf_dict_puts(pages, "Kids", kids); pdf_drop_obj(kids); /* Also preserve the (partial) Dests name tree */ if (olddests) { int i; pdf_obj *names = pdf_new_dict(ctx, 1); pdf_obj *dests = pdf_new_dict(ctx, 1); pdf_obj *names_list = pdf_new_array(ctx, 32); int len = pdf_dict_len(olddests); for (i = 0; i < len; i++) { pdf_obj *key = pdf_dict_get_key(olddests, i); pdf_obj *val = pdf_dict_get_val(olddests, i); pdf_obj *key_str = pdf_new_string(ctx, pdf_to_name(key), strlen(pdf_to_name(key))); pdf_obj *dest = pdf_dict_gets(val, "D"); dest = pdf_array_get(dest ? dest : val, 0); if (pdf_array_contains(pdf_dict_gets(pages, "Kids"), dest)) { pdf_array_push(names_list, key_str); pdf_array_push(names_list, val); } pdf_drop_obj(key_str); } root = pdf_dict_gets(xref->trailer, "Root"); pdf_dict_puts(dests, "Names", names_list); pdf_dict_puts(names, "Dests", dests); pdf_dict_puts(root, "Names", names); pdf_drop_obj(names); pdf_drop_obj(dests); pdf_drop_obj(names_list); pdf_drop_obj(olddests); } }
void pdf_delete_annot(pdf_document *doc, pdf_page *page, pdf_annot *annot) { fz_context *ctx = doc->ctx; pdf_annot **annotptr; pdf_obj *old_annot_arr; pdf_obj *annot_arr; if (annot == NULL) return; /* Remove annot from page's list */ for (annotptr = &page->annots; *annotptr; annotptr = &(*annotptr)->next) { if (*annotptr == annot) break; } /* Check the passed annotation was of this page */ if (*annotptr == NULL) return; *annotptr = annot->next; /* If the removed annotation was the last in the list adjust the end pointer */ if (*annotptr == NULL) page->annot_tailp = annotptr; /* Stick it in the deleted list */ annot->next = page->deleted_annots; page->deleted_annots = annot; pdf_drop_xobject(ctx, annot->ap); annot->ap = NULL; /* Recreate the "Annots" array with this annot removed */ old_annot_arr = pdf_dict_gets(page->me, "Annots"); if (old_annot_arr) { int i, n = pdf_array_len(old_annot_arr); annot_arr = pdf_new_array(doc, n?(n-1):0); fz_try(ctx) { for (i = 0; i < n; i++) { pdf_obj *obj = pdf_array_get(old_annot_arr, i); if (obj != annot->obj) pdf_array_push(annot_arr, obj); } if (pdf_is_indirect(old_annot_arr)) pdf_update_object(doc, pdf_to_num(old_annot_arr), annot_arr); else pdf_dict_puts(page->me, "Annots", annot_arr); if (pdf_is_indirect(annot->obj)) pdf_delete_object(doc, pdf_to_num(annot->obj)); } fz_always(ctx) { pdf_drop_obj(annot_arr); } fz_catch(ctx) { fz_rethrow(ctx); } } pdf_drop_obj(annot->obj); annot->obj = NULL; doc->dirty = 1; }
/* When resetting or submitting a form, the fields to act upon are defined by an array of either field references or field names, plus a flag determining whether to act upon the fields in the array, or all fields other than those in the array. specified_fields interprets this information and produces the array of fields to be acted upon. */ static pdf_obj *specified_fields(pdf_document *doc, pdf_obj *fields, int exclude) { fz_context *ctx = doc->ctx; pdf_obj *form = pdf_dict_getp(pdf_trailer(doc), "Root/AcroForm/Fields"); int i, n; pdf_obj *result = pdf_new_array(doc, 0); pdf_obj *nil = NULL; fz_var(nil); fz_try(ctx) { /* The 'fields' array not being present signals that all fields * should be acted upon, so handle it using the exclude case - excluding none */ if (exclude || !fields) { /* mark the fields we don't want to act upon */ nil = pdf_new_null(doc); n = pdf_array_len(fields); for (i = 0; i < n; i++) { pdf_obj *field = pdf_array_get(fields, i); if (pdf_is_string(field)) field = pdf_lookup_field(form, pdf_to_str_buf(field)); if (field) pdf_dict_puts(field, "Exclude", nil); } /* Act upon all unmarked fields */ n = pdf_array_len(form); for (i = 0; i < n; i++) add_field_hierarchy_to_array(result, pdf_array_get(form, i)); /* Unmark the marked fields */ n = pdf_array_len(fields); for (i = 0; i < n; i++) { pdf_obj *field = pdf_array_get(fields, i); if (pdf_is_string(field)) field = pdf_lookup_field(form, pdf_to_str_buf(field)); if (field) pdf_dict_dels(field, "Exclude"); } } else { n = pdf_array_len(fields); for (i = 0; i < n; i++) { pdf_obj *field = pdf_array_get(fields, i); if (pdf_is_string(field)) field = pdf_lookup_field(form, pdf_to_str_buf(field)); if (field) add_field_hierarchy_to_array(result, field); } } } fz_always(ctx) { pdf_drop_obj(nil); } fz_catch(ctx) { pdf_drop_obj(result); fz_rethrow(ctx); } return result; }
pdf_obj * pdf_new_xobject(pdf_document *doc, const fz_rect *bbox, const fz_matrix *mat) { int idict_num; pdf_obj *idict = NULL; pdf_obj *dict = NULL; pdf_xobject *form = NULL; pdf_obj *obj = NULL; pdf_obj *res = NULL; pdf_obj *procset = NULL; fz_context *ctx = doc->ctx; fz_var(idict); fz_var(dict); fz_var(form); fz_var(obj); fz_var(res); fz_var(procset); fz_try(ctx) { dict = pdf_new_dict(doc, 0); obj = pdf_new_rect(doc, bbox); pdf_print_obj(obj); pdf_dict_puts(dict, "BBox", obj); pdf_drop_obj(obj); obj = NULL; obj = pdf_new_int(doc, 1); pdf_dict_puts(dict, "FormType", obj); pdf_drop_obj(obj); obj = NULL; obj = pdf_new_int(doc, 0); pdf_dict_puts(dict, "Length", obj); pdf_drop_obj(obj); obj = NULL; obj = pdf_new_matrix(doc, mat); pdf_dict_puts(dict, "Matrix", obj); pdf_drop_obj(obj); obj = NULL; res = pdf_new_dict(doc, 0); procset = pdf_new_array(doc, 2); obj = pdf_new_name(doc, "PDF"); pdf_array_push(procset, obj); pdf_drop_obj(obj); obj = NULL; obj = pdf_new_name(doc, "Text"); pdf_array_push(procset, obj); pdf_drop_obj(obj); obj = NULL; pdf_dict_puts(res, "ProcSet", procset); pdf_drop_obj(procset); procset = NULL; pdf_dict_puts(dict, "Resources", res); obj = pdf_new_name(doc, "Form"); pdf_dict_puts(dict, "Subtype", obj); pdf_drop_obj(obj); obj = NULL; obj = pdf_new_name(doc, "XObject"); pdf_dict_puts(dict, "Type", obj); pdf_drop_obj(obj); obj = NULL; form = fz_malloc_struct(ctx, pdf_xobject); FZ_INIT_STORABLE(form, 1, pdf_free_xobject_imp); form->resources = NULL; form->contents = NULL; form->colorspace = NULL; form->me = NULL; form->iteration = 0; form->bbox = *bbox; form->matrix = *mat; form->isolated = 0; form->knockout = 0; form->transparency = 0; form->resources = res; res = NULL; idict_num = pdf_create_object(doc); pdf_update_object(doc, idict_num, dict); idict = pdf_new_indirect(doc, idict_num, 0); pdf_drop_obj(dict); dict = NULL; pdf_store_item(ctx, idict, form, pdf_xobject_size(form)); form->contents = pdf_keep_obj(idict); form->me = pdf_keep_obj(idict); pdf_drop_xobject(ctx, form); form = NULL; } fz_catch(ctx) { pdf_drop_obj(procset); pdf_drop_obj(res); pdf_drop_obj(obj); pdf_drop_obj(dict); pdf_drop_obj(idict); pdf_drop_xobject(ctx, form); fz_rethrow_message(ctx, "failed to create xobject)"); } return idict; }
static void wmupdf_convert_single_page_to_form(pdf_document *xref,fz_context *ctx,int pageno) { pdf_obj *array,*srcpageobj,*srcpagecontents; int i,len,streamlen,pageref,pagegen,compressed; double bbox_array[4]; double matrix[6]; /* New source page, so get the source page objects */ srcpageobj = xref->page_objs[pageno-1]; pageref=pdf_to_num(xref->page_refs[pageno-1]); pagegen=pdf_to_gen(xref->page_refs[pageno-1]); wmupdf_page_bbox(srcpageobj,bbox_array); for (i=0;i<6;i++) matrix[i]=0.; matrix[0]=matrix[3]=1.; srcpagecontents=pdf_dict_gets(srcpageobj,"Contents"); /* Concatenate all indirect streams from source page directly into it. */ // printf("Adding streams to source page %d (pageref=%d, pagegen=%d)...\n",pageno,pageref,pagegen); streamlen=0; if (pdf_is_array(srcpagecontents)) { int k; for (k=0;k<pdf_array_len(srcpagecontents);k++) { pdf_obj *obj; obj=pdf_array_get(srcpagecontents,k); if (pdf_is_indirect(obj)) pdf_resolve_indirect(obj); streamlen=add_to_srcpage_stream(xref,ctx,pageref,pagegen,obj); } } else { if (pdf_is_indirect(srcpagecontents)) pdf_resolve_indirect(srcpagecontents); streamlen=add_to_srcpage_stream(xref,ctx,pageref,pagegen,srcpagecontents); } compressed=stream_deflate(xref,ctx,pageref,pagegen,&streamlen); srcpageobj = xref->page_objs[pageno-1]; pageref=pdf_to_num(xref->page_refs[pageno-1]); len=pdf_dict_len(srcpageobj); for (i=0;i<len;i++) { pdf_obj *key; /* *value */ key=pdf_dict_get_key(srcpageobj,i); /* if (pdf_is_name(key)) printf("key[%d] = name = %s\n",i,pdf_to_name(key)); else printf("key[%d] = ??\n",i); */ /* value=pdf_dict_get_val(srcpageobj,i); */ /* Keep same resources */ if (!pdf_is_name(key)) continue; if (pdf_is_name(key) && !stricmp("Resources",pdf_to_name(key))) continue; /* Drop dictionary entry otherwise */ // printf("Deleting key %s.\n",pdf_to_name(key)); pdf_dict_del(srcpageobj,key); i=-1; len=pdf_dict_len(srcpageobj); } pdf_dict_puts(srcpageobj,"Type",pdf_new_name(ctx,"XObject")); pdf_dict_puts(srcpageobj,"Subtype",pdf_new_name(ctx,"Form")); pdf_dict_puts(srcpageobj,"FormType",pdf_new_int(ctx,1)); if (compressed) pdf_dict_puts(srcpageobj,"Filter",pdf_new_name(ctx,"FlateDecode")); pdf_dict_puts(srcpageobj,"Length",pdf_new_int(ctx,streamlen)); array=pdf_new_array(ctx,4); for (i=0;i<4;i++) pdf_array_push(array,pdf_new_real(ctx,bbox_array[i])); pdf_dict_puts(srcpageobj,"BBox",array); array=pdf_new_array(ctx,6); for (i=0;i<6;i++) pdf_array_push(array,pdf_new_real(ctx,matrix[i])); pdf_dict_puts(srcpageobj,"Matrix",array); /* (It's no longer a "page"--it's a Form-type XObject) */ /* I don't think this call should be made since it will call fz_drop_object on srcpageobj */ /* pdf_update_object(xref,pageref,srcpageobj); */ }