def test_subprocess_fails(client, mocker):
    mock_popen = mocker.patch('subprocess.Popen')
    mock_popen.return_value.returncode = 1
    mock_popen.return_value.communicate.return_value = ('Failed',
                                                        'There was an error')

    with pytest.raises(Exception) as excinfo:
        html = HTML(string=str('<html></html>'))
        pdf = BytesIO(html.write_pdf())
        convert_pdf_to_cmyk(pdf)
        assert 'ghostscript process failed with return code: 1' in str(
            excinfo.value)
Beispiel #2
0
def create_pdf_for_templated_letter(self, encrypted_letter_data):
    letter_details = current_app.encryption_client.decrypt(
        encrypted_letter_data)
    current_app.logger.info(
        f"Creating a pdf for notification with id {letter_details['notification_id']}"
    )
    logo_filename = f'{letter_details["logo_filename"]}.svg' if letter_details[
        'logo_filename'] else None

    template = LetterPrintTemplate(
        letter_details['template'],
        values=letter_details['values'] or None,
        contact_block=letter_details['letter_contact_block'],
        # letter assets are hosted on s3
        admin_base_url=current_app.config['LETTER_LOGO_URL'],
        logo_file_name=logo_filename,
    )
    with current_app.test_request_context(''):
        html = HTML(string=str(template))

    try:
        pdf = BytesIO(html.write_pdf())
    except WeasyprintError as exc:
        self.retry(exc=exc, queue=QueueNames.SANITISE_LETTERS)

    cmyk_pdf = convert_pdf_to_cmyk(pdf)
    page_count = get_page_count(cmyk_pdf.read())
    cmyk_pdf.seek(0)

    try:
        # If the file already exists in S3, it will be overwritten
        if letter_details["key_type"] == "test":
            bucket_name = current_app.config['TEST_LETTERS_BUCKET_NAME']
        else:
            bucket_name = current_app.config['LETTERS_PDF_BUCKET_NAME']
        s3upload(
            filedata=cmyk_pdf,
            region=current_app.config['AWS_REGION'],
            bucket_name=bucket_name,
            file_location=letter_details["letter_filename"],
        )

        current_app.logger.info(
            f"Uploaded letters PDF {letter_details['letter_filename']} to {bucket_name} for "
            f"notification id {letter_details['notification_id']}")

    except BotoClientError:
        current_app.logger.exception(
            f"Error uploading {letter_details['letter_filename']} to pdf bucket "
            f"for notification {letter_details['notification_id']}")
        return

    notify_celery.send_task(name=TaskNames.UPDATE_BILLABLE_UNITS_FOR_LETTER,
                            kwargs={
                                "notification_id":
                                letter_details["notification_id"],
                                "page_count":
                                page_count,
                            },
                            queue=QueueNames.LETTERS)
Beispiel #3
0
def print_letter_template():
    """
    POST /print.pdf with the following json blob
    {
        "letter_contact_block": "contact block for service, if any",
        "template": {
            "template data, as it comes out of the database"
        }
        "values": {"dict of placeholder values"},
        "filename": {"type": "string"}
    }
    """
    json = get_and_validate_json_from_request(request, preview_schema)
    filename = f'{json["filename"]}.svg' if json['filename'] else None

    template = LetterPrintTemplate(
        json['template'],
        values=json['values'] or None,
        contact_block=json['letter_contact_block'],
        # letter assets are hosted on s3
        admin_base_url=current_app.config['LETTER_LOGO_URL'],
        logo_file_name=filename,
    )
    html = HTML(string=str(template))
    pdf = BytesIO(html.write_pdf())

    cmyk_pdf = convert_pdf_to_cmyk(pdf)

    response = send_file(cmyk_pdf,
                         as_attachment=True,
                         attachment_filename='print.pdf')
    response.headers['X-pdf-page-count'] = get_page_count(cmyk_pdf.read())
    cmyk_pdf.seek(0)
    return response
Beispiel #4
0
def rewrite_pdf(file_data, *, page_count, allow_international_letters,
                filename):
    file_data, recipient_address, redaction_failed_message = rewrite_address_block(
        file_data,
        page_count=page_count,
        allow_international_letters=allow_international_letters,
    )

    if not does_pdf_contain_cmyk(file_data) or does_pdf_contain_rgb(file_data):
        file_data = convert_pdf_to_cmyk(file_data)

    if contains_unembedded_fonts(file_data):
        file_data = remove_embedded_fonts(file_data)
        if contains_unembedded_fonts(file_data):
            # To start with log this is happening, later mark file as validation-failed
            current_app.logger.info(
                f"File still contains embedded fonts after remove_embedded_fonts for file name {filename}"
            )
        else:
            current_app.logger.info(
                f"File no longer contains embedded fonts for file name {filename}"
            )

    # during switchover, DWP and CYSP will still be sending the notify tag. Only add it if it's not already there
    if not is_notify_tag_present(file_data):
        file_data = add_notify_tag_to_letter(file_data)

    return file_data, recipient_address, redaction_failed_message
Beispiel #5
0
def test_convert_pdf_to_cmyk_does_not_strip_images():
    result = convert_pdf_to_cmyk(BytesIO(public_guardian_sample))
    first_page = PdfFileReader(result).getPage(0)

    image_refs = first_page['/Resources']['/XObject'].values()
    images = [image_ref.getObject() for image_ref in image_refs]
    assert not any(['/Matte' in image for image in images])
def test_convert_pdf_to_cmyk_does_not_rotate_pages():
    file_with_rotated_text = BytesIO(portrait_rotated_page)

    transformed_pdf = PdfFileReader(
        convert_pdf_to_cmyk(file_with_rotated_text))
    page = transformed_pdf.getPage(0)

    page_height = float(page.mediaBox.getHeight()) / mm
    page_width = float(page.mediaBox.getWidth()) / mm
    rotation = page.get('/Rotate')

    assert rotation is None
    assert _is_page_A4_portrait(page_height, page_width, rotation) is True
Beispiel #7
0
def test_convert_pdf_to_cmyk_preserves_black(client):
    data = BytesIO(rgb_black_pdf)
    assert does_pdf_contain_rgb(data)
    assert not does_pdf_contain_cmyk(data)

    result = convert_pdf_to_cmyk(data)
    doc = fitz.open(stream=result, filetype="pdf")
    first_image = doc.getPageImageList(pno=0)[0]
    image_object_number = first_image[0]
    pixmap = fitz.Pixmap(doc, image_object_number)

    assert 'CMYK' in str(pixmap.colorspace)
    assert pixmap.pixel(100, 100) == [0, 0, 0,
                                      255]  # [C,M,Y,K], where 'K' is black
Beispiel #8
0
def rewrite_pdf(file_data, *, page_count, allow_international_letters):
    file_data, recipient_address, redaction_failed_message = rewrite_address_block(
        file_data,
        page_count=page_count,
        allow_international_letters=allow_international_letters,
    )

    if not does_pdf_contain_cmyk(file_data) or does_pdf_contain_rgb(file_data):
        file_data = convert_pdf_to_cmyk(file_data)

    if contains_unembedded_fonts(file_data):
        file_data = remove_embedded_fonts(file_data)

    # during switchover, DWP and CYSP will still be sending the notify tag. Only add it if it's not already there
    if not is_notify_tag_present(file_data):
        file_data = add_notify_tag_to_letter(file_data)

    return file_data, recipient_address, redaction_failed_message
def test_convert_pdf_to_cmyk_outputs_valid_pdf(pdf):
    data = convert_pdf_to_cmyk(BytesIO(pdf))
    assert data.read(9) == b'%PDF-1.7\n'
Beispiel #10
0
def test_convert_pdf_to_cmyk(client, data):
    result = convert_pdf_to_cmyk(BytesIO(data))
    assert not does_pdf_contain_rgb(result)
    assert does_pdf_contain_cmyk(result)