mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
feat: image editing (#24155)
This commit is contained in:
@@ -28,6 +28,7 @@ import { AlbumUserTable } from 'src/schema/tables/album-user.table';
|
||||
import { AlbumTable } from 'src/schema/tables/album.table';
|
||||
import { ApiKeyTable } from 'src/schema/tables/api-key.table';
|
||||
import { AssetAuditTable } from 'src/schema/tables/asset-audit.table';
|
||||
import { AssetEditTable } from 'src/schema/tables/asset-edit.table';
|
||||
import { AssetExifTable } from 'src/schema/tables/asset-exif.table';
|
||||
import { AssetFaceAuditTable } from 'src/schema/tables/asset-face-audit.table';
|
||||
import { AssetFaceTable } from 'src/schema/tables/asset-face.table';
|
||||
@@ -86,6 +87,7 @@ export class ImmichDatabase {
|
||||
AlbumTable,
|
||||
ApiKeyTable,
|
||||
AssetAuditTable,
|
||||
AssetEditTable,
|
||||
AssetFaceTable,
|
||||
AssetFaceAuditTable,
|
||||
AssetMetadataTable,
|
||||
@@ -179,6 +181,7 @@ export interface DB {
|
||||
|
||||
asset: AssetTable;
|
||||
asset_audit: AssetAuditTable;
|
||||
asset_edit: AssetEditTable;
|
||||
asset_exif: AssetExifTable;
|
||||
asset_face: AssetFaceTable;
|
||||
asset_face_audit: AssetFaceAuditTable;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Kysely, sql } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await sql`ALTER TABLE "asset" ADD COLUMN "width" integer;`.execute(db);
|
||||
await sql`ALTER TABLE "asset" ADD COLUMN "height" integer;`.execute(db);
|
||||
|
||||
// Populate width and height from exif data with orientation-aware swapping
|
||||
await sql`
|
||||
UPDATE "asset"
|
||||
SET
|
||||
"width" = CASE
|
||||
WHEN "asset_exif"."orientation" IN ('5', '6', '7', '8', '-90', '90') THEN "asset_exif"."exifImageHeight"
|
||||
ELSE "asset_exif"."exifImageWidth"
|
||||
END,
|
||||
"height" = CASE
|
||||
WHEN "asset_exif"."orientation" IN ('5', '6', '7', '8', '-90', '90') THEN "asset_exif"."exifImageWidth"
|
||||
ELSE "asset_exif"."exifImageHeight"
|
||||
END
|
||||
FROM "asset_exif"
|
||||
WHERE "asset"."id" = "asset_exif"."assetId"
|
||||
AND ("asset_exif"."exifImageWidth" IS NOT NULL OR "asset_exif"."exifImageHeight" IS NOT NULL)
|
||||
`.execute(db);
|
||||
}
|
||||
|
||||
export async function down(db: Kysely<any>): Promise<void> {
|
||||
await sql`ALTER TABLE "asset" DROP COLUMN "width";`.execute(db);
|
||||
await sql`ALTER TABLE "asset" DROP COLUMN "height";`.execute(db);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Kysely, sql } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await sql`
|
||||
CREATE TABLE "asset_edit" (
|
||||
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||
"assetId" uuid NOT NULL,
|
||||
"action" varchar NOT NULL,
|
||||
"parameters" jsonb NOT NULL
|
||||
);
|
||||
`.execute(db);
|
||||
|
||||
await sql`ALTER TABLE "asset_edit" ADD CONSTRAINT "asset_edit_pkey" PRIMARY KEY ("id");`.execute(db);
|
||||
await sql`ALTER TABLE "asset_edit" ADD CONSTRAINT "asset_edit_assetId_fkey" FOREIGN KEY ("assetId") REFERENCES "asset" ("id") ON UPDATE CASCADE ON DELETE CASCADE;`.execute(
|
||||
db,
|
||||
);
|
||||
await sql`CREATE INDEX "asset_edit_assetId_idx" ON "asset_edit" ("assetId")`.execute(db);
|
||||
}
|
||||
|
||||
export async function down(db: Kysely<any>): Promise<void> {
|
||||
await sql`DROP TABLE IF EXISTS "asset_edit";`.execute(db);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Kysely, sql } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await sql`ALTER TABLE "asset_ocr" ADD COLUMN "isVisible" boolean NOT NULL DEFAULT TRUE`.execute(db);
|
||||
await sql`ALTER TABLE "asset_face" ADD COLUMN "isVisible" boolean NOT NULL DEFAULT TRUE`.execute(db);
|
||||
}
|
||||
|
||||
export async function down(db: Kysely<any>): Promise<void> {
|
||||
await sql`ALTER TABLE "asset_ocr" DROP COLUMN "isVisible";`.execute(db);
|
||||
await sql`ALTER TABLE "asset_face" DROP COLUMN "isVisible";`.execute(db);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { AssetEditAction, AssetEditActionParameter } from 'src/dtos/editing.dto';
|
||||
import { AssetTable } from 'src/schema/tables/asset.table';
|
||||
import { Column, ForeignKeyColumn, Generated, PrimaryGeneratedColumn } from 'src/sql-tools';
|
||||
|
||||
export class AssetEditTable<T extends AssetEditAction = AssetEditAction> {
|
||||
@PrimaryGeneratedColumn()
|
||||
id!: Generated<string>;
|
||||
|
||||
@ForeignKeyColumn(() => AssetTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false })
|
||||
assetId!: string;
|
||||
|
||||
@Column()
|
||||
action!: T;
|
||||
|
||||
@Column({ type: 'jsonb' })
|
||||
parameters!: AssetEditActionParameter[T];
|
||||
}
|
||||
@@ -78,4 +78,7 @@ export class AssetFaceTable {
|
||||
|
||||
@UpdateIdColumn()
|
||||
updateId!: Generated<string>;
|
||||
|
||||
@Column({ type: 'boolean', default: true })
|
||||
isVisible!: Generated<boolean>;
|
||||
}
|
||||
|
||||
@@ -42,4 +42,7 @@ export class AssetOcrTable {
|
||||
|
||||
@Column({ type: 'text' })
|
||||
text!: string;
|
||||
|
||||
@Column({ type: 'boolean', default: true })
|
||||
isVisible!: Generated<boolean>;
|
||||
}
|
||||
|
||||
@@ -137,4 +137,10 @@ export class AssetTable {
|
||||
|
||||
@Column({ enum: asset_visibility_enum, default: AssetVisibility.Timeline })
|
||||
visibility!: Generated<AssetVisibility>;
|
||||
|
||||
@Column({ type: 'integer', nullable: true })
|
||||
width!: number | null;
|
||||
|
||||
@Column({ type: 'integer', nullable: true })
|
||||
height!: number | null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user