var topLeftY = 0;
var topRightX = 0;
var topRightY = 0;
var bottomLeftX = 0;
var bottomLeftY = 0;
var bottomRightX = 0;
var bottomRightY = 0;
var offset = 200;
var dragging = null;
var fileName = null;
var whiteThreshold = 100;
var worker = null;
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: (evt.clientX - rect.left) / (rect.right - rect.left) * canvas.width,
y: (evt.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height
};
}
function render() {
var src = document.getElementById("sourcecanvas");
var dst = document.getElementById("destcanvas");
whiteThreshold = document.getElementById("whitethreshold").value;
var finalWidth = Math.floor(((topRightX + bottomRightX) / 2) - ((topLeftX + bottomLeftX) / 2));
var finalHeight = Math.floor(((bottomLeftY + bottomRightY) / 2) - ((topLeftY + topRightY) / 2));
dst.width = finalWidth;
dst.height = finalHeight;
var srcd = src.getContext("2d").getImageData(0, 0, src.width, src.height);
var dstd = dst.getContext("2d").getImageData(0, 0, dst.width, dst.height);
var sw = src.width;
var dw = dst.width;
var dh = dst.height;
//processImage(srcd, dstd, sw, dw, dh, topLeftX, topLeftY, bottomLeftX, bottomLeftY, topRightX, topRightY, bottomRightX, bottomRightY);
worker.postMessage({
srcd: srcd,
dstd: dstd,
sw: sw,
dw: dw,
dh: dh,
whiteThreshold: whiteThreshold,
topLeftX: topLeftX,
topLeftY: topLeftY,
bottomLeftX: bottomLeftX,
bottomLeftY: bottomLeftY,
topRightX: topRightX,
topRightY: topRightY,
bottomRightX: bottomRightX,
bottomRightY: bottomRightY
});
//var ctx = dst.getContext("2d");
//ctx.putImageData(dstd, 0, 0);
}
function finishRender(e) {
var dst = document.getElementById("destcanvas");
var ctx = dst.getContext("2d");
ctx.putImageData(e.data.dstd, 0, 0);
prepareDownloadImage();
}
function processImage(srcd, dstd, sw, dw, dh, whiteThreshold, topLeftX, topLeftY, bottomLeftX, bottomLeftY, topRightX, topRightY, bottomRightX, bottomRightY) {
for (var y = 0; y < dh; y++) {
var dy = y / dh;
var startX = topLeftX + dy*(bottomLeftX-topLeftX);
var startY = topLeftY + dy*(bottomLeftY-topLeftY);
var endX = topRightX + dy*(bottomRightX-topRightX);
var endY = topRightY + dy*(bottomRightY-topRightY);
for (var x = 0; x < dw; x++) {
var dx = x / dw;
var pointX = Math.floor(startX + dx*(endX-startX));
var pointY = Math.floor(startY + dx*(endY-startY));
var dstxy = (y*dw+x)*4;
var srcxy = (pointY*sw+pointX)*4;
if (((srcd.data[srcxy+0] + srcd.data[srcxy+1] + srcd.data[srcxy+2]) / 3) > whiteThreshold) {
dstd.data[dstxy+0] = 255;
dstd.data[dstxy+1] = 255;
dstd.data[dstxy+2] = 255;
dstd.data[dstxy+3] = 255;
} else {
dstd.data[dstxy+0] = srcd.data[srcxy+0];
dstd.data[dstxy+1] = srcd.data[srcxy+1];
dstd.data[dstxy+2] = srcd.data[srcxy+2];
dstd.data[dstxy+3] = srcd.data[srcxy+3];
}
}
}
}
function updatePoints() {
var overlay = document.getElementById("overlay");
var ctx = overlay.getContext("2d");
var s = 10;
overlay.width = overlay.width;
ctx.clearRect(0, 0, ctx.width, ctx.height);
ctx.beginPath();
ctx.lineWidth=s;
ctx.moveTo(topLeftX, topLeftY);
ctx.lineTo(topRightX,topRightY);
ctx.lineTo(bottomRightX,bottomRightY);
ctx.lineTo(bottomLeftX,bottomLeftY);
ctx.lineTo(topLeftX, topLeftY);
ctx.stroke();
ctx.closePath();
ctx.fillStyle="#fff";
ctx.fillRect(topLeftX-s*3, topLeftY-s*3, s*6, s*6);
ctx.fillRect(bottomLeftX-s*3, bottomLeftY-s*3, s*6, s*6);
ctx.fillRect(topRightX-s*3, topRightY-s*3, s*6, s*6);
ctx.fillRect(bottomRightX-s*3, bottomRightY-s*3, s*6, s*6);
};
function getOrientation(file, callback) {
var reader = new FileReader();
reader.onload = function(e) {
var view = new DataView(e.target.result);
if (view.getUint16(0, false) != 0xFFD8) return callback(-2);
var length = view.byteLength, offset = 2;
while (offset < length) {
var marker = view.getUint16(offset, false);
offset += 2;
if (marker == 0xFFE1) {
if (view.getUint32(offset += 2, false) != 0x45786966) return callback(-1);
var little = view.getUint16(offset += 6, false) == 0x4949;
offset += view.getUint32(offset + 4, little);
var tags = view.getUint16(offset, little);
offset += 2;
for (var i = 0; i < tags; i++)
if (view.getUint16(offset + (i * 12), little) == 0x0112)
return callback(view.getUint16(offset + (i * 12) + 8, little));
}
else if ((marker & 0xFF00) != 0xFF00) break;
else offset += view.getUint16(offset, false);
}
return callback(-1);
};
reader.readAsArrayBuffer(file);
}
function hover(e) {
// file drag hover
e.stopPropagation();
e.preventDefault();
e.target.className = (e.type == "dragover" ? "hover" : "");
}
function prepareDownloadImage() {
var dst = document.getElementById("destcanvas");
var downloadImage = document.getElementById("download-image");
if (fileName) {
downloadImage.href = dst.toDataURL("image/jpeg");
downloadImage.download = fileName + ".jpg";
}
}
document.addEventListener("DOMContentLoaded", function() {
var src = document.getElementById("sourcecanvas");
var dst = document.getElementById("destcanvas");
var overlay = document.getElementById("overlay");
var cc = document.getElementById("canvascontainer");
worker = new Worker("./imageWorker.js");
worker.onmessage = finishRender;
document.getElementById("download-pdf").addEventListener("click", function(e) {
var imgData = dst.toDataURL("image/jpeg", 1.0);
var pdf = new jsPDF();
var margin = 0;
var width = pdf.internal.pageSize.width - margin*2;
var height = pdf.internal.pageSize.height - margin*2;
var pdfRatio = height / width;
var currentRatio = dst.height / dst.width;
console.log("page width: " + width);
console.log("page height: " + height);
console.log("image width: " + dst.width);
console.log("image height: " + dst.height);
console.log("page ratio: " + pdfRatio);
console.log("image ratio: " + currentRatio);
if (pdfRatio > currentRatio) {
pdf.addImage(imgData, 'JPEG', margin, margin, width, width * currentRatio);
} else {
pdf.addImage(imgData, 'JPEG', margin + (width - height / currentRatio) / 2, margin, height / currentRatio, height);
}
pdf.save(fileName + ".pdf");
});
function processFiles(files) {
if (files.length != 1) {
alert("Please drag and drop one file");
return;
}
var file = files[0];
if (file.type.indexOf("image") != 0) {
alert("Please drop an image");
return;
}
fileName = file.name.substring(0, file.name.lastIndexOf('.'));
var reader = new FileReader();
reader.onload = function(e) {
var img = new Image();
img.onload = function(e) {
getOrientation(file, function(orientation) {
src.width = img.width;
src.height = img.height;
var ctx = src.getContext("2d");
var width = img.width;
var height = img.height;
// set proper canvas dimensions before transform & export
if ([5,6,7,8].indexOf(orientation) > -1) {
src.width = height;
src.height = width;
} else {
src.width = width;
src.height = height;
}
// copy dst attributes
dst.width = src.width;
dst.height = src.height;
overlay.width = src.width;
overlay.height = src.height;
switch (orientation) {
case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
case 3: ctx.transform(-1, 0, 0, -1, width, height ); break;
case 4: ctx.transform(1, 0, 0, -1, 0, height ); break;
case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
case 6: ctx.transform(0, 1, -1, 0, height , 0); break;
case 7: ctx.transform(0, -1, -1, 0, height , width); break;
case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
default: ctx.transform(1, 0, 0, 1, 0, 0);
}
ctx.drawImage(img, 0, 0);
ctx.setTransform(1, 0, 0, 1, 0, 0);
topLeftX = offset;
topLeftY = offset;
topRightX = dst.width - offset;
topRightY = offset;
bottomLeftX = offset;
bottomLeftY = dst.height - offset;
bottomRightX = dst.width - offset;
bottomRightY = dst.height - offset;
updatePoints();
render();
});
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
}
document.getElementById("upload-file").addEventListener("change", function(e) {
var files = e.target.files;
processFiles(files);
});
overlay.addEventListener("dragover", hover, false);
overlay.addEventListener("dragleave", hover, false);
overlay.addEventListener("drop", function(e) {
e.stopPropagation();
e.preventDefault();
e.target.classList.remove("hover");
processFiles(e.dataTransfer.files);
});
overlay.addEventListener("mousedown", function(e) {
var pos = getMousePos(src, e);
var sen = 20;
if ((pos.x > topLeftX - sen) && (pos.y > topLeftY - sen) && (pos.x < topLeftX + sen) && (pos.y < topLeftY + sen)) {
dragging = "topleft";
}
if ((pos.x > topRightX - sen) && (pos.y > topRightY - sen) && (pos.x < topRightX + sen) && (pos.y < topRightY + sen)) {
dragging = "topright";
}
if ((pos.x > bottomLeftX - sen) && (pos.y > bottomLeftY - sen) && (pos.x < bottomLeftX + sen) && (pos.y < bottomLeftY + sen)) {
dragging = "bottomleft";
}
if ((pos.x > bottomRightX - sen) && (pos.y > bottomRightY - sen) && (pos.x < bottomRightX + sen) && (pos.y < bottomRightY + sen)) {
dragging = "bottomright";
}
updatePoints();
});
overlay.addEventListener("mousemove", function(e) {
var pos = getMousePos(src, e);
var sen = 20;
if ((pos.x > topLeftX - sen) && (pos.y > topLeftY - sen) && (pos.x < topLeftX + sen) && (pos.y < topLeftY + sen)) {
overlay.style.cursor = "pointer";
}
else if ((pos.x > topRightX - sen) && (pos.y > topRightY - sen) && (pos.x < topRightX + sen) && (pos.y < topRightY + sen)) {
overlay.style.cursor = "pointer";
}
else if ((pos.x > bottomLeftX - sen) && (pos.y > bottomLeftY - sen) && (pos.x < bottomLeftX + sen) && (pos.y < bottomLeftY + sen)) {
overlay.style.cursor = "pointer";
}
else if ((pos.x > bottomRightX - sen) && (pos.y > bottomRightY - sen) && (pos.x < bottomRightX + sen) && (pos.y < bottomRightY + sen)) {
overlay.style.cursor = "pointer";
} else {
overlay.style.cursor = "inherit";
}
if (dragging) {
var pos = getMousePos(src, e);
if (dragging == "topleft") {
topLeftX = pos.x;
topLeftY = pos.y;
}
if (dragging == "topright") {
topRightX = pos.x;
topRightY = pos.y;
}
if (dragging == "bottomleft") {
bottomLeftX = pos.x;
bottomLeftY = pos.y;
}
if (dragging == "bottomright") {
bottomRightX = pos.x;
bottomRightY = pos.y;
}
updatePoints();
}
});
overlay.addEventListener("mouseup", function(e) {
dragging = null;
updatePoints();
render();
});
});
HTML源代码:
| <html> |
| <head> |
| <title>ImageToScan.com</title> |
| <meta name="description" content="Convert images into scanned PDF documents"> |
|
|
| <meta property="og:title" content="ImageToScan.com"/> |
| <meta property="og:url" content="http://www.imagetoscan.com/"/> |
| <meta property="og:image" content="http://www.imagetoscan.com/ois-logo-fb.png"/> |
| <meta property="og:description" content="Convert images into scanned PDF documents"/> |
|
|
| <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"/> |
| <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"/> |
| <link rel="icon" href="ois.png"/> |
|
|
| <script src="http://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.3/jspdf.min.js"></script> |
| <script src="ois.js"></script> |
| <style> |
| canvas { |
| width: 100%; |
| border: 1px solid #ccc; |
| } |
|
|
| canvas.hover { |
| background-color: #eee; |
| } |
|
|
| #canvascontainer { |
| position: relative; |
| width: 100%; |
| } |
|
|
| #overlay, #sourcecanvas { |
| position: absolute; |
| top: 0; |
| bottom: 0; |
| left: 0; |
| right: 0; |
| } |
|
|
| #overlay { |
| cursor: pointer; |
| } |
|
|
| .point { |
| position: absolute; |
| width: 10px; |
| height: 10px; |
| border-radius: 10px; |
| background-color: white; |
| boder: 1px solid #ccc; |
| } |
|
|
| #instructions { |
| text-align: center; |
| color: #aaa; |
| font-size: 30px; |
| padding-top: 50px; |
| } |
|
|
| #instructions i { |
| font-size: 100px; |
| } |
|
|
| </style> |
| </head> |
| <body> |
| <img src="ois-logo.png" style="width: 300px; margin: 30px auto; display: block; "> |
|
|
| <h1 style="background-color: #f8f8f8; border: 1px solid #ccc; padding: 20px 0; font-size: 50px; text-align: center">ImageToScan<span style="color: #888">.com</span></h1> |
| <div class="container"> |
|
|
| <h4 style="text-align: center">Convert images into scanned PDF documents.</h4> |
| <hr/> |
|
|
|
|
|
|
| <div class="row"> |
| <div class="col-lg-6"> |
| <h3><i class="fa fa-sign-in"></i> Source</h3> |
| <hr/> |
| <p>1. Select an image by dragging & dropping it or by using the Upload button.</p> |
| <p>2. Move the white corners to match the corners of the page in the photo.</p> |
| <p> |
| <label class="btn btn-primary btn-file"> |
| <i class="fa fa-upload"></i> Upload <input type="file" id="upload-file" style="display: none;"> |
| </label> |
|
|
| </p> |
|
|
| <div id="canvascontainer"> |
| <canvas id="sourcecanvas"></canvas> |
| <canvas id="overlay"></canvas> |
| <div id="instructions"> |
| <p><i class="fa fa-cloud-upload"></i></p> |
| <p>Drag and drop an image here</p> |
| </div> |
|
|
| </div> |
| </div> |
| <div class="col-lg-6"> |
| <h3><i class="fa fa-sign-out"></i> Destination</h3> |
| <hr/> |
| <p>3. Adjust the white threshold of the document as needed.</p> |
| <p>4. When ready, click the "Download" button, or right click the image and save.</p> |
| <div class="row"> |
|
|
| <div class="col-lg-4"> |
| <p>White Threshold: <input type="range" id="whitethreshold" min="0" max="255" value="100" onchange="render()"></p> |
| </div> |
| <div class="col-lg-8" style="text-align: right"> |
| <a id="download-image" class="btn btn-primary"><i class="fa fa-file-image-o"></i> Download Image</a> |
| <a id="download-pdf" class="btn btn-success"><i class="fa fa-file-pdf-o"></i> Download PDF</a> |
| </div> |
| </div> |
| <canvas id="destcanvas"></canvas> |
| </div> |
| </div> |
|
|
| <hr/> |
| <footer style="color: #666; text-align: center; margin: 30px 0; font-size: 14px">Copyright © ImageToScan.com. For support please contact <a href="mailto:support@imagetoscan.com">support@imagetoscan.com</a></footer> |
| </div> |
|
|
| </body> |