Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 48 - Use high resolution assets when possible #52

Merged
merged 5 commits into from
Aug 24, 2023
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 65 additions & 15 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 @@
// 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 = [
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mimetypes supported "natively" by the clipboard API (from the browser)

'image/png',
];
const SUPPORTED_RENDITIONS_FORMATS = [
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renditions mimetypes that we can use in Franklin documents (needed for filtering).

'image/png',
'image/jpeg',
];

let imsInstance = null;
let imsEnvironment = IMS_ENV_PROD;
Expand Down Expand Up @@ -200,9 +207,9 @@
// 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)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only look at mimetypes we can convert to use with the clipboard APIs...

&& (!maxRendition || maxRendition.width < rendition.width)) {
maxRendition = rendition;
}
});
Expand All @@ -227,6 +234,40 @@
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) {

Check failure on line 257 in blocks/aem-asset-selector/aem-asset-selector-util.js

View workflow job for this annotation

GitHub Actions / build

Default parameters should be last

Check failure on line 257 in blocks/aem-asset-selector/aem-asset-selector-util.js

View workflow job for this annotation

GitHub Actions / build

Operator '=' must be spaced
const imageElement = await loadImageIntoHtmlElement(assetPublicUrl);

return new Promise(resolve => {

Check failure on line 260 in blocks/aem-asset-selector/aem-asset-selector-util.js

View workflow job for this annotation

GitHub Actions / build

Expected parentheses around arrow function argument
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 +276,31 @@
* @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 clipboardOptions = {};

Check failure on line 280 in blocks/aem-asset-selector/aem-asset-selector-util.js

View workflow job for this annotation

GitHub Actions / build

'clipboardOptions' is never reassigned. Use 'const' instead

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

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 blob = await binary.blob();
if (!blob) {
throw new Error('No blob provided in asset response');
}
clipboardOptions[mimeType] = blob;
}
const clipboardOptions = {};
clipboardOptions[mimeType] = blob;

const data = [
new ClipboardItem(clipboardOptions),
];

return navigator.clipboard.write(data);
}

Expand Down Expand Up @@ -325,9 +375,9 @@
logMessage('Rendition download JSON not provided');
return false;
}
await copyToClipboardWithBinary(downloadJson.href, downloadJson.type);
await copyToClipboardWithBinary(downloadJson.href, downloadJson.type, asset);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Asset info is needed to give the canvas the proper size

} catch (e) {
logMessage('error copying asset to clipboard', e);
logMessage('Error copying asset using R-API to clipboard', e);
return false;
}

Expand All @@ -352,7 +402,7 @@
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
Loading