def makepdf(self, prev, udct, algomd, zeros): catalog = prev.trailer["/Root"] size = prev.trailer["/Size"] pages = catalog["/Pages"].getObject() page0ref = pages["/Kids"][udct.get("sigpage", 0)] while len(self._objects) < size - 1: self._objects.append(None) obj13 = po.DictionaryObject() obj13ref = self._addObject(obj13) obj12 = po.DictionaryObject() obj12ref = self._addObject(obj12) obj12.update({ po.NameObject("/Type"): po.NameObject("/Sig"), po.NameObject("/Filter"): po.NameObject("/Adobe.PPKLite"), po.NameObject("/SubFilter"): po.NameObject("/adbe.pkcs7.detached"), po.NameObject("/Name"): po.createStringObject(udct["contact"]), po.NameObject("/Location"): po.createStringObject(udct["location"]), po.NameObject("/Reason"): po.createStringObject(udct["reason"]), po.NameObject("/M"): po.createStringObject(udct["signingdate"]), po.NameObject("/Contents"): UnencryptedBytes(zeros), po.NameObject("/ByteRange"): po.ArrayObject([ WNumberObject(0), WNumberObject(0), WNumberObject(0), WNumberObject(0), ]), }) obj13.update({ po.NameObject("/FT"): po.NameObject("/Sig"), po.NameObject("/Type"): po.NameObject("/Annot"), po.NameObject("/Subtype"): po.NameObject("/Widget"), po.NameObject("/F"): po.NumberObject(udct.get("sigflagsft", 132)), po.NameObject("/T"): EncodedString(udct.get("sigfield", "Signature1")), po.NameObject("/V"): obj12ref, po.NameObject("/P"): page0ref, po.NameObject("/Rect"): po.ArrayObject([ po.FloatObject(0.0), po.FloatObject(0.0), po.FloatObject(0.0), po.FloatObject(0.0), ]), }) box = udct.get("signaturebox", None) if box is not None: from endesive.pdf.PyPDF2_annotate.annotations.text import FreeText from endesive.pdf.PyPDF2_annotate.annotations.image import Image from endesive.pdf.PyPDF2_annotate.config.appearance import Appearance from endesive.pdf.PyPDF2_annotate.config.location import Location from endesive.pdf.PyPDF2_annotate.util.geometry import identity annotationtext = udct.get("signature", None) x1, y1, x2, y2 = box if annotationtext is not None: annotation = FreeText( Location(x1=x1, y1=y1, x2=x2, y2=y2, page=0), Appearance( fill=[0, 0, 0], stroke_width=1, wrap_text=True, font_size=12, content=annotationtext, ), ) names = ("BS", "C", "Contents", "DA") if not udct.get("sigbutton", False): obj13[po.NameObject("/Subtype")] = po.NameObject( "/FreeText") else: ap = Appearance() ap.image = udct["signature_img"] annotation = Image( Location(x1=x1, y1=y1, x2=x2, y2=y2, page=0), ap) if not udct.get("sigbutton", False): names = ( # "Subtype", ) else: names = () pdfa = annotation.as_pdf_object(identity(), page=page0ref) objapn = self._extend(pdfa["/AP"]["/N"]) objapnref = self._addObject(objapn) for name in names + ( "Rect", # "Subtype", ): key = po.NameObject("/" + name) v = pdfa[key] obj13[key] = v objap = po.DictionaryObject() objap[po.NameObject("/N")] = objapnref obj13.update({ po.NameObject("/AP"): objap, po.NameObject("/SM"): po.createStringObject("TabletPOSinline"), }) page0 = page0ref.getObject() annots = po.ArrayObject([obj13ref]) if "/Annots" in page0: page0annots = page0["/Annots"] if isinstance(page0annots, po.IndirectObject): annots.insert(0, page0annots) elif isinstance(page0annots, po.ArrayObject): annots = page0annots annots.append(obj13ref) page0.update({po.NameObject("/Annots"): annots}) self._objects[page0ref.idnum - 1] = page0 if "/Perms" not in catalog: obj10 = po.DictionaryObject() obj10ref = self._addObject(obj10) obj11 = po.DictionaryObject() obj11ref = self._addObject(obj11) obj14 = po.DictionaryObject() obj14ref = self._addObject(obj14) obj14.update({po.NameObject("/DocMDP"): obj12ref}) obj10.update({ po.NameObject("/Type"): po.NameObject("/TransformParams"), po.NameObject("/P"): po.NumberObject(2), po.NameObject("/V"): po.NameObject("/1.2"), }) obj11.update({ po.NameObject("/Type"): po.NameObject("/SigRef"), po.NameObject("/TransformMethod"): po.NameObject("/DocMDP"), po.NameObject("/DigestMethod"): po.NameObject("/" + algomd.upper()), po.NameObject("/TransformParams"): obj10ref, }) obj12[po.NameObject("/Reference")] = po.ArrayObject([obj11ref]) catalog[po.NameObject("/Perms")] = obj14ref if "/AcroForm" in catalog: form = catalog["/AcroForm"].getObject() if "/Fields" in form: fields = form["/Fields"] else: fields = po.ArrayObject() fields.append(obj13ref) form.update({ po.NameObject("/Fields"): fields, po.NameObject("/SigFlags"): po.NumberObject(udct.get("sigflags", 3)), }) formref = catalog.raw_get("/AcroForm") if isinstance(formref, po.IndirectObject): self._objects[formref.idnum - 1] = form form = formref else: form = po.DictionaryObject() form.update({ po.NameObject("/Fields"): po.ArrayObject([obj13ref]), po.NameObject("/SigFlags"): po.NumberObject(udct.get("sigflags", 3)), }) catalog[po.NameObject("/AcroForm")] = form if "/Metadata" in catalog: catalog[po.NameObject("/Metadata")] = catalog.raw_get("/Metadata") x_root = prev.trailer.raw_get("/Root") self._objects[x_root.idnum - 1] = catalog self.x_root = po.IndirectObject(x_root.idnum, 0, self) self.x_info = prev.trailer.raw_get("/Info")
def makepdf(self, prev, udct, algomd, zeros, cert, **params): catalog = prev.trailer["/Root"] size = prev.trailer["/Size"] pages = catalog["/Pages"].getObject() page0ref = prev.getPage(udct.get("sigpage", 0)).indirectRef self._objects = [] while len(self._objects) < size - 1: self._objects.append(None) ## if params['mode'] == 'timestamp': ## # deal with extensions ## if '/Extensions' not in catalog: ## extensions = po.DictionaryObject() ## else: ## extensions = catalog['/Extensions'] ## ## if '/ESIC' not in extensions: ## extensions.update({ ## po.NameObject("/ESIC"): po.DictionaryObject({ ## po.NameObject('/BaseVersion'): po.NameObject('/1.7'), ## po.NameObject('/ExtensionLevel'): po.NumberObject(1), ## }) ## }) ## else: ## esic = extensions['/ESIC'] ## major, minor = esic['/BaseVersion'].lstrip('/').split('.') ## if int(major) < 1 or int(minor) < 7: ## esic.update({ ## po.NameObject('/BaseVersion'): po.NameObject('/1.7'), ## po.NameObject('/ExtensionLevel'): po.NumberObject(1), ## }) ## catalog.update({ ## po.NameObject('/Extensions'): extensions ## }) # obj12 is the digital signature obj12, obj12ref = self._make_signature( Type=po.NameObject("/Sig"), SubFilter=po.NameObject("/adbe.pkcs7.detached"), Contents=UnencryptedBytes(zeros), ) if params['mode'] == 'timestamp': # obj12 is a timestamp this time obj12.update({ po.NameObject("/Type"): po.NameObject("/DocTimeStamp"), po.NameObject("/SubFilter"): po.NameObject("/ETSI.RFC3161"), po.NameObject("/V"): po.NumberObject(0), }) else: obj12.update({ po.NameObject("/Name"): po.createStringObject(udct["contact"]), po.NameObject("/Location"): po.createStringObject(udct["location"]), po.NameObject("/Reason"): po.createStringObject(udct["reason"]), }) if params.get('use_signingdate'): obj12.update({ po.NameObject("/M"): po.createStringObject(udct["signingdate"]), }) # obj13 is a combined AcroForm Sig field with Widget annotation new_13 = True #obj13 = po.DictionaryObject() if udct.get('signform', False): # Attaching signature to existing field in AcroForm if "/AcroForm" in catalog: form = catalog["/AcroForm"].getObject() if "/Fields" in form: fields = form["/Fields"].getObject() obj13ref = [ f for f in fields if f.getObject()['/T'] == udct.get( 'sigfield', 'Signature1') ][0] obj13 = obj13ref.getObject() self._objects[obj13ref.idnum - 1] = obj13 new_13 = False # box is coordinates of the annotation to fill box = udct.get("signaturebox", None) if new_13: obj13, obj13ref = self._make_sig_annotation( F=po.NumberObject(udct.get("sigflagsft", 132)), T=EncodedString(udct.get("sigfield", "Signature1")), Vref=obj12ref, Pref=page0ref, ) else: # original obj13 is a merged SigField/SigAnnot # Setting /V on the AcroForm field sets the signature # for the field obj13.update({ po.NameObject("/V"): obj12ref, }) # fill the existing signature field annotation, # ignore any other location if "/Rect" in obj13: box = [float(f) for f in obj13["/Rect"]] # add an annotation if there is a field to fill if box is not None: from endesive.pdf.PyPDF2_annotate.annotations.signature import Signature from endesive.pdf.PyPDF2_annotate.config.appearance import Appearance from endesive.pdf.PyPDF2_annotate.config.location import Location from endesive.pdf.PyPDF2_annotate.util.geometry import identity x1, y1, x2, y2 = box annotation = Signature( Location(x1=x1, y1=y1, x2=x2, y2=y2, page=0), Appearance(), ) if 'signature' in udct: # Plain text signature with the default font # text to render is contained in udct['signature'] # font parameters are in udct['signature']['text'] annotationtext = udct["signature"] wrap_text = udct.get('text', {}).get('wraptext', True) font_size = udct.get('text', {}).get('fontsize', 12) text_align = udct.get('text', {}).get('textalign', 'left') line_spacing = udct.get('text', {}).get('linespacing', 1.2) annotation.add_default_font() annotation.set_signature_appearance( ['fill_colour', 0, 0, 0], ['font', 'default', font_size], [ 'text_box', annotationtext, 'default', 0, 0, x2 - x1, y2 - y1, font_size, wrap_text, text_align, 'middle', line_spacing ]) elif 'signature_img' in udct: # Simple image signature, stretches to fit the box # image to render is contained in udct['signature_image'] annotation.add_image(udct["signature_img"], "Image") annotation.set_signature_appearance([ 'image', "Image", 0, 0, x2 - x1, y2 - y1, udct.get('signature_img_distort', True), udct.get('signature_img_centred', False), ]) elif 'signature_appearance' in udct: # Adobe-inspired signature with text and images # Parameters are contained in udct['signature_appearance'] # If a field is included in the display list, that field # will be contained in the annotation. # # Text and border are the colour specified by outline, # and border is the the inset distance from the outer # edge of the annotation. The R G B values range between # 0 and 1. # # Icon is an image to display above the background and # border at the left-hand side of the anntoation. If # there is no text, it is centred. # # The text block is left-aligned to the right of the icon # image. If there is no image, the text is left-aliged # with the left-hand border of the annotation # # display fields: # CN, DN, date, contact, reason, location # # Dict format: # appearance = dict( # background = Image with alpha / None, # icon = Image with alpha / None, # labels = bool, # display = list, # software = str, # outline = [R, G, B], # border = int, # ) sig = {} for f in ('background', 'icon', 'labels', 'border', 'outline'): if f in udct['signature_appearance']: sig[f] = udct['signature_appearance'][f] toggles = udct['signature_appearance'].get('display', []) for f in ('contact', 'reason', 'location', 'contact', 'signingdate'): if f in toggles: sig[f] = udct.get(f, '{} unknown'.format(f)) if 'date' in toggles: sig['date'] = udct['signingdate'] if 'CN' in toggles: from cryptography.x509 import ObjectIdentifier sig['CN'] = cert.subject.get_attributes_for_oid( ObjectIdentifier('2.5.4.3'))[0].value if 'DN' in toggles: sig['DN'] = cert.subject.rfc4514_string() annotation.simple_signature(sig) else: # Manual signature annotation creation # # Make your own appearance with an arbitrary number of # images and fonts if 'manual_images' in udct: for name, img in udct['manual_images'].items(): annotation.add_image(img, name=name) if 'manual_fonts' in udct: for name, path in udct['manual_fonts'].items(): annotation.add_ttf_font(path, name=name) annotation.add_default_font() annotation.set_signature_appearance(*udct['signature_manual']) pdfa = annotation.as_pdf_object(identity(), page=page0ref) objapn = self._extend(pdfa["/AP"]["/N"]) objapnref = self._addObject(objapn) objap = po.DictionaryObject() objap[po.NameObject("/N")] = objapnref obj13.update({ po.NameObject("/Rect"): po.ArrayObject([ po.FloatObject(x1), po.FloatObject(y1), po.FloatObject(x2), po.FloatObject(y2), ]), po.NameObject("/AP"): objap, #po.NameObject("/SM"): po.createStringObject("TabletPOSinline"), }) page0 = page0ref.getObject() if new_13: annots = po.ArrayObject([obj13ref]) if "/Annots" in page0: page0annots = page0["/Annots"] if isinstance(page0annots, po.IndirectObject): annots.insert(0, page0annots) elif isinstance(page0annots, po.ArrayObject): annots = page0annots annots.append(obj13ref) else: annots = page0["/Annots"] page0.update({po.NameObject("/Annots"): annots}) self._objects[page0ref.idnum - 1] = page0 if udct.get("sigandcertify", False) and "/Perms" not in catalog: obj10 = po.DictionaryObject() obj10ref = self._addObject(obj10) obj11 = po.DictionaryObject() obj11ref = self._addObject(obj11) obj14 = po.DictionaryObject() obj14ref = self._addObject(obj14) obj14.update({po.NameObject("/DocMDP"): obj12ref}) obj10.update({ po.NameObject("/Type"): po.NameObject("/TransformParams"), po.NameObject("/P"): po.NumberObject(udct.get("sigflags", 3)), po.NameObject("/V"): po.NameObject("/1.2"), }) obj11.update({ po.NameObject("/Type"): po.NameObject("/SigRef"), po.NameObject("/TransformMethod"): po.NameObject("/DocMDP"), po.NameObject("/DigestMethod"): po.NameObject("/" + algomd.upper()), po.NameObject("/TransformParams"): obj10ref, }) obj12[po.NameObject("/Reference")] = po.ArrayObject([obj11ref]) catalog[po.NameObject("/Perms")] = obj14ref if "/AcroForm" in catalog: form = catalog["/AcroForm"].getObject() if "/Fields" in form: fields = form["/Fields"] old_field_names = [f.getObject()['/T'] for f in fields] else: fields = po.ArrayObject() old_field_names = [] if udct.get('auto_sigfield', False) and obj13['/T'] in old_field_names: name_base = udct.get('sigfield', 'Signature1') checklist = [ f[len(name_base):] for f in old_field_names if f.startswith(name_base) ] for i in range(1, len(checklist) + 1): suffix = '_{}'.format(i) if suffix in checklist: next new_name = '{}{}'.format(name_base, suffix) obj13.update( {po.NameObject("/T"): EncodedString(new_name)}) break old_flags = int(form.get("/SigFlags", 0)) new_flags = int(form.get("/SigFlags", 0)) | udct.get("sigflags", 3) if new_13: fields.append(obj13ref) form.update({ po.NameObject("/Fields"): fields, po.NameObject("/SigFlags"): po.NumberObject(new_flags), }) elif new_flags > old_flags: form.update({ po.NameObject("/SigFlags"): po.NumberObject(new_flags), }) formref = catalog.raw_get("/AcroForm") if isinstance(formref, po.IndirectObject): self._objects[formref.idnum - 1] = form form = formref else: form = po.DictionaryObject() form.update({ po.NameObject("/Fields"): po.ArrayObject([obj13ref]), po.NameObject("/SigFlags"): po.NumberObject(udct.get("sigflags", 3)), }) catalog[po.NameObject("/AcroForm")] = form if "/Metadata" in catalog: catalog[po.NameObject("/Metadata")] = catalog.raw_get("/Metadata") x_root = prev.trailer.raw_get("/Root") self._objects[x_root.idnum - 1] = catalog self.x_root = po.IndirectObject(x_root.idnum, 0, self) self.x_info = prev.trailer.get("/Info")