Skip to content

Instantly share code, notes, and snippets.

@duhaime
Last active May 11, 2018 14:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save duhaime/d3b53be24e27b889a807642e4fb884fc to your computer and use it in GitHub Desktop.
Save duhaime/d3b53be24e27b889a807642e4fb884fc to your computer and use it in GitHub Desktop.
Procedure for cropping image from page scan
[{"y1": 0.1001984126984127, "y0": 0.07787698412698413, "x0": 0.0875, "x1": 0.20625}, {"y1": 0.09871031746031746, "y0": 0.07539682539682539, "x0": 0.2294642857142857, "x1": 0.3580357142857143}, {"y1": 0.09226190476190477, "y0": 0.07539682539682539, "x0": 0.3794642857142857, "x1": 0.4544642857142857}, {"y1": 0.09176587301587301, "y0": 0.07490079365079365, "x0": 0.47946428571428573, "x1": 0.5303571428571429}, {"y1": 0.09722222222222222, "y0": 0.07490079365079365, "x0": 0.5553571428571429, "x1": 0.6455357142857143}, {"y1": 0.09077380952380952, "y0": 0.07341269841269842, "x0": 0.66875, "x1": 0.7026785714285714}, {"y1": 0.09077380952380952, "y0": 0.07242063492063493, "x0": 0.7223214285714286, "x1": 0.775}, {"y1": 0.09077380952380952, "y0": 0.07291666666666667, "x0": 0.7973214285714286, "x1": 0.8366071428571429}, {"y1": 0.12202380952380952, "y0": 0.10119047619047619, "x0": 0.08839285714285715, "x1": 0.15982142857142856}, {"y1": 0.11656746031746032, "y0": 0.10119047619047619, "x0": 0.1732142857142857, "x1": 0.18660714285714286}, {"y1": 0.11656746031746032, "y0": 0.09871031746031746, "x0": 0.19910714285714284, "x1": 0.3080357142857143}, {"y1": 0.11607142857142858, "y0": 0.09871031746031746, "x0": 0.32410714285714287, "x1": 0.38839285714285715}, {"y1": 0.11557539682539683, "y0": 0.09771825396825397, "x0": 0.4044642857142857, "x1": 0.48035714285714287}, {"y1": 0.11706349206349206, "y0": 0.09821428571428571, "x0": 0.49910714285714286, "x1": 0.5875}, {"y1": 0.11507936507936507, "y0": 0.09771825396825397, "x0": 0.6116071428571429, "x1": 0.6678571428571428}, {"y1": 0.11458333333333333, "y0": 0.09871031746031746, "x0": 0.6866071428571429, "x1": 0.7375}, {"y1": 0.1130952380952381, "y0": 0.09672619047619048, "x0": 0.7598214285714285, "x1": 0.8357142857142857}, {"y1": 0.14285714285714285, "y0": 0.12301587301587301, "x0": 0.08839285714285715, "x1": 0.16785714285714284}, {"y1": 0.13938492063492064, "y0": 0.12202380952380952, "x0": 0.18035714285714285, "x1": 0.3205357142857143}, {"y1": 0.13839285714285715, "y0": 0.12103174603174603, "x0": 0.33482142857142855, "x1": 0.4607142857142857}, {"y1": 0.1433531746031746, "y0": 0.12251984126984126, "x0": 0.4732142857142857, "x1": 0.5196428571428572}, {"y1": 0.13839285714285715, "y0": 0.12053571428571429, "x0": 0.5357142857142857, "x1": 0.6285714285714286}, {"y1": 0.28521825396825395, "y0": 0.2748015873015873, "x0": 0.5794642857142858, "x1": 0.7410714285714286}, {"y1": 0.2906746031746032, "y0": 0.27380952380952384, "x0": 0.7482142857142857, "x1": 0.8973214285714286}, {"y1": 0.6359126984126984, "y0": 0.6200396825396826, "x0": 0.14285714285714285, "x1": 0.15625}, {"y1": 0.6359126984126984, "y0": 0.6200396825396826, "x0": 0.17857142857142858, "x1": 0.23839285714285716}, {"y1": 0.6359126984126984, "y0": 0.6180555555555556, "x0": 0.2642857142857143, "x1": 0.3580357142857143}, {"y1": 0.6408730158730159, "y0": 0.6185515873015873, "x0": 0.37857142857142856, "x1": 0.45714285714285713}, {"y1": 0.6403769841269841, "y0": 0.6170634920634921, "x0": 0.48392857142857143, "x1": 0.7053571428571429}, {"y1": 0.6334325396825397, "y0": 0.6170634920634921, "x0": 0.73125, "x1": 0.7919642857142857}, {"y1": 0.6334325396825397, "y0": 0.6165674603174603, "x0": 0.8151785714285714, "x1": 0.8544642857142857}, {"y1": 0.6597222222222222, "y0": 0.6428571428571429, "x0": 0.10357142857142858, "x1": 0.2044642857142857}, {"y1": 0.6641865079365079, "y0": 0.6428571428571429, "x0": 0.21875, "x1": 0.2571428571428571}, {"y1": 0.6587301587301587, "y0": 0.6423611111111112, "x0": 0.28214285714285714, "x1": 0.31160714285714286}, {"y1": 0.6631944444444444, "y0": 0.6423611111111112, "x0": 0.32589285714285715, "x1": 0.3732142857142857}, {"y1": 0.6631944444444444, "y0": 0.6418650793650794, "x0": 0.3875, "x1": 0.4758928571428571}, {"y1": 0.6567460317460317, "y0": 0.6408730158730159, "x0": 0.4901785714285714, "x1": 0.5348214285714286}, {"y1": 0.6636904761904762, "y0": 0.6398809523809523, "x0": 0.5482142857142858, "x1": 0.71875}, {"y1": 0.6557539682539683, "y0": 0.6393849206349206, "x0": 0.7669642857142858, "x1": 0.7803571428571429}, {"y1": 0.6557539682539683, "y0": 0.6398809523809523, "x0": 0.7955357142857142, "x1": 0.8571428571428571}, {"y1": 0.6879960317460317, "y0": 0.6656746031746031, "x0": 0.10535714285714286, "x1": 0.1705357142857143}, {"y1": 0.6820436507936508, "y0": 0.6656746031746031, "x0": 0.18392857142857144, "x1": 0.21428571428571427}, {"y1": 0.6815476190476191, "y0": 0.6651785714285714, "x0": 0.22767857142857142, "x1": 0.27053571428571427}, {"y1": 0.6810515873015873, "y0": 0.6651785714285714, "x0": 0.28482142857142856, "x1": 0.3205357142857143}, {"y1": 0.6805555555555556, "y0": 0.6641865079365079, "x0": 0.33482142857142855, "x1": 0.3919642857142857}, {"y1": 0.6805555555555556, "y0": 0.6641865079365079, "x0": 0.40625, "x1": 0.45535714285714285}, {"y1": 0.6805555555555556, "y0": 0.6636904761904762, "x0": 0.46964285714285714, "x1": 0.5482142857142858}, {"y1": 0.6795634920634921, "y0": 0.6626984126984127, "x0": 0.5616071428571429, "x1": 0.5946428571428571}, {"y1": 0.6825396825396826, "y0": 0.6622023809523809, "x0": 0.6071428571428571, "x1": 0.6955357142857143}, {"y1": 0.6785714285714286, "y0": 0.6622023809523809, "x0": 0.7098214285714286, "x1": 0.7660714285714286}, {"y1": 0.6790674603174603, "y0": 0.6626984126984127, "x0": 0.7794642857142857, "x1": 0.8553571428571428}, {"y1": 0.7053571428571429, "y0": 0.689484126984127, "x0": 0.10625, "x1": 0.15446428571428572}, {"y1": 0.7083333333333334, "y0": 0.6879960317460317, "x0": 0.16071428571428573, "x1": 0.3098214285714286}, {"y1": 0.7038690476190477, "y0": 0.6865079365079365, "x0": 0.3196428571428571, "x1": 0.5258928571428572}, {"y1": 0.7023809523809523, "y0": 0.6850198412698413, "x0": 0.5357142857142857, "x1": 0.6348214285714285}, {"y1": 0.7083333333333334, "y0": 0.6850198412698413, "x0": 0.6455357142857143, "x1": 0.7866071428571428}, {"y1": 0.7013888888888888, "y0": 0.6840277777777778, "x0": 0.7973214285714286, "x1": 0.8571428571428571}, {"y1": 0.7331349206349206, "y0": 0.7103174603174603, "x0": 0.10625, "x1": 0.18035714285714285}, {"y1": 0.7271825396825397, "y0": 0.7093253968253969, "x0": 0.19375, "x1": 0.2294642857142857}, {"y1": 0.7306547619047619, "y0": 0.7088293650793651, "x0": 0.24017857142857144, "x1": 0.32767857142857143}, {"y1": 0.7271825396825397, "y0": 0.7098214285714286, "x0": 0.35714285714285715, "x1": 0.4133928571428571}, {"y1": 0.7256944444444444, "y0": 0.7083333333333334, "x0": 0.4276785714285714, "x1": 0.4901785714285714}, {"y1": 0.7251984126984127, "y0": 0.7078373015873016, "x0": 0.5142857142857142, "x1": 0.5598214285714286}, {"y1": 0.7261904761904762, "y0": 0.7078373015873016, "x0": 0.5794642857142858, "x1": 0.6419642857142858}, {"y1": 0.7242063492063492, "y0": 0.7078373015873016, "x0": 0.68125, "x1": 0.7767857142857143}, {"y1": 0.7237103174603174, "y0": 0.7098214285714286, "x0": 0.7955357142857142, "x1": 0.8589285714285714}, {"y1": 0.7509920634920635, "y0": 0.7405753968253969, "x0": 0.10714285714285714, "x1": 0.125}, {"y1": 0.7509920634920635, "y0": 0.7346230158730159, "x0": 0.1375, "x1": 0.2125}, {"y1": 0.7534722222222222, "y0": 0.7331349206349206, "x0": 0.22589285714285715, "x1": 0.3107142857142857}, {"y1": 0.7559523809523809, "y0": 0.7331349206349206, "x0": 0.3223214285714286, "x1": 0.3821428571428571}, {"y1": 0.7495039682539683, "y0": 0.7331349206349206, "x0": 0.39553571428571427, "x1": 0.49464285714285716}, {"y1": 0.753968253968254, "y0": 0.7321428571428571, "x0": 0.5142857142857142, "x1": 0.5830357142857143}, {"y1": 0.7485119047619048, "y0": 0.7321428571428571, "x0": 0.60625, "x1": 0.7035714285714286}, {"y1": 0.748015873015873, "y0": 0.7311507936507936, "x0": 0.7196428571428571, "x1": 0.7321428571428571}, {"y1": 0.748015873015873, "y0": 0.7356150793650794, "x0": 0.7464285714285714, "x1": 0.80625}, {"y1": 0.7475198412698413, "y0": 0.7366071428571429, "x0": 0.8285714285714286, "x1": 0.8580357142857142}, {"y1": 0.7743055555555556, "y0": 0.7574404761904762, "x0": 0.10803571428571429, "x1": 0.18482142857142858}, {"y1": 0.7733134920634921, "y0": 0.7569444444444444, "x0": 0.2044642857142857, "x1": 0.25357142857142856}, {"y1": 0.779265873015873, "y0": 0.7569444444444444, "x0": 0.2732142857142857, "x1": 0.3419642857142857}, {"y1": 0.7728174603174603, "y0": 0.7554563492063492, "x0": 0.3705357142857143, "x1": 0.46785714285714286}, {"y1": 0.7723214285714286, "y0": 0.7544642857142857, "x0": 0.4830357142857143, "x1": 0.5830357142857143}, {"y1": 0.7718253968253969, "y0": 0.7544642857142857, "x0": 0.6035714285714285, "x1": 0.6392857142857142}, {"y1": 0.7718253968253969, "y0": 0.7534722222222222, "x0": 0.6642857142857143, "x1": 0.7508928571428571}, {"y1": 0.7713293650793651, "y0": 0.7529761904761905, "x0": 0.7741071428571429, "x1": 0.8008928571428572}, {"y1": 0.7703373015873016, "y0": 0.7534722222222222, "x0": 0.81875, "x1": 0.8580357142857142}, {"y1": 0.7976190476190477, "y0": 0.7797619047619048, "x0": 0.11071428571428571, "x1": 0.1982142857142857}, {"y1": 0.7966269841269841, "y0": 0.78125, "x0": 0.21875, "x1": 0.2714285714285714}, {"y1": 0.7986111111111112, "y0": 0.779265873015873, "x0": 0.29017857142857145, "x1": 0.39017857142857143}, {"y1": 0.7956349206349206, "y0": 0.779265873015873, "x0": 0.40982142857142856, "x1": 0.4616071428571429}, {"y1": 0.7956349206349206, "y0": 0.7782738095238095, "x0": 0.48660714285714285, "x1": 0.5098214285714285}, {"y1": 0.8005952380952381, "y0": 0.7767857142857143, "x0": 0.5339285714285714, "x1": 0.6866071428571429}, {"y1": 0.7946428571428571, "y0": 0.777281746031746, "x0": 0.7071428571428572, "x1": 0.74375}, {"y1": 0.7931547619047619, "y0": 0.7762896825396826, "x0": 0.7696428571428572, "x1": 0.875}, {"y1": 0.8258928571428571, "y0": 0.8035714285714286, "x0": 0.10892857142857143, "x1": 0.18303571428571427}, {"y1": 0.8199404761904762, "y0": 0.8030753968253969, "x0": 0.20089285714285715, "x1": 0.26964285714285713}, {"y1": 0.8199404761904762, "y0": 0.8020833333333334, "x0": 0.2910714285714286, "x1": 0.34732142857142856}, {"y1": 0.8189484126984127, "y0": 0.8025793650793651, "x0": 0.36875, "x1": 0.43660714285714286}, {"y1": 0.8244047619047619, "y0": 0.8020833333333334, "x0": 0.45625, "x1": 0.5053571428571428}, {"y1": 0.8214285714285714, "y0": 0.8015873015873016, "x0": 0.525, "x1": 0.6026785714285714}, {"y1": 0.8174603174603174, "y0": 0.7996031746031746, "x0": 0.6258928571428571, "x1": 0.6821428571428572}, {"y1": 0.8169642857142857, "y0": 0.8010912698412699, "x0": 0.7017857142857142, "x1": 0.7526785714285714}, {"y1": 0.8219246031746031, "y0": 0.7996031746031746, "x0": 0.7741071428571429, "x1": 0.8589285714285714}, {"y1": 0.8432539682539683, "y0": 0.8268849206349206, "x0": 0.10982142857142857, "x1": 0.18392857142857144}, {"y1": 0.8427579365079365, "y0": 0.8258928571428571, "x0": 0.19732142857142856, "x1": 0.24375}, {"y1": 0.8427579365079365, "y0": 0.8258928571428571, "x0": 0.2571428571428571, "x1": 0.36428571428571427}, {"y1": 0.8472222222222222, "y0": 0.8244047619047619, "x0": 0.3794642857142857, "x1": 0.50625}, {"y1": 0.8407738095238095, "y0": 0.8244047619047619, "x0": 0.5214285714285715, "x1": 0.5767857142857142}, {"y1": 0.8402777777777778, "y0": 0.8234126984126984, "x0": 0.5910714285714286, "x1": 0.7401785714285715}, {"y1": 0.8387896825396826, "y0": 0.8229166666666666, "x0": 0.7803571428571429, "x1": 0.8598214285714286}, {"y1": 0.8665674603174603, "y0": 0.8501984126984127, "x0": 0.1125, "x1": 0.14642857142857144}, {"y1": 0.8670634920634921, "y0": 0.8492063492063492, "x0": 0.15803571428571428, "x1": 0.20714285714285716}, {"y1": 0.8680555555555556, "y0": 0.8492063492063492, "x0": 0.21964285714285714, "x1": 0.30089285714285713}, {"y1": 0.8660714285714286, "y0": 0.8487103174603174, "x0": 0.3142857142857143, "x1": 0.3767857142857143}, {"y1": 0.8650793650793651, "y0": 0.8472222222222222, "x0": 0.3892857142857143, "x1": 0.5285714285714286}, {"y1": 0.8680555555555556, "y0": 0.8472222222222222, "x0": 0.5410714285714285, "x1": 0.6116071428571429}, {"y1": 0.8630952380952381, "y0": 0.8467261904761905, "x0": 0.6258928571428571, "x1": 0.7098214285714286}, {"y1": 0.8630952380952381, "y0": 0.8472222222222222, "x0": 0.7241071428571428, "x1": 0.7946428571428571}, {"y1": 0.8621031746031746, "y0": 0.8447420634920635, "x0": 0.8160714285714286, "x1": 0.8598214285714286}, {"y1": 0.8859126984126984, "y0": 0.8685515873015873, "x0": 0.775, "x1": 0.8205357142857143}]
;(function() {
var canvas = document.querySelector('#uncropped'),
container = document.querySelector('.find-image .content'),
label = document.querySelector('#find-image-label'),
hiddenImg = document.querySelector('#scaled-hidden-image'),
fullHiddenImg = document.querySelector('#full-hidden-image'),
ctx = canvas.getContext('2d'),
width = hiddenImg.clientWidth,
height = hiddenImg.clientHeight,
svg = d3.select('#pixel-sums'),
size = 1, // height of row values (1 = 1 pixel tall rows)
pixelSums = {y: {}}, // store of row-level pixel sums
color = '#FE4445', // color of boxes and active d3 bars
boxes = {}; // d[x][y] = True for coords where x,y should be whited-out
/**
* Data fetchers
**/
function get(url, onSuccess, onErr, onProgress) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status === 200) {
if (onSuccess) onSuccess(xmlhttp.responseText)
} else {
if (onErr) onErr(xmlhttp)
}
};
};
xmlhttp.open('GET', url, true);
xmlhttp.send();
};
function getCanvas(w, h) {
var canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
return canvas;
}
/**
* 0. Draw the canvas and prepare for sequence
**/
function startSequence(data) {
// remove the cropped image (only present after first full cycle)
var cropped = document.querySelector('#cropped');
if (cropped) cropped.parentNode.removeChild(cropped);
canvas.width = width;
canvas.height = height;
ctx.imageSmoothingEnabled = false;
ctx.drawImage(hiddenImg,
0, 0, fullHiddenImg.clientWidth, fullHiddenImg.clientHeight,
-1, 0, width, height);
measureRawSums(data);
}
/**
* 1. Measure the darkness of each pixel row
**/
function measureRawSums(data) {
setLabel('1. Sum each row of pixels in the image')
sumPixels({whiteout: false})
setTimeout(drawBoxes.bind(null, data), 1500);
}
/**
* Find the sum of pixel darkness for each row of pixels
**/
function sumPixels(config) {
// finding pixel darkness is much faster on hidden canvas than drawn canvas
var hiddenCanvas = getCanvas(width, height);
hiddenCanvas.getContext('2d').drawImage(hiddenImg, 0, 0, width, height);
// measure the pixel darkness for each row of the hidden canvas
var ySums = {};
for (var x=0; x<hiddenCanvas.width; x++) {
for (var y=0; y<hiddenCanvas.height; y++) {
// get the pixel value at position x, y
var _ctx = hiddenCanvas.getContext('2d');
var pixel = config.whiteout && boxes[x] && boxes[x][y] ? 255
: _ctx.getImageData(x, y, size, size).data[0];
ySums[y] = ySums[y] + pixel || pixel;
}
}
// find the pixel sum for each row; 255 * width = max possible row sum
pixelSums.y = Object.keys(ySums).reduce(function(arr, y) {
arr.push({
y: y,
sum: Math.abs((255 * width) - ySums[y])
})
return arr;
}, [])
// draw the pixel sums on the svg
drawSums()
}
/**
* Draw the cumulative darkness of each pixel row on SVG target
**/
function drawSums() {
var w = canvas.clientWidth * .5; // make the svg 50% the width of the canvas
var h = canvas.clientHeight;
// set the svg size
svg.transition()
.attr('height', h)
.attr('width', w)
// select or get the group element to which rects are bound
var g = svg.select('g').size() ? svg.select('.rects')
: svg.append('g').attr('class', 'rects')
/**
* Scales
**/
var yScale = d3.scaleLinear()
.domain(d3.extent(pixelSums.y, function(d) { return d.sum; }))
.range([0, w])
/**
* Draw bars
**/
var bars = g.selectAll('rect').data(pixelSums.y)
var barEnter = bars.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d, idx) { return idx * size; })
.attr('height', size)
bars.merge(barEnter).transition()
.delay(function(d, idx) { return idx * 1.5; })
.attr('width', function(d) { return yScale(d.sum) })
}
/**
* 2. Draw a box around each word in a page image
**/
function drawBoxes(data) {
setLabel('2. Use OCR to find word coordinates')
data.forEach(function(i, idx) {
setTimeout(drawBox.bind(null, i), idx * 20);
if (idx + 1 === data.length) {
setTimeout(fillBoxes.bind(null, data), idx * 20 + 500)
}
})
}
/**
* Draw a single box to indicate a word boundary
* @args:
* obj
* x0: starting x position for the word coordinate in %
* x1: ending x position for the word coordinate in %
* y0: starting y position for the word coordinate in %
* y1: ending y position for the word coordinate in %
**/
function drawBox(i) {
var left = (i.x0 * width),
top = (i.y0 * height),
w = (i.x1 - i.x0) * width,
h = (i.y1 - i.y0) * height,
pad = 0; // padding around box
ctx.strokeStyle = color; // stroke color
ctx.lineWidth = 2; // stroke-width
ctx.strokeRect( // x, y, width, height
left - pad,
top - pad,
w + (2 * pad),
h + (2 * pad)
);
// store the fact that these boxes are whited out
for (var x=parseInt(left); x<parseInt(left+w); x++) {
for (var y=parseInt(top); y<parseInt(top+h); y++) {
boxes[x] = boxes[x] || {};
boxes[x][y] = true;
}
}
}
/**
* 3. Fill each box with a white background color
**/
function fillBoxes(data) {
setLabel('3. White out each identified word')
data.forEach(function(i, idx) {
setTimeout(fillBox.bind(null, i), (idx * 20));
if (idx + 1 === data.length) {
setTimeout(measureWhitedSums, idx * 20 + 500)
}
})
}
/**
* Draw a single box to indicate a word boundary
* @args:
* obj
* x0: starting x position for the word coordinate in %
* x1: ending x position for the word coordinate in %
* y0: starting y position for the word coordinate in %
* y1: ending y position for the word coordinate in %
**/
function fillBox(i) {
var pad = 2; // padding around box; needed to get 2px border boxes
ctx.fillStyle = '#fff'; // stroke color
ctx.fillRect( // x, y, width, height
(i.x0 * width) - pad,
(i.y0 * height) - pad,
((i.x1 - i.x0) * width) + (2 * pad),
((i.y1 - i.y0) * height) + (2 * pad)
);
}
/**
* 4. Remeasure the darkness of each pixel row
**/
function measureWhitedSums() {
setLabel('4. Re-measure the darkness of each pixel row')
sumPixels({whiteout: true})
setTimeout(findMaxStreaks, 1500);
}
/**
* Helper to set the label content
**/
function setLabel(str) {
label.innerHTML = str;
}
/**
* 5. Identify the longest sequence of sufficiently dark pixel rows / cols
**/
function findMaxStreaks() {
setLabel('5. Identify the longest streak of dark rows')
var windowSize = 10, // window length used to smooth pixel sums; must be even
windowHalf = windowSize / 2, // n rows before/after value to use when smoothing
minSum = .005 * (width * 255), // min pixel sum to use when smoothing
streak = [], // index positions of rows sufficiently dark to be retained
maxStreak = []; // longest sequence of such index positions
// find the smoothed value for each position along the selected axis
for (var i=windowHalf; i<pixelSums.y.length - windowHalf; i++) {
var positionSum = 0;
for (var j=-windowHalf; j<windowHalf; j++) {
positionSum += pixelSums.y[i + j].sum;
}
// divide the sum of this window by window length to get mean pixel value
if ((positionSum / windowSize) >= minSum) {
streak.push(i)
} else if (streak.length > maxStreak.length) {
maxStreak = streak;
streak = [];
}
}
drawMaxStreak(maxStreak);
}
/**
* Visually represent the max streak of y pixel values
* @args:
* arr maxStreak: contains one element for each unit in the maximally
* long streak along the y axis. Each unit represents the index position
* of a row within the streak
**/
function drawMaxStreak(maxStreak) {
var pad = 4; // number of rows / cols to add to image area after cropping
// update the bars in the pixel chart
svg.selectAll('rect').transition()
.delay(function(d, idx) { return 2 * idx; })
.attr('fill', function(d, idx) {
return idx >= maxStreak[0] && idx <= maxStreak[maxStreak.length-1] ?
color : 'black'
})
setTimeout(function() {
// draw a rect around the chosen image
var h = (maxStreak.length + (2 * pad)) * (pixelSums.y.length / height),
top = (maxStreak[0] - pad) * (pixelSums.y.length / height);
cropImage({ height: h, top: top })
}, 1500)
}
/**
* 6. Crop out the selected image
**/
function cropImage(config) {
setLabel('6. Crop the identified image')
// hidden is a canvas sized to the shown image;
// cropped is just the image portion of that canvas;
var hidden = getCanvas(width, height);
var cropped = getCanvas(width, config.height);
hidden.getContext('2d').drawImage(hiddenImg, 0, 0, width, height);
// img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight
cropped.getContext('2d').drawImage(hidden,
0, config.top, width, config.height,
-1, 0, width, config.height
);
// add the cropped image to the DOM, but make it invisible
cropped.id = 'cropped';
cropped.style.transform = 'translate(0px,' + config.top + 'px)';
cropped.style.left = '0px';
cropped.style.opacity = 0;
container.appendChild(cropped);
setTimeout(function() {
d3.select('#cropped').style('opacity', 1);
}, 10)
setTimeout(function() {
canvas.style.opacity = 0;
svg.style('opacity', 0);
}, 1000)
setTimeout(function() {
cropped.style.transform = 'translate(0px,0px)';
}, 2500)
setTimeout(function() {
cropped.style.transform = 'translate(0px,' + config.top + 'px)';
}, 5000)
setTimeout(function() {
reset();
}, 5500)
}
/**
* Reset animation for another pass
**/
function reset() {
canvas.style.opacity = 1;
ctx.clearRect(0, 0, width, height);
svg.selectAll('rect').remove();
svg.style('opacity', 1);
setTimeout(animate, 1000);
}
/**
* Main
**/
function animate() {
get('000630070000650-words.json', function(data) {
startSequence(JSON.parse(data));
})
}
document.addEventListener('DOMContentLoaded', function() {
animate()
}, false);
})();
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>title</title>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet'>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Open Sans';
}
canvas {
image-rendering: optimizeSpeed; // Older versions of FF
image-rendering: -moz-crisp-edges; // FF 6.0+
image-rendering: -webkit-optimize-contrast; // Webkit (non standard naming)
image-rendering: -o-crisp-edges; // OS X & Windows Opera (12.02+)
image-rendering: crisp-edges; // Possible future browsers.
-ms-interpolation-mode: nearest-neighbor; // IE (non standard naming)
}
/**
* Containers
**/
.find-image {
width: 100%;
max-width: 600px;
padding: 40px;
margin: 0 auto;
}
.find-image .inner {
padding: 40px;
}
.find-image .content {
display: block;
position: relative;
}
.well {
min-height: 20px;
margin-bottom: 20px;
background-color: #f5f5f5;
border: 1px solid #e3e3e3;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.05);
box-shadow: inset 0 1px 1px rgba(0,0,0,.05);
}
/**
* Scene elements
**/
#find-image-label {
margin-bottom: 30px;
font-size: 18px;
}
#uncropped {
outline: 2px solid #000;
vertical-align: top;
display: inline-block;
}
#uncropped,
#scaled-hidden-image {
width: 60%;
}
.hidden-image {
position: absolute;
top: -1000%;
left: -1000%;
opacity: 0;
z-index: -1;
}
#cropped {
position: absolute;
opacity: 0;
transition: opacity 2s, transform 2s;
z-index: 10;
}
.fade {
transition: opacity 1.2s;
}
@media(max-width: 600px) {
.find-image {
padding: 15px;
}
.find-image .inner {
padding: 25px;
}
}
</style>
</head>
<body>
<div class='find-image'>
<div class='inner well'>
<div id='find-image-label'>&nbsp;</div>
<div class='content'>
<img id='full-hidden-image' class='hidden-image'
src='000630070000650.jpg'>
<img id='scaled-hidden-image' class='hidden-image'
src='000630070000650.jpg'>
<canvas id='uncropped' class='fade'></canvas>
<svg id='pixel-sums' class='fade' width='0'></svg>
</div>
</div>
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js'></script>
<script src='find-image.js'></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment