feat: product barcode pdf resize

This commit is contained in:
2025-01-19 17:37:13 +04:00
parent b8947ce68e
commit defe31b55e
5 changed files with 52 additions and 36 deletions

View File

@@ -1,6 +1,5 @@
from abc import abstractmethod from abc import abstractmethod
from typing import BinaryIO
from fastapi import UploadFile
class BaseImagesUploader: class BaseImagesUploader:
@@ -18,5 +17,5 @@ class BaseImagesUploader:
pass pass
@abstractmethod @abstractmethod
async def upload(self, upload_file: UploadFile) -> str: async def upload(self, file: BinaryIO, filename: str) -> str:
pass pass

View File

@@ -1,11 +1,10 @@
from pathlib import Path from pathlib import Path
from typing import BinaryIO
from uuid import uuid4 from uuid import uuid4
from aioshutil import copyfileobj from aioshutil import copyfileobj
from fastapi import UploadFile
from barcodes.images_uploader.base import BaseImagesUploader from barcodes.images_uploader.base import BaseImagesUploader
from barcodes.pdf import PDFGenerator
from constants import APP_PATH, API_ROOT from constants import APP_PATH, API_ROOT
@@ -29,10 +28,10 @@ class BarcodeImagesUploader(BaseImagesUploader):
if file_location.exists(): if file_location.exists():
file_location.unlink() file_location.unlink()
async def upload(self, upload_file: UploadFile) -> str: async def upload(self, file: BinaryIO, filename: str) -> str:
filename = str(uuid4()) + '.' + upload_file.filename.split('.')[-1] filename = str(uuid4()) + '.' + filename.split('.')[-1]
file_location = self.storage_path / filename file_location = self.storage_path / filename
with open(file_location, 'wb') as buffer: with open(file_location, 'wb') as buffer:
await copyfileobj(upload_file.file, buffer) await copyfileobj(file, buffer)
return filename return filename

View File

@@ -1,10 +1,8 @@
from io import BytesIO from io import BytesIO
from typing import BinaryIO
from fpdf import FPDF import fitz
import pdfrw import pdfrw
from pdfrw import PdfReader from fpdf import FPDF
from pdfrw.objects.pdfdict import PdfDict
class PdfMaker: class PdfMaker:
@@ -42,27 +40,44 @@ class PdfMaker:
return result_io return result_io
@staticmethod @staticmethod
def check_is_correct_aspects_ratio(file: BinaryIO): def _get_target_rect(page: fitz.Page, target_ratio: float) -> fitz.Rect:
pdf = PdfReader(file) original_width, original_height = page.rect.width, page.rect.height
allowed_aspects_ratio = 1.45
page: PdfDict
try: if original_width / original_height > target_ratio:
page: PdfDict = pdf.getPage(0) # Image is wider than target aspect ratio
except IndexError: new_width = original_width
raise Exception("Ошибка. В документе нет страниц.") 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)
try: return fitz.Rect(0, 0, new_width, new_height)
pdf.getPage(1)
raise Exception("Ошибка. В документе должна быть только одна страница.")
except IndexError:
pass
media_box = page.MediaBox @staticmethod
width = float(media_box[2]) - float(media_box[0]) def resize_pdf_with_reportlab(input_pdf_bytesio: BytesIO) -> BytesIO:
height = float(media_box[3]) - float(media_box[1]) output_pdf = BytesIO()
aspect_ratio = width / height pdf_document = fitz.open(stream=input_pdf_bytesio.getvalue(), filetype="pdf")
if abs(aspect_ratio - allowed_aspects_ratio) > 0.01:
raise Exception("Ошибка. Страница документа должна быть размером 58х40.") if len(pdf_document) != 1:
file.seek(0) 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

View File

@@ -32,4 +32,5 @@ reportlab
weasyprint weasyprint
number_to_string number_to_string
pdfrw pdfrw
fpdf fpdf
PyMuPDF

View File

@@ -1,3 +1,4 @@
from io import BytesIO
from typing import Optional from typing import Optional
from fastapi import HTTPException, UploadFile from fastapi import HTTPException, UploadFile
@@ -278,12 +279,13 @@ class ProductService(BaseService):
async def upload_barcode_image(self, product_id: int, upload_file: UploadFile) -> ProductUploadBarcodeImageResponse: async def upload_barcode_image(self, product_id: int, upload_file: UploadFile) -> ProductUploadBarcodeImageResponse:
try: try:
PdfMaker.check_is_correct_aspects_ratio(upload_file.file)
await self.get_model_by_id(product_id) await self.get_model_by_id(product_id)
uploader = BarcodeImagesUploader() uploader = BarcodeImagesUploader()
await self.delete_model_barcode_image(uploader, product_id) await self.delete_model_barcode_image(uploader, product_id)
filename = await uploader.upload(upload_file)
file = PdfMaker.resize_pdf_with_reportlab(BytesIO(upload_file.file.read()))
filename = await uploader.upload(file, upload_file.filename)
barcode_image_url = uploader.get_url(filename) barcode_image_url = uploader.get_url(filename)
product_barcode_image = ProductBarcodeImage( product_barcode_image = ProductBarcodeImage(