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)
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)
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
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
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
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
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'
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)