On this page
Whole-canvas rotate, scale, and crop transforms that rewrite every frame's pixel and role buffers to match the browser's results byte-for-byte on the server.
#server.src.pixelweaver.dimension_ops
#server.src.pixelweaver.dimension_ops
Whole-canvas dimension transforms for authoritative server state.
Ports the browser's rotate_canvas / scale_canvas / crop_to_selection transforms (plugins/builtin/effects/rotate.ts, scale.ts, and src/lib/ui/image-commands.ts) so the server reproduces byte-identical results when those commands are forwarded. resize_canvas reuses the anchored remap in resize.py.
Each transform rewrites every frame's RGBA pixel buffer (and, defensively, role planes -- though the client hard-errors while any role layer exists for rotate/scale/crop) and updates the canvas dimensions exactly once.
#has_role_layers
def has_role_layers(canvas: CanvasState) -> boolWhether the canvas declares any role-kind layer (mirrors the client's assertRgbaPixelLayers guard for whole-canvas transforms).
#rotate_rgba
def rotate_rgba(buf: bytes, w: int, h: int, angle: float) -> tuple[bytes, int, int]Rotate an RGBA buffer (port of computeRotation). Returns (new_bytes, new_width, new_height).
#scale_rgba
def scale_rgba(buf: bytes, w: int, h: int, nw: int, nh: int) -> bytesNearest-neighbor scale of an RGBA buffer (port of computeScale).
#crop_rgba
def crop_rgba(buf: bytes, w: int, h: int, x: int, y: int, cw: int, ch: int) -> bytesExtract the (x, y, cw, ch) sub-region (port of PixelBuffer.getRegion); out-of-bounds source pixels become transparent.
#rotate_canvas
def rotate_canvas(canvas: CanvasState, angle: float) -> NoneRotate every frame/layer buffer by angle and update dims in place.
#scale_canvas
def scale_canvas(canvas: CanvasState, new_width: int, new_height: int) -> NoneScale every frame/layer buffer to (new_width, new_height) in place.
#crop_canvas
def crop_canvas(canvas: CanvasState, x: int, y: int, w: int, h: int) -> NoneCrop every frame/layer buffer to the (x, y, w, h) region in place.