Skip to content

Frame

Frame class for “draw:frame” tag and DrawTextBox for “draw:text-box” tag.

Classes:

Name Description
AnchorMix

Anchor parameter, how the element is attached to its environment.

DrawTextBox

ODF text box, “draw:text-box”.

Frame

ODF Frame, “draw:frame”.

PosMix

Position relative to anchor point.

SizeMix

Size of the frame.

ZMix

Z-index position.

Functions:

Name Description
default_frame_position_style

Generate a style for positioning frames in desktop applications.

Attributes:

Name Type Description
DPI Decimal

DPI module-attribute

DPI: Decimal = 640 * Decimal('2.54') / 17

AnchorMix

Bases: Element

Anchor parameter, how the element is attached to its environment.

value can be: ‘page’, ‘frame’, ‘paragraph’, ‘char’ or ‘as-char’

Attributes:

Name Type Description
ANCHOR_VALUE_CHOICE
anchor_page int | None

Get or set the number of the page when the anchor type is ‘page’.

anchor_type str | None

Get or set the anchor type “text:anchor-type”.

Source code in odfdo/frame.py
 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
class AnchorMix(Element):
    """Anchor parameter, how the element is attached to its environment.

    value can be: 'page', 'frame', 'paragraph', 'char' or 'as-char'
    """

    _tag = "draw:anchormix-odfdo-notodf"
    _properties: tuple[PropDef | PropDefBool, ...] = ()

    ANCHOR_VALUE_CHOICE = {  # noqa: RUF012
        "page",
        "frame",
        "paragraph",
        "char",
        "as-char",
    }

    @property
    def anchor_type(self) -> str | None:
        """Get or set the anchor type "text:anchor-type"."""
        return self.get_attribute_string("text:anchor-type")

    @anchor_type.setter
    def anchor_type(self, anchor_type: str) -> None:
        if anchor_type not in self.ANCHOR_VALUE_CHOICE:
            raise TypeError(f"anchor_type not valid: '{anchor_type!r}'")
        self.set_attribute("text:anchor-type", anchor_type)

    @property
    def anchor_page(self) -> int | None:
        """Get or set the number of the page when the anchor type is 'page'.

        Returns:
            int | None: The page number, or None if not set.
        """
        anchor_page = self.get_attribute("text:anchor-page-number")
        if anchor_page is None:
            return None
        return int(anchor_page)

    @anchor_page.setter
    def anchor_page(self, anchor_page: int | None) -> None:
        self._set_attribute_int("text:anchor-page-number", anchor_page)

ANCHOR_VALUE_CHOICE class-attribute instance-attribute

ANCHOR_VALUE_CHOICE = {
    "page",
    "frame",
    "paragraph",
    "char",
    "as-char",
}

_properties class-attribute instance-attribute

_properties: tuple[PropDef | PropDefBool, ...] = ()

_tag class-attribute instance-attribute

_tag = 'draw:anchormix-odfdo-notodf'

anchor_page property writable

anchor_page: int | None

Get or set the number of the page when the anchor type is ‘page’.

Returns:

Type Description
int | None

int | None: The page number, or None if not set.

anchor_type property writable

anchor_type: str | None

Get or set the anchor type “text:anchor-type”.

DrawTextBox

Bases: MDDrawTextBox, ListMixin, TocMixin, SectionMixin

ODF text box, “draw:text-box”.

Minimal class to facilitate internal iterations.

Source code in odfdo/frame.py
616
617
618
619
620
621
622
class DrawTextBox(MDDrawTextBox, ListMixin, TocMixin, SectionMixin):
    """ODF text box, "draw:text-box".

    Minimal class to facilitate internal iterations.
    """

    _tag = "draw:text-box"

_tag class-attribute instance-attribute

_tag = 'draw:text-box'

Frame

Bases: MDDrawFrame, SvgMixin, AnchorMix, PosMix, ZMix, SizeMix, Element

ODF Frame, “draw:frame”.

Frames are not useful by themselves. Consider calling Frame.image_frame() or Frame.text_frame directly.

Methods:

Name Description
__init__

ODF Frame, “draw:frame”.

get_formatted_text

Get the formatted text representation of the frame.

get_image

Get the image element contained in the frame.

get_text_box

Get the text box element contained in the frame.

image_frame

Create a ready-to-use image, since image must be embedded in a

set_image

Set or replace the image in the frame.

set_text_box

Set the text box content of the frame.

text_frame

Create a ready-to-use text box, since text box must be embedded in a

Attributes:

Name Type Description
anchor_page
anchor_type
draw_id
layer
name
position
presentation_class
presentation_style
size
style
text_content str

Get or set the “draw:text-box” text content.

z_index
Source code in odfdo/frame.py
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
class Frame(MDDrawFrame, SvgMixin, AnchorMix, PosMix, ZMix, SizeMix, Element):
    """ODF Frame, "draw:frame".

    Frames are not useful by themselves. Consider calling Frame.image_frame()
    or Frame.text_frame directly.
    """

    _tag = "draw:frame"
    _properties: tuple[PropDef | PropDefBool, ...] = (
        PropDef("name", "draw:name"),
        PropDef("draw_id", "draw:id"),
        PropDef("style", "draw:style-name"),
        PropDef("presentation_class", "presentation:class"),
        PropDef("layer", "draw:layer"),
        PropDef("presentation_style", "presentation:style-name"),
    )

    def __init__(
        self,
        name: str | None = None,
        draw_id: str | None = None,
        style: str | None = None,
        position: tuple | None = None,
        size: tuple = ("1cm", "1cm"),
        z_index: int = 0,
        presentation_class: str | None = None,
        anchor_type: str | None = None,
        anchor_page: int | None = None,
        layer: str | None = None,
        presentation_style: str | None = None,
        **kwargs: Any,
    ) -> None:
        """ODF Frame, "draw:frame".

        Frames are not useful by themselves. Consider calling
        Frame.image_frame() or Frame.text_frame directly.

        Create a frame element of the given size. Position is relative to the
        context the frame is inserted in. If positioned by page, give the page
        number and the x, y position.

        Size is a (width, height) tuple and position is a (left, top) tuple; items
        are strings including the unit, e.g. ('10cm', '15cm').

        Frames are not useful by themselves. You should consider calling:
            Frame.image_frame()
        or
            Frame.text_frame()

        Args:
            name: The name of the frame.
            draw_id: The ID of the drawing object.
            style: The name of the style to apply to the frame.
            position: The position of the frame as a (x, y) tuple of strings
                including units (e.g., ('1cm', '1cm')).
            size: The size of the frame as a (width, height) tuple of strings
                including units (e.g., ('1cm', '1cm')). Defaults to ('1cm', '1cm').
            z_index: The z-index for stacking order. Defaults to 0.
            presentation_class: The presentation class of the frame.
            anchor_type: How the frame is anchored to the document. Can be
                'page', 'frame', 'paragraph', 'char', or 'as-char'.
            anchor_page: The page number if `anchor_type` is 'page'.
            layer: The drawing layer to which the frame belongs.
            presentation_style: The presentation style of the frame.
        """
        super().__init__(**kwargs)
        if self._do_init:
            self.size = size
            self.z_index = z_index
            if name:
                self.name = name
            if draw_id is not None:
                self.draw_id = draw_id
            if style is not None:
                self.style = style
            if position is not None:
                self.position = position
            if presentation_class is not None:
                self.presentation_class = presentation_class
            if anchor_type:
                self.anchor_type = anchor_type
            if position and not anchor_type:
                self.anchor_type = "paragraph"
            if anchor_page is not None:
                self.anchor_page = anchor_page
            if layer is not None:
                self.layer = layer
            if presentation_style is not None:
                self.presentation_style = presentation_style

    @classmethod
    def image_frame(
        cls,
        image: DrawImage | str,
        text: str | None = None,
        name: str | None = None,
        draw_id: str | None = None,
        style: str | None = None,
        position: tuple | None = None,
        size: tuple = ("1cm", "1cm"),
        z_index: int = 0,
        presentation_class: str | None = None,
        anchor_type: str | None = None,
        anchor_page: int | None = None,
        layer: str | None = None,
        presentation_style: str | None = None,
        **kwargs: Any,
    ) -> Frame:
        """Create a ready-to-use image, since image must be embedded in a
        frame.

        The optional text will appear above the image.

        Args:
            image: A `DrawImage` element or the URL of the image.
            text: Optional text to appear above the image.
            name: The name of the frame.
            draw_id: The ID of the drawing object.
            style: The name of the style to apply to the frame.
            position: The position of the frame as a (x, y) tuple of strings
                including units (e.g., ('1cm', '1cm')).
            size: The size of the frame as a (width, height) tuple of strings
                including units (e.g., ('1cm', '1cm')). Defaults to ('1cm', '1cm').
            z_index: The z-index for stacking order. Defaults to 0.
            presentation_class: The presentation class of the frame.
            anchor_type: How the frame is anchored to the document. Can be
                'page', 'frame', 'paragraph', 'char', or 'as-char'.
            anchor_page: The page number if `anchor_type` is 'page'.
            layer: The drawing layer to which the frame belongs.
            presentation_style: The presentation style of the frame.

        Returns:
            Frame: The created Frame element.
        """
        frame = cls(
            name=name,
            draw_id=draw_id,
            style=style,
            position=position,
            size=size,
            z_index=z_index,
            presentation_class=presentation_class,
            anchor_type=anchor_type,
            anchor_page=anchor_page,
            layer=layer,
            presentation_style=presentation_style,
            **kwargs,
        )
        image_element = frame.set_image(image)
        if text:
            image_element.text_content = text
        return frame

    @classmethod
    def text_frame(
        cls,
        text_or_element: Iterable[Element] | Element | str,
        text_style: str | None = None,
        name: str | None = None,
        draw_id: str | None = None,
        style: str | None = None,
        position: tuple | None = None,
        size: tuple = ("1cm", "1cm"),
        z_index: int = 0,
        presentation_class: str | None = None,
        anchor_type: str | None = None,
        anchor_page: int | None = None,
        layer: str | None = None,
        presentation_style: str | None = None,
        **kwargs: Any,
    ) -> Frame:
        """Create a ready-to-use text box, since text box must be embedded in a
        frame.

        The optional text will appear above the image.

        Args:
            text_or_element: The text content of the text box, can be a string,
                an `Element`, or an iterable of strings/Elements.
            text_style: The name of the style for the text within the text box.
            name: The name of the frame.
            draw_id: The ID of the drawing object.
            style: The name of the style to apply to the frame.
            position: The position of the frame as a (x, y) tuple of strings
                including units (e.g., ('1cm', '1cm')).
            size: The size of the frame as a (width, height) tuple of strings
                including units (e.g., ('1cm', '1cm')). Defaults to ('1cm', '1cm').
            z_index: The z-index for stacking order. Defaults to 0.
            presentation_class: The presentation class of the frame.
            anchor_type: How the frame is anchored to the document. Can be
                'page', 'frame', 'paragraph', 'char', or 'as-char'.
            anchor_page: The page number if `anchor_type` is 'page'.
            layer: The drawing layer to which the frame belongs.
            presentation_style: The presentation style of the frame.

        Returns:
            Frame: The created Frame element.
        """
        frame = cls(
            name=name,
            draw_id=draw_id,
            style=style,
            position=position,
            size=size,
            z_index=z_index,
            presentation_class=presentation_class,
            anchor_type=anchor_type,
            anchor_page=anchor_page,
            layer=layer,
            presentation_style=presentation_style,
            **kwargs,
        )
        frame.set_text_box(text_or_element, text_style)
        return frame

    @property
    def text_content(self) -> str:
        """Get or set the "draw:text-box" text content."""
        text_box = self.get_element("draw:text-box")
        if text_box is None:
            return ""
        return text_box.text_content

    @text_content.setter
    def text_content(self, text: str | Element | None) -> None:
        text_box = self.get_element("draw:text-box")
        if text_box is None:
            text_box = Element.from_tag("draw:text-box")
            self.append(text_box)
        if isinstance(text, Element):
            text_box.clear()
            text_box.append(text)
        else:
            text_box.text_content = text

    def get_image(
        self,
        position: int = 0,
        name: str | None = None,
        url: str | None = None,
        content: str | None = None,
    ) -> DrawImage | None:
        """Get the image element contained in the frame.

        Args:
            position: Position of the image (not used, for compatibility).
            name: Filter by image name (not used, for compatibility).
            url: Filter by URL (not used, for compatibility).
            content: Filter by content (not used, for compatibility).

        Returns:
            DrawImage | None: The image element if found, None otherwise.
        """
        return cast(None | DrawImage, self.get_element("draw:image"))

    def set_image(self, url_or_element: DrawImage | str) -> DrawImage:
        """Set or replace the image in the frame.

        Args:
            url_or_element: Either a URL string pointing to the image,
                or a DrawImage element to insert.

        Returns:
            DrawImage: The image element that was added or updated.
        """
        image: DrawImage | None = self.get_image()
        if image is None:
            if isinstance(url_or_element, str):
                draw_image = DrawImage(url_or_element)
                self.append(draw_image)
            else:
                draw_image = url_or_element
                self.append(draw_image)
        else:
            if isinstance(url_or_element, str):
                draw_image = image
                draw_image.url = url_or_element
            else:
                image.delete()
                draw_image = url_or_element
                self.append(draw_image)
        return draw_image

    def get_text_box(self) -> DrawTextBox | None:
        """Get the text box element contained in the frame.

        Returns:
            DrawTextBox | None: The text box element if found, None otherwise.
        """
        return cast(None | DrawTextBox, self.get_element("draw:text-box"))

    def set_text_box(
        self,
        text_or_element: Iterable[Element | str] | Element | str,
        text_style: str | None = None,
    ) -> DrawTextBox:
        """Set the text box content of the frame.

        Args:
            text_or_element: The text content of the text box, can be a string,
                an `Element`, or an iterable of strings/Elements.
            text_style: The name of the style for the text within the text box.

        Returns:
            DrawTextBox: The text box element.
        """
        text_box: DrawTextBox | None = self.get_text_box()
        if text_box is None:
            text_box = DrawTextBox()
            self.append(text_box)
        else:
            text_box.clear()
        if isinstance(text_or_element, (Element, str)):
            text_or_element_list: Iterable[Element | str] = [text_or_element]
        else:
            text_or_element_list = text_or_element
        for item in text_or_element_list:
            if isinstance(item, str):
                text_box.append(Paragraph(item, style=text_style))
            else:
                text_box.append(item)
        return text_box

    @staticmethod
    def _get_formatted_text_subresult(context: dict, element: Element) -> str:
        """Get formatted text from a child element with indentation.

        Args:
            context: The rendering context dictionary.
            element: The element to extract text from.

        Returns:
            str: The formatted text with proper indentation.
        """
        str_list = ["  "]
        for child in element.children:
            str_list.append(child.get_formatted_text(context))
        subresult = "".join(str_list)
        subresult = subresult.replace("\n", "\n  ")
        return subresult.rstrip(" ")

    def get_formatted_text(
        self,
        context: dict | None = None,
    ) -> str:
        """Get the formatted text representation of the frame.

        Handles images and text boxes within the frame, converting them
        to appropriate text formats (e.g., reStructuredText for images).

        Args:
            context: Optional dictionary containing rendering context,
                including 'rst_mode' and image counters.

        Returns:
            str: The formatted text representation of the frame content.
        """
        if not context:
            context = {}
        result = []
        for element in self.children:
            tag = element.tag
            if tag == "draw:image":
                if context.get("rst_mode"):
                    filename = element.get_attribute("xlink:href")
                    # Compute width and height
                    width, height = self.size
                    if width is not None:
                        uwidth = Unit(width)
                        uwidth = uwidth.convert("px", DPI)
                        width = str(uwidth)
                    if height is not None:
                        uheight = Unit(height)
                        uheight = uheight.convert("px", DPI)
                        height = str(uheight)
                    # Insert or not ?
                    if context.get("no_img_level"):
                        counter = context.get("img_counter") or 0
                        counter += 1
                        context["img_counter"] = counter
                        ref = f"|img{counter}|"
                        result.append(ref)
                        images = context.get("images") or []
                        images.append((ref, filename, (width, height)))
                        context["images"] = images
                    else:
                        result.append(f"\n.. image:: {filename}\n")
                        if width is not None:
                            result.append(f"   :width: {width}\n")
                        if height is not None:
                            result.append(f"   :height: {height}\n")
                else:
                    result.append(f"[Image {element.get_attribute('xlink:href')}]\n")
            elif tag == "draw:text-box":
                result.append(self._get_formatted_text_subresult(context, element))
            else:
                result.append(element.get_formatted_text(context))
        result.append("\n")
        return "".join(result)

_properties class-attribute instance-attribute

_properties: tuple[PropDef | PropDefBool, ...] = (
    PropDef("name", "draw:name"),
    PropDef("draw_id", "draw:id"),
    PropDef("style", "draw:style-name"),
    PropDef("presentation_class", "presentation:class"),
    PropDef("layer", "draw:layer"),
    PropDef(
        "presentation_style", "presentation:style-name"
    ),
)

_tag class-attribute instance-attribute

_tag = 'draw:frame'

anchor_page instance-attribute

anchor_page = anchor_page

anchor_type instance-attribute

anchor_type = anchor_type

draw_id instance-attribute

draw_id = draw_id

layer instance-attribute

layer = layer

name instance-attribute

name = name

position instance-attribute

position = position

presentation_class instance-attribute

presentation_class = presentation_class

presentation_style instance-attribute

presentation_style = presentation_style

size instance-attribute

size = size

style instance-attribute

style = style

text_content property writable

text_content: str

Get or set the “draw:text-box” text content.

z_index instance-attribute

z_index = z_index

__init__

__init__(
    name: str | None = None,
    draw_id: str | None = None,
    style: str | None = None,
    position: tuple | None = None,
    size: tuple = ("1cm", "1cm"),
    z_index: int = 0,
    presentation_class: str | None = None,
    anchor_type: str | None = None,
    anchor_page: int | None = None,
    layer: str | None = None,
    presentation_style: str | None = None,
    **kwargs: Any,
) -> None

ODF Frame, “draw:frame”.

Frames are not useful by themselves. Consider calling Frame.image_frame() or Frame.text_frame directly.

Create a frame element of the given size. Position is relative to the context the frame is inserted in. If positioned by page, give the page number and the x, y position.

Size is a (width, height) tuple and position is a (left, top) tuple; items are strings including the unit, e.g. (‘10cm’, ‘15cm’).

Frames are not useful by themselves. You should consider calling: Frame.image_frame() or Frame.text_frame()

Parameters:

Name Type Description Default
name str | None

The name of the frame.

None
draw_id str | None

The ID of the drawing object.

None
style str | None

The name of the style to apply to the frame.

None
position tuple | None

The position of the frame as a (x, y) tuple of strings including units (e.g., (‘1cm’, ‘1cm’)).

None
size tuple

The size of the frame as a (width, height) tuple of strings including units (e.g., (‘1cm’, ‘1cm’)). Defaults to (‘1cm’, ‘1cm’).

('1cm', '1cm')
z_index int

The z-index for stacking order. Defaults to 0.

0
presentation_class str | None

The presentation class of the frame.

None
anchor_type str | None

How the frame is anchored to the document. Can be ‘page’, ‘frame’, ‘paragraph’, ‘char’, or ‘as-char’.

None
anchor_page int | None

The page number if anchor_type is ‘page’.

None
layer str | None

The drawing layer to which the frame belongs.

None
presentation_style str | None

The presentation style of the frame.

None
Source code in odfdo/frame.py
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
def __init__(
    self,
    name: str | None = None,
    draw_id: str | None = None,
    style: str | None = None,
    position: tuple | None = None,
    size: tuple = ("1cm", "1cm"),
    z_index: int = 0,
    presentation_class: str | None = None,
    anchor_type: str | None = None,
    anchor_page: int | None = None,
    layer: str | None = None,
    presentation_style: str | None = None,
    **kwargs: Any,
) -> None:
    """ODF Frame, "draw:frame".

    Frames are not useful by themselves. Consider calling
    Frame.image_frame() or Frame.text_frame directly.

    Create a frame element of the given size. Position is relative to the
    context the frame is inserted in. If positioned by page, give the page
    number and the x, y position.

    Size is a (width, height) tuple and position is a (left, top) tuple; items
    are strings including the unit, e.g. ('10cm', '15cm').

    Frames are not useful by themselves. You should consider calling:
        Frame.image_frame()
    or
        Frame.text_frame()

    Args:
        name: The name of the frame.
        draw_id: The ID of the drawing object.
        style: The name of the style to apply to the frame.
        position: The position of the frame as a (x, y) tuple of strings
            including units (e.g., ('1cm', '1cm')).
        size: The size of the frame as a (width, height) tuple of strings
            including units (e.g., ('1cm', '1cm')). Defaults to ('1cm', '1cm').
        z_index: The z-index for stacking order. Defaults to 0.
        presentation_class: The presentation class of the frame.
        anchor_type: How the frame is anchored to the document. Can be
            'page', 'frame', 'paragraph', 'char', or 'as-char'.
        anchor_page: The page number if `anchor_type` is 'page'.
        layer: The drawing layer to which the frame belongs.
        presentation_style: The presentation style of the frame.
    """
    super().__init__(**kwargs)
    if self._do_init:
        self.size = size
        self.z_index = z_index
        if name:
            self.name = name
        if draw_id is not None:
            self.draw_id = draw_id
        if style is not None:
            self.style = style
        if position is not None:
            self.position = position
        if presentation_class is not None:
            self.presentation_class = presentation_class
        if anchor_type:
            self.anchor_type = anchor_type
        if position and not anchor_type:
            self.anchor_type = "paragraph"
        if anchor_page is not None:
            self.anchor_page = anchor_page
        if layer is not None:
            self.layer = layer
        if presentation_style is not None:
            self.presentation_style = presentation_style

_get_formatted_text_subresult staticmethod

_get_formatted_text_subresult(
    context: dict, element: Element
) -> str

Get formatted text from a child element with indentation.

Parameters:

Name Type Description Default
context dict

The rendering context dictionary.

required
element Element

The element to extract text from.

required

Returns:

Name Type Description
str str

The formatted text with proper indentation.

Source code in odfdo/frame.py
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
@staticmethod
def _get_formatted_text_subresult(context: dict, element: Element) -> str:
    """Get formatted text from a child element with indentation.

    Args:
        context: The rendering context dictionary.
        element: The element to extract text from.

    Returns:
        str: The formatted text with proper indentation.
    """
    str_list = ["  "]
    for child in element.children:
        str_list.append(child.get_formatted_text(context))
    subresult = "".join(str_list)
    subresult = subresult.replace("\n", "\n  ")
    return subresult.rstrip(" ")

get_formatted_text

get_formatted_text(context: dict | None = None) -> str

Get the formatted text representation of the frame.

Handles images and text boxes within the frame, converting them to appropriate text formats (e.g., reStructuredText for images).

Parameters:

Name Type Description Default
context dict | None

Optional dictionary containing rendering context, including ‘rst_mode’ and image counters.

None

Returns:

Name Type Description
str str

The formatted text representation of the frame content.

Source code in odfdo/frame.py
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
def get_formatted_text(
    self,
    context: dict | None = None,
) -> str:
    """Get the formatted text representation of the frame.

    Handles images and text boxes within the frame, converting them
    to appropriate text formats (e.g., reStructuredText for images).

    Args:
        context: Optional dictionary containing rendering context,
            including 'rst_mode' and image counters.

    Returns:
        str: The formatted text representation of the frame content.
    """
    if not context:
        context = {}
    result = []
    for element in self.children:
        tag = element.tag
        if tag == "draw:image":
            if context.get("rst_mode"):
                filename = element.get_attribute("xlink:href")
                # Compute width and height
                width, height = self.size
                if width is not None:
                    uwidth = Unit(width)
                    uwidth = uwidth.convert("px", DPI)
                    width = str(uwidth)
                if height is not None:
                    uheight = Unit(height)
                    uheight = uheight.convert("px", DPI)
                    height = str(uheight)
                # Insert or not ?
                if context.get("no_img_level"):
                    counter = context.get("img_counter") or 0
                    counter += 1
                    context["img_counter"] = counter
                    ref = f"|img{counter}|"
                    result.append(ref)
                    images = context.get("images") or []
                    images.append((ref, filename, (width, height)))
                    context["images"] = images
                else:
                    result.append(f"\n.. image:: {filename}\n")
                    if width is not None:
                        result.append(f"   :width: {width}\n")
                    if height is not None:
                        result.append(f"   :height: {height}\n")
            else:
                result.append(f"[Image {element.get_attribute('xlink:href')}]\n")
        elif tag == "draw:text-box":
            result.append(self._get_formatted_text_subresult(context, element))
        else:
            result.append(element.get_formatted_text(context))
    result.append("\n")
    return "".join(result)

get_image

get_image(
    position: int = 0,
    name: str | None = None,
    url: str | None = None,
    content: str | None = None,
) -> DrawImage | None

Get the image element contained in the frame.

Parameters:

Name Type Description Default
position int

Position of the image (not used, for compatibility).

0
name str | None

Filter by image name (not used, for compatibility).

None
url str | None

Filter by URL (not used, for compatibility).

None
content str | None

Filter by content (not used, for compatibility).

None

Returns:

Type Description
DrawImage | None

DrawImage | None: The image element if found, None otherwise.

Source code in odfdo/frame.py
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
def get_image(
    self,
    position: int = 0,
    name: str | None = None,
    url: str | None = None,
    content: str | None = None,
) -> DrawImage | None:
    """Get the image element contained in the frame.

    Args:
        position: Position of the image (not used, for compatibility).
        name: Filter by image name (not used, for compatibility).
        url: Filter by URL (not used, for compatibility).
        content: Filter by content (not used, for compatibility).

    Returns:
        DrawImage | None: The image element if found, None otherwise.
    """
    return cast(None | DrawImage, self.get_element("draw:image"))

get_text_box

get_text_box() -> DrawTextBox | None

Get the text box element contained in the frame.

Returns:

Type Description
DrawTextBox | None

DrawTextBox | None: The text box element if found, None otherwise.

Source code in odfdo/frame.py
495
496
497
498
499
500
501
def get_text_box(self) -> DrawTextBox | None:
    """Get the text box element contained in the frame.

    Returns:
        DrawTextBox | None: The text box element if found, None otherwise.
    """
    return cast(None | DrawTextBox, self.get_element("draw:text-box"))

image_frame classmethod

image_frame(
    image: DrawImage | str,
    text: str | None = None,
    name: str | None = None,
    draw_id: str | None = None,
    style: str | None = None,
    position: tuple | None = None,
    size: tuple = ("1cm", "1cm"),
    z_index: int = 0,
    presentation_class: str | None = None,
    anchor_type: str | None = None,
    anchor_page: int | None = None,
    layer: str | None = None,
    presentation_style: str | None = None,
    **kwargs: Any,
) -> Frame

Create a ready-to-use image, since image must be embedded in a frame.

The optional text will appear above the image.

Parameters:

Name Type Description Default
image DrawImage | str

A DrawImage element or the URL of the image.

required
text str | None

Optional text to appear above the image.

None
name str | None

The name of the frame.

None
draw_id str | None

The ID of the drawing object.

None
style str | None

The name of the style to apply to the frame.

None
position tuple | None

The position of the frame as a (x, y) tuple of strings including units (e.g., (‘1cm’, ‘1cm’)).

None
size tuple

The size of the frame as a (width, height) tuple of strings including units (e.g., (‘1cm’, ‘1cm’)). Defaults to (‘1cm’, ‘1cm’).

('1cm', '1cm')
z_index int

The z-index for stacking order. Defaults to 0.

0
presentation_class str | None

The presentation class of the frame.

None
anchor_type str | None

How the frame is anchored to the document. Can be ‘page’, ‘frame’, ‘paragraph’, ‘char’, or ‘as-char’.

None
anchor_page int | None

The page number if anchor_type is ‘page’.

None
layer str | None

The drawing layer to which the frame belongs.

None
presentation_style str | None

The presentation style of the frame.

None

Returns:

Name Type Description
Frame Frame

The created Frame element.

Source code in odfdo/frame.py
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
@classmethod
def image_frame(
    cls,
    image: DrawImage | str,
    text: str | None = None,
    name: str | None = None,
    draw_id: str | None = None,
    style: str | None = None,
    position: tuple | None = None,
    size: tuple = ("1cm", "1cm"),
    z_index: int = 0,
    presentation_class: str | None = None,
    anchor_type: str | None = None,
    anchor_page: int | None = None,
    layer: str | None = None,
    presentation_style: str | None = None,
    **kwargs: Any,
) -> Frame:
    """Create a ready-to-use image, since image must be embedded in a
    frame.

    The optional text will appear above the image.

    Args:
        image: A `DrawImage` element or the URL of the image.
        text: Optional text to appear above the image.
        name: The name of the frame.
        draw_id: The ID of the drawing object.
        style: The name of the style to apply to the frame.
        position: The position of the frame as a (x, y) tuple of strings
            including units (e.g., ('1cm', '1cm')).
        size: The size of the frame as a (width, height) tuple of strings
            including units (e.g., ('1cm', '1cm')). Defaults to ('1cm', '1cm').
        z_index: The z-index for stacking order. Defaults to 0.
        presentation_class: The presentation class of the frame.
        anchor_type: How the frame is anchored to the document. Can be
            'page', 'frame', 'paragraph', 'char', or 'as-char'.
        anchor_page: The page number if `anchor_type` is 'page'.
        layer: The drawing layer to which the frame belongs.
        presentation_style: The presentation style of the frame.

    Returns:
        Frame: The created Frame element.
    """
    frame = cls(
        name=name,
        draw_id=draw_id,
        style=style,
        position=position,
        size=size,
        z_index=z_index,
        presentation_class=presentation_class,
        anchor_type=anchor_type,
        anchor_page=anchor_page,
        layer=layer,
        presentation_style=presentation_style,
        **kwargs,
    )
    image_element = frame.set_image(image)
    if text:
        image_element.text_content = text
    return frame

set_image

set_image(url_or_element: DrawImage | str) -> DrawImage

Set or replace the image in the frame.

Parameters:

Name Type Description Default
url_or_element DrawImage | str

Either a URL string pointing to the image, or a DrawImage element to insert.

required

Returns:

Name Type Description
DrawImage DrawImage

The image element that was added or updated.

Source code in odfdo/frame.py
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
def set_image(self, url_or_element: DrawImage | str) -> DrawImage:
    """Set or replace the image in the frame.

    Args:
        url_or_element: Either a URL string pointing to the image,
            or a DrawImage element to insert.

    Returns:
        DrawImage: The image element that was added or updated.
    """
    image: DrawImage | None = self.get_image()
    if image is None:
        if isinstance(url_or_element, str):
            draw_image = DrawImage(url_or_element)
            self.append(draw_image)
        else:
            draw_image = url_or_element
            self.append(draw_image)
    else:
        if isinstance(url_or_element, str):
            draw_image = image
            draw_image.url = url_or_element
        else:
            image.delete()
            draw_image = url_or_element
            self.append(draw_image)
    return draw_image

set_text_box

set_text_box(
    text_or_element: Iterable[Element | str]
    | Element
    | str,
    text_style: str | None = None,
) -> DrawTextBox

Set the text box content of the frame.

Parameters:

Name Type Description Default
text_or_element Iterable[Element | str] | Element | str

The text content of the text box, can be a string, an Element, or an iterable of strings/Elements.

required
text_style str | None

The name of the style for the text within the text box.

None

Returns:

Name Type Description
DrawTextBox DrawTextBox

The text box element.

Source code in odfdo/frame.py
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
def set_text_box(
    self,
    text_or_element: Iterable[Element | str] | Element | str,
    text_style: str | None = None,
) -> DrawTextBox:
    """Set the text box content of the frame.

    Args:
        text_or_element: The text content of the text box, can be a string,
            an `Element`, or an iterable of strings/Elements.
        text_style: The name of the style for the text within the text box.

    Returns:
        DrawTextBox: The text box element.
    """
    text_box: DrawTextBox | None = self.get_text_box()
    if text_box is None:
        text_box = DrawTextBox()
        self.append(text_box)
    else:
        text_box.clear()
    if isinstance(text_or_element, (Element, str)):
        text_or_element_list: Iterable[Element | str] = [text_or_element]
    else:
        text_or_element_list = text_or_element
    for item in text_or_element_list:
        if isinstance(item, str):
            text_box.append(Paragraph(item, style=text_style))
        else:
            text_box.append(item)
    return text_box

text_frame classmethod

text_frame(
    text_or_element: Iterable[Element] | Element | str,
    text_style: str | None = None,
    name: str | None = None,
    draw_id: str | None = None,
    style: str | None = None,
    position: tuple | None = None,
    size: tuple = ("1cm", "1cm"),
    z_index: int = 0,
    presentation_class: str | None = None,
    anchor_type: str | None = None,
    anchor_page: int | None = None,
    layer: str | None = None,
    presentation_style: str | None = None,
    **kwargs: Any,
) -> Frame

Create a ready-to-use text box, since text box must be embedded in a frame.

The optional text will appear above the image.

Parameters:

Name Type Description Default
text_or_element Iterable[Element] | Element | str

The text content of the text box, can be a string, an Element, or an iterable of strings/Elements.

required
text_style str | None

The name of the style for the text within the text box.

None
name str | None

The name of the frame.

None
draw_id str | None

The ID of the drawing object.

None
style str | None

The name of the style to apply to the frame.

None
position tuple | None

The position of the frame as a (x, y) tuple of strings including units (e.g., (‘1cm’, ‘1cm’)).

None
size tuple

The size of the frame as a (width, height) tuple of strings including units (e.g., (‘1cm’, ‘1cm’)). Defaults to (‘1cm’, ‘1cm’).

('1cm', '1cm')
z_index int

The z-index for stacking order. Defaults to 0.

0
presentation_class str | None

The presentation class of the frame.

None
anchor_type str | None

How the frame is anchored to the document. Can be ‘page’, ‘frame’, ‘paragraph’, ‘char’, or ‘as-char’.

None
anchor_page int | None

The page number if anchor_type is ‘page’.

None
layer str | None

The drawing layer to which the frame belongs.

None
presentation_style str | None

The presentation style of the frame.

None

Returns:

Name Type Description
Frame Frame

The created Frame element.

Source code in odfdo/frame.py
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
@classmethod
def text_frame(
    cls,
    text_or_element: Iterable[Element] | Element | str,
    text_style: str | None = None,
    name: str | None = None,
    draw_id: str | None = None,
    style: str | None = None,
    position: tuple | None = None,
    size: tuple = ("1cm", "1cm"),
    z_index: int = 0,
    presentation_class: str | None = None,
    anchor_type: str | None = None,
    anchor_page: int | None = None,
    layer: str | None = None,
    presentation_style: str | None = None,
    **kwargs: Any,
) -> Frame:
    """Create a ready-to-use text box, since text box must be embedded in a
    frame.

    The optional text will appear above the image.

    Args:
        text_or_element: The text content of the text box, can be a string,
            an `Element`, or an iterable of strings/Elements.
        text_style: The name of the style for the text within the text box.
        name: The name of the frame.
        draw_id: The ID of the drawing object.
        style: The name of the style to apply to the frame.
        position: The position of the frame as a (x, y) tuple of strings
            including units (e.g., ('1cm', '1cm')).
        size: The size of the frame as a (width, height) tuple of strings
            including units (e.g., ('1cm', '1cm')). Defaults to ('1cm', '1cm').
        z_index: The z-index for stacking order. Defaults to 0.
        presentation_class: The presentation class of the frame.
        anchor_type: How the frame is anchored to the document. Can be
            'page', 'frame', 'paragraph', 'char', or 'as-char'.
        anchor_page: The page number if `anchor_type` is 'page'.
        layer: The drawing layer to which the frame belongs.
        presentation_style: The presentation style of the frame.

    Returns:
        Frame: The created Frame element.
    """
    frame = cls(
        name=name,
        draw_id=draw_id,
        style=style,
        position=position,
        size=size,
        z_index=z_index,
        presentation_class=presentation_class,
        anchor_type=anchor_type,
        anchor_page=anchor_page,
        layer=layer,
        presentation_style=presentation_style,
        **kwargs,
    )
    frame.set_text_box(text_or_element, text_style)
    return frame

PosMix

Bases: Element

Position relative to anchor point.

Setting the position may require a specific style for actual display on some graphical rendering softwares.

Position is a (left, top) tuple with items including the unit, e.g. (‘10cm’, ‘15cm’).

Attributes:

Name Type Description
position tuple[str | None, str | None]

Get or set the tuple of position (“svg:x”, “svg:y”).

Source code in odfdo/frame.py
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
class PosMix(Element):
    """Position relative to anchor point.

    Setting the position may require a specific style for actual display on
    some graphical rendering softwares.

    Position is a (left, top) tuple with items including the unit, e.g.
    ('10cm', '15cm').
    """

    _tag = "draw:posmixin-odfdo-notodf"
    _properties: tuple[PropDef | PropDefBool, ...] = (
        PropDef("pos_x", "svg:x"),
        PropDef("pos_y", "svg:y"),
    )

    @property
    def position(self) -> tuple[str | None, str | None]:
        """Get or set the tuple of position ("svg:x", "svg:y")."""
        get_attr = self.get_attribute_string
        return get_attr("svg:x"), get_attr("svg:y")

    @position.setter
    def position(self, position: tuple[str, str] | list[str]) -> None:
        self.pos_x = position[0]
        self.pos_y = position[1]

_properties class-attribute instance-attribute

_properties: tuple[PropDef | PropDefBool, ...] = (
    PropDef("pos_x", "svg:x"),
    PropDef("pos_y", "svg:y"),
)

_tag class-attribute instance-attribute

_tag = 'draw:posmixin-odfdo-notodf'

position property writable

position: tuple[str | None, str | None]

Get or set the tuple of position (“svg:x”, “svg:y”).

SizeMix

Bases: Element

Size of the frame.

Size is a (width, height) tuple with items including the unit, e.g. (‘10cm’, ‘15cm’).

Attributes:

Name Type Description
size tuple[str | None, str | None]

Get or set the tuple of size (“svg:width”, “svg:height”).

Source code in odfdo/frame.py
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
class SizeMix(Element):
    """Size of the frame.

    Size is a (width, height) tuple with items including the unit, e.g.
    ('10cm', '15cm').
    """

    _tag = "draw:sizemix-odfdo-notodf"
    _properties: tuple[PropDef | PropDefBool, ...] = (
        PropDef("width", "svg:width"),
        PropDef("height", "svg:height"),
    )

    @property
    def size(self) -> tuple[str | None, str | None]:
        """Get or set the tuple of size ("svg:width", "svg:height")."""
        return (self.width, self.height)

    @size.setter
    def size(self, size: tuple[str, str] | list[str]) -> None:
        self.width = size[0]
        self.height = size[1]

_properties class-attribute instance-attribute

_properties: tuple[PropDef | PropDefBool, ...] = (
    PropDef("width", "svg:width"),
    PropDef("height", "svg:height"),
)

_tag class-attribute instance-attribute

_tag = 'draw:sizemix-odfdo-notodf'

size property writable

size: tuple[str | None, str | None]

Get or set the tuple of size (“svg:width”, “svg:height”).

ZMix

Bases: Element

Z-index position.

z-index is an integer.

Attributes:

Name Type Description
z_index int | None

Get or set the z index “draw:z-index”.

Source code in odfdo/frame.py
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
class ZMix(Element):
    """Z-index position.

    z-index is an integer.
    """

    _tag = "draw:zmix-odfdo-notodf"
    _properties: tuple[PropDef | PropDefBool, ...] = ()

    @property
    def z_index(self) -> int | None:
        """Get or set the z index "draw:z-index"."""
        return cast(
            None | int,
            self.get_attribute_integer("draw:z-index"),
        )

    @z_index.setter
    def z_index(self, z_index: int | None) -> None:
        self._set_attribute_int("draw:z-index", z_index)

_properties class-attribute instance-attribute

_properties: tuple[PropDef | PropDefBool, ...] = ()

_tag class-attribute instance-attribute

_tag = 'draw:zmix-odfdo-notodf'

z_index property writable

z_index: int | None

Get or set the z index “draw:z-index”.

default_frame_position_style

default_frame_position_style(
    name: str = "FramePosition",
    horizontal_pos: str = "from-left",
    vertical_pos: str = "from-top",
    horizontal_rel: str = "paragraph",
    vertical_rel: str = "paragraph",
) -> Style

Generate a style for positioning frames in desktop applications.

Default arguments should be enough.

Use the returned Style as the frame style or build a new graphic style with this style as the parent.

Parameters:

Name Type Description Default
name str

Style name, default to “.

'FramePosition'
horizontal_pos str

Position horizontal, default to “from-left”.

'from-left'
vertical_pos str

Position vertical, default to “from-top”.

'from-top'
horizontal_rel str

Relative position horizontal, default to “paragraph”.

'paragraph'
vertical_rel str

Relative position vertical, default to “paragraph”.

'paragraph'

Returns:

Name Type Description
Style Style

The generated style.

Source code in odfdo/frame.py
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
def default_frame_position_style(
    name: str = "FramePosition",
    horizontal_pos: str = "from-left",
    vertical_pos: str = "from-top",
    horizontal_rel: str = "paragraph",
    vertical_rel: str = "paragraph",
) -> Style:
    """Generate a style for positioning frames in desktop applications.

    Default arguments should be enough.

    Use the returned Style as the frame style or build a new graphic style with
    this style as the parent.

    Args:
        name: Style name, default to ".
        horizontal_pos: Position horizontal, default to "from-left".
        vertical_pos: Position vertical, default to "from-top".
        horizontal_rel: Relative position horizontal, default to "paragraph".
        vertical_rel: Relative position vertical, default to "paragraph".

    Returns:
        Style: The generated style.
    """
    return cast(
        Style,
        Style(
            family="graphic",
            name=name,
            horizontal_pos=horizontal_pos,
            horizontal_rel=horizontal_rel,
            vertical_pos=vertical_pos,
            vertical_rel=vertical_rel,
        ),
    )