JSFiddle - React, Tailwind, and code Playground

Image Comparison Tool: Open two local file system folders with image files, pair them using drag and drop, and show the differences between the pairs.

by skibulk

HTML

<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
<div id="about">
  <h1>Graphic Diff (Coming&nbsp;Soon!)</h1>
  <p>This tool highlights differences between similar graphics by compositing them with <a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation">difference blending mode</a>. It enables you to select two
    local folders on your computer and compare documents between them. Graphic Diff is intended to compare different versions of the same document in order to identify changes made from one version to the next. It supports the formats BMP, GIF, JPG, PDF,
    PNG, SVG, TIFF, and WebP. <a href="https://github.com/lachmanski/graphic-diff">Graphic Diff is on GitHub</a> and uses <a href="https://github.com/mozilla/pdf.js">PDF.js</a>, <a href="https://github.com/photopea/UTIF.js">UTIF.js</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API">web workers</a>,
    and
    <a href="https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas">offscreen canvas</a>, which is an experimental technology currently enabled in Chrome. © 2019 <a href="https://github.com/lachmanski">Lachmanski</a></p>
  <p><button id="continue">Continue</button></p>
</div>
<div id="app">
  <div id="menu">
    <label><input id="colABrowse" class="browse" type="file" webkitdirectory directory multiple/><span role="button"><i class="fas fa-folder-open"></i> 1</span></label>
    <label><input id="colBBrowse" class="browse" type="file" webkitdirectory directory multiple/><span role="button"><i class="fas fa-folder-open"></i> 2</span></label>
    <input type="checkbox" id="subfolders">
    <label for="subfolders" id="subfoldersOff" title="Exclude...

CSS

* {
  box-sizing: border-box;
  margin: 0;
  border: 0;
  padding: 0;
}

html,
body {
  width: 100%;
  min-width: 320px;
  height: 100%;
  min-height: 320px;
  font-family: arial;
  font-size: 16px;
  line-height: 1.5rem;
}

#about {
  padding: 40px;
  margin: 0 auto;
  max-width: 600px;
}

h1,
h2,
h3,
p {
  padding-bottom: 20px;
}

button,
[role=button] {
  margin: 0;
  padding: 8px 16px;
  color: white;
  background: #3498DB;
  cursor: pointer;
  font-size: 1rem;
}

#app {
  display: none;
  width: 100%;
  height: 100%;
  user-select: none;
}

#menu, #scroll {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
}

#menu {
  text-align: center;
}

label {
  cursor: pointer;
}

input[type=file],
input[type=checkbox] {
  display: none;
}

#subfolders:not(:checked)~#subfoldersOn {
  display: none;
}

#subfolders:checked~#subfoldersOff {
  display: none;
}

#scroll {
  margin-top: 28px;
  bottom: 0;
  font-size: 0;
  overflow-x: scroll;
}

.set {
  height: 50%;
  white-space: nowrap;
}

.box {
  display: inline-block;
  width: 200px;
  height: 100%;
  background: #f5f5f5;
}

JavaScript

$("#continue").click(function(event) {
  $("#about").hide();
  $("#app").show();
});

/*
To-Do
// https://github.com/mozilla/pdf.js
// https://github.com/seikichi/tiff.js

Browse, Drag + Drop, Multi-Add
Remove All / Remove Folder / Remove Multi-Page Doc
Skip Images <200px w/h

PDF Pages

User Interface:
Select
Top
Up
Down
Bottom
Path

Remove / Hide
Remove / Hide Series

Cache Processed Images

Web Workers
https://www.html5rocks.com/en/tutorials/file/filesystem-sync/
https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas

chrome://flags/#enable-experimental-canvas-features

https://github.com/photopea/UTIF.js

Alternative to OffscreenCanvas?:
https://github.com/nodeca/pica/blob/master/dist/pica.js

Formats: JPEG, GIF, PNG, SVG, BMP, TIFF, PDF
*/

(function($) {
  "use strict";

  var canvas = document.getElementById("artboard");
  var context = canvasA.getContext('2d');

  $('#colABrowse').on('change', function(event) {
    addImages(event.target.files, colA);
  });

  $('#colBBrowse').on('change', function(event) {
    addImages(event.target.files, colB);
  });

  function addImages(files, container) {

    $(container).empty();
    $("#colC").empty();

    var queue = 0;

    $(files).each(function(i, file) {

      if (file.type.indexOf("image") == 0) {

        var li = $("<li class='ui-state-default'></li>");

        // Shift-Click Sends to Bottom
        li.mousedown(function(event) {

          if (event.shiftKey) {

            $(this).parent().append(this);
            updateResults();
            event.stopPropagation();
          }
        });

        li.appendTo(container);

        var $canvas = $("<canvas width='300' height='300'>");
        $canvas.appendTo(li);
        var ctx = $canvas[0].getContext('2d');

        queue++;
        var img = new Image;
        img.onload = function() {

          // https://github.com/viliusle/Hermite-resize
          ctx.drawImage(img, 0, 0, 300, 300);
          URL.revokeObjectURL(img.src)

         ...