JPEGのExif情報の確認と削除 [EXIF.js]
「EXIF.js」を使用してJPEGファイルのExif情報の取得と削除を行います。併せて「effect.js」を利用する事で取得したExifの「画像方向」(タグ番号274のOrientation)の情報を元に画像を正しく回転/反転させます。
この2つのライブラリはオープンソースかつMITライセンスという非常に緩いライセンスです。他の言語にも移植可能です。
EXIF.js
https://github.com/TakeshiOkamoto/EXIF.js
effect.js
https://github.com/TakeshiOkamoto/effect.js
DEMO
https://www.petitmonte.com/labo/exif/
ソースコード
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <script src="EXIF.js"></script> <script src="effect.js"></script> <style> table, th, td { border : 1px solid #ccc; } th{ background-color : #ccc; } #btn_start { margin: 0 8px 0 0; width:160px; font-size:20px; font-weight:bold; text-align:center; padding:8px 0 10px 0; color:#fff; background-color:#ff6347; } #btn_start:hover{ margin: 0 8px 0 0; width:160px; font-size:20px; font-weight:bold; text-align:center; padding:8px 0 10px 0; color:#fff; background-color:#ff4500; } </style> <script> var ExifMaster; var filename; // キャンバス var src_canvas, dst_canvas; var src_ctx, dst_ctx; // イメージ var image; window.onload = function(){ src_canvas = document.getElementById("SrcCanvas"); src_ctx = src_canvas.getContext("2d"); dst_canvas = document.getElementById("DstCanvas"); dst_ctx = dst_canvas.getContext("2d"); image = document.getElementById("img_source"); src_canvas.width = image.width; src_canvas.height = image.height; src_ctx.drawImage(image,0,0); document.getElementById("btn_start").style.backgroundColor ="#ccc"; document.getElementById("btn_start").disabled = true; } function onDragOver(event){ event.preventDefault(); } function onDrop(event){ onAddFile(event); event.preventDefault(); } function run() { if(!ExifMaster) return false; try{ ExifMaster.SaveToFile(filename, !document.form1.chk_orientation.checked); }catch(e){ alert(e); } return false; } function onAddFile(event) { var files; var reader = new FileReader(); if(event.target.files){ files = event.target.files; }else{ files = event.dataTransfer.files; } // *********************** // ArrayBuffer // ※ファイルの読み込み // *********************** reader.onload = function (event) { try{ ExifMaster = new TExifMaster(new Uint8Array(reader.result)); // プロパティ確認用 console.log(ExifMaster.Analyst); var html = "<p>"+ filename +" (" + ExifMaster.Analyst.Width + "x" + ExifMaster.Analyst.Height +")</p>"; if(ExifMaster.Analyst.IFD.main.length == 0){ html += '<p style="color:red;font-weight:bold;">このファイルには「Exif情報」はありません。</p>'; document.getElementById("btn_start").style.backgroundColor ="#ccc"; document.getElementById("btn_start").disabled = true; }else{ // ----------------- // メイン // ----------------- html += "<h3>メイン</h3>"; html += "<p></p>"; html += "<table>"; for(var i=0;i<ExifMaster.Analyst.IFD.main.length;i++){ html += "<tr>"; html += "<th>" + ExifMaster.Analyst.IFD.main[i].key + "</th>"; html += "<td>" + ExifMaster.Analyst.IFD.main[i].data + "</td>"; html += "</tr>"; } html += "</table>"; html += "<p></p>"; // ----------------- // GPS // ----------------- html += "<h3>GPS</h3>"; if(ExifMaster.Analyst.IFD.gps.length != 0){ if(ExifMaster.Analyst.DMS){ // Googleマップ用のURLの生成 var dms = ExifMaster.Analyst.DMS.replace('"','%22'); dms = dms.replace('"','%22'); dms = dms.replace('°','%C2%B0'); dms = dms.replace('°','%C2%B0'); html +='<p><a href="https://www.google.co.jp/maps/place/' + dms + '">Googleマップでこの座標の位置を確認する。</a></p>'; }else{ html += "<p></p>"; } html += "<table>"; for(var i=0;i<ExifMaster.Analyst.IFD.gps.length;i++){ html += "<tr>"; html += "<th>" + ExifMaster.Analyst.IFD.gps[i].key + "</th>"; html += "<td>" + ExifMaster.Analyst.IFD.gps[i].data + "</td>"; html += "</tr>"; } html += "</table>"; html += "<p>※UTC(協定世界時)に+9時間すると日本標準時となります。</p>"; }else{ html += "<p>GPS情報はありません。</p>"; } // ----------------- // カメラ // ----------------- html += "<h3>カメラ</h3>"; if(ExifMaster.Analyst.IFD.camera.length != 0){ html += "<p></p>"; html += "<table>"; for(var i=0;i<ExifMaster.Analyst.IFD.camera.length;i++){ html += "<tr>"; html += "<th>" + ExifMaster.Analyst.IFD.camera[i].key + "</th>"; html += "<td>" + ExifMaster.Analyst.IFD.camera[i].data + "</td>"; html += "</tr>"; } html += "</table>"; }else{ html += "<p>カメラ情報はありません。</p>"; } document.getElementById("btn_start").style.backgroundColor = "#ff6347"; document.getElementById("btn_start").disabled = false; } }catch(e){ alert(e); document.getElementById("btn_start").style.backgroundColor ="#ccc"; document.getElementById("btn_start").disabled = true; document.getElementById("result").innerHTML = ""; image.onload =function(e){ src_canvas.width = image.width; src_canvas.height = image.height; src_ctx.drawImage(image,0,0); } image.src = "dropbox.png"; return; } // *********************** // Base64 // ※リサイズ/回転/反転 // *********************** var base64 = new FileReader(); base64.onload = function (event) { image.onload = function (){ // 回転/反転なし var Orientation = ExifMaster.Analyst.Orientation; if (!Orientation){ Orientation = 1; } // ----------------- // リサイズ // ----------------- var size = 280; if(image.width > image.height){ // 幅を基準にアスペクト比を調整する var aspect_ratio = image.width / size; var another = Math.round(image.height / aspect_ratio); src_canvas.width = size; src_canvas.height = another; }else{ // 高さを基準にアスペクト比を調整する var aspect_ratio = image.height / size; var another = Math.round(image.width / aspect_ratio); src_canvas.width = another; src_canvas.height = size; } src_ctx.drawImage(image,0,0,src_canvas.width,src_canvas.height); // ----------------- // 生データの取得 // ----------------- var src, dst; switch (Orientation){ // サイズ変更なし case 2:;case 3:;case 4: dst_canvas.width = src_canvas.width; dst_canvas.height = src_canvas.height; break; // サイズ変更あり case 5:;case 6:;case 7:;case 8: dst_canvas.width = src_canvas.height; dst_canvas.height = src_canvas.width; } src = src_ctx.getImageData(0, 0, src_canvas.width, src_canvas.height); dst = dst_ctx.getImageData(0, 0, dst_canvas.width, dst_canvas.height); // ----------------- // エフェクト // ----------------- switch (Orientation){ // [状態]左右反転 case 2: EffectMirror(src, dst);break; // [状態]180度回転 case 3: EffectTrun(src, dst, 3);break; // [状態]上下反転 case 4: EffectFlip(src, dst);break; // [状態]右90度回転 + 左右反転 case 5: // 左90度 EffectTrun(src, dst ,1); src_canvas.width = dst_canvas.width; src_canvas.height = dst_canvas.height; src_ctx.putImageData(dst,0,0); // 左右反転 src = src_ctx.getImageData(0, 0, src_canvas.width, src_canvas.height); dst = dst_ctx.getImageData(0, 0, dst_canvas.width, dst_canvas.height); EffectMirror(src, dst); break; // [状態]左90度回転 case 6: EffectTrun(src, dst ,2);break; // [状態]左90度回転 + 左右反転 case 7: // 右90度 EffectTrun(src, dst ,2); src_canvas.width = dst_canvas.width; src_canvas.height = dst_canvas.height; src_ctx.putImageData(dst,0,0); // 左右反転 src = src_ctx.getImageData(0, 0, src_canvas.width, src_canvas.height); dst = dst_ctx.getImageData(0, 0, dst_canvas.width, dst_canvas.height); EffectMirror(src, dst); break; // [状態]右90度回転 case 8: EffectTrun(src, dst ,1);break; } if(Orientation != 1){ src_canvas.width = dst_canvas.width; src_canvas.height = dst_canvas.height; src_ctx.putImageData(dst,0,0); } } image.src = base64.result; } base64.readAsDataURL(new Blob([reader.result],{type:"image/jpeg"})); document.getElementById("result").innerHTML = html; }; if (files[0]){ filename = files[0].name; reader.readAsArrayBuffer(files[0]); document.getElementById("inputfile").value = ""; } } </script> </head> <body ondrop="onDrop(event);" ondragover="onDragOver(event);"> <div style="margin-left:5px;"> <h1>Exifの確認と削除</h1> <form name="form1"> <p><input type="file" id="inputfile" onchange="onAddFile(event);" accept="image/jpeg"></p> <canvas id="SrcCanvas" onclick='document.getElementById("inputfile").click();'></canvas> <canvas id="DstCanvas" style="display:none;"></canvas> <img id="img_source" style="display:none;" src="dropbox.png"> <p><input type="checkbox" id="chk_orientation" checked="checked"><label for="chk_orientation">Exifに画像方向の情報が存在するときは「画像方向」を残す。</label></p> <input type="submit" id="btn_start" onclick="return run();" value="削 除" style="background-color:#ccc;" disabled="disabled"> </form> <div id="result"></div> </div> </body> </html>
※dropbox.pngは各自で用意してください。
EXIF.jsでは「メイン、GPS、カメラ撮影」の標準的なExifの情報を取得します。その他は「一般社団法人 カメラ映像機器工業会」(ソニーやニコン、富士フィルムなどが参加)が公開しているExif2.3(DC-008-2012_J.pdf)などの仕様書を参考にして各自で機能を強化して下さい。
スポンサーリンク
関連記事
前の記事: | MP3/OGG/AAC/FLACファイルをWaveファイルに変換する [WAVE.js] |
次の記事: | JavaScriptでC/C++コードを実行してネイティブアプリのように高速にする [WebAssembly] |
公開日:2019年03月09日
記事NO:02742