質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

0回答

3615閲覧

Cropper.jsを使用して、トリミング+画像補正(明度調整)を行い、画像をアップロードしたい

suzukiz

総合スコア10

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2018/11/10 20:42

編集2018/11/10 20:50

前提・実現したいこと

webサービスのフロントUIコーディングをしています。
画像アップロードの機能があるのですが、アップロードの際にトリミング/画像補正を行える仕様につまづいしまし、困っています。

まず大まかに説明しますと、
・モーダルウィンドウのなかに実装
・トリミング・画像補正は同時に行える
・リアルタイムでプレビューができる
・やり直しができる

現状の実装方法は
cropper.jsをつかって画像トリミング
・画像補正(明度補正)はinput rangeのスライダーでガンマ値を増減して明度補正(valueをjsで拾ってガンマ値に入れる)

■一連の動き、現在の問題点

- 01:モーダルウィンドウ立ち上げ時にcropper.jsでトリミング画像を取得し対象とする
↓↓
- 02:【パターン1 トリミング】
①画像を拡大縮小、回転、移動して、トリミング範囲を指定
②スライダー隣のトリミングボタンを押下
③トリミング用のjsが動き、画像をcanvasに描画
④canvasから画像に変換
※最後の④がうまくいっていない

- 02:【パターン2 画像補正】
①input rangeのスライダーでガンマ値(value値)を指定
②トリミング用のjsが動き、画像をcanvasに描画
③ガンマ値から画像補正処理を実行
④canvasけら画像に変換
※最後の④がうまくいっていない
※スライダーのトリガーはスライドが終わったタイミング
↓↓
- 03: やり直しボタンで01の状態まで戻る
↓↓
- 04: 02のトリミングor画像補正を再度行う

という流れです。

問題点は
1、canvasから画像へ変換が出来ていない
2、画像(canvas)補正時に補正処理が2回走ってしまい補正したものが上書きされる

という状況です。
誰かお力をkしていただければ助かります。

該当のソースコード

js

1//明度補正 2function canvasresultChange(id,src){ 3 var canvaswrap = document.getElementById("canvasresult"); 4 var gammaVal = document.getElementById("cropRange").value; 5 var canvas = canvaswrap.firstElementChild; 6 7 picWidth = canvas.clientWidth, 8 picHeight = canvas.clientHeight, 9 picLength = picWidth * picHeight, 10 mg = new Image(); 11 12 if(canvas.getContext){ 13 14 var ctx = canvas.getContext("2d"); 15 mg.onload = function() { 16 ctx.drawImage(mg,0,0); 17 18 // 画像情報の取得(offsetX, offsetY, 幅、高さ) 19 var imageData = ctx.getImageData(0, 0, 394, 221); 20 // imageData.dataが1pxごとのRGBAが含まれる 21 var data = imageData.data; 22 23 // ガンマ値=2.0 24 const gamma = gammaVal; 25 console.log(gammaVal); 26 // 補正式 27 const correctify = val => 255 * Math.pow(val / 255, 1 / gamma); 28 for (var i = 0; i < data.length; i += 4) { 29 data[i] = correctify(data[i]); 30 data[i+1] = correctify(data[i+1]); 31 data[i+2] = correctify(data[i+2]); 32 } 33 ctx.putImageData(imageData, 0, 0); 34 console.log(data.length); 35 if(i = data.length){ 36 console.log("end"); 37 canvasToimg(); 38 } 39 } 40 mg.src = src; 41 } 42} 43 44 45function canvasToimg(){ 46 console.log("change"); 47 var canvaswrap = document.getElementById("canvasresult"); 48 var canvas = canvaswrap.firstElementChild; 49 var imgdata = canvas.toDataURL('image/jpeg'); 50 51 // 画像として出力 52 var outputImg = document.getElementById('image'); 53 var delCanvas = document.getElementById('canvas'); 54 var newCanvas = document.getElementById('canvasresult'); 55 outputImg.src = imgdata; 56 document.getElementById('imageresult').appendChild(outputImg); 57 delCanvas.parentNode.removeChild(delCanvas); 58 var newCanvasinner = document.createElement('canvas'); 59 newCanvasinner.setAttribute("width", "394"); 60 newCanvasinner.setAttribute("height", "221"); 61 newCanvasinner.setAttribute("id", "canvas"); 62 newCanvas.appendChild(newCanvasinner); 63 64} 65 66 67 68 69function uploadimg(){ 70 71 'use strict'; 72 73 var Cropper = window.Cropper; 74 var URL = window.URL || window.webkitURL; 75 var container = document.querySelector('.img-container'); 76 //var image = container.getElementsByTagName('img').item(0); 77 var image = container.getElementsByTagName('img').item(0); 78 var download = document.getElementById('download'); 79 var actions = document.getElementById('actions'); 80 var dataX = document.getElementById('dataX'); 81 var dataY = document.getElementById('dataY'); 82 var dataHeight = document.getElementById('dataHeight'); 83 var dataWidth = document.getElementById('dataWidth'); 84 var dataRotate = document.getElementById('dataRotate'); 85 var dataScaleX = document.getElementById('dataScaleX'); 86 var dataScaleY = document.getElementById('dataScaleY'); 87 var options = { 88 viewMode: 3, 89 dragMode: 'move', 90 autoCropArea: 1, 91 restore: false, 92 modal: true, 93 guides: true, 94 highlight: false, 95 cropBoxMovable: false, 96 cropBoxResizable: false, 97 toggleDragModeOnDblclick: false, 98 //aspectRatio: 16 / 9, 99 preview: '.img-preview', 100 }; 101 var cropper = new Cropper(image, options); 102 var originalImageURL = image.src; 103 var uploadedImageType = 'image/jpeg'; 104 var uploadedImageName = 'cropped.jpg'; 105 var uploadedImageURL; 106 107 // Methods 108 actions.querySelector('.docs-buttons').onclick = function (event) { 109 var e = event || window.event; 110 var target = e.target || e.srcElement; 111 var cropped; 112 var result; 113 var input; 114 var data; 115 var reset; 116 117 if (!cropper) { 118 return; 119 } 120 121 while (target !== this) { 122 if (target.getAttribute('data-method')) { 123 break; 124 } 125 126 target = target.parentNode; 127 } 128 129 if (target === this || target.disabled || target.className.indexOf('disabled') > -1) { 130 return; 131 } 132 133 data = { 134 method: target.getAttribute('data-method'), 135 target: target.getAttribute('data-target'), 136 option: target.getAttribute('data-option') || undefined, 137 secondOption: target.getAttribute('data-second-option') || undefined 138 }; 139 140 cropped = cropper.cropped; 141 142 if (data.method) { 143 if (typeof data.target !== 'undefined') { 144 input = document.querySelector(data.target); 145 146 if (!target.hasAttribute('data-option') && data.target && input) { 147 try { 148 data.option = JSON.parse(input.value); 149 } catch (e) { 150 console.log(e.message); 151 } 152 } 153 } 154 155 switch (data.method) { 156 case 'rotate': 157 if (cropped && options.viewMode > 0) { 158 cropper.clear(); 159 } 160 161 break; 162 163 case 'getCroppedCanvas': 164 try { 165 data.option = JSON.parse(data.option); 166 } catch (e) { 167 console.log(e.message); 168 } 169 170 if (uploadedImageType === 'image/jpeg') { 171 if (!data.option) { 172 data.option = {}; 173 } 174 175 data.option.fillColor = '#fff'; 176 } 177 178 break; 179 } 180 181 result = cropper[data.method](data.option, data.secondOption); 182 183 switch (data.method) { 184 case 'rotate': 185 if (cropped && options.viewMode > 0) { 186 cropper.crop(); 187 } 188 189 break; 190 191 case 'scaleX': 192 case 'scaleY': 193 target.setAttribute('data-option', -data.option); 194 break; 195 196 case 'getCroppedCanvas': 197 if (result) { 198 var cropdata = result.toDataURL(uploadedImageType); 199 var canvasresulttarget = document.getElementById('canvasresult'); 200 canvasresulttarget.iinnerHTML += result; 201 setTimeout(canvasresultChange('canvas',cropdata), 1000); 202 } 203 204 break; 205 206 case 'destroy': 207 cropper = null; 208 209 if (uploadedImageURL) { 210 URL.revokeObjectURL(uploadedImageURL); 211 uploadedImageURL = ''; 212 image.src = originalImageURL; 213 } 214 215 case 'reset': 216 217 document.getElementById('cropRange').value = "1"; 218 219 break; 220 } 221 222 if (typeof result === 'object' && result !== cropper && input) { 223 try { 224 input.value = JSON.stringify(result); 225 } catch (e) { 226 console.log(e.message); 227 } 228 } 229 } 230 }; 231 232}; 233 234//ガンマスライダーで即時にcanvas変換 235window.onload = function () { 236 document.getElementById( "cropRange" ).onchange = function(){ 237 document.getElementById('croppedCanvas').click(); 238 }; 239} 240 241//ガンマ値スライダー 242var cropelem = document.getElementById('cropRange'); 243var target = document.getElementById('channelNum'); 244var croprangeValue = function (cropelem, target) { 245 return function(evt){ 246 target.innerHTML = cropelem.value; 247 cropRange(); 248 } 249} 250cropelem.addEventListener('input', rangeValue(cropelem, target)); 251cropRange(); 252function cropRange(){ 253 var targetActive = document.getElementById('crop--rangeActive'); 254 var croprangeValue = cropelem.value; 255 var active = 200 * (croprangeValue / 100); 256 targetActive.style.width = active+"px"; 257 var cnt = cropelem.value; 258} 259 260//ガンマスライダー初期化 261function croprangeValueDel(){ 262 document.getElementById('cropreset').click(); 263} 264

html

1<!-- モーダルトリガー --> 2<a onclick="uploadimg()" href="#modal"le>モーダル立ち上げ</a> 3 4<!-- モーダルウィンドウ --> 5<ul class="flex list"> 6 <li class="width-auto popup__crop--tool-range"> 7 <div id="crop--rangeBase"></div> 8 <i><img src="../img/icon/km_icon_icon_ganma.svg" style="width: 22px;"></i> 9 <input id="cropRange" class="range popup__range-slider" type="range" value="125" min="0" max="255" step="1" name="crop--radiorange" data-method="getCroppedCanvas" data-option="{ &quot;width&quot;: 394, &quot;height&quot;: 221 }"> 10 <div id="crop--rangeActive"></div> 11 </li> 12 <li class="width-expand"> 13 <button type="button" class="btn__gray" id="croppedCanvas" data-method="getCroppedCanvas" data-option="{ &quot;width&quot;: 394, &quot;height&quot;: 221 }"> 14 <i><img src="icon_crop_white.svg" style="width: 22px;"></i> 15 </button> 16 <button type="button" class="btn__gray" data-method="rotate" data-option="45" title="Rotate Right"> 17 <i><img src="icon_rotate_white.svg" style="width: 22px;"></i> 18 </button> 19 </li> 20</ul> 21<!-- ツールボタン類 --> 22<ul class="list grid-small popup__bottom-btn" grid> 23 <li class="width-1-3"> 24 <button class="btn__gray" type="button"><i style="float: left;" icon="arrow-left"></i>戻る</button> 25 </li> 26 <li class="width-1-3"> 27 <button id="cropreset" class="btn__gray" type="button" data-method="reset" title="Reset"><i icon="refresh"></i>やり直す</button> 28 </li> 29 <li class="width-1-3"> 30 <button class="btn__primary" type="button"><i icon="check"></i>編集完了</button> 31 </li> 32</ul> 33

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問