def __init__( self, field_name, *, box=None, include_on_page=None, is_annotation=True, # this sets the "print" bit annot_flags=0b100): if box is not None: rect = list(map(generic.FloatObject, box)) else: rect = [generic.FloatObject(0)] * 4 super().__init__({ # Signature field properties pdf_name('/FT'): pdf_name('/Sig'), pdf_name('/T'): pdf_string(field_name), }) if is_annotation: # Annotation properties: bare minimum self['/Type'] = pdf_name('/Annot') self['/Subtype'] = pdf_name('/Widget') self['/F'] = generic.NumberObject(annot_flags) self['/Rect'] = generic.ArrayObject(rect) if include_on_page is not None: self['/P'] = include_on_page
def __init__(self, cf: CIDFont): tt = cf.tt_font # Some metrics hhea = tt['hhea'] head = tt['head'] bbox = [head.xMin, head.yMin, head.xMax, head.yMax] os2 = tt['OS/2'] weight = os2.usWeightClass stemv = int(10 + 220 * (weight - 50) / 900) super().__init__({ pdf_name('/Type'): pdf_name('/FontDescriptor'), pdf_name('/FontName'): pdf_name('/' + cf.name), pdf_name('/Ascent'): generic.NumberObject(hhea.ascent), pdf_name('/Descent'): generic.NumberObject(hhea.descent), pdf_name('/FontBBox'): generic.ArrayObject( map(generic.NumberObject, bbox) ), # FIXME I'm setting the Serif and Symbolic flags here, but # is there any way we can read/infer those from the TTF metadata? pdf_name('/Flags'): generic.NumberObject(0b110), pdf_name('/StemV'): generic.NumberObject(stemv), pdf_name('/ItalicAngle'): generic.FloatObject( getattr(tt['post'], 'italicAngle', 0) ), pdf_name('/CapHeight'): generic.NumberObject( getattr(os2, 'sCapHeight', 750) ) })
def __init__(self, field_name, *, box=None, include_on_page=None, combine_annotation=True, # this sets the "print" and "lock" bits annot_flags=0b10000100): if box is not None: rect = list(map(generic.FloatObject, box)) else: rect = [generic.FloatObject(0)] * 4 super().__init__({ # Signature field properties pdf_name('/FT'): pdf_name('/Sig'), pdf_name('/T'): pdf_string(field_name), }) if combine_annotation: annot_dict = self else: annot_dict = generic.DictionaryObject() # Annotation properties: bare minimum annot_dict['/Type'] = pdf_name('/Annot') annot_dict['/Subtype'] = pdf_name('/Widget') annot_dict['/F'] = generic.NumberObject(annot_flags) annot_dict['/Rect'] = generic.ArrayObject(rect) self.page_ref = include_on_page if include_on_page is not None: annot_dict['/P'] = include_on_page self.annot_dict = annot_dict
def __init__(self, field_name, include_on_page, *, writer, sig_object_ref=None, box=None, appearances: Optional[AnnotAppearances] = None): if box is not None: visible = True rect = list(map(generic.FloatObject, box)) if appearances is not None: ap = appearances.as_pdf_object() else: ap = None else: rect = [generic.FloatObject(0)] * 4 ap = None visible = False # this sets the "Print" bit, and activates "Locked" if the # signature field is ready to be filled flags = 0b100 if sig_object_ref is None else 0b10000100 super().__init__({ # Signature field properties pdf_name('/FT'): pdf_name('/Sig'), pdf_name('/T'): pdf_string(field_name), # Annotation properties: bare minimum pdf_name('/Type'): pdf_name('/Annot'), pdf_name('/Subtype'): pdf_name('/Widget'), pdf_name('/F'): generic.NumberObject(flags), pdf_name('/P'): include_on_page, pdf_name('/Rect'): generic.ArrayObject(rect) }) if sig_object_ref is not None: self[pdf_name('/V')] = sig_object_ref if ap is not None: self[pdf_name('/AP')] = ap # register ourselves self.reference = self_reference = writer.add_object(self) # if we're building an invisible form field, this is all there is to it if visible: writer.register_annotation(include_on_page, self_reference)
def _render_background(self): bg = self.style.background bg.set_writer(self.writer) bg_content = bg.render() # render first, in case the BBox is lazy bg_box = bg.box if bg_box.width_defined and bg_box.height_defined: # apply layout rule positioning = self.style.background_layout.fit( self.box, bg_box.width, bg_box.height ) else: # No idea about the background dimensions, so just use # the left/bottom margins and hope for the best margins = self.style.background_layout.margins positioning = layout.Positioning( x_scale=1, y_scale=1, x_pos=margins.left, y_pos=margins.bottom ) # set opacity in graphics state opacity = generic.FloatObject(self.style.background_opacity) self.set_resource( category=content.ResourceType.EXT_G_STATE, name=pdf_name('/BackgroundGS'), value=generic.DictionaryObject({ pdf_name('/CA'): opacity, pdf_name('/ca'): opacity }) ) # Position & render the background command = b'q /BackgroundGS gs %s %s Q' % ( positioning.as_cm(), bg_content ) # we do this after render(), just in case our background resource # decides to pull in extra stuff during rendering self.import_resources(bg.resources) return command
def render(self): command_stream = [b'q'] # text rendering self._init_text_box() _text_params = self.get_default_text_params() if self.text_params is not None: _text_params.update(self.text_params) text = self.style.stamp_text % _text_params self.text_box.content = text stamp_height = self.get_stamp_height() stamp_width = self.get_stamp_width() bg = self.style.background if bg is not None: # TODO this is one of the places where some more clever layout # engine would really help, since all of this is pretty ad hoc and # makes a number of non-obvious choices that would be better off # delegated to somewhere else. bg.set_writer(self.writer) # scale the background bg_height = 0.9 * stamp_height if bg.box.height_defined: sf = bg_height / bg.box.height else: bg.box.height = bg_height sf = 1 bg_y = 0.05 * stamp_height bg_width = bg.box.width * sf bg_x = 0 if bg_width <= stamp_width: bg_x = (stamp_width - bg_width) // 2 # set opacity in graphics state opacity = generic.FloatObject(self.style.background_opacity) self.set_resource(category=ResourceType.EXT_G_STATE, name=pdf_name('/BackgroundGS'), value=generic.DictionaryObject({ pdf_name('/CA'): opacity, pdf_name('/ca'): opacity })) command_stream.append( b'q /BackgroundGS gs %g 0 0 %g %g %g cm %s Q' % (sf, sf, bg_x, bg_y, bg.render())) self.import_resources(bg.resources) tb = self.text_box text_commands = tb.render() text_scale = 1 if self.expected_text_width is not None and tb.box.width_defined: text_scale = self.expected_text_width / tb.box.width command_stream.append( b'q %g 0 0 %g %g %g cm' % (text_scale, text_scale, self.text_box_x(), self.text_box_y())) command_stream.append(text_commands) command_stream.append(b'Q') # append additional drawing commands command_stream.extend(self.extra_commands()) # draw border around stamp command_stream.append( b'%g w 0 0 %g %g re S' % (self.style.border_width, stamp_width, stamp_height)) command_stream.append(b'Q') return b' '.join(command_stream)