Personal-Site/markdown-it-image-size.js

111 lines
2.8 KiB
JavaScript

const imageSize = require("image-size");
const markdownIt = require("markdown-it");
const fetch = require("sync-fetch");
function markdownItImageSize(md) {
md.renderer.rules.image = (tokens, index, options, env) => {
const token = tokens[index];
const srcIndex = token.attrIndex("src");
const imageUrl = token.attrs[srcIndex][1];
const caption = md.utils.escapeHtml(token.content);
const otherAttributes = generateAttributes(md, token);
const isExternalImage =
imageUrl.startsWith("http://") ||
imageUrl.startsWith("https://") ||
imageUrl.startsWith("//");
const isLocalAbsoluteUrl = imageUrl.startsWith("/");
let { width, height } = isExternalImage
? getImageDimensionsFromExternalImage(imageUrl)
: getImageDimensions(`${isLocalAbsoluteUrl ? "./src" : ""}${imageUrl}`);
let imageFileName = imageUrl
.replaceAll("\\", "/")
.split("/")
.pop();
let scaleMatches = Array.from(imageFileName.matchAll(/_([0-9])x/g));
if (scaleMatches.length > 0){
let scale = scaleMatches.pop()[1];
width = width / scale;
height = height / scale;
}
const dimensionsAttributes = width && height
? ` width="${width}" height="${height}"`
: "";
return `<img src="${imageUrl}" alt="${caption}"${dimensionsAttributes}${
otherAttributes ? " " + otherAttributes : ""
}>`;
};
}
function generateAttributes(md, token) {
const ignore = ["src", "alt"];
const escape = ["title"];
return token.attrs
.filter(([key]) => !ignore.includes(key))
.map(([key, value]) => {
const escapeAttributeValue = escape.includes(key);
const finalValue = escapeAttributeValue
? md.utils.escapeHtml(value)
: value;
return `${key}="${finalValue}"`;
})
.join(" ");
}
const customPluginDefaults = {
getAbsPathFromEnv: (env) => {
const markdownPath = env?.page?.inputPath; // 11ty
if (markdownPath) {
return markdownPath
.substring(0, markdownPath.lastIndexOf("/"))
.replace(/\/\.\//g, "/");
}
return undefined;
},
};
function getImageDimensions(imageUrl, env) {
try {
const { width, height } = imageSize(imageUrl);
return { width, height };
} catch (error) {
const isRelativePath = !imageUrl.startsWith("/");
const inputPath = customPluginDefaults.getAbsPathFromEnv(env);
if (isRelativePath && inputPath) {
return getImageDimensions(`${inputPath}/${imageUrl}`);
}
console.error(
`markdown-it-image-size: Could not get dimensions of image with url ${imageUrl}.\n\n`,
error,
);
return { width: undefined, height: undefined };
}
}
function getImageDimensionsFromExternalImage(imageUrl) {
const isMissingProtocol = imageUrl.startsWith("//");
const response = fetch(isMissingProtocol ? `https:${imageUrl}` : imageUrl);
const buffer = response.buffer();
const { width, height } = imageSize(buffer);
return { width, height };
}
exports.markdownItImageSize = markdownItImageSize;