Spaces:
Sleeping
Sleeping
File size: 6,096 Bytes
6a6918c 146f4af 6a6918c 146f4af 6a6918c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.utils import ImageReader
from io import BytesIO
from models.schemas import MeasurementMetadata, MeasurementResult
from PIL import Image, ImageDraw
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class PdfService:
"""
A service to generate PDF reports.
"""
def create_report(
self,
image_bytes: bytes,
metadata: MeasurementMetadata,
results: MeasurementResult,
ml_results: dict
) -> bytes:
"""
Generates a PDF report with the measurement data.
"""
logger.info(f"Creating PDF with metadata: {metadata}")
logger.info(f"Creating PDF with results: {results}")
buffer = BytesIO()
p = canvas.Canvas(buffer, pagesize=letter)
width, height = letter
# Title
p.setFont("Helvetica-Bold", 16)
p.drawString(72, height - 72, "Ship Draft Measurement Report")
# Metadata
p.setFont("Helvetica", 12)
p.drawString(72, height - 108, f"Ship ID: {metadata.ship_id}")
p.drawString(72, height - 126, f"Timestamp: {metadata.timestamp.strftime('%Y-%m-%d %H:%M:%S')}")
p.drawString(72, height - 144, f"Latitude: {metadata.latitude}")
p.drawString(72, height - 162, f"Longitude: {metadata.longitude}")
# # Measurement Results
# p.setFont("Helvetica-Bold", 14)
# p.drawString(72, height - 198, "Measurement Results")
# p.setFont("Helvetica", 12)
# p.drawString(90, height - 218, f"Draft Measurement: {results.draft_measurement:.1f} meters")
# p.drawString(90, height - 236, f"Confidence Score: {results.confidence_score:.2%}")
# ML Results
p.setFont("Helvetica-Bold", 14)
y_position = height - 270
p.drawString(72, y_position, "ML Results")
y_position -= 18
p.setFont("Helvetica", 12)
# Highlight draft from ML results
if 'draft' in ml_results:
p.setFont("Helvetica-Bold", 12) # Highlight
p.drawString(90, y_position, f"ML Draft: {ml_results['draft']:.2f} meters")
p.setFont("Helvetica", 12) # Reset font
y_position -= 18
# Add other ML results (excluding arrays and images)
for key, value in ml_results.items():
if key in ['pose_results', 'segment_results', 'original_image', 'pose_image_result', 'segment_image_result', 'final_image_result']:
continue
p.drawString(90, y_position, f"{key.replace('_', ' ').title()}: {value}")
y_position -= 18
# Images
p.setFont("Helvetica-Bold", 14)
y_position -= 18
p.drawString(72, y_position, "Images")
y_position -= 18
p.setFont("Helvetica", 12)
# Convert numpy arrays to PIL Image and then to bytes for ReportLab
def get_image_bytes(np_array):
if np_array is None:
return None
img = Image.fromarray(np_array.astype('uint8'))
img_byte_arr = BytesIO()
img.save(img_byte_arr, format='PNG')
return img_byte_arr.getvalue()
# Define starting positions and dimensions for horizontal layout
x_start = 72
image_width = 150
image_height = 150 # Assuming square or adjust as needed
y_image_row = y_position - image_height - 20 # Position for the bottom of the images
current_x = x_start
# Draw original image
# if 'original_image' in ml_results and ml_results['original_image'] is not None:
# original_img_bytes = get_image_bytes(ml_results['original_image'])
# if original_img_bytes:
# p.drawString(current_x, y_image_row + image_height + 5, "Original Image:") # Label above image
# p.drawImage(ImageReader(BytesIO(original_img_bytes)), current_x, y_image_row, width=image_width, height=image_height, preserveAspectRatio=True)
# current_x += image_width + 20 # Move x for next image
if 'extracted_mark_image' in ml_results and ml_results['extracted_mark_image'] is not None:
original_img_bytes = get_image_bytes(ml_results['extracted_mark_image'])
if original_img_bytes:
p.drawString(current_x, y_image_row + image_height + 5, "Extracted Mark Image:") # Label above image
p.drawImage(ImageReader(BytesIO(original_img_bytes)), current_x, y_image_row, width=image_width, height=image_height, preserveAspectRatio=True)
current_x += image_width + 20 # Move x for next image
# Draw pose image result
if 'pose_image_result' in ml_results and ml_results['pose_image_result'] is not None:
pose_img_bytes = get_image_bytes(ml_results['pose_image_result'])
if pose_img_bytes:
p.drawString(current_x, y_image_row + image_height + 5, "Pose Image Result:")
p.drawImage(ImageReader(BytesIO(pose_img_bytes)), current_x, y_image_row, width=image_width, height=image_height, preserveAspectRatio=True)
current_x += image_width + 20
# Draw segment image result
if 'segment_image_result' in ml_results and ml_results['segment_image_result'] is not None:
segment_img_bytes = get_image_bytes(ml_results['segment_image_result'])
if segment_img_bytes:
p.drawString(current_x, y_image_row + image_height + 5, "Segment Image Result:")
p.drawImage(ImageReader(BytesIO(segment_img_bytes)), current_x, y_image_row, width=image_width, height=image_height, preserveAspectRatio=True)
# No need to update current_x as it's the last image in the row
# Update y_position for content after images
y_position = y_image_row - 20 # Adjust y_position to be below the images
p.showPage()
p.save()
pdf_bytes = buffer.getvalue()
buffer.close()
return pdf_bytes
|