fix(web): only copy images via canvas (#22225)

This commit is contained in:
Jason Rasmussen 2025-09-21 15:34:10 -04:00 committed by GitHub
parent afc4085b55
commit 0bbeb20595
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 8 additions and 34 deletions

View file

@ -920,7 +920,6 @@
"cant_get_number_of_comments": "Can't get number of comments",
"cant_search_people": "Can't search people",
"cant_search_places": "Can't search places",
"clipboard_unsupported_mime_type": "The system clipboard does not support copying this type of content: {mimeType}",
"error_adding_assets_to_album": "Error adding assets to album",
"error_adding_users_to_album": "Error adding users to album",
"error_deleting_shared_user": "Error deleting shared user",

View file

@ -23,6 +23,7 @@
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { AppRoute } from '$lib/constants';
import { photoViewerImgElement } from '$lib/stores/assets-store.svelte';
import { featureFlags } from '$lib/stores/server-config.store';
import { user } from '$lib/stores/user.store';
import { photoZoomState } from '$lib/stores/zoom-image.store';
@ -151,7 +152,7 @@
onclick={onZoomImage}
/>
{/if}
{#if canCopyImageToClipboard() && asset.type === AssetTypeEnum.Image}
{#if canCopyImageToClipboard() && asset.type === AssetTypeEnum.Image && $photoViewerImgElement}
<IconButton
color="secondary"
variant="ghost"

View file

@ -92,20 +92,13 @@
};
copyImage = async () => {
if (!canCopyImageToClipboard()) {
if (!canCopyImageToClipboard() || !$photoViewerImgElement) {
return;
}
try {
const result = await copyImageToClipboard($photoViewerImgElement ?? assetFileUrl);
if (result.success) {
notificationController.show({ type: NotificationType.Info, message: $t('copied_image_to_clipboard') });
} else {
notificationController.show({
type: NotificationType.Error,
message: $t('errors.clipboard_unsupported_mime_type', { values: { mimeType: result.mimeType } }),
});
}
await copyImageToClipboard($photoViewerImgElement);
notificationController.show({ type: NotificationType.Info, message: $t('copied_image_to_clipboard') });
} catch (error) {
handleError(error, $t('copy_error'));
}

View file

@ -620,26 +620,7 @@ const imgToBlob = async (imageElement: HTMLImageElement) => {
throw new Error('Canvas context is null');
};
const urlToBlob = async (imageSource: string) => {
const response = await fetch(imageSource);
return await response.blob();
};
export const copyImageToClipboard = async (
source: HTMLImageElement | string,
): Promise<{ success: true } | { success: false; mimeType: string }> => {
if (source instanceof HTMLImageElement) {
// do not await, so the Safari clipboard write happens in the context of the user gesture
await navigator.clipboard.write([new ClipboardItem({ ['image/png']: imgToBlob(source) })]);
return { success: true };
}
// if we had a way to get the mime type synchronously, we could do the same thing here
const blob = await urlToBlob(source);
if (!ClipboardItem.supports(blob.type)) {
return { success: false, mimeType: blob.type };
}
await navigator.clipboard.write([new ClipboardItem({ [blob.type]: blob })]);
return { success: true };
export const copyImageToClipboard = async (source: HTMLImageElement) => {
// do not await, so the Safari clipboard write happens in the context of the user gesture
await navigator.clipboard.write([new ClipboardItem({ ['image/png']: imgToBlob(source) })]);
};