# ora_edit.py A command-line utility for editing OpenRaster (ORA) files, supporting layer creation, masking, and entity management. ## Overview `ora_edit.py` provides four main subcommands: - `create`: Create a new ORA file from a PNG image - `mask_element`: Add masked layers for specific entities within an ORA file - `inspect`: Display the structure of an ORA file - `extract_png`: Extract a layer from an ORA file as a PNG ## Usage ### Creating an ORA File Create a new ORA file from a PNG: ```bash python3 ora_edit.py create input.png [output.ora] [--layer-name NAME] ``` **Examples:** ```bash # Create ORA with default layer name "base" python3 ora_edit.py create scene.png scene.ora # Create ORA with custom layer name python3 ora_edit.py create scene.png scene.ora --layer-name "background" # Auto-detect output name (creates scene.ora) python3 ora_edit.py create scene.png ``` ### Masking Elements Add a masked layer for an entity using a black-and-white mask image: ```bash python3 ora_edit.py mask_element --mask --entity [--layer LAYER] [--output OUTPUT] ``` **Examples:** ```bash # Mask an element using default "base" layer python3 ora_edit.py mask_element scene.ora --mask door_mask.png --entity "door" # Specify which layer to copy and mask python3 ora_edit.py mask_element scene.ora --mask window_mask.png --entity "window" --layer "background" # Chain: Convert PNG to ORA, then add masked element python3 ora_edit.py mask_element scene.png --mask tree_mask.png --entity "tree" --output scene_with_tree.ora ``` **How it works:** - Creates an entity group (or uses existing one) - Copies the specified source layer - Applies the mask as the alpha channel - Saves as `entity_N` (auto-incremented: door_0, door_1, etc.) ### Inspecting ORA Files Display the layer structure and group hierarchy of an ORA file: ```bash python3 ora_edit.py inspect ``` **Examples:** ```bash # View structure of an ORA file python3 ora_edit.py inspect scene.ora # Check what's in a file before adding more elements python3 ora_edit.py inspect character.ora ``` ### Extracting Layers as PNG Extract a specific layer from an ORA file and save it as a PNG: ```bash python3 ora_edit.py extract_png --layer [--output ] ``` **Examples:** ```bash # Extract a layer with default output name python3 ora_edit.py extract_png scene.ora --layer door_0 # Extract with custom output name python3 ora_edit.py extract_png scene.ora --layer background --output bg.png # Extract all layers from an ORA (use with inspect) for layer in $(python3 ora_edit.py inspect scene.ora | grep "Layer" | awk '{print $NF}'); do python3 ora_edit.py extract_png scene.ora --layer "$layer" --output "${layer}.png" done ``` **Output format:** ``` File: scene.ora ================================================== ORA STRUCTURE SUMMARY ================================================== 📁 Group 1: door └─ Layer 1: door_0 └─ Layer 2: door_1 📁 Group 2: window └─ Layer 1: window_0 🖼️ Base Layer 3: background ================================================== ``` ## Workflow Examples ### Example 1: Game Scene Composition Building a scene with multiple masked elements: ```bash # Start with background python3 ora_edit.py create background.png scene.ora --layer-name "room" # Add a door masked from the room layer python3 ora_edit.py mask_element scene.ora \ --mask door_alpha.png \ --entity "door" \ --layer "room" # Add a window python3 ora_edit.py mask_element scene.ora \ --mask window_alpha.png \ --entity "window" \ --layer "room" # Add another door variant (auto-increments to door_1) python3 ora_edit.py mask_element scene.ora \ --mask door_open_alpha.png \ --entity "door" \ --layer "room" # Check the final structure python3 ora_edit.py inspect scene.ora ``` **Resulting structure:** ``` 📁 Group: door └─ door_0 └─ door_1 📁 Group: window └─ window_0 🖼️ Base Layer: room ``` ### Example 2: Character Animation Creating animation frames with masked body parts: ```bash # Create base character python3 ora_edit.py create character_base.png character.ora --layer-name "body" # Add masked arm that can be animated python3 ora_edit.py mask_element character.ora \ --mask arm_mask.png \ --entity "arm" \ --layer "body" # Add masked head python3 ora_edit.py mask_element character.ora \ --mask head_mask.png \ --entity "head" \ --layer "body" ``` ### Example 3: AI-Generated Assets Working with AI-generated masks: ```bash # Generate mask using ComfyUI or other tool python3 extract_mask.py "the wooden chest" scene.png chest_mask.png # Add to ORA python3 ora_edit.py mask_element scene.ora \ --mask chest_mask.png \ --entity "chest" \ --layer "background" ``` ### Example 4: Iterative Design Refining elements with multiple mask attempts: ```bash # First iteration python3 ora_edit.py mask_element scene.ora \ --mask door_v1.png \ --entity "door" \ --layer "background" # Second iteration (creates door_1) python3 ora_edit.py mask_element scene.ora \ --mask door_v2.png \ --entity "door" \ --layer "background" # Third iteration (creates door_2) python3 ora_edit.py mask_element scene.ora \ --mask door_v3.png \ --entity "door" \ --layer "background" ``` The ORA now contains all three versions to compare in GIMP/Krita. ### Example 5: Layer-Based Masking Using different source layers for different entities: ```bash # Create ORA with multiple base layers python3 ora_edit.py create day_scene.png scene.ora --layer-name "day" python3 ora_edit.py create night_scene.png scene_night.ora --layer-name "night" # Extract and use specific layers # (Assume we've combined these into one ORA manually or via script) # Mask using day layer python3 ora_edit.py mask_element scene.ora \ --mask sun_mask.png \ --entity "sun" \ --layer "day" # Mask using night layer python3 ora_edit.py mask_element scene.ora \ --mask moon_mask.png \ --entity "moon" \ --layer "night" ``` ### Example 6: Exporting Layers for External Use Extracting layers for use in other tools or workflows: ```bash # Check what layers exist python3 ora_edit.py inspect character.ora # Extract specific animation frames python3 ora_edit.py extract_png character.ora --layer arm_0 --output arm_frame1.png python3 ora_edit.py extract_png character.ora --layer arm_1 --output arm_frame2.png # Extract background for compositing python3 ora_edit.py extract_png scene.ora --layer background --output bg_composite.png ``` ## Command Reference ### `create` Create an ORA file from a PNG image. ``` positional arguments: input_png Input PNG file output_ora Output ORA file (default: same name with .ora extension) options: -h, --help Show help message --layer-name NAME Name for the root layer (default: base) ``` ### `mask_element` Create a masked layer for an entity. ``` positional arguments: input Input ORA or PNG file options: -h, --help Show help message --mask MASK Mask file to use as alpha channel (required) --entity ENTITY Entity name/group name (required) --layer LAYER Source layer to copy and mask (default: base) --output OUTPUT Output ORA file (default: same as input) ``` **Important behaviors:** - If input is PNG: Automatically converts to ORA first, using "base" as the layer name - Entity groups are created above base layers in the stack - Layer names auto-increment within groups (entity_0, entity_1, ...) - If the specified `--layer` doesn't exist, the command errors and lists available layers ### `inspect` Display the structure of an ORA file without modifying it. ``` positional arguments: ora_file ORA file to inspect options: -h, --help Show help message ``` **Output includes:** - File path - Entity groups with their layer counts - Base layers - Total layer/group statistics ### `extract_png` Extract a layer from an ORA file as a PNG image. ``` positional arguments: ora_file ORA file to extract from options: -h, --help Show help message --layer LAYER Name of the layer to extract (required) --output OUTPUT Output PNG file (default: .png) ``` **Use cases:** - Export layers for use in other graphics applications - Extract masked elements for game development - Create individual assets from composed ORA files - Backup or archive specific layers **Important behaviors:** - If the specified `--layer` doesn't exist, the command errors and lists available layers - Output defaults to `.png` if not specified - Preserves transparency (RGBA) from the original layer ## Tips ### Mask Requirements - Masks can be grayscale (L mode) or RGB/RGBA - White = fully opaque, Black = fully transparent - Grayscale values create partial transparency ### Layer Organization - Entity groups appear first in the layer stack - Base layers appear at the end - This organization makes it easy to toggle entities on/off in GIMP/Krita ### Workflow Integration - Combine with `extract_mask.py` for AI-powered masking - Use `mask_to_polygon.py` to convert masks to Godot collision polygons - Chain multiple `mask_element` calls in shell scripts for batch processing ## Error Handling The tool provides clear error messages: ```bash # Missing layer $ python3 ora_edit.py mask_element scene.ora --mask x.png --entity door --layer "missing" Error: Layer 'missing' not found in ORA file Available layers: - base - door_0 - door_1 ``` ## Dependencies - Python 3.8+ - Pillow (PIL) Install dependencies: ```bash pip install Pillow ``` ## ORA Format OpenRaster (.ora) is an open standard for layered raster graphics. This tool creates ORA 0.0.3 compatible files that can be opened in: - GIMP (with ora plugin) - Krita - MyPaint - Other ORA-supporting applications The generated structure: ``` archive.ora/ ├── mimetype # "image/openraster" ├── stack.xml # Layer hierarchy ├── mergedimage.png # Flattened preview ├── Thumbnails/ │ └── thumbnail.png # 256x256 preview └── data/ ├── base.png # Layer images └── entity/ └── entity_0.png ```