[C#] 關於 Rotate 90 CW 解決 iPhone 拍照網頁使用問題

2020-02-27

這一陣子遇到一個很惱人的問題,因為最近處理到有朋友需要直接把照片上傳到網站上,他是透過手機拍照,然後利用 iPad or iPhone 上傳照片,他是直的拍,他用手機看也是直的,上傳到網頁上面,他用 Safari or Chrome on iPhone Device 也是直的,但是我電腦看就變成橫的,如果用電腦上面的 Chrome 直接看那張圖就是直的,非常詭異,順帶一題我電腦是 Windows 10 + Chrome 去看得,仔細看了一下,我猜測是 照片 EXIF 的問題,結果經過測試真的是…


如上圖,在 iPhone 的世界中拍照時後 你手機頭部往左的拍照,這叫做正常,之後你打直拍照,在 EXIF 中 Orientation 會變成 Rotate 90 CW  其中 CW  的意思就是指順時針(ClockWise),所以從手機頭部往左叫做正常分別順時針旋轉,分別角度是 Horizontal (normal)、Rotate 90 CW、Rotate 180、Rotate 270 CW。

所以基本上如果你在後台拿到這張照片,你希望前面一律顯示正常,你需要自己將圖片順時針轉 90度之後再往前端送,我的作法不一定很好,如果你有更好的方法也可以跟我說一下。

Step1. 首先,我們得先了解 EXIF 資訊抓出 Orientation ,我是透過一個 nuget 上的套件 MetadataExtractor (https://www.nuget.org/packages/MetadataExtractor/)

列出所有參數:

var infos = ImageMetadataReader.ReadMetadata(imageFilePath); //列出所有資訊 foreach (var info in infos) { foreach (var tag in info.Tags) { ltlLog.Text += info.Name + ":" + tag.Name + ":" + tag.Description + "<br>"; } } //Sample Result //JPEG:Compression Type:Baseline //JPEG:Data Precision:8 bits //JPEG:Image Height:3024 pixels //JPEG:Image Width:4032 pixels //JPEG:Number of Components:3 //JPEG:Component 1:Y component: Quantization table 0, Sampling factors 2 horiz/2 vert //JPEG:Component 2:Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert //JPEG:Component 3:Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert //Exif IFD0:Orientation:Bottom, right side(Rotate 180) //Exif IFD0:X Resolution:72 dots per inch //Exif IFD0:Y Resolution:72 dots per inch //Exif IFD0:Resolution Unit:Inch //Exif IFD0:YCbCr Positioning:Center of pixel array //Exif SubIFD:Exif Version:2.21 //Exif SubIFD:Components Configuration:YCbCr //Exif SubIFD:FlashPix Version:1.00 //Exif SubIFD:Color Space:sRGB //Exif SubIFD:Exif Image Width:4032 pixels //Exif SubIFD:Exif Image Height:3024 pixels //Exif SubIFD:Scene Capture Type:Standard //Exif Thumbnail:Compression:JPEG(old-style) //Exif Thumbnail:X Resolution:72 dots per inch //Exif Thumbnail:Y Resolution:72 dots per inch //Exif Thumbnail:Resolution Unit:Inch //Exif Thumbnail:Thumbnail Offset:286 bytes //Exif Thumbnail:Thumbnail Length:15458 bytes //ICC Profile:Profile Size:548 //ICC Profile:CMM Type:appl //ICC Profile:Version:4.0.0 //ICC Profile:Class:Display Device //ICC Profile:Color space:RGB //ICC Profile:Profile Connection Space:XYZ //ICC Profile:Profile Date/Time:2017:07:07 13:22:32 //ICC Profile:Signature:acsp //ICC Profile:Primary Platform:Apple Computer, Inc. //ICC Profile:Device manufacturer:APPL //ICC Profile:XYZ values:0.964 1 0.825 //ICC Profile:Tag Count:10 //ICC Profile:Profile Description:Display P3 //ICC Profile:Copyright:Copyright Apple Inc., 2017 //ICC Profile:Media White Point:(0.9505, 1, 1.0891) //ICC Profile:Red Colorant:(0.5151, 0.2412, 65536) //ICC Profile:Green Colorant:(0.292, 0.6922, 0.0419) //ICC Profile:Blue Colorant:(0.1571, 0.0666, 0.7841) //ICC Profile:Red TRC:para(0x70617261) : 32 bytes //ICC Profile:Chromatic Adaptation:sf32(0x73663332) : 44 bytes //ICC Profile:Blue TRC:para(0x70617261) : 32 bytes //ICC Profile:Green TRC:para(0x70617261) : 32 bytes //Huffman:Number of Tables:4 Huffman tables //File Type:Detected File Type Name:JPEG //File Type:Detected File Type Long Name:Joint Photographic Experts Group //File Type:Detected MIME Type:image/jpeg //File Type:Expected File Name Extension:jpg //File:File Name:xxx.gif //File:File Size:5317342 bytes //File:File Modified Date:週二 二月 25 10:54:10 +08:00 2020

所以我們可以透過這樣拿到  Orientation  的資訊

//Orientation var infoOrientation = infos.SelectMany(x => x.Tags.Where(y => y.Name == "Orientation") .Select(z => z.Description)).FirstOrDefault();


Step2. 在來就是轉向的問題 ,基本上我是用 .net 內建的 System.Drawing 的進行轉向

//取的 Orientation 資訊 var infoOrientation = infos.SelectMany(x => x.Tags.Where(y => y.Name == "Orientation").Select(z => z.Description)).FirstOrDefault(); if (!string.IsNullOrEmpty(infoOrientation)) { var exifOrientation = System.Text.RegularExpressions.Regex.Replace(infoOrientation, @"\s+", ""); //如果是順時針90度 if (exifOrientation.ToUpper().Contains("90CW")) { RotateCWAndSave(imageFilePath, System.Drawing.RotateFlipType.Rotate90FlipNone, AppDomain.CurrentDomain.BaseDirectory + "result.gif", System.Drawing.Imaging.ImageFormat.Jpeg); } //如果是順時針270度 else if (exifOrientation.ToUpper().Contains("270CW")) { RotateCWAndSave(imageFilePath, System.Drawing.RotateFlipType.Rotate270FlipNone, AppDomain.CurrentDomain.BaseDirectory + "result.gif", System.Drawing.Imaging.ImageFormat.Jpeg); } //如果是順時針180度 else if (exifOrientation.ToUpper().Contains("ROTATE180")) { RotateCWAndSave(imageFilePath, System.Drawing.RotateFlipType.Rotate180FlipNone, AppDomain.CurrentDomain.BaseDirectory + "result.gif", System.Drawing.Imaging.ImageFormat.Jpeg); } } else { // 沒有資訊就正常處理 } public static System.Drawing.Image RotateCWAndSave(string sourcePath, RotateFlipType rotateType, string targetPath, ImageFormat imageFormat) { if (!System.IO.File.Exists(sourcePath)) { throw new Exception("File is not Existed."); } var bytes = File.ReadAllBytes(sourcePath); var bitmap = System.Drawing.Image.FromStream(new MemoryStream(bytes)); bitmap.RotateFlip(rotateType); bitmap.Save(targetPath, imageFormat); bitmap.Dispose(); return bitmap; }

這樣看起來解決了問題了,這點真的很惱人,因為不一樣瀏覽器根據照片直出真的比較麻煩。

參考網站:

https://stackoverflow.com/questions/46476930/change-exif-in-photo-metadata-extractor-c-sharp

https://docs.microsoft.com/zh-tw/dotnet/api/system.drawing.rotatefliptype?view=netframework-4.8


當麻許的碎念筆記 2014 | Donma Hsu Design.