Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!DOCTYPE html>
<html lang="ja">
<head>

  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">

  <!-- JavaScript -->
  <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
  <script type="text/javascript" src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" crossorigin="anonymous"></script>

  <!-- CSS -->
  <link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
  <link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.13.1/css/all.css">
 
</head>
<body>
  <div id="generator" class="container px-3 mt-4 mb-4">
    <div class="card">
        <div class="card-header font-weight-bold"><i class="fas fa-image"></i>Canvas に正しい向きで画像を描画する</div>
      <div class="card-body px-3 px-md-5 pt-4">
        <p>
          <canvas id="canvas" width="1920" height="1080" style="display: block; background-color: #272727; width: 100%;"></canvas>
        </p>
        <p class="text-center text-md-left">
          <input type="file" class="btn btn-info" accept="image/*" style="max-width: 100%; cursor: pointer;" />
        </p>
        <p class="mb-0 text-center text-md-left">
          <button id="save" class="btn btn-info" style="cursor: pointer;">
            <i class="fas fa-download"></i>
            画像を保存する
          </button>
        </p>
      </div>
    </div>
  </div>
</body>
</html>

              
            
!

CSS

              
                
body {
    background-color: #dffbeb !important;
}

i {
    width: 17px;
    margin-right: 10px;
}
              
            
!

JS

              
                $(function(){
  
  // Canvas を作っておく
  var canvas = document.getElementById('canvas');
  var context = canvas.getContext('2d');
  context.fillStyle = '#272727';

  // ファイルが選択された時
  $('input[type=file]').change(function(event){

    // ファイル情報を取得
    file = event.target.files[0];

    // キャンセルされたら戻る
    if (file === undefined){
      return;
    }

    // 画像ファイル以外だったらエラー出して戻る
    if (!file.type.match('image.*')) {
      alert('画像を選択してください!');
      return;
    }

    // 選択されたファイルを読み込む
    var reader = new FileReader();

    // 読み込まれたら実行
    reader.onloadend = function(){

      // 画像が回転している場合は正しい向きに直す
      clearOrientation(reader.result, function(result) {

        // result: 横向きが直った base64 画像データ
        // これを使って改めて Canvas を描画

        picture = new Image();
        picture.src = result;

        // 回転が修正された画像を読み込む
        picture.onload = function(event){

          // アスペクト比にあわせて計算
          // 画像の幅
          var width = picture.naturalWidth;
          // 画像の高さ
          var height = picture.naturalHeight;
          // アスペクト比
          var aspect = height / width;
          
          // キャンバスからはみ出ないように調整
          // 16:9 より縦長なら
          if (aspect >= 0.5625) { // 0.5625 … 16:9
            
            console.log('縦長')
          
            // 描画する幅
            // 描画する高さ ÷ アスペクト比 = 描画する幅
            var draw_width = canvas.height / aspect;
            
            // 描画する高さ
            var draw_height = canvas.height;
           
          // 16:9 より縦長なら
          } else if (aspect < 0.5625) {
            
            console.log('横長')
          
            // 描画する幅
            var draw_width = canvas.width;
            
            // 描画する高さ
            // 描画する幅 × アスペクト比 = 描画する高さ
            var draw_height = canvas.width * aspect;
            
          }

          // 左上からの幅
          // Canvas の幅から描画幅を引いた残りの空間を半分に割る
          var draw_left = (canvas.width - draw_width) / 2;
          
          // 左上からの高さ
          // Canvas の高さから描画高を引いた残りの空間を半分に割る
          var draw_top = (canvas.height - draw_height) / 2;

          // 予め塗りつぶしておく
          context.fillRect(0, 0, canvas.width, canvas.height);

          // 画像を描画する
          context.drawImage(picture, draw_left, draw_top, draw_width, draw_height);

        };

      });

    };

    // 画像の読み込みを実行
    if (file) {
      reader.readAsDataURL(file);
    }

  });

});

// 保存する
$('#save').click(function(event){
  if (canvas.msToBlob) {
    var blob = canvas.msToBlob();
    window.navigator.msSaveBlob(blob, 'image.png');
  } else {
    canvas.toBlob(function(blob){
      var a = document.createElement('a');
      a.href = URL.createObjectURL(blob);
      a.download = 'image.png';
      a.click();
    });
  }
});

// ブラウザが画像の自動回転機能をサポートしているか
// サポートしていれば true・サポートしていなければ false を返す
function isSupportedImageAutoRotation() {
    // image-orientation: from-image; がサポートされた環境では image-orientation の既定値が from-image になっていることを利用
    return getComputedStyle(document.body)['imageOrientation'] === 'from-image';
}

// 回転している画像を正しい向きに直す
// 参考: https://qiita.com/mo49/items/a3d61d97f1883ead333b
function clearOrientation(imgDataURL, callBack) {

    var byteString = atob(imgDataURL.split(',')[1]);
    var orientation = byteStringToOrientation(byteString);

    // Exif の Orientation が存在している &
    // Exif の Orientation が 1 以外 &
    // ブラウザが画像の自動回転に対応していない場合 だけ画像を正しい向きに回転する
    if (orientation !== undefined && orientation !== 1 && !isSupportedImageAutoRotation()){

        var img = new Image();
        img.onload = function() {

            var canvas = document.createElement('canvas');
            var ctx = canvas.getContext('2d');
            switch (orientation) {
                case 3: //画像が180度回転している時
                    canvas.width = img.width;
                    canvas.height = img.height;
                    ctx.rotate(Math.PI);
                    ctx.drawImage(img, -img.width, -img.height);
                    ctx.rotate(-Math.PI);
                    break;
                case 6: //画像が時計回りに90度回っている時
                    canvas.width = img.height;
                    canvas.height = img.width;
                    ctx.rotate(Math.PI * 0.5);
                    ctx.drawImage(img, 0, -img.height);
                    ctx.rotate(-Math.PI * 0.5);
                    break;
                case 8: //画像が反時計回りに90度回っている時
                    canvas.width = img.height;
                    canvas.height = img.width;
                    ctx.rotate(-Math.PI * 0.5);
                    ctx.drawImage(img, -img.width, 0);
                    ctx.rotate(Math.PI * 0.5);
                    break;
                default:
                    canvas.width = img.width;
                    canvas.height = img.height;
                    ctx.drawImage(img, 0, 0);
            }
            callBack(canvas.toDataURL('image/jpeg'));
        }
        img.src = imgDataURL;

    } else {

        callBack(imgDataURL); // 渡された DataURL をそのまま返す

    }
}

// Exif 情報の Orientation を取得する
// 参考: https://qiita.com/mo49/items/a3d61d97f1883ead333b
function byteStringToOrientation(img) {
    var head = 0;
    var orientation;
    while (1) {
        if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 218) {
            break;
        }
        if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 216) {
            head += 2;
        } else {
            var length = img.charCodeAt(head + 2) * 256 + img.charCodeAt(head + 3);
            var endPoint = head + length + 2;
            if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 225) {
                var segment = img.slice(head, endPoint);
                var bigEndian = segment.charCodeAt(10) == 77;
                if (bigEndian) {
                    var count = segment.charCodeAt(18) * 256 + segment.charCodeAt(19);
                } else {
                    var count = segment.charCodeAt(18) + segment.charCodeAt(19) * 256;
                }
                for (var i = 0; i < count; i++) {
                    var field = segment.slice(20 + 12 * i, 32 + 12 * i);
                    if ((bigEndian && field.charCodeAt(1) == 18) || (!bigEndian && field.charCodeAt(0) == 18)) {
                        orientation = bigEndian ? field.charCodeAt(9) : field.charCodeAt(8);
                    }
                }
                break;
            }
            head = endPoint;
        }
        if (head > img.length) {
            break;
        }
    }
    return orientation;
}

              
            
!
999px

Console