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>
This commit is contained in:
pewdiepie-archdaemon
2026-10-15 11:57:35 +00:00
co-authored by Claude Opus 5.5
parent c74f475679
commit 5fac693c1c
290 changed files with 34358 additions and 766 deletions
+44 -1
View File
@@ -18,7 +18,7 @@
* }} deps
*/
import { state } from './state.js';
import { flipDocument, rotateDocument } from './document-geometry.js';
import { flipDocument, rotateDocument, rotateDocumentArbitrary, flipLayer as flipLayerGeometry, rotateLayer as rotateLayerGeometry } from './document-geometry.js';
export function createCanvasTransforms({
saveState, composite, fitZoom, showCanvasLoading, hideCanvasLoading, renderLayerPanel,
@@ -52,6 +52,29 @@ export function createCanvasTransforms({
});
},
/**
* Rotate the entire document by an arbitrary angle in degrees
* (clockwise; negative for counter-clockwise), expanding the canvas
* so nothing is clipped. Right angles use the exact integer path.
*/
rotateAllArbitrary(deg) {
if (!state.layers.length) return;
saveState(`Rotate ${deg}°`);
showCanvasLoading('Rotating…');
requestAnimationFrame(() => {
try {
const result = rotateDocumentArbitrary(state, deg);
const sizeLabel = document.getElementById('ge-canvas-size');
if (sizeLabel && result) sizeLabel.textContent = `${result.width}×${result.height}`;
fitZoom();
composite();
renderLayerPanel?.();
} finally {
hideCanvasLoading();
}
});
},
/**
* Mirror every layer horizontally ('h') or vertically ('v').
* Canvas dimensions don't change. Each layer offset is reflected
@@ -64,5 +87,25 @@ export function createCanvasTransforms({
composite();
renderLayerPanel?.();
},
/** Flip only the active layer, in place (Edit ▸ Transform ▸ Flip). */
flipLayer(axis) {
const layer = state.layers.find((item) => item.id === state.activeLayerId);
if (!layer) return;
saveState(axis === 'h' ? 'Flip layer horizontal' : 'Flip layer vertical');
flipLayerGeometry(state, layer, axis);
composite();
renderLayerPanel?.();
},
/** Rotate only the active layer by 90/180/270°, centre preserved. */
rotateLayer(deg) {
const layer = state.layers.find((item) => item.id === state.activeLayerId);
if (!layer) return;
saveState(`Rotate layer ${deg}°`);
rotateLayerGeometry(state, layer, deg);
composite();
renderLayerPanel?.();
},
};
}