Cropper.js は画像をウェブページ上で加工するための JavaScript のライブラリです。人気で古くから続くライブラリで npm のみならず CDN でも配信されています。Cropeer.js のソースコードとデモは次にあります。
fengyuanchen/cropperjs: JavaScript image cropper.
Cropper.js#デモ
Cropper.js の使い方は様々です。使い方の一つとして画像のサイズや比率が決まっている中でユーザーにそのフォーマットを守らせつつ任意の画像をアップロードさせる、という使い方があります。これを行う時はユーザーのローカルの画像ファイルをHTML上のimg要素に展開し、そのimg要素にCropper.jsをかけ、Cropper.jsの結果をinput要素に出力し、それを送信する、とする必要があります。これを実際に作ったデモとソースコードが次です。
ソースコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Cropper.js ファイルから読み込みデモ</title>
<!-- CDNで Cropper.js を取得 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js" integrity="sha512-ooSWpxJsiXe6t4+PPjCgYmVfr1NS5QXJACcR/FPpsdm6kqG1FmQ2SVyg2RXeVuCRBLr0lWHnWJP6Zs1Efvxzww==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.css" integrity="sha512-+VDbDxc9zesADd49pfvz7CgsOl2xREI/7gnzcdyA9XjuTxLXrdpuz21VVIqc5HPfZji2CypSbxx1lgD7BgBK5g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script>
document.addEventListener('DOMContentLoaded', function (){
/** @var {Cropper|null} Cropperインスタンスを保持する関数 */
let cropper = null
document.querySelector('input[name="src-img"]').addEventListener('change', function(changeFileEvent){
if(cropper){
// 既に Cropper で何がしかの切り抜きをしている場合、それを入れ替えるために既存インスタンスを削除します
cropper.destroy();
}
// 入力された画像ファイルを Cropper で扱う img 要素に渡します
// FileReader を用いることで入力されたファイルを DataURI にすることでできます
// @see https://developer.mozilla.org/ja/docs/Web/API/FileReader/readAsDataURL
const fReaderForURI = new FileReader();
fReaderForURI.readAsDataURL(changeFileEvent.target.files[0]);
fReaderForURI.onload = () => {
// 生成した DataURI を img 要素に渡し、それに対して Cropper を用意します
const imgEl = document.getElementById('cropper-tgt');
imgEl.src = String(fReaderForURI.result);
cropper = new Cropper(imgEl, {aspectRatio: 16 / 9});
}
document.getElementById('btn-crop-action').addEventListener('click', function(){
// Cropper インスタンスから現在の切り抜き範囲の画像を canvas 要素として取れます。
/** @var {HTMLCanvasElement} croppedCanvas */
const croppedCanvas = cropper.getCroppedCanvas();
// canvas要素にはimg要素のsrcプロパティに渡した時に画像として表示される形式のデータを返すメソッド toDataURL があります。
// これをimg要素に渡すことで切り抜き結果を画面に表示できます。
// @see https://developer.mozilla.org/ja/docs/Web/API/HTMLCanvasElement/toDataURL
document.getElementById('preview').src = croppedCanvas.toDataURL()
// canvas 要素には描画されているデータを Blob としてを扱える様にするメソッド toBlob があります。
// これを img 要素に渡すことで切り抜き結果を画面に表示できます。
// @see https://developer.mozilla.org/ja/docs/Web/API/HTMLCanvasElement/toDataURL
croppedCanvas.toBlob(function(imgBlob){
// Blob を元に File 化します。
const croppedImgFile = new File([imgBlob], '切り抜き画像.png' , {type: "image/png"});
// DataTransfer インスタンスを介することで input 要素の files に
// JavaScript 内で作った File を渡せます。
// 直に new FileList から作って渡そうとすると失敗します。
const dt = new DataTransfer();
dt.items.add(croppedImgFile);
document.querySelector('input[name="cropped-img"]').files = dt.files;
});
})
})
})
</script>
<style>
.control {
display: flex;
flex-direction: column;
width: fit-content;
gap: 8px;
}
#cropper-tgt {
max-width: 100%;
}
.cropper-area {
max-width: 60vw;
display: flex;
flex-direction: column;
gap: 8px;
}
.cropped-form{
border-top: dashed 2px black;
margin-top: 1em;
display: flex;
justify-content: center;
flex-direction: column;
gap: 8px;
}
.caption {
font-weight: bold;
font-size: 1.2em;
}
</style>
</head>
<body>
<div class="cropper-area">
<span class="caption">Cropper.jsによる切り抜き</span>
<img id="cropper-tgt">
<div class="control">
<label>画像ファイル<input type="file" name="src-img" accept="image/*"></label>
<button type="button" id="btn-crop-action">切り取り</button>
</div>
</div>
<form class="cropped-form" action="" enctype="multipart/form-data" method="post">
<span class="caption">送信フォーム</span>
<img id="preview">
<label>切り抜き後画像ファイル<input type="file" name="cropped-img" accept="image/*"></label>
<button type="submit">画像を送信</button>
</form>
</body>
</html>
入力されたファイルを元に Cropper を動かす部分を抜き出すと次です。
document.querySelector('input[name="src-img"]').addEventListener('change', function(changeFileEvent){
// 入力された画像ファイルを Cropper で扱う img 要素に渡します
// FileReader を用いることで入力されたファイルを DataURI にすることでできます
// @see https://developer.mozilla.org/ja/docs/Web/API/FileReader/readAsDataURL
const fReaderForURI = new FileReader();
fReaderForURI.readAsDataURL(changeFileEvent.target.files[0]);
fReaderForURI.onload = () => {
// 生成した DataURI を img 要素に渡し、それに対して Cropper を用意します
const imgEl = document.getElementById('cropper-tgt');
imgEl.src = String(fReaderForURI.result);
cropper = new Cropper(imgEl, {aspectRatio: 16 / 9});
}
}
<img id="cropper-tgt">
<div class="control">
<label>画像ファイル<input type="file" name="src-img" accept="image/*"></label>
<button type="button" id="btn-crop-action">切り取り</button>
</div>
JavaScript には FileReader というユーザーのローカルにあるファイルを読み取る機能があります。これを用いてファイルの中身を DataURI 化して img 要素の src プロパティに渡すことでローカルファイルを画像として表示できます。ここまでこれば普段の Cropper,js 同様です。Cropper.js の切り抜き対象にローカルファイルを展開した img 要素を指定して切り抜きを開始できます。
出力については以前の記事が詳しいです。Cropper.js の機能で切り抜いた部分を canvas にして、それを img 要素、input 要素に渡しているだけです。渡した時点でプレビュー画像が見えるファイルセット済みフォームができあがっており、後は送信するだけです。