iPhoneのsafariで写真撮影画像と撮影した画像をアップロードする方法調査

2018年6月3日

Javascript mobile テクノロジー プログラミング

ずいぶん昔ですが、iPhoneのsafariブラウザで入力フォームの「input type='file'」を使って撮影した画像をアップロードできるようになりました。 ・・・が、実はあまりこの機能を使っておらず、普通にアップロードできるだろうとたかをくくっていたところ、いくつかの問題が発生していたので、それらの対処方法を書いておきます。

iPhoneのsafariブラウザのファイル(写真)アップロード問題点

1. 画像が回転してしまう。 2. 撮影した画像はアップロードできるが、フォトライブラリの画像をアップロードしようとすると、何故かファイルが正常にアップロードできない。 3. 撮影画像アップロードと、フォトライブラリアップロードは、ファイルの拡張子が変わる(2018.6.2現在 , iOS11.3.1)
この機能を使った事がある人であれば、どれもネットで検索すれば対応方法は出てきますが、何故かまとまったやり方が書かれていなかったので、まとめて対応したいと思います。 ※ただし、対応方法はそれぞれ別々です。

1. 画像が回転してしまう事象の対応方法

画像が回転してしまう原因は、EXIF情報を取得して、正確にorientation値を反映しなければいけません。 EXIFが何かわからない人は、下記のリンクを参照ください。 https://ja.wikipedia.org/wiki/Exchangeable_image_file_format 簡単に言うと、撮影した画像(jpeg)ファイルに書き込まれている情報の事です。 この情報を取り出すには、ライブラリを使うのが簡単です。 exifというjavascriptのライブラリですが、下記のGithubから、「exif.js」だけをダウンロードして使うのがいいでしょう。 ライセンスも「MIT」と書かれているので、全く問題ありません。 https://github.com/exif-js/exif-js そして、下記のようなjavascriptのコードを記述する事で、exif情報が取得できます。 ※途中省いてますが、取れる情報はなんとなくわかると思います。 var img = new Image(); img.src = URL.createObjectURL(files[0]); // input type="file"で読み込まれた画像 img.onload = function(){ EXIF.getData(img , function() { var exif = EXIF.getAllTags(this); console.log(JSON.stringify(exif)); }); var exit={}; }; 結果 { "Make": "Apple", "Model": "iPhone X", "Orientation": 6, "XResolution": 72, "YResolution": 72, "ResolutionUnit": 2, "Software": "11.3.1", "DateTime": "2018:05:24 08:36:07", "undefined": 50, "ExifIFDPointer": 218, "GPSInfoIFDPointer": 1760, "ExposureTime": 0.05, "FNumber": 1.8, "ExposureProgram": "Normal program", "ISOSpeedRatings": 40, "ExifVersion": "0221", "DateTimeOriginal": "2018:05:24 08:36:07", "DateTimeDigitized": "2018:05:24 08:36:07", "ComponentsConfiguration": "YCbCr", "ShutterSpeedValue": 4.324497991967871, "ApertureValue": 1.6959937156323646, "BrightnessValue": 2.9389373513084855, "ExposureBias": 0, "MeteringMode": "Pattern", "Flash": "Flash did not fire, compulsory flash mode", "FocalLength": 4, "SubjectArea": [ 2015, 1511, 2217, 1330 ], "MakerNote": [ 65, 112, 112, 108, 101, 32, 105, 79, 83, .......... ], "SubsecTimeOriginal": "470", "SubsecTimeDigitized": "470", "FlashpixVersion": "0100", "PixelXDimension": 4032, "PixelYDimension": 3024, "SensingMethod": "One-chip color area sensor", "SceneType": "Directly photographed", "ExposureMode": 0, "WhiteBalance": "Auto white balance", "FocalLengthIn35mmFilm": 28, "SceneCaptureType": "Standard", "GPSLatitudeRef": "N", "GPSLatitude": [ 35, 31, 59.46 ], "GPSLongitudeRef": "E", "GPSLongitude": [ 139, 27, 30.2 ], "GPSAltitudeRef": 0, "GPSAltitude": 84.68011527377521, "GPSTimeStamp": [ 23, 36, 6 ], "GPSSpeedRef": "K", "GPSSpeed": 1.88, "GPSImgDirectionRef": "M", "GPSImgDirection": 248.44410876132932, "GPSDestBearingRef": "M", "GPSDestBearing": 248.44410876132932, "GPSDateStamp": "2018:05:23", "thumbnail": {} } 本番はこれからで、"Orientation"という値がポイントで、以下の表のような構成になっています。
内容
1 そのまま
2 上下反転
3 180度回転
4 左右反転
5 上下反転、時計周りに270度回転
6 時計周りに90度回転
7 上下反転、時計周りに90度回転
8 時計周りに270度回転
http://dqn.sakusakutto.jp/2009/02/jpegexiforientaion.html 3番、6番、8番に対応すれば、だいたい問題ないでしょう。 そして、canvas画像では、以下のような判定で行なってみました。 var canvas = document.createElement("canvas"); canvas.img = img; var ctx = canvas.getContext('2d'); var size = {w:img.width , h:img.height}; switch(exif.Orientation){ case 1: // normal canvas.width = size.w; canvas.height = size.h; break; case 2: // flip width canvas.width = size.h; canvas.height = size.w; ctx.scale(-1.0 , 1.0); ctx.translate(-size.h , 0); break; case 3: // rotate 180deg canvas.width = size.w; canvas.height = size.h; ctx.rotate(180 * Math.PI / 180); ctx.translate(-size.w, -size.h); break; case 4: // flip height canvas.width = size.h; canvas.height = size.w; ctx.scale(1.0 , -1.0); ctx.translate(0, -size.h); break; case 5: // flip width + rotate 90deg canvas.width = size.h; canvas.height = size.w; ctx.rotate(90 * Math.PI / 180); ctx.scale(-1.0 , 1.0); ctx.translate(-size.w, -size.h); break; case 6: // rotate 90deg canvas.width = size.h; canvas.height = size.w; ctx.rotate(90 * Math.PI / 180); ctx.translate(0, -size.h); break; case 7: // flip height + rotate 90deg canvas.width = size.h; canvas.height = size.w; ctx.rotate(90 * Math.PI / 180); ctx.scale(1.0 , -1.0); break; case 8: // rotate 270deg canvas.width = size.h; canvas.height = size.w; ctx.rotate(270 * Math.PI / 180); ctx.translate(-size.w, 0); break; default: canvas.width = size.w; canvas.height = size.h; break; } ctx.drawImage(img, 0, 0, size.w, size.h); 長いですが、この手の関数を作っておくと便利でしょうね。

2. 撮影した画像はアップロードできるが、フォトライブラリの画像をアップロードしようとすると、何故かファイルが正常にアップロードできない。

PC(Mac)のChromeブラウザでは、正常に動いていたので安心していたんですが、iPhoneのsafariブラウザでアップロードできないという事象に焦りました。 これは、入力フォームタグの属性に問題がありました。 基本的に画像アップロードするためには、PCでもスマホでも以下のように書くようにすると、正常に動作するでしょう。 <form method="post" enctype="multipart/form-data"> <input type="file" name="file[]" accept="image/*" > <input type="submit" value="upload"> </form> formタグのenctypeとtype="file"の"image/*"が重要なようです。ビデオをアップロードしたい場合は、"video/*"とするらしいですよ。

3. 撮影画像アップロードと、フォトライブラリアップロードは、ファイルの拡張子が変わる(2018.6.2現在 , iOS11.3.1)

これは不思議でしょうがなかったんですが、現バージョンでは、撮影画像は、拡張し「jpg」で、フォトライブラリの画像は「jpeg」でした。 受け側のサーバー(PHPなど)で、どちらの拡張子でも、大文字小文字でも対応できるようにしておけばいいと思います。 めんどくさい人は、受診時に、複数ばらけてしまう拡張子をまとめてjpg一つに変換してしまうと楽かもしれませんね。

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ