Files
odysseus/tests/test_editor_patch.py
T
pewdiepie-archdaemonandClaude Opus 5.5 5fac693c1c feat(photo-editor): Ajax Image Editor client (Photoshop-parity tools)
Photoshop-parity editor client: layers, selection/masking, brushes,
smart filters, LUT import, Quick Edit, mobile gestures, workspaces,
batch operations, and the service-worker versioning (v978->v1006).

Source: vendor/photocraft (ad1cff44) photo-editor client files, merged
onto upstream/dev (a8c147b2). Conflict resolution documented in
pr_work/A_conflicts.md; editor files taken from vendor/photocraft
(upstream's editor is an earlier snapshot of the same feature).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 11:57:35 +00:00

99 lines
5.1 KiB
Python

from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def _read(*parts):
return (ROOT.joinpath(*parts)).read_text(encoding="utf-8")
def test_patch_engine_is_offline_and_canvas_seam_injected():
ops = _read("static/js/editor", "patch-ops.js")
# Pure helpers with a createCanvas seam (like mask-ops.js) — no network.
assert "export function patchRegion(createCanvas, layerCanvas, maskCanvas, offset, dx, dy, feather = 0)" in ops
assert "export function contentAwareMove(createCanvas, layerCanvas, maskCanvas, offset, dx, dy, iterations = 16)" in ops
assert "function restrictToMask(createCanvas, source, mask, width, height)" in ops
assert "function featherMask(createCanvas, mask, width, height, radius)" in ops
assert "function maskInLayerSpace(createCanvas, mask, offset, width, height)" in ops
assert "fetch(" not in ops
def test_patch_region_samples_the_source_through_a_feathered_mask():
ops = _read("static/js/editor", "patch-ops.js")
region = ops[ops.index("export function patchRegion"):ops.index("export function contentAwareMove")]
assert "const shifted = createCanvas(w, h);" in region
# Sampling at (x+dx, y+dy) == the layer drawn shifted by (-dx, -dy).
assert "shifted.getContext('2d').drawImage(layerCanvas, -dx, -dy);" in region
assert "const sourceInMask = restrictToMask(createCanvas, shifted, localMask, w, h);" in region
assert "if (feather > 0) localMask = featherMask(createCanvas, localMask, w, h, feather);" in region
assert "octx.drawImage(sourceInMask, 0, 0);" in region
def test_content_aware_move_cuts_pastes_and_diffusion_fills_the_hole():
ops = _read("static/js/editor", "patch-ops.js")
move = ops[ops.index("export function contentAwareMove"):]
assert "const cut = restrictToMask(createCanvas, layerCanvas, localMask, w, h);" in move
# Hole starts transparent, then the edge colour grows inward.
assert "fctx.globalCompositeOperation = 'destination-out';" in move
assert "fctx.drawImage(localMask, 0, 0);" in move
assert "fctx.globalCompositeOperation = 'destination-over';" in move
assert "const radius = Math.ceil(Math.max(bw, bh) / 2);" in move
# Nearest-boundary inward fill: grow one pixel per pass, four directions.
assert "for (let i = 0; i < passes; i++)" in move
assert "fctx.drawImage(fill, 1, 0);" in move
assert "fctx.drawImage(fill, -1, 0);" in move
assert "fctx.drawImage(fill, 0, 1);" in move
assert "fctx.drawImage(fill, 0, -1);" in move
assert "const maskedAvg = restrictToMask(createCanvas, avg, localMask, w, h);" in move
# Paste the cut content at the offset, on top of the filled base.
assert "octx.drawImage(filledHole, 0, 0);" in move
assert "octx.drawImage(cut, dx, dy);" in move
def test_patch_tool_tracks_a_drag_offset_and_applies_on_release():
tool = _read("static/js/editor", "tools", "patch.js")
assert "export function createPatchTool({" in tool
assert "import { state } from '../state.js';" in tool
assert "showToast?.('Make a selection, then drag the Patch tool to a source area');" in tool
assert "state.patchDx = Math.round(coords.x - start.x);" in tool
assert "state.patchDy = Math.round(coords.y - start.y);" in tool
assert "saveState?.('Patch');" in tool
assert "onApply?.(dx, dy);" in tool
assert "return { begin, drag, end, cancel };" in tool
def test_galleryeditor_wires_the_patch_tool_and_ops():
editor = _read("static/js", "galleryEditor.js")
assert "import { createPatchTool } from './editor/tools/patch.js';" in editor
assert "import { patchRegion as _patchRegion, contentAwareMove as _contentAwareMove } from './editor/patch-ops.js';" in editor
assert "const _patchTool = createPatchTool({" in editor
assert "function _applyPatchOffset(dx, dy, { history = true } = {})" in editor
assert "function _applyContentAwareMove(dx, dy, { history = true } = {})" in editor
assert "_patchRegion(_patchCreateCanvas, layer.canvas, state.wandMask, offset, dx, dy, 4)" in editor
assert "_contentAwareMove(_patchCreateCanvas, layer.canvas, state.wandMask, offset, dx, dy)" in editor
# Dispatcher hooks (begin / drag / end) mirror object-selection.
assert "if (state.tool === 'patch') return _patchTool.begin(e);" in editor
assert "if (state.tool === 'patch') return _patchTool.drag(e);" in editor
assert "if (state.tool === 'patch') return _patchTool.end(e);" in editor
# Control ops.
assert "'patch.apply': {" in editor
assert "'edit.contentAwareMove': {" in editor
def test_patch_is_exposed_in_the_toolbar_and_edit_menu():
toolbar = _read("static/js/editor/build", "toolbar.js")
topbar = _read("static/js/editor/build", "topbar.js")
extra = _read("static/js/editor", "wire-extra-menus.js")
assert "patch: { label: 'Patch'," in toolbar
assert "['clone', 'heal', 'patch']" in toolbar
assert 'data-edit-action="content-aware-move"' in topbar
assert "else if (action === 'content-aware-move')" in extra
assert "window.geEditorControl?.invoke('edit.contentAwareMove', { dx: Math.round(parts[0]), dy: Math.round(parts[1]) });" in extra