Add thumbnails to Markdown

Add thumbnails to Markdown

Markdown is a text format that allows inclusion of links to other documents. However, many people would not only like to see a link of a document, but also an image. With Quicklook, macOS provides a function that allows to take a quick peek at a document in the Finder. The same technique can be used to generate a thumbnail of a linked document and paste it into a Markdown file.

The idea behind the function shown below is simple: A Markdown file can contain any valid HTML code. So one can insert an img element with a data URL: That is an URL which embeds the image data directly into the img element.

Beware: The resulting Markdown file will be a lot bigger than without the images, and it might become a bit weird to work with, since the images are basically huge blobs of unintelligible text.

The inverse process, namely extracting embedded documents (images, PDF etc.) from an HTML file, is described in the section Extract embedded data from Evernote files.

function getDataURL(path) {
  /* Take the path to a file and return a Quicklook thumbnail */
ObjC.import("Foundation");
ObjC.import('QuickLook');
ObjC.import('AppKit');

/* Get the path as URL */
const pathURL = $.NSURL.fileURLWithPath(path);
if (!pathURL) {
  return null;
}
  
/* Create the Quicklook thumbnail with 
 * maximum dimensions 300 by 400 pixels.
 * You might want to go with a smaller image 
*/
const qlThumb = $.QLThumbnailImageCreate($.kCFAllocatorDefault, 
    pathURL, $.CGSizeMake(300,400), {});

if (!qlThumb) {
  return null;
}
/* Convert the thumbnail to Bitmap */
const bitMap = $.NSBitmapImageRep.alloc.initWithCGImage(qlThumb);

  /* Convert Bitmap to PNG */
const pngData = bitMap.representationUsingTypeProperties(
    $.NSPNGFileType,{});
const b64 = 'data:image/png;base64,' +
    ObjC.unwrap(pngData.base64EncodedStringWithOptions(0));
return(b64);
}

In your main script, you’d go over the content of a markdown file and find all links to files, pass the file’s path to getDataURL() and add the returned data URL to your markdown file. An example might look like this

function addDataURLs(text) {
  let start = 0;
  let newText = '';
  /* Regular expression to extract all MD links 
    possibly starting with a ! indicating an image */
  const linkRE = /!?\[.*?\]\((.*?)\)/g;
  const linkMatches = [...text.matchAll(linkRE)];
  linkMatches.forEach(match => {
    /* get the data URL for this link */
    const dataURL = getDataURL(match[1]);
    if (dataURL) {
      /* Add an img element with the data URL to the link
       and update the new text */
      const newLink = `${match[0]}\n<img src="${dataURL}">\n`;
      const matchStart = match.index;
      newText += text.substring(start, matchStart - 1) + newLink;
      /* Increase the start position for the next bunch of text */
      start = matchStart + match[0].length;
    }
  })
  /* Append everything after the last link to the new text */
  newText += text.substring(start);
return(newText)
}

With a sample Markdown file

# Markdown file containing sample links

There is a numbers document that I'd like to link to 
[here](./adresses.numbers)

Having an image of it included in the file makes 
it easier to see what I'm talking about.

The same goes for a PDF: 
[Linking to it](./Everyday AppleScriptObjC 3ed.pdf) is nice, 
but an image says more than 1000 words

you’d get a preview, for example in iAWriter, like this

Markdown file with preview thumbnails

This new markdown file is about 250 times the size of the original (about 85 KB vs. 341 bytes). So, you have a nice(r) MD preview on the upside and a considerably bigger file on the downside. You can download the complete script and the sample files as a ZIP archive. Run the script from the terminal like so
osascript -l JavaScript script.js > newMarkdown.md, since it writes to the standard output. This command line captures the modified Markdown data in the file “newMarkdown.md”.