Image Optimizer


icon

auto_awesome

name

Imagenie

description

Image optimisation for note publishers.
Do you regularly publish your notes on Amplenote? This plugin is for you.


instructions

Not every reader has access to fast internet, and large images on your published notes take more time to load causing a degraded user experience. Imagenie can help you effortlessly reduce image file sizes on your note without sacrificing quality. Keep readers engaged and make your notes accessible to everyone, regardless of their internet speed.

How to use ?

When you are ready to publish your note, open the note menu and choose the option Imagenie: Optimise Images

The plugin finds the number of large images on your note and offers to optimise them.

Click Proceed to let Imagenie work its magic on your note.

link💻 On Device Optimisation

Image optimisation directly happens on your browser and no data leaves your device ever. We do NOT rely on any third-party services.

link🌟 Image quality

Every image is different and to assure we optimise the image size without losing much on quality, we do not force a fixed compression ratio and let your browser decide the best for each image.

In future we plan to provide additional controls over directly selecting the image quality for the most perseverant publishers out there on Amplenote!

link❗Limitations

Due to the nature of Amplenote's Plugin API, there could be unintentional side effects when this plugin us used on a note with code blocks. Do not use this plugin if your note has any code blocks. While there is no direct solution for this, you can take a copy of your code block and paste it back after running the plugin.

link
🔮Future Plans

In future we plan to provide additional controls where you can directly set the image quality you wish to use for optimisation. More power to the most perseverant publishers out there on Amplenote!

We welcome your comments, suggestions and feedback on Imagenie.


{
noteOption: {
'Optimize Images': async function run(app, noteUUID) {
 
 
console.log("Starting...");
 
const _extractImageURLs = function (noteContent) {
// Regular expression to match image syntax in markdown
const regex = /!\[.*\]\((https?:\/\/.*?)\)/g; // Regex focused on image URLs
const imageUrls = [];
 
let match;
while ((match = regex.exec(noteContent)) !== null) {
console.log(match);
imageUrls.push(match[1]); // Extract only the image URL from the match
 
}
console.log("image urls inside", imageUrls);
return imageUrls;
 
}
const getImageBlobFromUrl = async function (imgUrl) {
try {
const response = await fetch(`https://amplenote-plugins-cors-anywhere.onrender.com/${imgUrl}`);
const blob = await response.blob();
 
return blob;
} catch (error) {
console.error('Error getting image:', error);
throw error; // Re-throw to allow handling at a higher level
}
}
 
const checkIfResizeRequired = function (blob) {
 
console.log("Original size", (blob.size / 1024).toFixed(2));
return blob.size > 500 * 1024; // Check for size exceeding 500 KB
 
}
 
 
const convertToWebp = async function (blob) {
 
const img = new Image();
img.src = await _dataURLFromBlob(blob);
 
await img.decode();
 
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, img.width, img.height);
 
const resizedBlob = await new Promise((resolve, reject) => {
canvas.toBlob((blob) => {
resolve(blob);
}, 'image/webp');
});
 
const convertedSize = (resizedBlob.size / 1024).toFixed(2); // Size in KB
console.log("convertedSize", convertedSize)
return await _dataURLFromBlob(resizedBlob);
 
};
 
 
const _dataURLFromBlob = async function (file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
 
reader.onload = event => {
resolve(event.target.result);
};
 
reader.onerror = function (event) {
reader.abort();
reject(event.target.error);
};
 
reader.readAsDataURL(file);
});
}
 
 
 
 
 
 
 
console.log("above notecontent init")
let noteContent = await app.getNoteContent({ uuid: noteUUID });
console.log(noteContent);
 
const imageUrls = _extractImageURLs(noteContent);
console.log("Image URLs:", imageUrls.length)
 
if (imageUrls.length == 0) {
app.alert("Your note has no images. You can open a different note with images to try Imagenie.", {
preface: "Good to go!",
primaryAction: { label: "OKAY" }
});
return;
}
let blobsToBeResized = [];
 
// Iterate over the image URLs
for (const imgUrl of imageUrls) {
 
const imageBlob = await getImageBlobFromUrl(imgUrl);
if (checkIfResizeRequired(imageBlob))
blobsToBeResized.push({blob: imageBlob, url: imgUrl});
}
 
if (blobsToBeResized.length == 0) {
app.alert("Your note has no large images. You can open a different note with large images to try Imagenie.", {
preface: "Good to go!",
primaryAction: { label: "OKAY" }
});
return;
}
 
const actionIndex = await app.alert(`Your note has ${blobsToBeResized.length} large image(s) that can be optimized. Do you want to continue?`, {
preface: "Let's optimize!",
primaryAction: { label: "PROCEED" }
});
 
console.log(actionIndex);
if (actionIndex !== -1)
return;
 
for (const obj of blobsToBeResized) {
//const resizedDataUrl = await resizeWithResmush(imageFile, 500 * 1024);
const resizedDataUrl = await convertToWebp(obj.blob);
//console.log("resized data url", resizedDataUrl);
const resizedImgUrl = await app.attachNoteMedia({ uuid: noteUUID }, resizedDataUrl);
 
// Replace the old image URL with the new one in the note content
noteContent = noteContent.replace(new RegExp(obj.url, 'g'), resizedImgUrl);
}
 
// Update the note content
await app.replaceNoteContent({ uuid: noteUUID }, noteContent);
 
app.alert("Optimization Complete.", {
preface: "Pixel perfect!",
primaryAction: { label: "AWESOME" }
});
 
}
}
}