Estimate if text overflows the shape bounds using PIL text measurement.
(self)
| 560 | return wrapped |
| 561 | |
| 562 | def _estimate_frame_overflow(self) -> None: |
| 563 | """Estimate if text overflows the shape bounds using PIL text measurement.""" |
| 564 | if not self.shape or not hasattr(self.shape, "text_frame"): |
| 565 | return |
| 566 | |
| 567 | text_frame = self.shape.text_frame # type: ignore |
| 568 | if not text_frame or not text_frame.paragraphs: |
| 569 | return |
| 570 | |
| 571 | # Get usable dimensions after accounting for margins |
| 572 | usable_width_px, usable_height_px = self._get_usable_dimensions(text_frame) |
| 573 | if usable_width_px <= 0 or usable_height_px <= 0: |
| 574 | return |
| 575 | |
| 576 | # Set up PIL for text measurement |
| 577 | dummy_img = Image.new("RGB", (1, 1)) |
| 578 | draw = ImageDraw.Draw(dummy_img) |
| 579 | |
| 580 | # Get default font size from placeholder or use conservative estimate |
| 581 | default_font_size = self._get_default_font_size() |
| 582 | |
| 583 | # Calculate total height of all paragraphs |
| 584 | total_height_px = 0 |
| 585 | |
| 586 | for para_idx, paragraph in enumerate(text_frame.paragraphs): |
| 587 | if not paragraph.text.strip(): |
| 588 | continue |
| 589 | |
| 590 | para_data = ParagraphData(paragraph) |
| 591 | |
| 592 | # Load font for this paragraph |
| 593 | font_name = para_data.font_name or "Arial" |
| 594 | font_size = int(para_data.font_size or default_font_size) |
| 595 | |
| 596 | font = None |
| 597 | font_path = self.get_font_path(font_name) |
| 598 | if font_path: |
| 599 | try: |
| 600 | font = ImageFont.truetype(font_path, size=font_size) |
| 601 | except Exception: |
| 602 | font = ImageFont.load_default() |
| 603 | else: |
| 604 | font = ImageFont.load_default() |
| 605 | |
| 606 | # Wrap all lines in this paragraph |
| 607 | all_wrapped_lines = [] |
| 608 | for line in paragraph.text.split("\n"): |
| 609 | wrapped = self._wrap_text_line(line, usable_width_px, draw, font) |
| 610 | all_wrapped_lines.extend(wrapped) |
| 611 | |
| 612 | if all_wrapped_lines: |
| 613 | # Calculate line height |
| 614 | if para_data.line_spacing: |
| 615 | # Custom line spacing explicitly set |
| 616 | line_height_px = para_data.line_spacing * 96 / 72 |
| 617 | else: |
| 618 | # PowerPoint default single spacing (1.0x font size) |
| 619 | line_height_px = font_size * 96 / 72 |
no test coverage detected