from io import BytesIO import fitz import pdfrw from fpdf import FPDF class PdfMaker: def __init__(self, size: tuple): self.size = size self.writer = pdfrw.PdfWriter() def clear(self): del self.writer self.writer = pdfrw.PdfWriter() def add_image(self, image_data): size = self.size fpdf = FPDF(format=size, unit="pt") width, height = self.size fpdf.add_page() fpdf.image(image_data, 0, 0, width, height) fpdf_reader: pdfrw.PdfReader = pdfrw.PdfReader(fdata=bytes(fpdf.output())) self.writer.addpage(fpdf_reader.getPage(0)) def add_pdf(self, pdf_data: BytesIO): pdf_reader = pdfrw.PdfReader(fdata=bytes(pdf_data.read())) self.writer.addpage(pdf_reader.getPage(0)) def add_pdfs(self, pdf_data: BytesIO): pdf_reader = pdfrw.PdfReader(fdata=bytes(pdf_data.read())) self.writer.addpages(pdf_reader.readpages(pdf_reader.Root)) def get_bytes(self): result_io = BytesIO() self.writer.write(result_io) result_io.seek(0) return result_io @staticmethod def _get_target_rect(page: fitz.Page, target_ratio: float) -> fitz.Rect: original_width, original_height = page.rect.width, page.rect.height if original_width / original_height > target_ratio: # Image is wider than target aspect ratio new_width = original_width new_height = int(original_width / target_ratio) else: # Image is taller than target aspect ratio new_height = original_height new_width = int(new_height * target_ratio) return fitz.Rect(0, 0, new_width, new_height) @staticmethod def resize_pdf_with_reportlab(input_pdf_bytesio: BytesIO) -> BytesIO: output_pdf = BytesIO() pdf_document = fitz.open(stream=input_pdf_bytesio.getvalue(), filetype="pdf") if len(pdf_document) != 1: raise Exception("Ошибка. В документе должна быть одна страница.") page = pdf_document[0] target_ratio = 29 / 20 actual_ratio = page.rect.width / page.rect.height if abs(actual_ratio - target_ratio) < 0.1: return input_pdf_bytesio rect = PdfMaker._get_target_rect(page, target_ratio) page.set_mediabox(rect) page.set_cropbox(rect) page.set_bleedbox(rect) page.set_trimbox(rect) pdf_document.save(output_pdf) pdf_document.close() output_pdf.seek(0) return output_pdf