LoginSignup
4
2

More than 3 years have passed since last update.

長方形の画像データをcanvasで回転させるのにぐだった話

Posted at

要件

html2canvasで得た画像データを90度回転させる。

詳細

html2canvasはページ一部の領域をhtml,css解読してスクリーンショット取ってくれる神ライブラリ。
今回は作品を紹介するような紹介カードを作れるという機能を実装したが、PC版で最初にやってしまったためスマホで同じサイズ比のカードテンプレートを作ろうと思うと90度回転しなければならなくなった。
canvasis.png

html2canvasの場合、対象領域のHTMLelementを渡すとコールバックでcanvasを渡してくれるが、この時点で幅・高さ・向きは決定してしまっているため、なかなか編集に手こずった。
コンテキストを回転させる方法はctx.rotateという。これは分かっていたのだが、そのまま適応させてもcanvas自体は回転していないのでこうなる ↓
canvasexif.png

また、canvasのサイズを後から変更すると描画内容も一緒に失われるのでこれも出来ない。

挙句の果てに迷走し、JSで画像データを(canvasでなく)そのままいじれないか!?とか考えてexif周りの事を調べたりもした。当然できなかった。

JSで画像データをいじる際は必ずcanvasを通して行います。
------------ https://ja.javascript.info/blob#ref-122

ちくしょうスマホのトリミング機能使いてぇ......

結果

新しくcanvasを作り、描画内容は元canvasからコピーしてくる。

canvasRotate.js
function canvasRotate270(img){
    const canvas = document.createElement('canvas');
    canvas.width = img.clientHeight;
    canvas.height = img.clientWidth;
    //縦横比反転canvas
    const ctx = canvas.getContext('2d');

    ctx.save();
    ctx.translate(0,canvas.height);
    ctx.rotate( 270 * Math.PI / 180 );
    ctx.drawImage(img, 0, 0,canvas.height,canvas.width,0,0,canvas.height,canvas.width);
    ctx.restore();
    return canvas;
}

canvas・contextの使い方をよく理解していなかった。


解説

ctx.drawImageは元画像のある指定領域を切り抜き、貼り付け先画像にも貼り付ける領域を指定できる(元画像データはimgからでなくてもcanvasからでも可。)
よってctx(コンテキスト)の向きが回転していても、ctx.translateで中心点ずれててもきちんと座標を指定できれば問題ない。

今回私の場合は270度の回転が必要だったが、中心点(グラフの座標原点みたいなイメージ)をしらべるとcanvasの縦横比に関わらず、左上に原点が設定されることが分かった。

よって、ctxの回転前にtranslateで描画原点を回転後のcanvasの左上に設定すればいい。

canvasRotate.js
ctx.translate(0,canvas.height);

kiji.png

あとはctx.drawImageで元画像(赤矩形)の(0,0)~(x,y)を指定し切り抜き、回転後の青の矩形で(0,0)~(x,y)へ貼り付ける。

canvasRotate.js
ctx.drawImage(img, 0, 0,canvas.height,canvas.width,0,0,canvas.height,canvas.width);

ctx.roteteのせいでx,yが反転してることに注意。

今考えたら90度でよくね??


まとめ

主に、drawImageの性質の理解が足りていなかった。本質は画像のコピーと貼り付けを同時に行えるクリップ機能だった。
これとtranslateとrotateがあれば何でもできる為、ネット記事では解説することもなかったのだろう。

なんだか書いてるうちにtranslateのあたりの座標説明がずれてるな....と感じたがそろそろ次の作業に入りたいのでやめておく。
コンテキストによる描画の回転ctx.rotate()について挙動がよく分からない方は正常なcanvasをctx.rotate(10 * Math.PI / 180)で10度だけ回してみたり、ちょっとだけctx.translateしてみたりするのが一番早いと思います。私も結局そうでした。

以上です。いろいろ落ち着いたらcanvas使ってゲーム作りたいな。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2