Skip to content

Commit

Permalink
Load high res assets into clipboard
Browse files Browse the repository at this point in the history
  • Loading branch information
tmathern committed Aug 23, 2023
1 parent e056736 commit b0a4c0d
Showing 1 changed file with 83 additions and 21 deletions.
104 changes: 83 additions & 21 deletions blocks/aem-asset-selector/aem-asset-selector-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ const REL_RENDITIONS = 'http://ns.adobe.com/adobecloud/rel/rendition';
// TODO: change this to Asset Link IMS client ID
const IMS_CLIENT_ID = 'p66302-franklin';
const ASSET_SELECTOR_ID = 'asset-selector';
const CLIPBOARD_SUPPORTED_BINARY_MIMETYPES = [
'image/png',
];
const SUPPORTED_RENDITIONS_FORMATS = [
'image/png',
'image/jpeg',
];

let imsInstance = null;
let imsEnvironment = IMS_ENV_PROD;
Expand Down Expand Up @@ -200,12 +207,16 @@ function getCopyRendition(asset) {
// TODO: the clipboard API only supports using PNGs as the blob, so
// only using PNG renditions. Will be fixed to allow altnernate
// formats in a follow-up ticket
.filter((rendition) => rendition.type === 'image/png')
.forEach((rendition) => {
if ((!maxRendition || maxRendition.width < rendition.width)) {
if (SUPPORTED_RENDITIONS_FORMATS.includes(rendition.type)
&& (!maxRendition || maxRendition.width < rendition.width)) {
maxRendition = rendition;
}
});

console.log("~~~~~~~~~ Picked rendition: ")
console.log(maxRendition)
console.log("~~~~~~~~~ ")
return maxRendition;
}

Expand All @@ -227,6 +238,42 @@ async function copyToClipboardWithHtml(assetPublicUrl) {
return navigator.clipboard.write(data);
}

async function loadImageIntoHtmlElement(url) {
return new Promise((resolve, reject) => {
const img = new Image();
/*
crossorigin needs to be anonymous to allow the future canvas export,
otherwise the canvas will be considered tainted and the export will fail
*/
img.setAttribute('crossorigin', 'anonymous');
img.addEventListener('load', () => resolve(img));
img.addEventListener('error', (err) => reject(err));
img.src = url;
});
}

/**
* Convert an image using an URL to a another image format
* @param {*} assetPublicUrl Public asset URL
* @param {*} targetMimeType Target mimetype (target format)
* @returns A conversion promise resolving to a blob of the target mimetype
*/
async function convertImage(assetPublicUrl, targetMimeType='image/png', asset) {
const main = document.querySelector('main');
const imageElement = await loadImageIntoHtmlElement(assetPublicUrl);

console.log('## convertImage: ', assetPublicUrl)
return new Promise(resolve => {
const canvas = document.createElement('canvas');
canvas.width = asset['tiff:imageWidth'];
canvas.height = asset['tiff:imageLength'];

const context = canvas.getContext('2d');
context.drawImage(imageElement, 0, 0);
canvas.toBlob(resolve, targetMimeType);
});
}

/**
* Uses the navigator global object to write a clipboard item to the clipboard.
* The clipboard item's content will be a Blob containing the image binary from
Expand All @@ -235,22 +282,37 @@ async function copyToClipboardWithHtml(assetPublicUrl) {
* @param {string} mimeType Content type of the image being retrieved.
* @returns {Promise} Resolves when the item has been written to the clipboard.
*/
async function copyToClipboardWithBinary(assetPublicUrl, mimeType) {
const binary = await fetch(assetPublicUrl);
async function copyToClipboardWithBinary(assetPublicUrl, mimeType, asset) {
let data;
console.log("## copyToClipboardWithBinary")
console.log(mimeType);
if (!CLIPBOARD_SUPPORTED_BINARY_MIMETYPES.includes(mimeType)) {
const copiedBlob = await convertImage(assetPublicUrl, 'image/png', asset);

if (!binary || !binary.ok) {
throw new Error(`Unexpected status code ${binary.status} retrieving asset binary`);
}
const clipboardOptions = {};
clipboardOptions['image/png'] = copiedBlob;
data = [
new ClipboardItem(clipboardOptions),
];
} else {
const binary = await fetch(assetPublicUrl);

const blob = await binary.blob();
if (!blob) {
throw new Error('No blob provided in asset response');
if (!binary || !binary.ok) {
throw new Error(`Unexpected status code ${binary.status} retrieving asset binary`);
}

const blob = await binary.blob();
if (!blob) {
throw new Error('No blob provided in asset response');
}

const clipboardOptions = {};
clipboardOptions[mimeType] = blob;
data = [
new ClipboardItem(clipboardOptions),
];
}
const clipboardOptions = {};
clipboardOptions[mimeType] = blob;
const data = [
new ClipboardItem(clipboardOptions),
];

return navigator.clipboard.write(data);
}

Expand Down Expand Up @@ -306,7 +368,7 @@ export async function copyAssetWithRapi(asset) {
}
const download = getRel(rendition, REL_DOWNLOAD);
if (!download || !download.href) {
logMessage('Rendition does not contain sufficient information');
console.log('Rendition does not contain sufficient information');
return false;
}
try {
Expand All @@ -317,17 +379,17 @@ export async function copyAssetWithRapi(asset) {
},
});
if (!res.ok) {
logMessage(`Download request for rendition binary failed with status code ${res.status}: ${res.statusText}`);
console.log(`Download request for rendition binary failed with status code ${res.status}: ${res.statusText}`);
return false;
}
const downloadJson = await res.json();
if (!downloadJson) {
logMessage('Rendition download JSON not provided');
console.log('Rendition download JSON not provided');
return false;
}
await copyToClipboardWithBinary(downloadJson.href, downloadJson.type);
await copyToClipboardWithBinary(downloadJson.href, downloadJson.type, asset);
} catch (e) {
logMessage('error copying asset to clipboard', e);
console.log('Error copying asset using R-API to clipboard', e);
return false;
}

Expand All @@ -352,7 +414,7 @@ function getAssetSelector() {
function handleAssetSelection(selection, cfg) {
if (cfg) {
if (selection.length && cfg.onAssetSelected) {
if (selection.length > 0) {
if (selection.length > 1) {
logMessage('Multiple items received in selection, but only the first will be used');
}
cfg.onAssetSelected(selection[0]);
Expand Down

0 comments on commit b0a4c0d

Please sign in to comment.