Cropper.jsとjquery-cropperで作る画像切り抜きUI入門

概要

ユーザーがアップロードした画像を、サーバーに送る前にブラウザ上で切り抜く——プロフィール画像やサムネイルの登録では定番のUIです。自前で実装するとドラッグ処理・リサイズハンドル・アスペクト比の固定などで一気に複雑になりますが、Cropper.js を使えば数行で実現できます。

本記事では、素のCropper.jsでの最小実装と、jQueryベースのプロジェクト向けラッパーである jquery-cropper での書き方を入門として整理します。アスペクト比固定、切り抜き結果の取得(Canvas / Blob)、サーバー送信までを一通り扱います。

環境

  • Cropper.js v1 系(本記事の記述は v1.6 を想定)
  • jquery-cropper を使う場合は jQuery 1.9.1 以降 + Cropper.js
  • 動作確認ブラウザ: 最新の Chrome / Firefox / Safari

> バージョンに関する注意:Cropper.js には v1(cropperjs)と、UI/APIを刷新した後継の v2 があります。v2 はWeb Componentsベースで本記事のAPIとは互換がありません。既存プロジェクトやjquery-cropperと組み合わせる前提では v1 系が実績豊富です。本記事は v1 系を前提にしています。

導入

CDNで読み込む

もっとも手軽なのはCDNです。CSSとJSの両方が必要な点に注意してください。

<!-- CSS -->
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/cropperjs@1.6.2/dist/cropper.min.css"
/>

<!-- JS -->
<script src="https://cdn.jsdelivr.net/npm/cropperjs@1.6.2/dist/cropper.min.js"></script>

jquery-cropperを使う場合は、jQuery → Cropper.js → jquery-cropper の順で読み込みます。

<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/cropperjs@1.6.2/dist/cropper.min.css"
/>
<script src="https://cdn.jsdelivr.net/npm/cropperjs@1.6.2/dist/cropper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-cropper@1.0.1/dist/jquery-cropper.min.js"></script>

npmで導入する

バンドラを使う場合は npm 経由が管理しやすいです。

npm install cropperjs
# jQuery連携する場合
npm install jquery jquery-cropper
import Cropper from "cropperjs";
import "cropperjs/dist/cropper.css";

> 注意:CSSの読み込み忘れは最頻出のハマりどころです。CSSが無いとクロップボックスやハンドルのスタイルが崩れ、ドラッグ領域が見えなくなります。「動かない」と感じたらまずCSSを疑ってください。

最小実装(素のCropper.js)

まずはHTML。Cropper.jsは <img> または <canvas> を対象に初期化します。ラップする親要素に幅を持たせるのがポイントです。

<div class="img-container" style="max-width: 600px;">
  <img id="image" src="/path/to/picture.jpg" alt="編集対象の画像" />
</div>

JavaScript側で初期化します。

const image = document.getElementById("image");

const cropper = new Cropper(image, {
  aspectRatio: 16 / 9, // アスペクト比を16:9に固定
  viewMode: 1,         // クロップボックスを画像の内側に制限
});

これだけで、ドラッグでクロップボックスを動かし、四隅・四辺のハンドルでリサイズできるUIが完成します。

よく使うオプション

オプション 説明
aspectRatio 切り抜き比率を固定。NaN(デフォルト)で自由比率
viewMode 0〜3。1 以上でクロップボックスが画像外に出ないよう制限
dragMode 'crop'(新規ボックス描画) / 'move'(画像移動) / 'none'
autoCropArea 初期クロップボックスの大きさ(0〜1の割合)
movable / zoomable / rotatable 画像の移動・ズーム・回転の可否
responsive ウィンドウリサイズ時に再描画するか(デフォルト true)

プロフィール画像のように正方形で切り抜きたいときは aspectRatio: 1 を指定します。

切り抜き結果を取得する

ユーザーが切り抜いた範囲を実際のデータとして取り出します。代表的なのは getCroppedCanvas() です。

// Canvasとして取得(出力サイズも指定できる)
const canvas = cropper.getCroppedCanvas({
  width: 400,
  height: 400,
  imageSmoothingQuality: "high",
});

// 1) data URL(プレビュー表示などに)
const dataUrl = canvas.toDataURL("image/jpeg", 0.9);
document.getElementById("preview").src = dataUrl;

// 2) Blob(サーバー送信に最適)
canvas.toBlob(
  (blob) => {
    const formData = new FormData();
    formData.append("avatar", blob, "avatar.jpg");

    fetch("/api/upload", {
      method: "POST",
      body: formData,
    });
  },
  "image/jpeg",
  0.9
);

> 補足:サーバー送信では data URL(base64文字列)より Blob + FormData を推奨します。base64は元データより約33%大きくなり、巨大な文字列をJSONに詰めると帯域もメモリも無駄が出ます。toBlob() ならバイナリのまま multipart で送れます。

座標だけ欲しい場合は getData() で切り抜き矩形の数値(x / y / width / height / rotate など)を取得できます。サーバー側で切り抜きを行う設計なら、この座標だけ送るのも手です。

const data = cropper.getData();
// { x, y, width, height, rotate, scaleX, scaleY }

jquery-cropperでの書き方

既存プロジェクトがjQueryベースなら、jquery-cropperでメソッドチェーンに馴染ませられます。中身はCropper.jsそのままで、$(...).cropper(...) という呼び出し形式を提供するラッパーです。

const $image = $("#image");

// 初期化
$image.cropper({
  aspectRatio: 1,
  viewMode: 1,
});

// メソッド呼び出し: cropper('メソッド名', 引数)
$image.cropper("rotate", 90);              // 90度回転
$image.cropper("zoom", 0.1);               // ズーム
$image.cropper("setAspectRatio", 16 / 9);  // 比率変更
$image.cropper("reset");                   // リセット

// 切り抜きCanvasの取得
const canvas = $image.cropper("getCroppedCanvas");

// インスタンス破棄
$image.cropper("destroy");

戻り値が必要なメソッド(getCroppedCanvas / getData など)は、素のCropper.jsと同じ値を返します。

ファイル選択と連動させる

実運用では <input type="file"> で選ばれた画像を読み込み直す流れが定番です。

<input type="file" id="fileInput" accept="image/*" />
<div class="img-container" style="max-width: 600px;">
  <img id="image" alt="" />
</div>
const fileInput = document.getElementById("fileInput");
const image = document.getElementById("image");
let cropper = null;

fileInput.addEventListener("change", (e) => {
  const file = e.target.files[0];
  if (!file) return;

  const url = URL.createObjectURL(file);
  image.src = url;

  if (cropper) {
    // 既存インスタンスがあれば画像だけ差し替える
    cropper.replace(url);
  } else {
    cropper = new Cropper(image, {
      aspectRatio: 1,
      viewMode: 1,
    });
  }
});

> メモリ管理:URL.createObjectURL() で作ったURLは URL.revokeObjectURL() で解放するとメモリリークを防げます。画像の load イベント後や、次の画像に差し替えるタイミングで解放しましょう。

確認方法

  1. ページを開き、画像上でドラッグしてクロップボックスが動くこと
  2. 四隅・四辺のハンドルでリサイズできること
  3. aspectRatio を指定した場合、比率が固定されたままリサイズされること
  4. 切り抜きボタンで getCroppedCanvas() の結果をプレビューに表示できること
  5. 送信後、サーバー側に指定サイズの画像が届くこと(出力 width/height と一致するか)

デバッグ時は cropper.getData() をコンソールに出し、座標が期待通りか確認すると原因の切り分けが早いです。

注意点

  • CSSの読み込みは必須。崩れたら真っ先に疑う。
  • 画像は crossOrigin に注意。別オリジンの画像を getCroppedCanvas() すると Canvas が汚染(tainted)され、toDataURL / toBlob が失敗します。CORS対応したURLを使うか、サーバー経由で取得してください。
  • viewMode: 0 だとクロップボックスが画像外に出られるため、意図しない余白が入ることがあります。多くのUIでは viewMode: 1 が無難です。
  • 初期化対象の <img> は、親要素に幅がないと表示されないことがあります。
  • v1 と v2 でAPIが大きく異なります。記事・サンプルを参照するときはバージョンを確認してください。
  • モバイルではタッチ操作に対応していますが、ピンチズームなどブラウザ標準のジェスチャと競合する場合があるため実機確認を推奨します。

まとめ

Cropper.js は、画像切り抜きUIで必要になる「ドラッグ・リサイズ・比率固定・結果の取り出し」をまとめて引き受けてくれるライブラリです。入門としては次の3点を押さえれば十分に動かせます。

  • new Cropper(img, options) で初期化(CSS必須・親要素に幅)
  • getCroppedCanvas() → toBlob() + FormData でサーバー送信
  • jQueryプロジェクトなら jquery-cropper で $(...).cropper(...) 形式に統一

まずは aspectRatio: 1 のプロフィール画像切り抜きから始めると、全体の流れがつかみやすいはずです。

\ 最新情報をチェック /

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。