mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-16 11:52:25 +02:00
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>
62 lines
2.6 KiB
Python
62 lines
2.6 KiB
Python
import json
|
|
import subprocess
|
|
import textwrap
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
MODULE = (ROOT / 'static/js/editor/aspect-fit.js').as_uri()
|
|
|
|
|
|
def run_node(body):
|
|
script = textwrap.dedent(f"""
|
|
import * as A from {json.dumps(MODULE)};
|
|
{body}
|
|
""")
|
|
result = subprocess.run(
|
|
['node', '--input-type=module', '-e', script],
|
|
cwd=ROOT, text=True, capture_output=True, check=True,
|
|
)
|
|
return json.loads(result.stdout)
|
|
|
|
|
|
def test_aspect_fit_preserves_subject_ratio_within_two_percent():
|
|
# A 900x600 canvas with a subject (face) whose bbox has ratio 0.62, ask for
|
|
# a 1080x1350 (4:5) Instagram post. The crop-to-aspect step then the uniform
|
|
# scale must keep the subject bbox w/h ratio within 2%.
|
|
out = run_node("""
|
|
const docW=900, docH=600;
|
|
const subj={x:330,y:120,w:260,h:420}; // ratio 0.619
|
|
const crop=A.aspectFitCropRect({width:docW,height:docH,focusX:subj.x+subj.w/2,focusY:subj.y+subj.h/2,targetAspect:1080/1350});
|
|
// subject clipped to the crop window
|
|
const ix=Math.max(subj.x,crop.x), iy=Math.max(subj.y,crop.y);
|
|
const ix2=Math.min(subj.x+subj.w,crop.x+crop.width), iy2=Math.min(subj.y+subj.h,crop.y+crop.height);
|
|
const sx=(ix2-ix)*(1080/crop.width), sy=(iy2-iy)*(1350/crop.height); // uniform scale
|
|
console.log(JSON.stringify({ crop, subjRatio:subj.w/subj.h, afterRatio:sx/sy }));
|
|
""")
|
|
assert abs(out['afterRatio'] - out['subjRatio']) / out['subjRatio'] <= 0.02, out
|
|
# The crop really is 4:5 and not the full 3:2 canvas.
|
|
assert abs(out['crop']['width'] / out['crop']['height'] - 1080 / 1350) <= 0.01
|
|
|
|
|
|
def test_aspect_fit_no_crop_when_aspect_already_matches():
|
|
out = run_node("""
|
|
const r=A.aspectFitCropRect({width:1080,height:1350,targetAspect:1080/1350});
|
|
console.log(JSON.stringify(r));
|
|
""")
|
|
assert out == {'x': 0, 'y': 0, 'width': 1080, 'height': 1350}
|
|
|
|
|
|
def test_aspect_fit_centres_on_focus_and_clamps_into_bounds():
|
|
out = run_node("""
|
|
// Tall subject near the left edge -> crop stays inside the document.
|
|
const crop=A.aspectFitCropRect({width:900,height:600,focusX:60,focusY:300,targetAspect:4/5});
|
|
const edge=A.aspectFitCropRect({width:900,height:600,focusX:450,focusY:300,targetAspect:4/5});
|
|
console.log(JSON.stringify({crop,edge}));
|
|
""")
|
|
# focus at x=60 -> centred crop would start at -180 -> clamped to 0
|
|
assert out['crop']['x'] == 0
|
|
assert out['crop']['height'] == 600 and out['crop']['width'] == 480
|
|
# centred focus -> starts at 210
|
|
assert out['edge']['x'] == 210
|