AlterProgramming's picture
Initial venture-studio deploy: pixel_cursor + studio + app.py
1e3ce4c verified
Raw
History Blame Contribute Delete
1.86 kB
"""Artifacts: the pixel-space data structures that only PixelCursor may produce.
External code may hold and inspect Artifacts but cannot construct them directly;
the only path to a fresh Artifact is a cursor write_* op or a loader in this
module. This is the structural enforcement of the "cursor owns the studio" claim.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Union
from pathlib import Path
import numpy as np
from ._internal import _MUTATION_TOKEN, _verify
@dataclass(frozen=True, slots=True, eq=False, repr=False)
class Image:
pixels: np.ndarray
name: str = ""
_token: object = field(default=None, repr=False)
def __post_init__(self) -> None:
_verify(self._token)
def __repr__(self) -> str:
return f"Image(shape={tuple(self.pixels.shape)}, name={self.name!r})"
@dataclass(frozen=True, slots=True, eq=False, repr=False)
class FrameStack:
frames: np.ndarray
fps: int = 24
name: str = ""
_token: object = field(default=None, repr=False)
def __post_init__(self) -> None:
_verify(self._token)
@property
def num_frames(self) -> int:
return int(self.frames.shape[0])
def __repr__(self) -> str:
return f"FrameStack(shape={tuple(self.frames.shape)}, fps={self.fps}, name={self.name!r})"
Artifact = Union[Image, FrameStack]
def _new_image(pixels: np.ndarray, name: str = "") -> Image:
return Image(pixels=pixels, name=name, _token=_MUTATION_TOKEN)
def _new_framestack(frames: np.ndarray, fps: int = 24, name: str = "") -> FrameStack:
return FrameStack(frames=frames, fps=fps, name=name, _token=_MUTATION_TOKEN)
def load_image(path: str | Path) -> Image:
from PIL import Image as PILImage
arr = np.array(PILImage.open(path).convert("RGB"))
return _new_image(arr, name=str(path))