Esempio n. 1
0
def test_four_qr_stamps(fixed_size):
    # Share a font subset, the text is the same everywhere
    gaf = GlyphAccumulatorFactory(NOTO_SANS, font_size=10)
    w = empty_page()
    positions = ((10, 700), (10, 500), (10, 10), (260, 10))
    for qr_pos, (x, y) in zip(QRPosition, positions):
        style = QRStampStyle(
            stamp_text='Test stamp text\nAnother line of text',
            text_box_style=TextBoxStyle(font=gaf),
            qr_position=qr_pos, background=STAMP_ART_CONTENT,
            background_opacity=0.4
        )
        if fixed_size:
            if qr_pos.horizontal_flow:
                box = layout.BoxConstraints(width=300, height=100)
            else:
                box = layout.BoxConstraints(width=100, height=300)
        else:
            box = None
        ts = QRStamp(
            writer=w, style=style, box=box, url='https://example.com'
        )
        ts.apply(0, x=x, y=y)
    postfix = 'fixed' if fixed_size else 'natural'
    compare_output(w, f'{EXPECTED_OUTPUT_DIR}/four-stamps-{postfix}.pdf')
Esempio n. 2
0
def test_stamp_with_fixed_pdf_content():
    w = empty_page()

    style = StaticStampStyle.from_pdf_file(
        'pyhanko_tests/data/pdf/pdf-background-test.pdf')

    stamp = style.create_stamp(w,
                               box=layout.BoxConstraints(200, 50),
                               text_params={})
    stamp.apply(0, x=30, y=600)

    compare_output(w, f'{EXPECTED_OUTPUT_DIR}/stamp-from-static-pdf.pdf')
Esempio n. 3
0
def test_simple_text_stamp_string_keyed_font():
    gaf = GlyphAccumulatorFactory(FREE_SERIF, font_size=10)

    w = empty_page()
    style = TextStampStyle(
        stamp_text=("Hi, this is a string-keyed font test.\n"
                    "This should have a ligature: difficult"),
        text_box_style=TextBoxStyle(font=gaf),
    )

    ts = TextStamp(w, style, box=layout.BoxConstraints(200, 50))
    ts.apply(dest_page=0, x=70, y=50)

    compare_output(w, f'{EXPECTED_OUTPUT_DIR}/freeserif-test.pdf')
Esempio n. 4
0
def test_stamp_with_scaled_bitmap_bg():
    w = empty_page()

    text = '\n'.join('Test test test test on a bitmap background!'
                     for _ in range(3))
    style = TextStampStyle(
        stamp_text=text,
        background=PdfImage('pyhanko_tests/data/img/stamp-indexed.png'),
    )

    ts = TextStamp(w, style, box=layout.BoxConstraints(400, 100))
    ts.apply(0, x=30, y=600)

    compare_output(w, f'{EXPECTED_OUTPUT_DIR}/scaled-bitmap-bg.pdf')
Esempio n. 5
0
def test_stamp_with_scaled_pdf_bg():
    w = empty_page()

    text = '\n'.join('Test test test test on a PDF background!'
                     for _ in range(3))
    style = TextStampStyle(
        stamp_text=text,
        background=ImportedPdfPage(
            'pyhanko_tests/data/pdf/pdf-background-test.pdf'),
    )

    ts = TextStamp(w, style, box=layout.BoxConstraints(200, 50))
    ts.apply(0, x=30, y=600)

    compare_output(w, f'{EXPECTED_OUTPUT_DIR}/stamp-on-pdf-bg.pdf')
Esempio n. 6
0
def _arabic_text_page(stream_xrefs):
    w = empty_page(stream_xrefs=stream_xrefs)
    style = TextStampStyle(
        stamp_text='اَلْفُصْحَىٰ',
        text_box_style=TextBoxStyle(
            font=GlyphAccumulatorFactory(NOTO_SANS_ARABIC), ),
        inner_content_layout=layout.SimpleBoxLayoutRule(
            x_align=layout.AxisAlignment.ALIGN_MID,
            y_align=layout.AxisAlignment.ALIGN_MID,
            inner_content_scaling=layout.InnerScaling.STRETCH_TO_FIT,
            margins=layout.Margins.uniform(5)))
    ts = TextStamp(writer=w,
                   style=style,
                   box=layout.BoxConstraints(width=300, height=200))
    ts.apply(0, x=10, y=60)
    return w
Esempio n. 7
0
def test_japanese_vertical_text_stamp():
    gaf = GlyphAccumulatorFactory(NOTO_SERIF_JP,
                                  font_size=10,
                                  writing_direction='ttb')
    w = empty_page()
    style = QRStampStyle(stamp_text=('テスト\n縦書きテスト\n改行してみましょう(括弧)\nPDF\n'
                                     'ちょっと長めの文を書いてみた。'),
                         text_box_style=TextBoxStyle(font=gaf,
                                                     vertical_text=True),
                         qr_position=QRPosition.ABOVE_TEXT,
                         background=STAMP_ART_CONTENT,
                         background_opacity=0.4)
    box = layout.BoxConstraints(width=100, height=300)
    ts = QRStamp(writer=w, style=style, box=box, url='https://example.com')
    ts.apply(0, x=10, y=415)
    ts = QRStamp(writer=w, style=style, box=None, url='https://example.com')
    ts.apply(0, x=400, y=415)
    compare_output(w, f'{EXPECTED_OUTPUT_DIR}/ja-vert-stamps.pdf')
Esempio n. 8
0
    def _inner_layout_natural_size(self):

        text_commands, (text_width, text_height) \
            = super()._inner_layout_natural_size()

        qr_ref, natural_qr_size = self._qr_xobject()
        self.set_resource(
            category=content.ResourceType.XOBJECT, name=pdf_name('/QR'),
            value=qr_ref
        )

        style = self.style
        stamp_box = self.box

        # To size the QR code, we proceed as follows:
        #  - If qr_inner_size is not None, use it
        #  - If the stamp has a fully defined bbox already,
        #    make sure it fits within the innseps, and it's not too much smaller
        #    than the text box
        #  - Else, scale down by DEFAULT_QR_SCALE and use that value
        #
        # Note: if qr_inner_size is defined AND the stamp bbox is available
        # already, scaling might still take effect depending on the inner layout
        # rule.
        innsep = style.innsep
        if style.qr_inner_size is not None:
            qr_size = style.qr_inner_size
        elif stamp_box.width_defined and stamp_box.height_defined:
            # ensure that the QR code doesn't shrink too much if the text
            # box is too tall.
            min_dim = min(
                max(stamp_box.height, text_height),
                max(stamp_box.width, text_width)
            )
            qr_size = min_dim - 2 * innsep
        else:
            qr_size = int(round(DEFAULT_QR_SCALE * natural_qr_size))

        qr_innunits_scale = qr_size / natural_qr_size
        qr_padded = qr_size + 2 * innsep
        # Next up: put the QR code and the text box together to get the
        # inner layout bounding box
        if style.qr_position.horizontal_flow:
            inn_width = qr_padded + text_width
            inn_height = max(qr_padded, text_height)
        else:
            inn_width = max(qr_padded, text_width)
            inn_height = qr_padded + text_height
        # grab the base layout rule from the QR position setting
        default_layout: layout.SimpleBoxLayoutRule = style.qr_position.value

        # Fill in the margins
        qr_layout_rule = layout.SimpleBoxLayoutRule(
            x_align=default_layout.x_align, y_align=default_layout.y_align,
            margins=layout.Margins.uniform(innsep),
            # There's no point in scaling here, the inner content canvas
            # is always big enough
            inner_content_scaling=layout.InnerScaling.NO_SCALING
        )

        inner_box = layout.BoxConstraints(inn_width, inn_height)
        qr_inn_pos = qr_layout_rule.fit(inner_box, qr_size, qr_size)

        # we still need to take the axis reversal into account
        # (which also implies an adjustment in the y displacement)
        draw_qr_command = b'q %g 0 0 %g %g %g cm /QR Do Q' % (
            qr_inn_pos.x_scale * qr_innunits_scale,
            -qr_inn_pos.y_scale * qr_innunits_scale,
            qr_inn_pos.x_pos, qr_inn_pos.y_pos + qr_size,
        )

        # Time to put in the text box now
        if style.qr_position == QRPosition.LEFT_OF_TEXT:
            tb_margins = layout.Margins(
                left=qr_padded, right=0, top=0, bottom=0
            )
        elif style.qr_position == QRPosition.RIGHT_OF_TEXT:
            tb_margins = layout.Margins(
                right=qr_padded, left=0, top=0, bottom=0
            )
        elif style.qr_position == QRPosition.BELOW_TEXT:
            tb_margins = layout.Margins(
                bottom=qr_padded, right=0, left=0, top=0
            )
        else:
            tb_margins = layout.Margins(
                top=qr_padded, right=0, left=0, bottom=0
            )

        tb_layout_rule = layout.SimpleBoxLayoutRule(
            # flip around the alignment conventions of the default layout
            # to position the text box on the other side
            x_align=default_layout.x_align.flipped,
            y_align=default_layout.y_align.flipped,
            margins=tb_margins,
            inner_content_scaling=layout.InnerScaling.NO_SCALING
        )

        # position the text box
        text_inn_pos = tb_layout_rule.fit(inner_box, text_width, text_height)

        commands = [draw_qr_command, b'q', text_inn_pos.as_cm()]
        commands.extend(text_commands)
        commands.append(b'Q')
        return commands, (inn_width, inn_height)
Esempio n. 9
0
    :param y:
        Vertical position of the stamp's lower left corner on the page.
    :param url:
        URL for the QR code to point to.
    :param text_params:
        Additional parameters for text template interpolation.
    """

    _stamp_file(
        input_name, output_name, style, QRStamp, dest_page, x, y,
        url=url, text_params=text_params
    )


STAMP_ART_CONTENT = content.RawContent(
    box=layout.BoxConstraints(width=100, height=100),
    data=b'''
q 1 0 0 -1 0 100 cm 
0.603922 0.345098 0.54902 rg
3.699 65.215 m 3.699 65.215 2.375 57.277 7.668 51.984 c 12.957 46.695 27.512
 49.34 39.418 41.402 c 39.418 41.402 31.48 40.078 32.801 33.465 c 34.125
 26.852 39.418 28.172 39.418 24.203 c 39.418 20.234 30.156 17.59 30.156
14.945 c 30.156 12.297 28.465 1.715 50 1.715 c 71.535 1.715 69.844 12.297
 69.844 14.945 c 69.844 17.59 60.582 20.234 60.582 24.203 c 60.582 28.172
 65.875 26.852 67.199 33.465 c 68.52 40.078 60.582 41.402 60.582 41.402
c 72.488 49.34 87.043 46.695 92.332 51.984 c 97.625 57.277 96.301 65.215
 96.301 65.215 c h f
3.801 68.734 92.398 7.391 re f
3.801 79.512 92.398 7.391 re f
3.801 90.289 92.398 7.391 re f
Q
Esempio n. 10
0
    w = empty_page()

    style = StaticStampStyle.from_pdf_file(
        'pyhanko_tests/data/pdf/pdf-background-test.pdf')

    stamp = style.create_stamp(w,
                               box=layout.BoxConstraints(200, 50),
                               text_params={})
    stamp.apply(0, x=30, y=600)

    compare_output(w, f'{EXPECTED_OUTPUT_DIR}/stamp-from-static-pdf.pdf')


@pytest.mark.parametrize('box', [
    None,
    layout.BoxConstraints(width=200),
    layout.BoxConstraints(height=50),
    layout.BoxConstraints(aspect_ratio=Fraction(4, 1)),
    layout.BoxConstraints()
])
def test_static_stamp_enforce_box_defined(box):
    w = empty_page()

    style = StaticStampStyle.from_pdf_file(
        'pyhanko_tests/data/pdf/pdf-background-test.pdf')

    with pytest.raises(layout.LayoutError, match="predetermined bounding box"):
        style.create_stamp(w, box=box, text_params={})


@with_layout_comparison
Esempio n. 11
0
    :param text_params:
        Additional parameters for text template interpolation.
    """

    _stamp_file(input_name,
                output_name,
                style,
                QRStamp,
                dest_page,
                x,
                y,
                url=url,
                text_params=text_params)


STAMP_ART_CONTENT = content.RawContent(box=layout.BoxConstraints(width=100,
                                                                 height=100),
                                       data=b'''
q 1 0 0 -1 0 100 cm 
0.603922 0.345098 0.54902 rg
3.699 65.215 m 3.699 65.215 2.375 57.277 7.668 51.984 c 12.957 46.695 27.512
 49.34 39.418 41.402 c 39.418 41.402 31.48 40.078 32.801 33.465 c 34.125
 26.852 39.418 28.172 39.418 24.203 c 39.418 20.234 30.156 17.59 30.156
14.945 c 30.156 12.297 28.465 1.715 50 1.715 c 71.535 1.715 69.844 12.297
 69.844 14.945 c 69.844 17.59 60.582 20.234 60.582 24.203 c 60.582 28.172
 65.875 26.852 67.199 33.465 c 68.52 40.078 60.582 41.402 60.582 41.402
c 72.488 49.34 87.043 46.695 92.332 51.984 c 97.625 57.277 96.301 65.215
 96.301 65.215 c h f
3.801 68.734 92.398 7.391 re f
3.801 79.512 92.398 7.391 re f
3.801 90.289 92.398 7.391 re f
Q