### Point Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-items.md Example of creating a Point object. ```python pt = Point(x=100.5, y=200.3, speed=50, direction=128, width=4, pressure=200) ``` -------------------------------- ### Line Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-items.md Example of creating a Line object. ```python line = Line( color=PenColor.BLACK, tool=Pen.BALLPOINT_1, points=[ Point(100, 200, 10, 0, 4, 200), Point(105, 205, 12, 45, 4, 200), Point(110, 210, 15, 90, 4, 200), ], thickness_scale=1.0, starting_length=0.0 ) ``` -------------------------------- ### Constructor Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-writer.md Example of initializing TaggedBlockWriter and writing a header. ```python with open('output.rm', 'wb') as f: writer = TaggedBlockWriter(f, options={"version": "3.2.2"}) writer.write_header() with writer.write_block(0x01, 1, 1): # write block content ``` -------------------------------- ### tell() Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/common-stream.md Example of getting the current position in the stream. ```python offset = stream.tell() print(f"Current position: {offset}") ``` -------------------------------- ### Group Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-items.md Example of creating a Group object. ```python layer = Group( node_id=CrdtId(0, 11), label=LwwValue(CrdtId(0, 12), "Layer 1"), visible=LwwValue(CrdtId(0, 10), True) ) ``` -------------------------------- ### BinaryIO Type Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Example of opening a file in binary mode using BinaryIO. ```python with open('document.rm', 'rb') as f: # BinaryIO reader = TaggedBlockReader(f) ``` -------------------------------- ### Tuple Type Examples Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Examples of type hints for tuples. ```python color: tuple[int, int, int, int] # RGBA paper_size: Optional[tuple[int, int]] # Width, height (min_ver, current_ver): tuple[int, int] ``` -------------------------------- ### write_block Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-writer.md Example of using the write_block context manager. ```python with writer.write_block(0x01, 1, 1): writer.write_id(1, CrdtId(0, 1)) writer.write_bool(2, True) ``` -------------------------------- ### PenColor Highlight Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-items.md Example of checking for the HIGHLIGHT PenColor and accessing color_rgba. ```python color = PenColor.HIGHLIGHT if color == PenColor.HIGHLIGHT: # Actual color is in the line's color_rgba field ``` -------------------------------- ### TagType Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Example of TagType usage. ```python from rmscene import TagType tag_type = TagType.ID tag_type == 0xF # True ``` -------------------------------- ### Paragraph Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/text-processing.md Example of creating a Paragraph object with CrdtStr contents, start ID, and style. ```python from dataclasses import dataclass from typing import List @dataclass class CrdtId: part1: int part2: int class ParagraphStyle: PLAIN = 0 class LwwValue: def __init__(self, id, value): self.id = id self.value = value @dataclass class CrdtStr: s: str = "" i: List[CrdtId] = None properties: dict = None @dataclass class Paragraph: contents: List[CrdtStr] start_id: CrdtId style: LwwValue[ParagraphStyle] para = Paragraph( contents=[ CrdtStr("Bold text", properties={"font-weight": "bold"}), CrdtStr(" normal text", properties={"font-weight": "normal"}) ], start_id=CrdtId(1, 1), style=LwwValue(CrdtId(1, 0), ParagraphStyle.PLAIN) ) print(str(para)) ``` -------------------------------- ### LwwValue Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Example of LwwValue usage. ```python visible = LwwValue(CrdtId(1, 100), True) print(f"Visible: {visible.value}, updated at {visible.timestamp}") # Updating requires creating new instance updated = LwwValue(CrdtId(1, 101), False) ``` -------------------------------- ### write_subblock Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-writer.md Example of using the write_subblock context manager. ```python with writer.write_subblock(2): writer.write_id(1, CrdtId(0, 0)) writer.write_string(2, "Layer 1") ``` -------------------------------- ### write_header Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-writer.md Example of writing the reMarkable v6 file header. ```python writer.write_header() ``` -------------------------------- ### Example Usage of Constructor Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-reader.md Demonstrates how to open a file and create a TaggedBlockReader instance. ```python with open('document.rm', 'rb') as f: reader = TaggedBlockReader(f) reader.read_header() with reader.read_block() as block_info: # read block content ``` -------------------------------- ### Dict Type Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Example type hints for dictionaries. ```python author_uuids: dict[int, UUID] styles: dict[CrdtId, LwwValue[ParagraphStyle]] ``` -------------------------------- ### CrdtSequenceItem Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Example of CrdtSequenceItem. ```python item = CrdtSequenceItem( item_id=CrdtId(1, 1), left_id=CrdtId(0, 0), right_id=CrdtId(0, 0), deleted_length=0, value="A" ) ``` -------------------------------- ### DataStream Constructor Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/common-stream.md Example of initializing a DataStream with a file object. ```python from rmscene.tagged_block_common import DataStream with open('document.rm', 'rb') as f: stream = DataStream(f) stream.read_header() ``` -------------------------------- ### CrdtSequence Constructor Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/crdt-sequence.md Example of initializing a CrdtSequence with initial items. ```python items = [ CrdtSequenceItem(CrdtId(1, 1), CrdtId(0, 0), CrdtId(0, 0), 0, "A"), CrdtSequenceItem(CrdtId(1, 2), CrdtId(1, 1), CrdtId(0, 0), 0, "B"), ] seq = CrdtSequence(items) ``` -------------------------------- ### Writing a Simple Text File Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/README.md This example shows how to create a simple text document and write it to a .rm file. ```python from rmscene import simple_text_document, write_blocks blocks = simple_text_document("Hello World") with open('output.rm', 'wb') as f: write_blocks(f, blocks) ``` -------------------------------- ### write_varuint() Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/common-stream.md Example demonstrating writing a variable-length unsigned integer (varuint) using LEB128 encoding. ```python stream.write_varuint(300) # Writes: 0xAC, 0x02 ``` -------------------------------- ### CrdtId Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Example of CrdtId usage. ```python id1 = CrdtId(1, 16) id2 = CrdtId(0, 1) print(id2 < id1) # True (0 < 1) ``` -------------------------------- ### write_color Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-writer.md Example of writing a tagged RGBA color. ```python # Write yellow color writer.write_color(8, (255, 255, 0, 255)) ``` -------------------------------- ### build_tree Example Usage Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Example of how to use the build_tree function to populate a SceneTree object from blocks read from a reMarkable file. ```python tree = SceneTree() with open('document.rm', 'rb') as f: build_tree(tree, read_blocks(f)) ``` -------------------------------- ### Example Workflow Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/text-processing.md Demonstrates reading a document, extracting text, and iterating through paragraphs and spans with their formatting. ```python from rmscene import read_tree, TextDocument # Read document from file with open('document.rm', 'rb') as f: tree = read_tree(f) # Extract and format text if tree.root_text: doc = TextDocument.from_scene_item(tree.root_text) # Iterate paragraphs for para_index, para in enumerate(doc.contents): print(f"\nParagraph {para_index} ({para.style.value.name}):") # Iterate spans within paragraph for span in para.contents: weight = span.properties.get('font-weight', 'normal') style = span.properties.get('font-style', 'normal') print(f" [{weight}/{style}] {span.s}") ``` -------------------------------- ### CrdtSequence Add Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/crdt-sequence.md Example of adding a new item to the CrdtSequence. ```python new_item = CrdtSequenceItem( item_id=CrdtId(1, 3), left_id=CrdtId(1, 2), right_id=CrdtId(0, 0), deleted_length=0, value="C" ) seq.add(new_item) ``` -------------------------------- ### write_blocks Example Usage Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Example of how to use the write_blocks function to write a list of blocks to a file, specifying the reMarkable format version. ```python blocks = [AuthorIdsBlock(...), TreeNodeBlock(...), RootTextBlock(...)] with open('output.rm', 'wb') as f: write_blocks(f, blocks, options={"version": "3.2.2"}) ``` -------------------------------- ### Generic Type Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Example of a generic class definition. ```python class CrdtSequence(Generic[_Ti]): def __getitem__(self, key: CrdtId) -> _Ti: ... ``` -------------------------------- ### read_varuint() Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/common-stream.md Example demonstrating the decoding of a variable-length unsigned integer (varuint) using LEB128 encoding. ```python # Bytes: 0xAC, 0x02 # 0xAC = 0b10101100 \u2192 0x2C = 44 (7 bits) + continuation # 0x02 = 0b00000010 \u2192 0x02 = 2 (7 bits) + no continuation # Result: 44 + (2 << 7) = 300 value = stream.read_varuint() # Returns 300 ``` -------------------------------- ### Optional Type Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Example usage of the Optional type for nullable values. ```python author_uuid: Optional[UUID] = None extra_data: Optional[bytes] = b"") ``` -------------------------------- ### CrdtSequenceItem Attributes Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/crdt-sequence.md Example of creating a CrdtSequenceItem. ```python item = CrdtSequenceItem( item_id=CrdtId(1, 16), left_id=CrdtId(0, 0), # First item right_id=CrdtId(0, 0), # Last item deleted_length=0, value="Hello" ) ``` -------------------------------- ### CrdtSequence Values Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/crdt-sequence.md Example of retrieving all values from a CrdtSequence in order. ```python for value in seq.values(): print(value) ``` -------------------------------- ### Copy file with specific version Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/README.md This example demonstrates how to copy a .rm file to a new file, specifying a target ReMarkable software version using `write_blocks`. ```python from rmscene import read_blocks, write_blocks with open('original.rm', 'rb') as f: blocks = list(read_blocks(f)) with open('copy.rm', 'wb') as f: write_blocks(f, blocks, options={"version": "3.2.2"}) ``` -------------------------------- ### ToposortItems Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/crdt-sequence.md Example of using toposort_items to sort CRDT items. ```python items = [...] # unsorted CRDT items sorted_ids = list(toposort_items(items)) ``` -------------------------------- ### Handling Warnings with Logging Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/errors.md Example of how to configure Python's logging module to capture and display warnings generated by the rmscene library. ```python import logging # Enable debug logging to see warnings logging.basicConfig(level=logging.WARNING) with open('document.rm', 'rb') as f: for block in read_blocks(f): pass # Warnings logged to stderr ``` -------------------------------- ### Example Usage of read_header Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-reader.md Shows how to call the read_header method. ```python reader.read_header() ``` -------------------------------- ### walk Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-tree.md Recursively yields all leaf items (non-group items) in the tree in depth-first order. ```python for item in tree.walk(): if isinstance(item, Line): print(f"Line with {len(item.points)} points") ``` -------------------------------- ### Reading a reMarkable File Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/README.md This example demonstrates how to read a reMarkable file, access its text content, and iterate through all scene items. ```python from rmscene import read_tree with open('document.rm', 'rb') as f: tree = read_tree(f) # Access text if tree.root_text: from rmscene import TextDocument doc = TextDocument.from_scene_item(tree.root_text) for para in doc.contents: print(para) # Iterate all items (lines, text, etc.) for item in tree.walk(): print(item) ``` -------------------------------- ### CrdtSequence GetItem Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/crdt-sequence.md Example of retrieving a value by its CrdtId from a CrdtSequence. ```python text = seq[CrdtId(1, 1)] ``` -------------------------------- ### Example CrdtSequenceItem Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/crdt-sequence.md Example of a CrdtSequenceItem, showing how END_MARKER is used for the first item in a sequence. ```python # First item in sequence first = CrdtSequenceItem( item_id=CrdtId(1, 1), left_id=END_MARKER, # No left neighbor right_id=CrdtId(1, 2), deleted_length=0, value="A" ) ``` -------------------------------- ### UUID Type Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Example usage of the UUID type for author identification. ```python from uuid import uuid4, UUID author_id = uuid4() stored_uuid = UUID(bytes_le=data) ``` -------------------------------- ### Iterable Type Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Example function signature using the Iterable type. ```python def read_blocks(data: BinaryIO) -> Iterator[Block] ``` -------------------------------- ### __getitem__ Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-tree.md Retrieves a Group node with the given ID. ```python layer = tree[CrdtId(0, 11)] print(f"Layer label: {layer.label.value}") ``` -------------------------------- ### read_blocks Example Usage Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Example of how to use the read_blocks function to iterate through blocks in a reMarkable file and identify SceneLineItemBlock instances. ```python with open('document.rm', 'rb') as f: for block in read_blocks(f): if isinstance(block, SceneLineItemBlock): print(f"Found line: {block.item.value}") ``` -------------------------------- ### CrdtSequence Iteration Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/crdt-sequence.md Example of iterating through item IDs in a CrdtSequence. ```python for item_id in seq: print(f"Item: {item_id}") ``` -------------------------------- ### CrdtSequence Items Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/crdt-sequence.md Example of iterating through (ID, value) pairs in a CrdtSequence. ```python for item_id, value in seq.items(): print(f"{item_id}: {value}") ``` -------------------------------- ### Extract all text Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/README.md This example demonstrates how to extract all text content from a .rm file using the `read_tree` function and `TextDocument` class. ```python from rmscene import read_tree, TextDocument with open('document.rm', 'rb') as f: tree = read_tree(f) if tree.root_text: doc = TextDocument.from_scene_item(tree.root_text) text = '\n'.join(str(para) for para in doc.contents) print(text) ``` -------------------------------- ### CrdtStr Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/text-processing.md Example of creating a CrdtStr object with string content, CRDT IDs, and formatting properties. ```python from dataclasses import dataclass from typing import List @dataclass class CrdtId: part1: int part2: int @dataclass class CrdtStr: s: str = "" i: List[CrdtId] = None properties: dict = None span = CrdtStr( s="Hello", i=[CrdtId(1, 1), CrdtId(1, 2), CrdtId(1, 3), CrdtId(1, 4), CrdtId(1, 5)], properties={"font-weight": "normal", "font-style": "normal"} ) ``` -------------------------------- ### Attributes Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-tree.md Accessing scene information and root text from the SceneTree. ```python if tree.scene_info: print(f"Paper size: {tree.scene_info.paper_size}") if tree.root_text: doc = TextDocument.from_scene_item(tree.root_text) ``` -------------------------------- ### Example: Low-Level Writing Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/common-stream.md Demonstrates how to write a CRDT ID to a reMarkable file using the low-level API. ```python from rmscene.tagged_block_common import DataStream, TagType, CrdtId with open('output.rm', 'wb') as f: stream = DataStream(f) stream.write_header() # Write a test value stream.write_tag(1, TagType.ID) stream.write_crdt_id(CrdtId(1, 42)) ``` -------------------------------- ### Processing Blocks Sequentially Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/README.md This example demonstrates how to read blocks from a file sequentially and process specific block types, such as SceneLineItemBlock. ```python from rmscene import read_blocks, SceneLineItemBlock with open('document.rm', 'rb') as f: for block in read_blocks(f): if isinstance(block, SceneLineItemBlock): line = block.item.value print(f"Line with {len(line.points)} points") ``` -------------------------------- ### expand_text_item Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/text-processing.md Example of expanding a multi-character text item into single-character CrdtSequenceItems. ```python from dataclasses import dataclass from typing import Iterator, List, Union @dataclass class CrdtId: part1: int part2: int @dataclass class CrdtSequenceItem: item_id: CrdtId left_id: CrdtId right_id: CrdtId deleted_length: int value: Union[str, int] def expand_text_item(item: CrdtSequenceItem[str | int]) -> Iterator[CrdtSequenceItem[str | int]]: if isinstance(item.value, str): for i, char in enumerate(item.value): new_item_id = CrdtId(item.item_id.part1, item.item_id.part2 + i) # For simplicity, left_id and right_id are not fully updated here as in the real implementation yield CrdtSequenceItem( item_id=new_item_id, left_id=item.left_id if i == 0 else CrdtId(new_item_id.part1, new_item_id.part2 - 1), right_id=item.right_id if i == len(item.value) - 1 else CrdtId(new_item_id.part1, new_item_id.part2 + 1), deleted_length=0, value=char ) else: yield item item = CrdtSequenceItem( item_id=CrdtId(1, 1), left_id=CrdtId(0, 0), right_id=CrdtId(0, 0), deleted_length=0, value="AB" ) expanded = list(expand_text_item(item)) for exp_item in expanded: print(exp_item) ``` -------------------------------- ### TextDocument.from_scene_item Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/text-processing.md Example of extracting and processing text from a scene Text item into a TextDocument. ```python from dataclasses import dataclass from typing import List, Iterator, Iterable # Assume Text, CrdtId, CrdtStr, Paragraph, LwwValue, ParagraphStyle are defined as above # Assume tree is an object with a root_text attribute class TextDocument: def __init__(self, contents: List[Paragraph]): self.contents = contents @classmethod def from_scene_item(cls, text) -> 'TextDocument': # Placeholder for actual implementation # This would involve parsing the 'text' object to create Paragraphs and CrdtStr print(f"Processing text item: {text}") # Dummy implementation for example: dummy_para = Paragraph( contents=[CrdtStr("Sample text", properties={'font-weight': 'normal'})], start_id=CrdtId(1,1), style=LwwValue(CrdtId(1,0), ParagraphStyle.PLAIN) ) return cls([dummy_para]) # Assuming 'tree' is available and has a 'root_text' attribute # text_item = tree.root_text # doc = TextDocument.from_scene_item(text_item) # for para in doc.contents: # print(f"Paragraph: {para}") # for span in para.contents: # print(f" {span.s} (weight={span.properties['font-weight']})") # Example usage with a mock text_item: class MockTextItem: def __init__(self, content): self.content = content mock_text_item = MockTextItem("This is a sample text.") doc = TextDocument.from_scene_item(mock_text_item) for para in doc.contents: print(f"Paragraph: {para}") for span in para.contents: print(f" {span.s} (weight={span.properties.get('font-weight', 'normal')})") ``` -------------------------------- ### Catching KeyError Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/errors.md Example of how to catch KeyError when accessing SceneTree or CrdtSequence. ```python from rmscene import read_tree, CrdtId tree = read_tree(open('document.rm', 'rb')) node_id = CrdtId(0, 99) if node_id in tree: node = tree[node_id] else: print(f"Node {node_id} not found") # Or catch the exception: try: node = tree[node_id] except KeyError: print(f"Node not found") ``` -------------------------------- ### Catching UnexpectedBlockError Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/errors.md Example of how to catch UnexpectedBlockError when reading tagged blocks. ```python from rmscene import UnexpectedBlockError, TaggedBlockReader try: reader = TaggedBlockReader(f) reader.read_header() with reader.read_block() as block_info: value = reader.read_int(1) except UnexpectedBlockError as e: print(f"Tag not found: {e}") ``` -------------------------------- ### Accessing Block Details Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/README.md This example shows how to use TaggedBlockReader to access detailed information about each block in a .rm file, including block type and version information. ```python from rmscene import read_blocks, MainBlockInfo, TaggedBlockReader with open('document.rm', 'rb') as f: reader = TaggedBlockReader(f) reader.read_header() with reader.read_block() as block_info: if block_info: print(f"Block type: 0x{block_info.block_type:02x}") print(f"Min version: {block_info.min_version}") print(f"Current version: {block_info.current_version}") ``` -------------------------------- ### Catching EOFError Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/errors.md Example of how to catch EOFError when reading blocks. ```python from rmscene import read_blocks try: with open('document.rm', 'rb') as f: for block in read_blocks(f): pass except EOFError: print("File truncated or incomplete") ``` -------------------------------- ### Catching ValueError Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/errors.md Example of how to catch ValueError during block reading. ```python from rmscene import read_blocks try: with open('document.rm', 'rb') as f: for block in read_blocks(f): pass except ValueError as e: print(f"Invalid data: {e}") ``` -------------------------------- ### expand_text_items Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/text-processing.md Example of expanding multiple text items into single-character items using CrdtSequence. ```python from typing import Iterable, Iterator, List, Union from dataclasses import dataclass @dataclass class CrdtId: part1: int part2: int @dataclass class CrdtSequenceItem: item_id: CrdtId left_id: CrdtId right_id: CrdtId deleted_length: int value: Union[str, int] class CrdtSequence: def __init__(self, items: Iterable[CrdtSequenceItem]): self._items = list(items) def sequence_items(self) -> Iterator[CrdtSequenceItem]: return iter(self._items) def expand_text_item(item: CrdtSequenceItem[str | int]) -> Iterator[CrdtSequenceItem[str | int]]: # (Implementation as provided in the expand_text_item example) if isinstance(item.value, str): for i, char in enumerate(item.value): new_item_id = CrdtId(item.item_id.part1, item.item_id.part2 + i) yield CrdtSequenceItem( item_id=new_item_id, left_id=item.left_id if i == 0 else CrdtId(new_item_id.part1, new_item_id.part2 - 1), right_id=item.right_id if i == len(item.value) - 1 else CrdtId(new_item_id.part1, new_item_id.part2 + 1), deleted_length=0, value=char ) else: yield item def expand_text_items(items: Iterable[CrdtSequenceItem[str | int]]) -> Iterator[CrdtSequenceItem[str | int]]: for item in items: yield from expand_text_item(item) # Example usage: item1 = CrdtSequenceItem(CrdtId(1, 1), CrdtId(0, 0), CrdtId(0, 0), 0, "AB") item2 = CrdtSequenceItem(CrdtId(2, 1), CrdtId(1, 3), CrdtId(3, 1), 0, "C") initial_items = [item1, item2] text_sequence = CrdtSequence(initial_items) char_items = expand_text_items(text_sequence.sequence_items()) char_sequence = CrdtSequence(list(char_items)) # Collect into a new sequence for demonstration print("Expanded character items:") for char_item in char_sequence.sequence_items(): print(char_item) ``` -------------------------------- ### Catching BlockOverflowError Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/errors.md Example of how to catch BlockOverflowError when reading blocks. ```python from rmscene import BlockOverflowError, read_blocks try: with open('document.rm', 'rb') as f: for block in read_blocks(f): print(block) except BlockOverflowError as e: print(f"Block too large: {e}") ``` -------------------------------- ### Count strokes by color Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/README.md This example shows how to count the number of strokes of each color in a .rm file using `read_blocks` and `SceneLineItemBlock`. ```python from rmscene import read_blocks, SceneLineItemBlock from collections import Counter color_counts = Counter() with open('document.rm', 'rb') as f: for block in read_blocks(f): if isinstance(block, SceneLineItemBlock): color = block.item.value.color color_counts[color] += 1 for color, count in color_counts.most_common(): print(f"{color.name}: {count}") ``` -------------------------------- ### Retrieving Version Info from Writer Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/configuration.md Access version from options. ```python from packaging.version import Version writer = TaggedBlockWriter(f, options={"version": "3.2.2"}) # Access version from options version = writer.options.get("version", Version("9.9.9")) if version >= Version("3.2.2"): # Use newer format pass ``` -------------------------------- ### add_node Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-tree.md Adds a new Group node to the tree as a child of the specified parent. ```python tree.add_node(CrdtId(0, 11), parent_id=CrdtId(0, 1)) ``` -------------------------------- ### Example: Low-Level Reading Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/common-stream.md Demonstrates how to read a CRDT ID from a reMarkable document using the low-level API. ```python from rmscene.tagged_block_common import DataStream, TagType from rmscene import TaggedBlockReader with open('document.rm', 'rb') as f: reader = TaggedBlockReader(f) reader.read_header() with reader.read_block() as block_info: if block_info: # Use DataStream for raw access data = reader.data # Check for specific tag if data.check_tag(1, TagType.ID): index, tag_type = data.read_tag(1, TagType.ID) crdt_id = data.read_crdt_id() print(f"ID at index 1: {crdt_id}") ``` -------------------------------- ### __contains__ Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-tree.md Checks whether a node with the given ID exists in the tree. ```python if CrdtId(0, 11) in tree: layer = tree[CrdtId(0, 11)] ``` -------------------------------- ### add_item Example Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-tree.md Adds a scene item (line, text, group reference, glyph) to a parent node's children. ```python line_item = CrdtSequenceItem( item_id=CrdtId(1, 16), left_id=CrdtId(0, 0), right_id=CrdtId(0, 0), deleted_length=0, value=Line(...) ) tree.add_item(line_item, parent_id=CrdtId(0, 11)) ``` -------------------------------- ### File Validation with Error Handling Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/errors.md Example of reading blocks from a file and handling potential exceptions like BlockOverflowError, ValueError, and EOFError, including checks for unreadable blocks. ```python from rmscene import read_blocks, UnreadableBlock, BlockOverflowError try: with open('document.rm', 'rb') as f: blocks = list(read_blocks(f)) # Check for unreadable blocks unreadable = [b for b in blocks if isinstance(b, UnreadableBlock)] if unreadable: print(f"Warning: {len(unreadable)} blocks could not be read") print(f"Successfully read {len(blocks)} blocks") except BlockOverflowError as e: print(f"File corruption detected: {e}") except ValueError as e: print(f"Invalid file format: {e}") except EOFError: print("File is truncated") ``` -------------------------------- ### Creating files for specific devices Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/configuration.md Specify the reMarkable version in the options to create files compatible with specific devices. ```python # Write for older device write_blocks(f, blocks, options={"version": "3.0"}) ``` ```python # Write for newer device write_blocks(f, blocks, options={"version": "3.8"}) ``` -------------------------------- ### write_blocks() Options Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/configuration.md Pass options dictionary to control output format. ```python def write_blocks( data: BinaryIO, blocks: Iterable[Block], options: Optional[dict] = None ) ``` ```python from rmscene import write_blocks blocks = [...] # Write for reMarkable v3.2.2 (older format) with open('old_format.rm', 'wb') as f: write_blocks(f, blocks, options={"version": "3.2.2"}) # Write for latest version (default) with open('latest.rm', 'wb') as f: write_blocks(f, blocks) ``` -------------------------------- ### Block Version Headers Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/configuration.md Return (min_version, current_version) for block header. ```python def version_info(self, writer: TaggedBlockWriter) -> tuple[int, int]: """Return (min_version, current_version) for block header.""" ``` -------------------------------- ### Round-Trip Compatibility Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/configuration.md Read file and write back in same format. ```python from rmscene import read_blocks, write_blocks # Read file with open('original.rm', 'rb') as f: blocks = list(read_blocks(f)) # Write back in same format # Option 1: Guess version from block headers min_version = min( (b.version_info(None)[0] for b in blocks if hasattr(b, 'version_info')), default="3.2.2" ) # Option 2: Specify explicit version with open('output.rm', 'wb') as f: write_blocks(f, blocks, options={"version": min_version}) ``` -------------------------------- ### Copying/Archiving Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/configuration.md When copying or archiving, write files with the version matching the original to preserve data fidelity. The version information is stored within each block, so no special option is needed during writing. ```python # Preserve original format with open('original.rm', 'rb') as f: blocks = list(read_blocks(f)) # Version info is in each block; no special option needed with open('backup.rm', 'wb') as f: write_blocks(f, blocks) ``` -------------------------------- ### Writing new files Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/configuration.md Omit the version option to write files in the latest format. ```python write_blocks(f, blocks) # Uses latest format ``` -------------------------------- ### Logging Configuration Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/configuration.md Configure logging to see version-related debug messages. ```python import logging # Enable debug logging logging.basicConfig(level=logging.DEBUG) # Enable debug logging only for rmscene logger = logging.getLogger('rmscene') logger.setLevel(logging.DEBUG) ``` -------------------------------- ### version_info Method Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Returns version information for the block. ```python def version_info(self, writer: TaggedBlockWriter) -> tuple[int, int]: # Returns (min_version, current_version) tuple for version info written to block header. # Default is (1, 1). pass ``` -------------------------------- ### TaggedBlockWriter Options Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/configuration.md The same options dictionary can be passed directly to TaggedBlockWriter. ```python def __init__(self, data: BinaryIO, options: Optional[dict] = None) ``` ```python from rmscene import TaggedBlockWriter from packaging.version import Version writer = TaggedBlockWriter(f, options={"version": "3.2.2"}) writer.write_header() # Writer now uses v3.2.2 format conventions ``` -------------------------------- ### simple_text_document function Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Generates minimal blocks representing plain text as a reMarkable document. ```python def simple_text_document(text: str, author_uuid: Optional[UUID] = None) -> Iterator[Block]: # ... implementation details ... pass ``` ```python blocks = simple_text_document("Hello World") with open('hello.rm', 'wb') as f: write_blocks(f, blocks) ``` -------------------------------- ### Constructor Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-reader.md Initializes TaggedBlockReader with a binary stream. ```python def __init__(self, data: BinaryIO) ``` -------------------------------- ### Safe Reading with Optional Values and Subblocks Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/errors.md Demonstrates using TaggedBlockReader to safely read optional values and check for subblocks, providing default values when necessary. ```python from rmscene import TaggedBlockReader, UnexpectedBlockError reader = TaggedBlockReader(f) reader.read_header() with reader.read_block() as block_info: if block_info: # Use optional readers with defaults value1 = reader.read_bool_optional(1, default=True) value2 = reader.read_int_optional(2, default=0) # Check before reading subblocks if reader.has_subblock(3): with reader.read_subblock(3): # safe to read pass ``` -------------------------------- ### is_highlighter method Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-items.md Checks whether a pen value represents a highlighter tool. ```python @classmethod def is_highlighter(cls, value: int) -> bool: # ... implementation ... ``` ```python if Pen.is_highlighter(line.tool): # This is a highlighter stroke ``` -------------------------------- ### SceneTree Population and Validation Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/errors.md Demonstrates reading a document into a SceneTree and performing basic checks on the populated tree, such as checking for root text and scene information. ```python from rmscene import read_tree, SceneTree try: with open('document.rm', 'rb') as f: tree = read_tree(f) # Check tree was populated if tree.root_text: print("Document contains text") if tree.scene_info: print(f"Paper size: {tree.scene_info.paper_size}") except ValueError as e: print(f"Failed to build tree: {e}") ``` -------------------------------- ### MigrationInfoBlock Class Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Migration information block (type 0x00) tracking document migration/sync history. ```python @dataclass class MigrationInfoBlock(Block): migration_id: CrdtId is_device: bool ``` -------------------------------- ### MainBlockInfo Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Metadata for a top-level block. ```python @dataclass class MainBlockInfo(BlockInfo) ``` -------------------------------- ### SceneTree Constructor Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-tree.md Creates a new empty SceneTree with a root Group node. ```python tree = SceneTree() ``` -------------------------------- ### _read_struct and _write_struct Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/common-stream.md Internal methods using struct module for efficient packing. Pattern strings use struct format codes with little-endian prefix. ```python def _read_struct(self, pattern: str) -> int | float def _write_struct(self, pattern: str, value: int | float) ``` -------------------------------- ### Text class Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-items.md Represents a block of text content with formatting. ```python @dataclass class Text(SceneItem): items: CrdtSequence[str | int] styles: dict[CrdtId, LwwValue[ParagraphStyle]] pos_x: float pos_y: float width: float ``` ```python text = Text( items=CrdtSequence([...]), styles={CrdtId(0, 0): LwwValue(CrdtId(1, 0), ParagraphStyle.PLAIN)}, pos_x=-468.0, pos_y=234.0, width=936.0 ) ``` -------------------------------- ### write Method Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Writes this block to the writer stream, including header and content. ```python def write(self, writer: TaggedBlockWriter): # Writes this block to the writer stream, including header and content. pass ``` -------------------------------- ### Pen Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Pen tool types. See [scene-items.md](api-reference/scene-items.md#pen) for complete list. ```python class Pen(enum.IntEnum) ``` -------------------------------- ### HEADER_V6 Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/common-stream.md The magic bytes (44 bytes total) that identify reMarkable v6 files. ```python HEADER_V6 = b"reMarkable .lines file, version=6 " ``` -------------------------------- ### to_stream Method (Abstract) Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Abstract method for subclasses to write their specific content to the stream. ```python @abstractmethod def to_stream(self, writer: TaggedBlockWriter): # Subclasses implement to write their specific content to the stream. pass ``` -------------------------------- ### Block Base Class Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Abstract base class for all block types in a reMarkable file. ```python @dataclass class Block(ABC): extra_data: bytes ``` -------------------------------- ### from_stream Class Method (Abstract) Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Abstract method for subclasses to parse their specific content from the stream. ```python @classmethod @abstractmethod def from_stream(cls, reader: TaggedBlockReader) -> Block: # Subclasses implement to parse their specific content from the stream. pass ``` -------------------------------- ### ParagraphStyle Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Paragraph-level text styling. See [scene-items.md](api-reference/scene-items.md#paragraphstyle) for complete list. ```python class ParagraphStyle(enum.IntEnum) ``` -------------------------------- ### ParagraphStyle enum Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-items.md Defines paragraph-level text styling. ```python class ParagraphStyle(enum.IntEnum): BASIC = 0 PLAIN = 1 HEADING = 2 BOLD = 3 BULLET = 4 BULLET2 = 5 CHECKBOX = 6 CHECKBOX_CHECKED = 7 ``` -------------------------------- ### SubBlockInfo Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Metadata for a sub-block. Inherits all BlockInfo attributes. ```python @dataclass class SubBlockInfo(BlockInfo) ``` -------------------------------- ### PenColor Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Pen color palette. See [scene-items.md](api-reference/scene-items.md#pencolor) for complete list. ```python class PenColor(enum.IntEnum) ``` -------------------------------- ### SceneItem Dataclass Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Abstract base class for content items in a scene. ```python @dataclass class SceneItem ``` -------------------------------- ### Rectangle class Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-items.md Represents a rectangular bounding box with floating-point coordinates. ```python @dataclass class Rectangle: x: float y: float w: float h: float ``` ```python rect = Rectangle(x=100.0, y=200.0, w=50.0, h=25.0) print(f"Right: {rect.x + rect.w}, Bottom: {rect.y + rect.h}") ``` -------------------------------- ### write_tag Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/common-stream.md Writes a tag (index and type combined into a varuint). ```python def write_tag(self, index: int, tag_type: TagType) ``` -------------------------------- ### build_tree Function Signature Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Function signature for build_tree, which reads blocks and populates a SceneTree structure. ```python def build_tree(tree: SceneTree, blocks: Iterable[Block]) ``` -------------------------------- ### read Class Method Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Reads a single block from the reader stream, handling unknown types gracefully. ```python @classmethod def read(cls, reader: TaggedBlockReader) -> Optional[Block]: # Reads a single block from the reader stream. # Handles unknown block types gracefully by returning an UnreadableBlock. pass ``` -------------------------------- ### UnexpectedBlockError Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/common-stream.md Raised when tag/index mismatch or other structural error in block stream. ```python class UnexpectedBlockError(Exception) ``` -------------------------------- ### read_header Method Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-reader.md Reads and validates the file header. ```python def read_header(self) -> None ``` -------------------------------- ### read_bool_optional Method Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-reader.md Reads a tagged bool, returning a default value if not present. ```python def read_bool_optional(self, index: int, default: Optional[bool] = None) -> Optional[bool] ``` -------------------------------- ### BlockInfo Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Metadata about a block or subblock in the file. ```python @dataclass class BlockInfo ``` -------------------------------- ### read_string Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-reader.md Reads a standard string block. ```python def read_string(self, index: int) -> str Reads a standard string block. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | index | int | Yes | Tag index | **Returns:** `str` — the decoded string. **Example:** ```python label = reader.read_string(2) ``` ``` -------------------------------- ### write_string_with_format Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-writer.md Writes a string block with formatting code. ```python def write_string_with_format(self, index: int, text: str, fmt: int) ``` ```python writer.write_string_with_format(6, "", 1) # Format code 1 for bold ``` -------------------------------- ### read_string_with_format Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-reader.md Reads a string block with optional formatting code. ```python def read_string_with_format(self, index: int) -> tuple[str, Optional[int]] Reads a string block with optional formatting code. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | index | int | Yes | Tag index | **Returns:** `tuple[str, Optional[int]]` — (string_content, format_code_or_none). ``` -------------------------------- ### write_string Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-writer.md Writes a standard string block. ```python def write_string(self, index: int, value: str) ``` ```python writer.write_string(2, "Example text") ``` -------------------------------- ### check_tag Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/common-stream.md Peeks ahead to check if the next tag matches the expected index and type without consuming it. ```python def check_tag(self, expected_index: int, expected_type: TagType) -> bool ``` -------------------------------- ### ParagraphStyle Enum Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/text-processing.md Defines paragraph-level text styling options. ```python class ParagraphStyle(enum.IntEnum) ``` -------------------------------- ### GlyphRange class Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-items.md Represents highlighted text in a PDF or document. ```python @dataclass class GlyphRange(SceneItem): start: Optional[int] length: int text: str color: PenColor rectangles: list[Rectangle] color_rgba: Optional[tuple[int, int, int, int]] ``` ```python glyph = GlyphRange( start=None, length=5, text="Hello", color=PenColor.HIGHLIGHT, rectangles=[Rectangle(100, 200, 50, 15)], color_rgba=(255, 255, 0, 255) # Yellow ) ``` -------------------------------- ### Paragraph Dataclass Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Represents a paragraph of text with styles. ```python @dataclass class Paragraph ``` -------------------------------- ### lookup Class Method Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/scene-stream.md Finds the Block subclass for a given block type code. ```python @classmethod def lookup(cls, block_type: int) -> Optional[Type[Block]]: # Finds the Block subclass for a given block type code. pass ``` -------------------------------- ### write_int_pair Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-writer.md Writes a subblock containing two uint32 values. ```python def write_int_pair(self, index: int, value: tuple[int, int]) ``` ```python writer.write_int_pair(5, (936, 1248)) # Paper size ``` -------------------------------- ### read_int_optional Method Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/api-reference/tagged-block-reader.md Reads a tagged 4-byte integer, returning a default value if not present. ```python def read_int_optional(self, index: int, default: Optional[int] = None) -> Optional[int] ``` -------------------------------- ### Point Source: https://github.com/ricklupton/rmscene/blob/main/_autodocs/types.md Point on a line stroke. See [scene-items.md](api-reference/scene-items.md#point). ```python @dataclass class Point ```