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 要素に渡しているだけです。渡した時点でプレビュー画像が見えるファイルセット済みフォームができあがっており、後は送信するだけです。