距離上次寫博客竟然過了一個月了,一方面是最近項目比較忙昏翰,另一方面是實在是有點兒懈怠了苍匆,強烈譴責一下自己。其實我最近在看一些技術書籍棚菊,發(fā)現(xiàn)一些好的書真心對自己幫助很大浸踩,看書的過程,好多原來模糊的概念统求、問題检碗,都能感覺恍然大悟。當提筆想總結成一篇文章的時候码邻,發(fā)現(xiàn)網(wǎng)上早已經(jīng)有大量的優(yōu)秀文章出現(xiàn)折剃,所以就不敢獻丑了。今天寫的一篇文章像屋,是最近自己項目中用到的怕犁,不算什么難點,只是感覺有必要記錄一下己莺。
需求
由于我們APP集成了有道翻譯的SDK奏甫,需要將拍出來的圖片翻譯成對應的語言,但是有道的SDK目前還做的不是很完善(比如:照片傾斜的時候凌受,返回的角度不是很對阵子,有道的技術說下個版本可能會更新)。于是產(chǎn)品要求拍照頁面做成跟系統(tǒng)相機類似胜蛉,當用戶橫屏拍攝的時候款筑,需要客戶端自己將圖片糾正回來智蝠,倒著拍的時候亦然。
自定義相機功能就不多說了奈梳,網(wǎng)上有大量的優(yōu)秀文章杈湾,這里隨便從網(wǎng)上找了一個,需要的可以參考下
基礎知識
首先我們需要知道每一個UIImage
對象攘须,都有一個imageOrientation
屬性漆撞,里面保存著方向信息:
typedef NS_ENUM(NSInteger, UIImageOrientation) {
UIImageOrientationUp, // default orientation
UIImageOrientationDown, // 180 deg rotation
UIImageOrientationLeft, // 90 deg CCW
UIImageOrientationRight, // 90 deg CW
UIImageOrientationUpMirrored, // as above but image mirrored along other axis. horizontal flip
UIImageOrientationDownMirrored, // horizontal flip
UIImageOrientationLeftMirrored, // vertical flip
UIImageOrientationRightMirrored, // vertical flip
};
根據(jù)這個屬性信息,我們便可以對圖像進行相應的旋轉(zhuǎn)于宙,將圖片轉(zhuǎn)到正確的方向浮驳,如何旋轉(zhuǎn)?捞魁?有兩種解決方案:
第一種:給UIImage添加Category
- (UIImage *)fixOrientation {
// No-op if the orientation is already correct
if (self.imageOrientation == UIImageOrientationUp) return self;
// 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;
switch (self.imageOrientation) {
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, 0, self.size.height);
transform = CGAffineTransformRotate(transform, -M_PI_2);
break;
case UIImageOrientationUp:
case UIImageOrientationUpMirrored:
break;
}
switch (self.imageOrientation) {
case UIImageOrientationUpMirrored:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationLeftMirrored:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, self.size.height, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationUp:
case UIImageOrientationDown:
case UIImageOrientationLeft:
case UIImageOrientationRight:
break;
}
// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
CGImageGetBitsPerComponent(self.CGImage), 0,
CGImageGetColorSpace(self.CGImage),
CGImageGetBitmapInfo(self.CGImage));
CGContextConcatCTM(ctx, transform);
switch (self.imageOrientation) {
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
// Grr...
CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);
break;
default:
CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);
break;
}
// 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;
}
第二種:利用drawInRect
方法將圖像畫到畫布上
- (UIImage *)normalizedImage {
if (self.imageOrientation == UIImageOrientationUp) return self;
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
[self drawInRect:(CGRect){0, 0, self.size}];
UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return normalizedImage;
}
通過上面兩種方式轉(zhuǎn)換之后的UIImage
對象至会,其imageOrientation
屬性,都會被修改成UIImageOrientationUp
谱俭,這樣將圖片傳到后臺奉件,或者導出相冊的時候,就不會出現(xiàn)照片旋轉(zhuǎn)90度的問題昆著。
但是有時候我們希望圖片該旋轉(zhuǎn)的時候县貌,按照我們的意愿旋轉(zhuǎn)(比如橫評拍攝的時候),豎直拍攝的時候凑懂,圖像正常顯示煤痕,這時候我們就不能直接用上面的方法來判斷了。仔細觀察系統(tǒng)相機的拍攝接谨,我發(fā)現(xiàn)除了豎直拍攝以外摆碉,別的情況下拍攝,圖片都會自動旋轉(zhuǎn)脓豪,這個時候就需要我們利用iPhone手機自帶的硬件傳感器對方向進行判斷巷帝,以達到我們想要的結果,這里主要用到加速儀
加速儀(類型:CMAcceleration)
加速儀可以檢測三維空間中的加速度 跑揉,坐標對應如下:
例如:當垂直手持手機且頂部向上,Y坐標上回收到 -1G的加速度埠巨,(0历谍,-1,0)辣垒,當手機頭部朝下望侈,得到的各個坐標為:(0,1勋桶,0)
主要代碼如下:
- (void)startDeviceMotion{
if (![self.motionManager isDeviceMotionAvailable]) {return;}
[self.motionManager setDeviceMotionUpdateInterval:1.f];
[self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
double gravityX = motion.gravity.x;
double gravityY = motion.gravity.y;
if (fabs(gravityY)>=fabs(gravityX)) {
if (gravityY >= 0) {
// UIDeviceOrientationPortraitUpsideDown
[self setDeviceDirection:SSDeviceDirectionDown];
NSLog(@"頭向下");
} else {
// UIDeviceOrientationPortrait
[self setDeviceDirection:SSDeviceDirectionUp];
NSLog(@"豎屏");
}
} else {
if (gravityX >= 0) {
// UIDeviceOrientationLandscapeRight
[self setDeviceDirection:SSDeviceDirectionRight];
NSLog(@"頭向右");
} else {
// UIDeviceOrientationLandscapeLef
[self setDeviceDirection:SSDeviceDirectionLeft];
NSLog(@"頭向左");
}
}
}];
}
獲取到方向信息脱衙,下面就可以對圖片進行對應的處理了侥猬,主要用到了下面的這個方法:
- (instancetype)initWithCIImage:(CIImage *)ciImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation NS_AVAILABLE_IOS(6_0);
該方法的作用是:
Creates and returns an image object with the specified scale and orientation factors.
創(chuàng)建并返回具有指定比例和方向特征的image對象。
最后對拍攝的圖片進行處理:
UIImage *transImage = [rsltImage fixOrientation];
switch (self.deviceDirection) {
case SSDeviceDirectionUp:
transImage = [rsltImage fixOrientation];
break;
case SSDeviceDirectionLeft:
transImage = [rsltImage fixImageByOrientation:UIImageOrientationLeft];
break;
case SSDeviceDirectionRight:
transImage = [rsltImage fixImageByOrientation:UIImageOrientationRight];
break;
case SSDeviceDirectionDown:
transImage = [rsltImage fixImageByOrientation:UIImageOrientationDown];
break;
default:
break;
}
最終效果圖
總結
功能實現(xiàn)起來其實并不難捐韩,當時和同事糾結的地方在于退唠,到底是采用支持橫豎屏還是采用加速度傳感器上面,最后經(jīng)過分析系統(tǒng)相機荤胁,我還是采用了利用傳感器做判斷瞧预,期間也是查閱了很多的技術文章,無意中發(fā)現(xiàn)了一篇真心值得仔細閱讀的關于圖片解壓縮的文章仅政。最后垢油,再次對最近的松懈進行反思,繼續(xù)擼起袖子圆丹,加油干L渤睢!辫封!
Refrence
https://www.cnblogs.com/sunyanyan/p/5213854.html
http://feihu.me/blog/2015/how-to-handle-image-orientation-on-iOS/