新規投稿
フォローする

Cropperを使ってトリミングをしながら画像アップロード

Cropper.jsは、画像のトリミングができるJavaScriptライブラリです。 トリミングとアップロードの作業がブラウザ上で一括して行えるので、作業の効率化が図れそうです。

※jQueryプラグイン版のCropperも公開されていますが、本記事ではCropper.jsの紹介をします。

サンプル

画像をトリミングしながらアップロードします。

フォーム設定


コード

まず、cropper.min.jsとcropper.min.cssを登録したのち、下記sample.jsとsample.cssを登録します。
※Cropper.js v1.4.1で動作を確認しています。

JavaScript

sample.js

(function() {
  "use strict";
  var cropper, file, cropperFile, cropperPreview, cropperCanvas, cropperHeight, cropperWidth;
  kintone.events.on([
    'app.record.create.show',
    'app.record.edit.show',
  ], function(event){
    kintone.app.record.setFieldShown('添付ファイル', false);
    kintone.app.record.getSpaceElement('space').innerHTML = '<div class="control-label-gaia"><span class="control-label-text-gaia">添付ファイル</span></div><div id="cropperWrapper"><input id="cropperFile" type="file"><div class="cropperContent"><div id="cropperPreview"></div><p><span id="cropperHeight"></span>*<span id="cropperWidth"></span>px</p></div><div class="cropperContent"><div id="cropperCanvas"></div></div></div>';
    cropperFile = document.getElementById('cropperFile');
    cropperPreview = document.getElementById('cropperPreview');
    cropperCanvas = document.getElementById('cropperCanvas');
    cropperHeight = document.getElementById('cropperHeight');
    cropperWidth = document.getElementById('cropperWidth');
    if(event.type === 'app.record.edit.show'){
      var xhr = new XMLHttpRequest();
      xhr.open('GET', '/k/v1/file.json?fileKey=' + event.record.添付ファイル.value[0].fileKey);
      xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
      xhr.responseType = 'blob';
      xhr.addEventListener('load', function(){
        var image = new Image();
        image.addEventListener('load', function(){
          cropperPreview.appendChild(image);
          cropperHeight.innerHTML = image.naturalHeight;
          cropperWidth.innerHTML = image.naturalWidth;
          document.getElementsByClassName('cropperContent')[0].style.display = 'block';
        });
        image.src = (window.URL || window.webkitURL).createObjectURL(xhr.response);
      });
      xhr.send();
    }
    cropperFile.addEventListener('change', function(e){
      var reader = new FileReader();
      file = e.target.files[0] || file;
      if(file.type.indexOf("image") < 0){
        return false;
      }
      reader.addEventListener('load', function(e){
        cropperCanvas.innerHTML = '<img src="' + e.target.result + '">';
        cropper = new Cropper(cropperCanvas.children[0], {
          aspectRatio: 1,
          preview: cropperPreview
        });
        cropperCanvas.children[0].addEventListener('crop', function(e){
          cropperHeight.innerHTML = Math.floor(e.detail.height);
          cropperWidth.innerHTML = Math.floor(e.detail.width);
        });
        [].forEach.call(document.getElementsByClassName('cropperContent'), function(element){
          element.style.display = 'block';
        });
      });
      reader.readAsDataURL(file);
    });
  });
  kintone.events.on([
    'app.record.create.submit.success',
    'app.record.edit.submit.success',
  ], function(event){
    if(!file) return event;
    return new kintone.Promise(function(resolve){
      cropper.getCroppedCanvas().toBlob(function(blob){
        var formData = new FormData();
        var xhr = new XMLHttpRequest();
        formData.append('__REQUEST_TOKEN__', kintone.getRequestToken());
        formData.append('file', blob, file.name);
        xhr.open('POST', encodeURI('/k/v1/file.json'));
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
        xhr.addEventListener('load', function(){
          kintone.api('/k/v1/record', 'PUT', {
            app: kintone.app.getId(),
            id: event.recordId,
            record: {
              添付ファイル: {
                value: [
                  {fileKey: JSON.parse(xhr.responseText).fileKey}
                ]
              }
            }
          }).then(function(){
            resolve(event);
          });
        });
        xhr.send(formData);
      }, file.type);
    });
  });
})();
// ポリフィル(参考URL:https://developer.mozilla.org/ja/docs/Web/API/HTMLCanvasElement/toBlob)
if(!HTMLCanvasElement.prototype.toBlob){
  Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
    value: function(callback, type, quality){
      var binStr = atob(this.toDataURL(type, quality).split(',')[1]),
        len = binStr.length,
        arr = new Uint8Array(len);
      for(var i=0; i<len; i++ ){
        arr[i] = binStr.charCodeAt(i);
      }
      callback(new Blob([arr], {type: type || 'image/png'}));
    }
  });
}

CSS

sample.css

#cropperWrapper{
  width: 600px;
}
#croppeWrapper:after{
  content: '';
  display: block;
  clear: both;
}
.cropperContent{
  float: left;
  margin: 10px;
  display: none;
}
#cropperFile{
  width: 100%;
}
#cropperPreview{
  text-align: center;
  overflow: hidden;
}
#cropperPreview,
#cropperPreview img{
  width: 100px;
  height: 100px;
}
#cropperCanvas{
  width: 400px;
  height: 200px;
}

トリミングのアスペクト比等々は、オプションで変更できます。 こちらを参考にしてください。

7

1件のコメント

Avatar
akatak

江田さん、いつもお世話になっております。本件の記事に関してですが、Mobile版に移植することは可能でしょうか?Mobile版で写真を撮影し加工(余白削除、明るさ調整等)したいニーズがございます。良いアイデアがありましたら、お知らせいただけると幸甚です。よろしくお願いします。

0
サインインしてコメントを残してください。