forked from Cutlery/immich
		
	fix(web): create face from video (#5544)
* fix: create face from video * fix: remove comment * fix: inaccurate bounding boxes
This commit is contained in:
		
							parent
							
								
									e4b24b6e04
								
							
						
					
					
						commit
						bc65bbfcc4
					
				@ -635,6 +635,7 @@
 | 
				
			|||||||
{#if showEditFaces}
 | 
					{#if showEditFaces}
 | 
				
			||||||
  <PersonSidePanel
 | 
					  <PersonSidePanel
 | 
				
			||||||
    assetId={asset.id}
 | 
					    assetId={asset.id}
 | 
				
			||||||
 | 
					    assetType={asset.type}
 | 
				
			||||||
    on:close={() => {
 | 
					    on:close={() => {
 | 
				
			||||||
      showEditFaces = false;
 | 
					      showEditFaces = false;
 | 
				
			||||||
    }}
 | 
					    }}
 | 
				
			||||||
 | 
				
			|||||||
@ -143,7 +143,7 @@
 | 
				
			|||||||
      />
 | 
					      />
 | 
				
			||||||
      {#each getBoundingBox($boundingBoxesArray, $photoZoomState, $photoViewer) as boundingbox}
 | 
					      {#each getBoundingBox($boundingBoxesArray, $photoZoomState, $photoViewer) as boundingbox}
 | 
				
			||||||
        <div
 | 
					        <div
 | 
				
			||||||
          class="absolute border-solid border-white border-[3px] rounded-lg p-3"
 | 
					          class="absolute border-solid border-white border-[3px] rounded-lg"
 | 
				
			||||||
          style="top: {boundingbox.top}px; left: {boundingbox.left}px; height: {boundingbox.height}px; width: {boundingbox.width}px;"
 | 
					          style="top: {boundingbox.top}px; left: {boundingbox.left}px; height: {boundingbox.height}px; width: {boundingbox.width}px;"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      {/each}
 | 
					      {/each}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
  import { api, type AssetFaceResponseDto, type PersonResponseDto } from '@api';
 | 
					  import { api, AssetTypeEnum, type AssetFaceResponseDto, type PersonResponseDto, ThumbnailFormat } from '@api';
 | 
				
			||||||
  import { createEventDispatcher } from 'svelte';
 | 
					  import { createEventDispatcher } from 'svelte';
 | 
				
			||||||
  import { linear } from 'svelte/easing';
 | 
					  import { linear } from 'svelte/easing';
 | 
				
			||||||
  import { fly } from 'svelte/transition';
 | 
					  import { fly } from 'svelte/transition';
 | 
				
			||||||
@ -14,6 +14,8 @@
 | 
				
			|||||||
  export let peopleWithFaces: AssetFaceResponseDto[];
 | 
					  export let peopleWithFaces: AssetFaceResponseDto[];
 | 
				
			||||||
  export let allPeople: PersonResponseDto[];
 | 
					  export let allPeople: PersonResponseDto[];
 | 
				
			||||||
  export let editedPersonIndex: number;
 | 
					  export let editedPersonIndex: number;
 | 
				
			||||||
 | 
					  export let assetType: AssetTypeEnum;
 | 
				
			||||||
 | 
					  export let assetId: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // loading spinners
 | 
					  // loading spinners
 | 
				
			||||||
  let isShowLoadingNewPerson = false;
 | 
					  let isShowLoadingNewPerson = false;
 | 
				
			||||||
@ -31,23 +33,38 @@
 | 
				
			|||||||
    dispatch('close');
 | 
					    dispatch('close');
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  const zoomImageToBase64 = async (face: AssetFaceResponseDto): Promise<string | null> => {
 | 
					  const zoomImageToBase64 = async (face: AssetFaceResponseDto): Promise<string | null> => {
 | 
				
			||||||
    if ($photoViewer === null) {
 | 
					    let image: HTMLImageElement | null = null;
 | 
				
			||||||
 | 
					    if (assetType === AssetTypeEnum.Image) {
 | 
				
			||||||
 | 
					      image = $photoViewer;
 | 
				
			||||||
 | 
					    } else if (assetType === AssetTypeEnum.Video) {
 | 
				
			||||||
 | 
					      const data = await api.getAssetThumbnailUrl(assetId, ThumbnailFormat.Webp);
 | 
				
			||||||
 | 
					      const img: HTMLImageElement = new Image();
 | 
				
			||||||
 | 
					      img.src = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await new Promise<void>((resolve) => {
 | 
				
			||||||
 | 
					        img.onload = () => resolve();
 | 
				
			||||||
 | 
					        img.onerror = () => resolve();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      image = img;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (image === null) {
 | 
				
			||||||
      return null;
 | 
					      return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const { boundingBoxX1: x1, boundingBoxX2: x2, boundingBoxY1: y1, boundingBoxY2: y2 } = face;
 | 
					    const { boundingBoxX1: x1, boundingBoxX2: x2, boundingBoxY1: y1, boundingBoxY2: y2 } = face;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const coordinates = {
 | 
					    const coordinates = {
 | 
				
			||||||
      x1: ($photoViewer.naturalWidth / face.imageWidth) * x1,
 | 
					      x1: (image.naturalWidth / face.imageWidth) * x1,
 | 
				
			||||||
      x2: ($photoViewer.naturalWidth / face.imageWidth) * x2,
 | 
					      x2: (image.naturalWidth / face.imageWidth) * x2,
 | 
				
			||||||
      y1: ($photoViewer.naturalHeight / face.imageHeight) * y1,
 | 
					      y1: (image.naturalHeight / face.imageHeight) * y1,
 | 
				
			||||||
      y2: ($photoViewer.naturalHeight / face.imageHeight) * y2,
 | 
					      y2: (image.naturalHeight / face.imageHeight) * y2,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const faceWidth = coordinates.x2 - coordinates.x1;
 | 
					    const faceWidth = coordinates.x2 - coordinates.x1;
 | 
				
			||||||
    const faceHeight = coordinates.y2 - coordinates.y1;
 | 
					    const faceHeight = coordinates.y2 - coordinates.y1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const faceImage = new Image();
 | 
					    const faceImage = new Image();
 | 
				
			||||||
    faceImage.src = $photoViewer.src;
 | 
					    faceImage.src = image.src;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await new Promise((resolve) => {
 | 
					    await new Promise((resolve) => {
 | 
				
			||||||
      faceImage.onload = resolve;
 | 
					      faceImage.onload = resolve;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
  import { fly } from 'svelte/transition';
 | 
					  import { fly } from 'svelte/transition';
 | 
				
			||||||
  import { linear } from 'svelte/easing';
 | 
					  import { linear } from 'svelte/easing';
 | 
				
			||||||
  import { api, type PersonResponseDto, AssetFaceResponseDto } from '@api';
 | 
					  import { api, type PersonResponseDto, AssetFaceResponseDto, AssetTypeEnum } from '@api';
 | 
				
			||||||
  import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
 | 
					  import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
 | 
				
			||||||
  import { handleError } from '$lib/utils/handle-error';
 | 
					  import { handleError } from '$lib/utils/handle-error';
 | 
				
			||||||
  import { createEventDispatcher, onMount } from 'svelte';
 | 
					  import { createEventDispatcher, onMount } from 'svelte';
 | 
				
			||||||
@ -15,6 +15,7 @@
 | 
				
			|||||||
  import { getPersonNameWithHiddenValue } from '$lib/utils/person';
 | 
					  import { getPersonNameWithHiddenValue } from '$lib/utils/person';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let assetId: string;
 | 
					  export let assetId: string;
 | 
				
			||||||
 | 
					  export let assetType: AssetTypeEnum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // keep track of the changes
 | 
					  // keep track of the changes
 | 
				
			||||||
  let numberOfPersonToCreate: string[] = [];
 | 
					  let numberOfPersonToCreate: string[] = [];
 | 
				
			||||||
@ -271,6 +272,8 @@
 | 
				
			|||||||
    {peopleWithFaces}
 | 
					    {peopleWithFaces}
 | 
				
			||||||
    {allPeople}
 | 
					    {allPeople}
 | 
				
			||||||
    {editedPersonIndex}
 | 
					    {editedPersonIndex}
 | 
				
			||||||
 | 
					    {assetType}
 | 
				
			||||||
 | 
					    {assetId}
 | 
				
			||||||
    on:close={() => (showSeletecFaces = false)}
 | 
					    on:close={() => (showSeletecFaces = false)}
 | 
				
			||||||
    on:createPerson={(event) => handleCreatePerson(event.detail)}
 | 
					    on:createPerson={(event) => handleCreatePerson(event.detail)}
 | 
				
			||||||
    on:reassign={(event) => handleReassignFace(event.detail)}
 | 
					    on:reassign={(event) => handleReassignFace(event.detail)}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user