画像を縮小してトリミング

Android端末を買ったので興味が出たのでやってみた。

方針としては、
・フォームで指定したFileReaderで読み込んで画像をCanvasに書き出す。
Canvasの画像の表示位置をマウスイベントで移動させる。
・スライドバーで画像の縮小率を変える。
・とりあえず、Chromeで動けばいいや。


見た目はこんな


コードはこんな

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>キャンバスに画像を読み込んでトリミング</title>

<script type="text/javascript">
// マウスボタンの状態
var mouseDown = false;
// Canvasサイズ
var viewSize = 400;
// トリミングサイズ
var trimSize = 200;
var trimPadding = 100;
// 画像描画開始位置
var viewX = 0;
var viewY = 0;
// マウスボタンを押したときの位置
var startX = 0;
var startY = 0;
// 読み込んだイメージのサイズ
var imageWidth;
var imageHeight;

var canvas;
var context;
var img;

// 縮小率
var range;
var retio = 1;

// トリム結果の表示先
var trimCanvas;

function setUp() {
  // Canvas
  canvas = document.getElementById('view_canvas');
  canvas.width = viewSize;
  canvas.height = viewSize;
  
  trimCanvas = document.getElementById('trim_canvas');
  trimCanvas.width = trimSize;
  trimCanvas.height = trimSize;
  
  // 画像
  img = new Image();
  img.onload = function() {
    context = canvas.getContext('2d');
    draw(0,0);
    imageWidth = 0 - img.width;
    imageHeight = 0 - img.height;
  }

  // スライドバー
  range = document.getElementById('image_ratio');
  range.onchange = function() {
    viewX = 0;
    viewY = 0;
    ratio = this.value / 100;
    draw(0, 0);
  }
}

// Canvasに選択した画像を展開
function preview(ele) {
  // ファイルが選択されているか?
  if (!ele.files.length) return;
  // Canvas使えるか?
  if ( ! canvas || ! canvas.getContext ) return;
  // 対象型式の画像か?
    var file = ele.files[0];
  if (!/^image\/(png|jpeg|gif)$/.test(file.type)) return;

  // リーダー
  var reader = new FileReader();
  reader.onload = function() {
    img.src = reader.result;
  }  
  //読み込み実施
  viewX = 0;
  viewY = 0;
  range.value = 100;
  ratio = 1;
  reader.readAsDataURL(file); 
}

// 画像の表示位置変更
function onCanvasMouseMove(event) {
  if (mouseDown){
    // 横位置計算
    viewX = viewX + (event.clientX - startX) / 20;
    // 画像の外まで飛んでいかないように
    if(viewX > trimPadding ) viewX = trimPadding;
    var maxX = imageWidth * ratio + viewSize - trimPadding;
    if(viewX < maxX) {
      viewX = maxX;
    }
    
    // 縦位置計算
    viewY = viewY + (event.clientY - startY) / 20;
    // 画像の外まで飛んでいかないように
    if(viewY > trimPadding ) viewY = trimPadding;
    var maxY = imageHeight * ratio + viewSize - trimPadding;
    if(viewY < maxY) {
      viewY = maxY;
    }
    // 再描画
    draw(viewX, viewY);
  }
}

// キャンバス上のマウスボタン押下
function onCanvasMouseDown(event) {
  mouseDown = true;
  startX = event.clientX;
  startY = event.clientY;
}

// キャンバス上のマウスボタン開放
function onCanvasMouseUp() {
  mouseDown = false;
  startX = 0;
  startY = 0;
}

// 画像をキャンバスに描画
function draw(x, y) {
  context.fillRect(0,0,viewSize,viewSize);
  context.drawImage(img, x, y, img.width * ratio, img.height * ratio);
  context.strokeStyle = 'rgb(0,0,0)';
  context.strokeRect(trimPadding - 1, trimPadding - 1, trimSize + 2, trimSize + 2);
  context.strokeStyle = 'rgb(255,255,255)';
  context.strokeRect(trimPadding - 2, trimPadding - 2, trimSize + 4, trimSize + 4);
}

// トリミング実施
function trimImage() {
  var trimData = context.getImageData(trimPadding, trimPadding, trimSize, trimSize);
  var trimContext = trimCanvas.getContext('2d');
  trimContext.putImageData(trimData, 0, 0 );
}
</script>
</head>

<body onload="setUp();">

<form>
<input type="file" name="file" onchange="preview(this);" />
<hr />
<h4>キャンバスに画像を読み込んでトリミング</h4>
<canvas id="view_canvas"
  onmousemove="onCanvasMouseMove(event);"
  onmousedown="onCanvasMouseDown(event);"
  onmouseup="onCanvasMouseUp();"
  onmouseout="onCanvasMouseUp();"
  style="border:solid 1px black;">
</canvas>
<canvas id="trim_canvas"
  style="border:solid 1px black;">
</canvas>
<br/>
10%
<input type="range" id="image_ratio" min="10" max="100" value="100" style="width:350px;"/>
100%
<br/>
<input type="button" value="切り出し" onclick="trimImage()"/>
<hr/>
</form>
</body>
</html>

おお、動いた。
FireFoxだとスライドバーが使えないけど、そこをクリアすればScript自体は動きそう。
OperaSafariは試してないけど、どうだろ?
IEはまあムリ。ExplorerCanvasはともかくFileReaderが。