diff --git a/i18n/en.json b/i18n/en.json
index db50aa3f2b..0fc959aabd 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -17,6 +17,14 @@
"add_a_title": "Add a title",
"add_birthday": "Add a birthday",
"add_endpoint": "Add endpoint",
+ "editor_crop_tool_h2_mirror": "Mirror",
+ "mirror_horizontal": "Horizontal",
+ "mirror_vertical": "Vertical",
+ "rotate_ccw": "CCW 90°",
+ "rotate_cw": "CW 90°",
+ "crop_aspect_ratio_free": "Free",
+ "crop_aspect_ratio_fixed": "Fixed",
+ "crop_aspect_ratio_original": "Original",
"add_exclusion_pattern": "Add exclusion pattern",
"add_location": "Add location",
"add_more_users": "Add more users",
diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte
index 2a06455896..bed69cca7b 100644
--- a/web/src/lib/components/asset-viewer/asset-viewer.svelte
+++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte
@@ -42,7 +42,7 @@
import ActivityStatus from './activity-status.svelte';
import ActivityViewer from './activity-viewer.svelte';
import DetailPanel from './detail-panel.svelte';
- import CropArea from './editor/crop-tool/crop-area.svelte';
+ import CropArea from './editor/transform-tool/crop-area.svelte';
import EditorPanel from './editor/editor-panel.svelte';
import ImagePanoramaViewer from './image-panorama-viewer.svelte';
import OcrButton from './ocr-button.svelte';
diff --git a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-tool.svelte b/web/src/lib/components/asset-viewer/editor/crop-tool/crop-tool.svelte
deleted file mode 100644
index 22fb5d2ab4..0000000000
--- a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-tool.svelte
+++ /dev/null
@@ -1,144 +0,0 @@
-
-
-
-
-
{$t('crop')}
-
- {#each sizesRows as sizesRow, index (index)}
-
- {#each sizesRow as size (size.name)}
-
- {/each}
-
- {/each}
-
-
{$t('editor_crop_tool_h2_rotation')}
-
-
- -
- transformManager.rotate(-90)}
- icon={mdiRotateLeft}
- />
-
- -
- transformManager.rotate(90)}
- icon={mdiRotateRight}
- />
-
-
-
diff --git a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-area.svelte b/web/src/lib/components/asset-viewer/editor/transform-tool/crop-area.svelte
similarity index 100%
rename from web/src/lib/components/asset-viewer/editor/crop-tool/crop-area.svelte
rename to web/src/lib/components/asset-viewer/editor/transform-tool/crop-area.svelte
diff --git a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-preset.svelte b/web/src/lib/components/asset-viewer/editor/transform-tool/crop-preset.svelte
similarity index 100%
rename from web/src/lib/components/asset-viewer/editor/crop-tool/crop-preset.svelte
rename to web/src/lib/components/asset-viewer/editor/transform-tool/crop-preset.svelte
diff --git a/web/src/lib/components/asset-viewer/editor/transform-tool/transform-tool.svelte b/web/src/lib/components/asset-viewer/editor/transform-tool/transform-tool.svelte
new file mode 100644
index 0000000000..e0e22ce8b9
--- /dev/null
+++ b/web/src/lib/components/asset-viewer/editor/transform-tool/transform-tool.svelte
@@ -0,0 +1,131 @@
+
+
+
+
+
{$t('crop')}
+
+
+
+
+
+
+
+
+
+
+
+
+
{$t('editor_crop_tool_h2_rotation')}
+
+
+
+
+
+
+
{$t('editor_crop_tool_h2_mirror')}
+
+
+
+
+
+
diff --git a/web/src/lib/managers/edit/edit-manager.svelte.ts b/web/src/lib/managers/edit/edit-manager.svelte.ts
index 4abcdab1e6..f84c6992e9 100644
--- a/web/src/lib/managers/edit/edit-manager.svelte.ts
+++ b/web/src/lib/managers/edit/edit-manager.svelte.ts
@@ -1,4 +1,4 @@
-import CropTool from '$lib/components/asset-viewer/editor/crop-tool/crop-tool.svelte';
+import TransformTool from '$lib/components/asset-viewer/editor/transform-tool/transform-tool.svelte';
import { transformManager } from '$lib/managers/edit/transform-manager.svelte';
import { waitForWebsocketEvent } from '$lib/stores/websocket';
import { editAsset, removeAssetEdits, type AssetEditsDto, type AssetResponseDto } from '@immich/sdk';
@@ -33,7 +33,7 @@ export class EditManager {
{
type: EditToolType.Transform,
icon: mdiCropRotate,
- component: CropTool,
+ component: TransformTool,
manager: transformManager,
},
];
diff --git a/web/src/lib/managers/edit/transform-manager.svelte.ts b/web/src/lib/managers/edit/transform-manager.svelte.ts
index 79ef640d71..11c9d2371d 100644
--- a/web/src/lib/managers/edit/transform-manager.svelte.ts
+++ b/web/src/lib/managers/edit/transform-manager.svelte.ts
@@ -40,7 +40,7 @@ class TransformManager implements EditToolManager {
cropFrame = $state(null);
cropImageSize = $state([1000, 1000]);
cropImageScale = $state(1);
- cropAspectRatio = $state('free' as CropAspectRatio);
+ cropAspectRatio = $state("free");
region = $state({ x: 0, y: 0, width: 100, height: 100 });
imageRotation = $state(0);
@@ -52,7 +52,7 @@ class TransformManager implements EditToolManager {
edits = $derived.by(() => this.getEdits());
- setAspectRatio(aspectRatio: CropAspectRatio) {
+ setAspectRatio(aspectRatio: string) {
this.cropAspectRatio = aspectRatio;
if (!this.imgElement || !this.cropAreaEl) {
@@ -161,7 +161,7 @@ class TransformManager implements EditToolManager {
this.onImageLoad();
}
- recalculateCrop(aspectRatio: CropAspectRatio = this.cropAspectRatio): CropSettings {
+ recalculateCrop(aspectRatio: string = this.cropAspectRatio): CropSettings {
if (!this.cropAreaEl) {
return this.region;
}
@@ -226,7 +226,7 @@ class TransformManager implements EditToolManager {
requestAnimationFrame(animate);
}
- keepAspectRatio(newWidth: number, newHeight: number, aspectRatio: CropAspectRatio = this.cropAspectRatio) {
+ keepAspectRatio(newWidth: number, newHeight: number, aspectRatio: string = this.cropAspectRatio) {
const [widthRatio, heightRatio] = aspectRatio.split(':').map(Number);
if (widthRatio && heightRatio) {
@@ -240,7 +240,7 @@ class TransformManager implements EditToolManager {
adjustDimensions(
newWidth: number,
newHeight: number,
- aspectRatio: CropAspectRatio,
+ aspectRatio: string,
xLimit: number,
yLimit: number,
minSize: number,
@@ -924,6 +924,16 @@ class TransformManager implements EditToolManager {
this.isInteracting = !toDark;
}
+
+ resetCrop() {
+ this.cropAspectRatio = 'free';
+ this.region = {
+ x: 0,
+ y: 0,
+ width: this.cropImageSize[0] * this.cropImageScale - 1,
+ height: this.cropImageSize[1] * this.cropImageScale - 1,
+ };
+ }
}
export const transformManager = new TransformManager();