-
卡片機時代
很重要的一點是,相機本身是沒有方向概念的,它不理解拍攝的內容,只會以相機自己的座標系去儲存資料,下圖展示了相機對“F”進行四個角度拍攝時返回的圖片資料。
最初的卡片機時代,照片都會經由底片洗出來,那時不存在照片的方向問題,我們總可以把洗出來的照片通過簡單的旋轉來進行觀看。比如這張照片牆中的照片,你能否說哪些照片是橫著?哪些顛倒著?你甚至都無法判斷每張照片相機是以何種角度拍攝的,因為每張都已經旋轉至適合觀看的角度。
-
數碼時代
可是到了數碼時代,不再需要底片,照片需要被存成一個影像檔案。對於上面的拍攝角度,儲存方式並沒有變化,所有的場景仍然是以相機的座標系來儲存。於是這些照片仍像上面一樣,原封不動的儲存了下來。
雖然儲存方式不變,和卡機機時代的實體相片不同的是,由於電子裝置可不知道照片應該如何旋轉,只能夠以它儲存於磁碟中的方向來展示。這便是為何照片傳到電腦上之後,會出現橫了,或者顛倒的情況。
-
方向感測器
為了克服這一情況,讓照片可以真實的反應人們拍攝時看到的場景,現在很多相機中就加入了方向感測器,它能夠記錄下拍攝時相機的方向,並將這一資訊儲存在照片中。照片的儲存方式還是沒有任何改變,它仍然是以相機的座標系來儲存,只是當相機來瀏覽這些照片時,相機可以根據照片中的方向資訊,結合此時相機的方向,對照片進行旋轉,從而轉到適合人們觀看的角度。
-
iPhone上的情況
在iOS的裝置中也包含了方向感測器,它但是它預設的照片方向並不是豎著拿手機時的情況,而是橫向,即Home鍵在右側,如下:
如此一來,如果豎著拿手機拍攝時,就相當於對手機順時針旋轉了90度,也即上面相機圖片中的最後一幅
-
iPhone拍照方向問題處理
iPhone通過API獲取到的是圖片內容資料,不帶方向資訊,此時,我們需要手動的根據感測器方向將方向資訊填充進去,並且根據方向資訊對照片進行相應的旋轉,得到人類視角正向的圖片。程式碼如下:
//iOS11以上支援AVCapturePhotoOutput代理
- (void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhoto:(AVCapturePhoto *)photo
error:(NSError *)error {
if (error) {
NSLog(@"獲取圖片錯誤 --- %@",error.localizedDescription);
}
if (photo) {
UIImageOrientation orient = UIImageOrientationUp;
//後置攝像頭
if (self.shootingOrientation == UIDeviceOrientationLandscapeRight){
orient = UIImageOrientationDown;
}else if(self.shootingOrientation == UIDeviceOrientationPortrait){
orient = UIImageOrientationRight;
}else if(self.shootingOrientation == UIDeviceOrientationLandscapeLeft){
orient = UIImageOrientationUp;
}else if(self.shootingOrientation == UIDeviceOrientationPortraitUpsideDown){
orient = UIImageOrientationLeft;
}
//前置攝像頭
AVCaptureDevice *currentDevice = [self.videoWriterManager.videoInput device];
AVCaptureDevicePosition currentPosition = [currentDevice position];
if (currentPosition == AVCaptureDevicePositionFront){
//前置攝像頭
if (self.shootingOrientation == UIDeviceOrientationLandscapeRight){
orient = UIImageOrientationUp;
}else if(self.shootingOrientation == UIDeviceOrientationLandscapeLeft){
orient = UIImageOrientationDown;
}
}
UIImage *image = [UIImage imageWithCGImage:photo.CGImageRepresentation scale:1 orientation:orient];
//圖片修正為人類視角看起來正向的圖片
//[self fixOrientation:image];
}
}
//將原始圖片資料調整為 人類視角正向的圖片
- (UIImage *)fixOrientation:(UIImage *)image{
// No-op if the orientation is already correct
if (image.imageOrientation == UIImageOrientationUp) return image;
// We need to calculate the proper transformation to make the image upright.
// We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
CGAffineTransform transform = CGAffineTransformIdentity;
CGFloat imageWidth = CGImageGetWidth(image.CGImage);
CGFloat imageHeight = CGImageGetHeight(image.CGImage);
//建立的點陣圖寬高
CGFloat contextWidth = imageWidth < imageHeight ? imageWidth : imageHeight;
CGFloat contextHeight = imageWidth > imageHeight ? imageWidth : imageHeight;
switch (image.imageOrientation) {
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:{
//建立橫著顯示的點陣圖上下文,寬大於高
CGFloat temp = contextWidth;
contextWidth = contextHeight;
contextHeight = temp;
//旋轉180度
transform = CGAffineTransformTranslate(transform, contextWidth, contextHeight);
transform = CGAffineTransformRotate(transform, M_PI);
}
break;
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
//逆時針旋轉90度
transform = CGAffineTransformTranslate(transform, contextWidth, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
//順時針90度
transform = CGAffineTransformTranslate(transform, 0, contextHeight);
transform = CGAffineTransformRotate(transform, -M_PI_2);
break;
default:
break;
}
switch (image.imageOrientation) {
case UIImageOrientationUpMirrored:
case UIImageOrientationDownMirrored:
//映象圖片Y軸翻轉座標系
transform = CGAffineTransformTranslate(transform, contextWidth, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationLeftMirrored:
case UIImageOrientationRightMirrored:
//映象圖片Y軸翻轉座標系
transform = CGAffineTransformTranslate(transform, contextHeight, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
default:
break;
}
//建立豎直顯示的畫布
CGContextRef ctx = CGBitmapContextCreate(NULL, contextWidth, contextHeight,
CGImageGetBitsPerComponent(image.CGImage), 0,
CGImageGetColorSpace(image.CGImage),
CGImageGetBitmapInfo(image.CGImage));
CGContextConcatCTM(ctx, transform);
CGContextDrawImage(ctx, CGRectMake(0, 0, imageWidth, imageHeight), image.CGImage);
// And now we just create a new UIImage from the drawing context
CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
UIImage *img = [UIImage imageWithCGImage:cgimg];
CGContextRelease(ctx);
CGImageRelease(cgimg);
return img;
}
圖片來源於(https://feihu.me/blog/2015/how-to-handle-image-orientation-on-iOS/)
參考 https://feihu.me/blog/2015/how-to-handle-image-orientation-on-iOS/