JavaScriptで画像をリサイズしてから画像をアップロードする
以前作成した上記のものにPDF対応にしたものを作成してみました。
サーバーサイドは無いので失敗しますが、以下のような感じになります。
(CSRFの処理はコメントアウトしています。)
https://jsfiddle.net/bfb4b39z/41/
コメントで指摘いただいたものを参考に更新しました。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="https://mozilla.github.io/pdf.js/build/pdf.js"></script>
<script type="text/javascript" src="https://mozilla.github.io/pdf.js/build/pdf.worker.js"></script>
<script>
let scaleSlider = null;
let scaleValue = null;
let canvas = null;
let context = null;
let image = null;
const reader = new FileReader();
let fixFileObject = null;
let scale = null;
let messageArea = null;
let pdfFlag = false;
const pdfImageExtention = "png";
const csrf_token_name = "{$csrf_token_name}";
let csrf_hash = "{$csrf_hash}";
document.addEventListener("DOMContentLoaded", function() {
canvas = document.getElementById("thumbnail");
context = canvas.getContext("2d");
scaleSlider = document.getElementById("scale");
scaleValue = document.getElementById("scale-value");
messageArea = document.getElementById("message")
scaleSlider.addEventListener("change", changeScale);
setFileEventListenner();
});
function changeScale() {
scaleValue.value = scaleSlider.value;
drawCanvas();
}
function setFileEventListenner() {
document.getElementById("file-selecter").addEventListener("change", createPreview);
}
function createPreview(event) {
fixFileObject = null;
let fileObject = event.target.files[0];
if (typeof fileObject === "undefined") {
return;
}
if (fileObject.type.match(/^(image\/jpeg|image\/png|application\/pdf)$/) === null) {
// jpegとpngとpdf以外の場合はクリアして終了
let fileArea = document.getElementById("file-input");
fileArea.innerHTML = fileArea.innerHTML;
setFileEventListenner();
return;
}
pdfFlag = fileObject.type.match(/^application\/pdf$/) !== null;
fixFileObject = fileObject;
image = new Image();
reader.onload = function(event) {
if ( ! pdfFlag) {
image.src = event.target.result;// base64
} else {
pdfjsLib.getDocument(new Uint8Array(event.target.result))
.then(pdf => {
return pdf.getPage(1);
})
.then(page => {
canvas.style.display = "none";// 読み込み時に下記のサイズで描画されるのでdrawCanvas()まで非表示にしておく
// ここで基準となるcanvasサイズが決まるのでscaleは1で読み込んでおく
let viewport = page.getViewport(1);
canvas.height = viewport.height;
canvas.width = viewport.width;
let renderContext = {
canvasContext: context,
viewport: viewport
};
// Render PDF page and set image
return page.render(renderContext);// Promise
})
.then(() => {
return new Promise(resolve => {
canvas.toBlob(blob => {
resolve(blob);
}, "image/" + pdfImageExtention);
});
})
.then(blob => {
if(image.src) {
const oldSrc = image.src;
URL.revokeObjectURL(oldSrc);// createObjectURLで作成したURLを削除
}
image.src = URL.createObjectURL(blob);
})
.catch(error => {
messageArea.innerHTML = '<span style="color: red;">ファイルの読み込みに失敗しました。</span>';
});
}
}
image.onload = function() {
drawCanvas();
}
pdfFlag ? reader.readAsArrayBuffer(fileObject) : reader.readAsDataURL(fileObject);
}
function drawCanvas() {
scale = scaleSlider.value;
if (image !== null) {
let imageWidth = parseInt(image.width * scale, 10);
let imageHeight = parseInt(image.height * scale, 10);
canvas.width = imageWidth;
canvas.height = imageHeight;
context.clearRect(0, 0, imageWidth, imageHeight);
context.drawImage(image, 0, 0, imageWidth, imageHeight);
}
if (canvas.style.display === "none")
{
canvas.style.display = "inherit";
}
}
// awaitを使うのでasync宣言
async function submitResizeFile() {
if (image !== null && fixFileObject !== null) {
let fileType = pdfFlag ? "image/" + pdfImageExtention : fixFileObject.type;
let fileName = pdfFlag ? fixFileObject.name.replace(/pdf/g, pdfImageExtention) : fixFileObject.name;
// toBlobが非同期処理なのでawaitでPromise待ち
let resizeFileObject = await (() => {
return new Promise(resolve => {
if (scale != 1 || pdfFlag === true) {
// 画像ファイルでサイズ変更があった場合またはPDFファイルの場合に送信用ファイルを作成
canvas.toBlob(blob => {
resolve(blob);
}, fileType);
} else {
// 画像ファイルでサイズ変更がない場合はそのまま
resolve(fixFileObject);
}
});
})();
let formData = new FormData();
formData.append(csrf_token_name, csrf_hash);
formData.append("file", resizeFileObject, fileName);
// input type file の 値はjavascriptで上書き出来ないのでajaxで送信する
fetch("/root/execute_upload", {
method: "POST",
body: formData,
credentials: "same-origin",// send Cookie csrf_token
}).then(response => {
// Forbidden is not json
if (response.status !== 403) {
response.json().then(function(json) {
csrf_hash = json.csrf_hash;
});
}
if (response.ok) {
messageArea.innerHTML = '<span style="color: green;">ファイルの送信に成功しました。</span>';
} else {
messageArea.innerHTML = '<span style="color: red;">ファイルの送信に失敗しました。</span>';
}
});
}
}
</script>
</head>
<body>
<form id="form">
Scale : <input id="scale" type="range" step="0.1" min="0.1" max="1" value="1"><input disabled id="scale-value" type="text" value="1" style="width: 2rem;">
<div id="file-input"><input id="file-selecter" type="file" name="file" accept="image/jpeg, image/png, application/pdf"></div>
<div><canvas id="thumbnail" style="display: none;"></canvas></div>
<input type="button" value="送信" onclick="submitResizeFile()">
<div id="message"></div>
</form>
</body>
</html>