fix: Add copy to clipboard option for capture (#5720)
* Add copy to clipboard option for capture * PR comments * Added toast feedback and updated labels --------- Co-authored-by: Dan Rukas <dan.rukas@gmail.com>
This commit is contained in:
parent
c85ca0e177
commit
53c67f3612
@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { ImageModal, FooterAction } from '@ohif/ui-next';
|
||||
import { ImageModal, FooterAction, toast } from '@ohif/ui-next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
const MAX_TEXTURE_SIZE = 10000;
|
||||
const DEFAULT_FILENAME = 'image';
|
||||
@ -16,6 +16,7 @@ interface ViewportDownloadFormNewProps {
|
||||
onEnableViewport: (element: HTMLElement) => void;
|
||||
onDisableViewport: () => void;
|
||||
onDownload: (filename: string, fileType: string) => void;
|
||||
onCopyToClipboard: () => void;
|
||||
warningState: { enabled: boolean; value: string };
|
||||
}
|
||||
|
||||
@ -32,6 +33,7 @@ function ViewportDownloadFormNew({
|
||||
onEnableViewport,
|
||||
onDisableViewport,
|
||||
onDownload,
|
||||
onCopyToClipboard,
|
||||
}: ViewportDownloadFormNewProps) {
|
||||
const [viewportElement, setViewportElement] = useState<HTMLElement | null>(null);
|
||||
const [showWarningMessage, setShowWarningMessage] = useState(true);
|
||||
@ -138,13 +140,27 @@ function ViewportDownloadFormNew({
|
||||
<FooterAction.Secondary onClick={onClose}>
|
||||
{t('Common:Cancel')}
|
||||
</FooterAction.Secondary>
|
||||
<FooterAction.Secondary
|
||||
onClick={async () => {
|
||||
try {
|
||||
await onCopyToClipboard();
|
||||
toast.success(t('Image copied to clipboard'));
|
||||
onClose();
|
||||
} catch (error) {
|
||||
toast.error(t('Failed to copy image to clipboard'));
|
||||
console.error('Failed to copy to clipboard:', error);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('Copy to Clipboard')}
|
||||
</FooterAction.Secondary>
|
||||
<FooterAction.Primary
|
||||
onClick={() => {
|
||||
onDownload(filename || DEFAULT_FILENAME, fileType);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t('Common:Save')}
|
||||
{t('Save Image')}
|
||||
</FooterAction.Primary>
|
||||
</FooterAction.Right>
|
||||
</FooterAction>
|
||||
|
||||
@ -118,16 +118,20 @@ const CornerstoneViewportDownloadForm = ({
|
||||
const downloadViewport = renderingEngine.getViewport(VIEWPORT_ID);
|
||||
|
||||
try {
|
||||
const properties = viewport.getProperties();
|
||||
if (downloadViewport instanceof StackViewport) {
|
||||
const imageId = viewport.getCurrentImageId();
|
||||
const properties = viewport.getProperties();
|
||||
|
||||
await downloadViewport.setStack([imageId]);
|
||||
downloadViewport.setProperties(properties);
|
||||
} else if (downloadViewport instanceof BaseVolumeViewport) {
|
||||
const volumeIds = viewport.getAllVolumeIds();
|
||||
downloadViewport.setVolumes([{ volumeId: volumeIds[0] }]);
|
||||
await downloadViewport.setVolumes([{ volumeId: volumeIds[0] }]);
|
||||
}
|
||||
downloadViewport.setProperties(properties);
|
||||
const viewRef = viewport.getViewReference();
|
||||
downloadViewport.setViewReference(viewRef);
|
||||
downloadViewport.render();
|
||||
|
||||
if (segmentationRepresentations?.length) {
|
||||
segmentationRepresentations.forEach(segRepresentation => {
|
||||
@ -230,6 +234,48 @@ const CornerstoneViewportDownloadForm = ({
|
||||
downloadUrl(canvas.toDataURL(`image/${fileType}`, 1.0), { filename });
|
||||
};
|
||||
|
||||
const handleCopyToClipboard = async () => {
|
||||
const divForDownloadViewport = document.querySelector(
|
||||
`div[data-viewport-uid="${VIEWPORT_ID}"]`
|
||||
);
|
||||
|
||||
if (!divForDownloadViewport) {
|
||||
console.debug('No viewport found for copy');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const canvas = await html2canvas(divForDownloadViewport as HTMLElement);
|
||||
|
||||
// Clipboard API only supports PNG format in most browsers
|
||||
const blob = await new Promise<Blob>((resolve, reject) => {
|
||||
canvas.toBlob(
|
||||
blob => {
|
||||
if (blob) {
|
||||
resolve(blob);
|
||||
} else {
|
||||
reject(new Error('Failed to create blob from canvas'));
|
||||
}
|
||||
},
|
||||
'image/png',
|
||||
1.0
|
||||
);
|
||||
});
|
||||
|
||||
// Copy to clipboard using the Clipboard API
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
'image/png': blob,
|
||||
}),
|
||||
]);
|
||||
|
||||
console.log('Image copied to clipboard successfully');
|
||||
} catch (error) {
|
||||
console.error('Failed to copy image to clipboard:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const ViewportDownloadFormNew = customizationService.getCustomization(
|
||||
'ohif.captureViewportModal'
|
||||
);
|
||||
@ -247,6 +293,7 @@ const CornerstoneViewportDownloadForm = ({
|
||||
onEnableViewport={handleEnableViewport}
|
||||
onDisableViewport={handleDisableViewport}
|
||||
onDownload={handleDownload}
|
||||
onCopyToClipboard={handleCopyToClipboard}
|
||||
warningState={warningState}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
{
|
||||
"Copy to Clipboard": "Copy Image",
|
||||
"File name": "File name",
|
||||
"Image size": "Image size",
|
||||
"Image size in pixels": "Image size in pixels",
|
||||
"Include annotations": "Include annotations",
|
||||
"Include warning message": "Include warning message",
|
||||
"Width": "Width",
|
||||
"Height": "Height"
|
||||
"Height": "Height",
|
||||
"Save Image": "Save Image",
|
||||
"Image copied to clipboard": "Image copied to clipboard",
|
||||
"Failed to copy image to clipboard": "Failed to copy image to clipboard"
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"Capture": "Capture",
|
||||
"Copy to Clipboard": "Copier dans le presse-papiers",
|
||||
"Cancel": "$t(Common:Cancel)",
|
||||
"Download": "$t(Common:Download)",
|
||||
"Image size": "Taille de l'image",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user