Unverified Commit bd022523 authored by Maxime Lefrançois's avatar Maxime Lefrançois
Browse files

support more corner cases in SAREF4LIFT and SAREF4WATR

parent e1341765
Loading
Loading
Loading
Loading
+82 −32
Original line number Diff line number Diff line
@@ -53,6 +53,8 @@ from docx.table import _Cell, Table
from docx.text.paragraph import Paragraph
from docx.text.hyperlink import Hyperlink
from docx.shape import InlineShape
from docx.oxml.ns import nsmap


from saref_pypeline._logging import TRACE_LEVEL
from saref_pypeline.docgen.utils import OWL_GRAPH, print_admonition, with_flags, pprint_xml
@@ -74,6 +76,7 @@ if TYPE_CHECKING:
    from saref_pypeline.docgen import SiteManager

logger = logging.getLogger(__name__)
nsmap["v"] = "urn:schemas-microsoft-com:vml"


class ExtractFormat(Enum):
@@ -234,6 +237,41 @@ def process_substitutions_md(md):

    return md

def parse_dml_crop(el) -> dict | None:
    """Parse DrawingML cropping (<pic:blipFill><a:srcRect>)."""
    crop_attrs = el.xpath(".//pic:blipFill/a:srcRect")
    if not crop_attrs:
        return None
    attrs = crop_attrs[0].attrib
    crop = {}
    for key in ("l", "r", "t", "b"):
        if key in attrs:
            # DrawingML: 1/1000 %
            crop[key] = int(attrs[key]) / 100000.0
    return crop or None


def parse_vml_crop(vml) -> dict | None:
    """Parse VML cropping (<v:imagedata croptop=... cropleft=...>).
        TODO: non urgent, VML cropping seems to shrink image vertically. 
    """
    crop = {}
    mapping = {
        "croptop": "t",
        "cropleft": "l",
        "cropright": "r",
        "cropbottom": "b",
    }
    for attr, key in mapping.items():
        if attr in vml.attrib:
            raw = vml.attrib[attr]
            if raw.endswith("f"):
                # VML "f" units: 1/65536
                val = int(raw[:-1]) / 65536.0
            else:
                val = float(raw)
            crop[key] = val
    return crop or None

def cell_align_style(cell):
    """
@@ -575,7 +613,8 @@ class TS2MDExtractor:
        try:
            style = P_STYLE(paragraph.style.name)
        except:
            style = P_STYLE.Normal
            logger.warning(f"Unknown style {paragraph.style.name}")
            style = paragraph.style

        fname = f"extract_{style.name}"
        if hasattr(self, fname) and callable(getattr(self, fname)):
@@ -896,6 +935,10 @@ class TS2MDExtractor:
        self, paragraph: Paragraph, extract_format: ExtractFormat = ExtractFormat.MD
    ):
        """Table title"""
        if paragraph.text.startswith("Figure"):
            logger.warning(f"Wrong style for {paragraph.text}")
            return self.extract_TF(paragraph, extract_format)
        else:
            return ""

    def extract_TAH(
@@ -993,44 +1036,41 @@ class TS2MDExtractor:
            return None, 0, None
        if isinstance(paragraph, Paragraph):
            for run in paragraph.runs:
                # An image inserted via add_picture() is stored as an inline shape
                if not run._element.xpath(".//pic:pic"):
                    continue
                el = run._element

                try:
                    inline_shape: InlineShape = run._element.xpath(".//a:blip/@r:embed")
                    if not inline_shape:
                        continue

                    # Get the relationship id
                # --- CASE 1: DrawingML ---
                inline_shape = el.xpath(".//a:blip/@r:embed")
                if inline_shape:
                    rId = inline_shape[0]

                    # Retrieve the image part from the relationship
                    image_part = paragraph.part.related_parts[rId]

                    # Width from the drawing element (in EMU)
                    cx_attr = run._element.xpath(".//a:xfrm/a:ext/@cx")
                    # width in EMU
                    cx_attr = el.xpath(".//a:xfrm/a:ext/@cx")
                    width_emu = float(cx_attr[0]) if cx_attr else None

                    # Original filename (as stored in the package, not necessarily original filesystem name)
                    filename = image_part.partname  # e.g. '/word/media/image1.png'
                    filename = image_part.partname
                    crop = parse_dml_crop(el)
                    return filename, width_emu, crop

                    # Cropping info (fractions of 1.0)
                    crop = {}
                    crop_attrs = run._element.xpath(".//pic:blipFill/a:srcRect")
                    if crop_attrs:
                        attrs = crop_attrs[0].attrib
                        for key in ("l", "r", "t", "b"):
                            if key in attrs:
                                # Convert from 1/1000 percent to fraction
                                crop[key] = int(attrs[key]) / 100000.0
                    else:
                        crop = None
                # --- CASE 2: VML ---
                vml_shape = el.xpath(".//v:imagedata")
                if vml_shape:
                    vml = vml_shape[0]
                    rId = vml.attrib.get("{http://schemas.openxmlformats.org/officeDocument/2006/relationships}id")
                    image_part = paragraph.part.related_parts[rId]

                    # width in EMU (pt → EMU)
                    style = el.xpath(".//v:shape/@style")
                    width_emu = None
                    if style:
                        m = re.search(r"width:(\d+(?:\.\d+)?)pt", style[0])
                        if m:
                            pt = float(m.group(1))
                            width_emu = int(pt * 12700)

                    filename = image_part.partname
                    crop = parse_vml_crop(vml)
                    return filename, width_emu, crop
                except Exception as ex:
                    print(str(ex))
                    continue

        image_paragraph = get_prev_block(self.document, paragraph)
        return self.get_paragraph_image_info(image_paragraph, i + 1)
@@ -1145,3 +1185,13 @@ class TS2MDExtractor:

        return level*4*" "+ "* " + self.extract_Normal(paragraph, extract_format).strip()


    def extract_Caption(
        self, paragraph: Paragraph, extract_format: ExtractFormat = ExtractFormat.MD
    ):
        """Table title"""
        if paragraph.text.startswith("Figure"):
            logger.warning(f"Wrong style for {paragraph.text}")
            return self.extract_TF(paragraph, extract_format)
        else:
            return ""