def overlay_template_pdf(): """ The api app calls this with a PDF as the POST body, expecting to receive a PDF back with the red overlay applied. This endpoint will raise an error if you try and include a page number because it assumes you meant to ask for a png in that case. """ encoded_string = request.get_data() if not encoded_string: raise InvalidRequest('no data received in POST') if request.args: raise InvalidRequest( f'Did not expect any args but received {request.args}. Did you mean to call overlay.png?' ) pdf = PdfFileReader(BytesIO(encoded_string)) for i in range(pdf.numPages): _colour_no_print_areas_of_page_in_red(pdf.getPage(i), is_first_page=(i == 0)) return send_file(filename_or_fp=bytesio_from_pdf(pdf), mimetype='application/pdf')
def overlay_template_png_for_page(): """ The admin app calls this multiple times to get pngs of each separate page to show on the front end. This endpoint expects a "page_number" param that _must_ be included. It also includes as the HTTP POST body the binary data of that individual page of the PDF. """ encoded_string = request.get_data() if not encoded_string: raise InvalidRequest('no data received in POST') file_data = BytesIO(encoded_string) if 'is_first_page' in request.args: is_first_page = request.args.get('is_first_page', '').lower() == 'true' elif 'page_number' in request.args: page = int(request.args.get('page_number')) is_first_page = page == 1 # page_number arg is one-indexed else: raise InvalidRequest( f'page_number or is_first_page must be specified in request params {request.args}' ) return send_file( filename_or_fp=png_from_pdf( _colour_no_print_areas_of_single_page_pdf_in_red( file_data, is_first_page=is_first_page), # the pdf is only one page, so this is always 1. page_number=1), mimetype='image/png', )
def _colour_no_print_areas_of_single_page_pdf_in_red(src_pdf, is_first_page): """ Overlays the non-printable areas onto the src PDF, this is so users know which parts of they letter fail validation. This function expects that src_pdf only represents a single page. It adds red areas (if `is_first_page` is set, then it'll add red areas around the address window too) and returns a single page pdf. :param BytesIO src_pdf: A file-like representing a single page pdf :param bool is_first_page: true if we should overlay the address block red area too. """ pdf = PdfFileReader(src_pdf) if pdf.numPages != 1: # this function is used to render images, which call template-preview separately for each page. This function # should be colouring a single page pdf (which might be any individual page of an original precompiled letter) raise InvalidRequest( '_colour_no_print_areas_of_page_in_red should only be called for a one-page-pdf' ) page = pdf.getPage(0) _colour_no_print_areas_of_page_in_red(page, is_first_page) out = bytesio_from_pdf(pdf) # it's a good habit to put things back exactly the way we found them src_pdf.seek(0) return out
def sanitise_precompiled_letter(): encoded_string = request.get_data() allow_international_letters = ( request.args.get('allow_international_letters') == 'true') if not encoded_string: raise InvalidRequest('no-encoded-string') sanitise_json = sanitise_file_contents( encoded_string, allow_international_letters=allow_international_letters, ) status_code = 400 if sanitise_json.get('message') else 200 return jsonify(sanitise_json), status_code
def _does_pdf_contain_colorspace(colourspace, data): doc = fitz.open(stream=data, filetype="pdf") for i in range(len(doc)): try: page = doc.getPageImageList(i) except RuntimeError: current_app.logger.warning("Fitz couldn't read page info for page {}".format(i + 1)) raise InvalidRequest("Invalid PDF on page {}".format(i + 1)) for img in page: xref = img[0] pix = fitz.Pixmap(doc, xref) if colourspace in pix.colorspace.__str__(): data.seek(0) return True data.seek(0) return False