ずいぶん昔ですが、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一つに変換してしまうと楽かもしれませんね。
0 件のコメント:
コメントを投稿