I'm Capturing image and storing it in NSData format. When i capture my image in portrait device orientation, the image is rotating left 90 degrees. when i'm capturing image in landscape device orientation, i'm getting image in proper manner. i trying below function. but i don't know what cgImage need to take as CGImage.
func rotateImageProperly(image:UIImage) -> UIImage {
let normalImage:UIImage!
if(image.imageOrientation == .up) {
normalImage = image
}else if (image.imageOrientation == .left){
normalImage = UIImage(cgImage: <#T##CGImage#>, scale: 1.0, orientation: UIImageOrientation.right)
}
return normalImage
}
use following code to properly rotate image :
func imageOrientation(_ src:UIImage)->UIImage {
if src.imageOrientation == UIImageOrientation.up {
return src
}
var transform: CGAffineTransform = CGAffineTransform.identity
switch src.imageOrientation {
case UIImageOrientation.down, UIImageOrientation.downMirrored:
transform = transform.translatedBy(x: src.size.width, y: src.size.height)
transform = transform.rotated(by: CGFloat(Double.pi))
break
case UIImageOrientation.left, UIImageOrientation.leftMirrored:
transform = transform.translatedBy(x: src.size.width, y: 0)
transform = transform.rotated(by: CGFloat(Double.pi))
break
case UIImageOrientation.right, UIImageOrientation.rightMirrored:
transform = transform.translatedBy(x: 0, y: src.size.height)
transform = transform.rotated(by: CGFloat(Double.pi))
break
case UIImageOrientation.up, UIImageOrientation.upMirrored:
break
}
switch src.imageOrientation {
case UIImageOrientation.upMirrored, UIImageOrientation.downMirrored:
transform.translatedBy(x: src.size.width, y: 0)
transform.scaledBy(x: -1, y: 1)
break
case UIImageOrientation.leftMirrored, UIImageOrientation.rightMirrored:
transform.translatedBy(x: src.size.height, y: 0)
transform.scaledBy(x: -1, y: 1)
case UIImageOrientation.up, UIImageOrientation.down, UIImageOrientation.left, UIImageOrientation.right:
break
}
let ctx:CGContext = CGContext(data: nil, width: Int(src.size.width), height: Int(src.size.height), bitsPerComponent: (src.cgImage)!.bitsPerComponent, bytesPerRow: 0, space: (src.cgImage)!.colorSpace!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
ctx.concatenate(transform)
switch src.imageOrientation {
case UIImageOrientation.left, UIImageOrientation.leftMirrored, UIImageOrientation.right, UIImageOrientation.rightMirrored:
ctx.draw(src.cgImage!, in: CGRect(x: 0, y: 0, width: src.size.height, height: src.size.width))
break
default:
ctx.draw(src.cgImage!, in: CGRect(x: 0, y: 0, width: src.size.width, height: src.size.height))
break
}
let cgimg:CGImage = ctx.makeImage()!
let img:UIImage = UIImage(cgImage: cgimg)
return img
}
Usage :
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]){
var image = info[UIImagePickerControllerOriginalImage] as! UIImage
image = self.imageOrientation(image)
}
Related
I'm using custom camera implementation in my app using Swift.
When the image is captured, is called func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?). I get the image data with photo.fileDataRepresentation() and after that I'm fixing the orientation of the photo using the following extension on UIImage.
func fixedOrientation() -> UIImage? {
guard imageOrientation != UIImage.Orientation.up else {
// This is default orientation, don't need to do anything
return self.copy() as? UIImage
}
guard let cgImage = self.cgImage else {
// CGImage is not available
return nil
}
guard let colorSpace = cgImage.colorSpace, let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
return nil // Not able to create CGContext
}
var transform = CGAffineTransform.identity
switch imageOrientation {
case .down, .downMirrored:
transform = transform.translatedBy(x: size.width, y: size.height)
transform = transform.rotated(by: CGFloat.pi)
case .left, .leftMirrored:
transform = transform.translatedBy(x: size.width, y: 0)
transform = transform.rotated(by: CGFloat.pi / 2.0)
case .right, .rightMirrored:
transform = transform.translatedBy(x: 0, y: size.height)
transform = transform.rotated(by: CGFloat.pi / -2.0)
case .up, .upMirrored:
break
#unknown default:
break
}
// Flip image one more time if needed to, this is to prevent flipped image
switch imageOrientation {
case .upMirrored, .downMirrored:
transform = transform.translatedBy(x: size.width, y: 0)
transform = transform.scaledBy(x: -1, y: 1)
case .leftMirrored, .rightMirrored:
transform = transform.translatedBy(x: size.height, y: 0)
transform = transform.scaledBy(x: -1, y: 1)
case .up, .down, .left, .right:
break
#unknown default:
break
}
ctx.concatenate(transform)
switch imageOrientation {
case .left, .leftMirrored, .right, .rightMirrored:
ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
default:
ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
}
guard let newCGImage = ctx.makeImage() else { return nil }
return UIImage(cgImage: newCGImage, scale: 1, orientation: .up)
}
Apparently this is working fine for images taken with back camera, but taking with frontal one I'm facing issues.
If the selfie photo is taken in portrait, the the method returns the photo mirrored.(which is not a big deal)
If the selfie photo is taken in landscape right/left, the outcode is photo also mirrored but wrongfully rotated. Here is where I want your help, to get the correct rotation of the photo.
Note: I'm also changing the videoOrientation from AVCaptureConnection when rotating the device.
It turned out that i was changing the videoOrientation when rotation did change, which was wrong. I had to move that logic before capturing the photo. Now it works fine. Also I've fixed the mirroring problem, by setting isVideoMirrored to true if using the front camera.
I want to add markar image on captured image from camera , then saving to photo library in swift , but the image saved with wrong orientation in photo library , so please suggest how I will fixed this issue .
I want to save image in pot-rate mode for iPhone and lanscape mode for iPad . so please suggest where I am wrong .
my code is there:
{
if let videoConnection = stillImageOutput.connection(with: AVMediaType.video) {
stillImageOutput.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (CMSampleBuffer, Error) in
if let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(CMSampleBuffer!) {
if let cameraImage = UIImage(data: imageData) {
if let img2 = self.imgWaterMark.image {
// let rect = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)
let rect = CGRect(x: 0, y: 0, width: (self.previewLayer?.frame.size.width)! , height: (self.previewLayer?.frame.size.height)!)
UIGraphicsBeginImageContextWithOptions((self.previewLayer?.frame.size)!, true, 180)
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(UIColor.white.cgColor)
context?.fill(rect)
cameraImage.draw(in: rect, blendMode: .normal, alpha: 1)
img2.draw(in:self.imgWaterMark.frame , blendMode: .normal, alpha: 1)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// let img = result
//let finalimage = self.rotateCameraImageToProperOrientation(imageSource: cameraImage)
UIImageWriteToSavedPhotosAlbum(result ?? cameraImage, nil, nil, nil)
// self.textToImage(drawText:self.lblTitle!.text! as NSString, inImage: result ?? cameraImage, atPoint: CGPoint(x: 0, y: 110))
AppSharedData.sharedInstance.showAlert(title: "", message: "Image saved", viewController: self, actions: ["OK"], callBack: { (action) in
})
}
}
}
})
}
}
I had used below code to get orientation of Image and converts to required orientation. Please see if you can use this.
img_Photo.image = self.imageOrientation((img_Photo?.image)!)
//*******************************
func imageOrientation(_ src:UIImage)->UIImage {
print(src.imageOrientation.rawValue)
print(src.imageOrientation.hashValue)
if src.imageOrientation == UIImageOrientation.up {
return src
}/*else if src.imageOrientation == UIImageOrientation.down {
return src
}else if src.imageOrientation == UIImageOrientation.left {
return src
}else if src.imageOrientation == UIImageOrientation.right {
return src
}*/
var transform: CGAffineTransform = CGAffineTransform.identity
switch src.imageOrientation {
case UIImageOrientation.up, UIImageOrientation.upMirrored:
transform = transform.translatedBy(x: src.size.width, y: src.size.height)
transform = transform.rotated(by: CGFloat(M_PI))
break
case UIImageOrientation.down, UIImageOrientation.downMirrored:
transform = transform.translatedBy(x: src.size.width, y: src.size.height)
transform = transform.rotated(by: CGFloat(M_PI))
break
case UIImageOrientation.left, UIImageOrientation.leftMirrored:
transform = transform.translatedBy(x: src.size.width, y: 0)
transform = transform.rotated(by: CGFloat(M_PI_2))
break
case UIImageOrientation.right, UIImageOrientation.rightMirrored:
transform = transform.translatedBy(x: 0, y: src.size.height)
transform = transform.rotated(by: CGFloat(-M_PI_2))
break
}
switch src.imageOrientation {
case UIImageOrientation.upMirrored, UIImageOrientation.downMirrored:
transform.translatedBy(x: src.size.width, y: 0)
transform.scaledBy(x: -1, y: 1)
break
case UIImageOrientation.leftMirrored, UIImageOrientation.rightMirrored:
transform.translatedBy(x: src.size.height, y: 0)
transform.scaledBy(x: -1, y: 1)
case UIImageOrientation.up, UIImageOrientation.down, UIImageOrientation.left, UIImageOrientation.right:
break
}
let ctx:CGContext = CGContext(data: nil, width: Int(src.size.width), height: Int(src.size.height), bitsPerComponent: (src.cgImage)!.bitsPerComponent, bytesPerRow: 0, space: (src.cgImage)!.colorSpace!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
ctx.concatenate(transform)
switch src.imageOrientation {
case UIImageOrientation.left, UIImageOrientation.leftMirrored, UIImageOrientation.right, UIImageOrientation.rightMirrored:
ctx.draw(src.cgImage!, in: CGRect(x: 0, y: 0, width: src.size.height, height: src.size.width))
break
default:
ctx.draw(src.cgImage!, in: CGRect(x: 0, y: 0, width: src.size.width, height: src.size.height))
break
}
let cgimg:CGImage = ctx.makeImage()!
let img:UIImage = UIImage(cgImage: cgimg)
return img
}
I hate to say that I'm the new guy to iOS development but the shoe fits...
My app needs to either load an image/capture one from camera (which it does) but then needs to crop in LANDSCAPE.
I now have an extension that takes the image and shrinks it down to a landscape image (looks good if the camera is taken from landscape position OR scrunches it to a landscape if taken in portrait). It places it in my "viewfinder" as a tiny landscape image (seen below) and I can swipe outward to make it the size of the "view finder" but that's not what I need.
(the "viewfinder" I had to draw because I didn't put borders on it but you can see the thumbnail in the top left)
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : Any]) {
setImageToCrop(image: info[UIImagePickerControllerOriginalImage] as!
UIImage)
picker.dismiss(animated: true, completion: nil)
}
// -------------
func setImageToCrop(image:UIImage){
imageView.image = image
imageViewWidth.constant = image.size.width
imageViewHeight.constant = image.size.height
let scaleHeight = scrollView.frame.size.width/image.size.width
let scaleWidth = scrollView.frame.size.height/image.size.height
scrollView.minimumZoomScale = max(scaleWidth, scaleHeight)
scrollView.zoomScale = max(scaleWidth, scaleHeight)
self.cropButton.isHidden = false
}
// ------------------
#IBAction func cropButtonPressed(_ sender: Any) {
let scale:CGFloat = 1/scrollView.zoomScale
let x:CGFloat = scrollView.contentOffset.x * scale
let y:CGFloat = scrollView.contentOffset.y * scale
let width:CGFloat = scrollView.frame.size.width * scale
let height:CGFloat = scrollView.frame.size.height * scale
let croppedCGImage = imageView.image?.cgImage?.cropping(to: CGRect(x: x, y: y, width: width, height: height))
let croppedImage = UIImage(cgImage: croppedCGImage!)
// "now you can use croppedImage as you like...."
setImageToCrop(image: croppedImage)
}
// ---------------
And then the extension that shrinks the image...
public extension UIImage {
/// Extension to fix orientation of an UIImage without EXIF
func fixOrientation() -> UIImage {
guard let cgImage = cgImage else { return self }
if imageOrientation == .up { return self }
var transform = CGAffineTransform.identity
switch imageOrientation {
case .down, .downMirrored:
transform = transform.translatedBy(x: size.width, y: size.height)
transform = transform.rotated(by: CGFloat(M_PI))
case .left, .leftMirrored:
transform = transform.translatedBy(x: size.width, y: 0)
transform = transform.rotated(by: CGFloat(M_PI_2))
case .right, .rightMirrored:
transform = transform.translatedBy(x: 0, y: size.height)
transform = transform.rotated(by: CGFloat(-M_PI_2))
case .up, .upMirrored:
break
}
switch imageOrientation {
case .upMirrored, .downMirrored:
transform.translatedBy(x: size.width, y: 0)
transform.scaledBy(x: -1, y: 1)
case .leftMirrored, .rightMirrored:
transform.translatedBy(x: size.height, y: 0)
transform.scaledBy(x: -1, y: 1)
case .up, .down, .left, .right:
break
}
if let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: cgImage.colorSpace!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) {
ctx.concatenate(transform)
switch imageOrientation {
case .left, .leftMirrored, .right, .rightMirrored:
ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
default:
ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
}
if let finalImage = ctx.makeImage() {
return (UIImage(cgImage: finalImage))
}
}
// something failed -- return original
return self
}
}
I have been around and around with different answers in StackOverFlow but haven't found the solution I'm looking for. I first found an extension that was the "fix all holy grail" but it did nothing. (The app still crops the image but stil rotates when it's saved.)
I'm 100% sure it's something stupid/small that I'm missing but I'm now lost in my code and if it means anything, I've been chasing this issue for WEEKS, if not MONTHS, now. I didn't want to ask unless I absolutely had to. Is there a better way to get an image and crop it it landscape without having it rotate? or is there a fix to this code?
When Image data is returned and applied to a UIImage, if the data comes from the camera then the image appears rotated 90 degrees.
I tried adding the
extension UIImage {
func correctlyOrientedImage() -> UIImage {
if self.imageOrientation == UIImageOrientation.up {
return self
}
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
self.draw(in: CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: self.size.width, height: self.size.height))
)
let normalizedImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext();
return normalizedImage;
}
}
in my code, I check to see if I have data saved for a specific user and if so I load the image data into profile_image, a UIImageView.
//profile_image
if let profile_imager = UserDefaults.standard.object(forKey: String(UserID)) as? Data {
let data = UserDefaults.standard.object(forKey: String(UserID)) as? Data
print("profile_imager: \(profile_imager)")
profile_image.image = UIImage(data: data!)
profile_image.backgroundColor = .white
}
How would I go about to use correctlyOrientedImage correctly
Thank you
Swift 4.2,
Created an UIImage extension to keep the image in the original position,
extension UIImage {
func fixedOrientation() -> UIImage {
if imageOrientation == .up {
return self
}
var transform: CGAffineTransform = CGAffineTransform.identity
switch imageOrientation {
case .down, .downMirrored:
transform = transform.translatedBy(x: size.width, y: size.height)
transform = transform.rotated(by: CGFloat.pi)
case .left, .leftMirrored:
transform = transform.translatedBy(x: size.width, y: 0)
transform = transform.rotated(by: CGFloat.pi / 2)
case .right, .rightMirrored:
transform = transform.translatedBy(x: 0, y: size.height)
transform = transform.rotated(by: CGFloat.pi / -2)
case .up, .upMirrored:
break
}
switch imageOrientation {
case .upMirrored, .downMirrored:
transform.translatedBy(x: size.width, y: 0)
transform.scaledBy(x: -1, y: 1)
case .leftMirrored, .rightMirrored:
transform.translatedBy(x: size.height, y: 0)
transform.scaledBy(x: -1, y: 1)
case .up, .down, .left, .right:
break
}
if let cgImage = self.cgImage, let colorSpace = cgImage.colorSpace,
let ctx: CGContext = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) {
ctx.concatenate(transform)
switch imageOrientation {
case .left, .leftMirrored, .right, .rightMirrored:
ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
default:
ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
}
if let ctxImage: CGImage = ctx.makeImage() {
return UIImage(cgImage: ctxImage)
} else {
return self
}
} else {
return self
}
}
}
Then set profile_image from fixedOrientation() method,
//profile_image
if let profile_imager = UserDefaults.standard.object(forKey: String(UserID)) as? Data {
let data = UserDefaults.standard.object(forKey: String(UserID)) as? Data
print("profile_imager: \(profile_imager)")
let actualImage = UIImage(data: data!)?.fixedOrientation()
profile_image.image = actualImage
profile_image.backgroundColor = .white
}
Part of my iOS app uses Firebase Storage to store and load images taken/uploaded by the user.
However, every time I upload a picture to Firebase in portrait orientation, when I retrieve it back from Firebase later on it comes in landscape orientation and thus displays incorrectly.
I've read that Firebase stores metadata to determine the correct orientation of an uploaded picture but it doesn't seem to be working for me.
Any one know how to get the orientation the image was uploaded in without manually having to rotate it within the app's code?
Thanks!
edit for code:
Uploading:
let imageMetaData = FIRStorageMetadata()
imageMetaData.contentType = "image/png"
var imageData = Data()
imageData = UIImagePNGRepresentation(chosenImage)!
let currentUserProfilePictureRef = currentUserStorageRef.child("ProfilePicture")
currentUserProfilePictureRef.put(imageData, metadata: imageMetaData) { (metaData, error) in
if error == nil {
let downloadUrl = metaData?.downloadURL()?.absoluteString
self.currentUserRef.updateChildValues(["profilePictureUrl": downloadUrl!])
if (chosenImage.size.width.isLess(than: (chosenImage.size.height))) {
self.currentUserRef.updateChildValues(["profilePictureOrientation": "portrait"])
}
else {
self.currentUserRef.updateChildValues(["profilePictureOrientation": "landscape"])
}
}
}
Retrieving:
self.currentUserStorageRef.child("ProfilePicture").data(withMaxSize: 20*1024*1024, completion: {(data, error) in
var profilePicture = UIImage(data:data!)
if(profilePicture?.size.width.isLess(than: (profilePicture?.size.height)!))! {
if (pictureOrientation == "landscape") {
profilePicture = profilePicture?.rotated(by: Measurement(value: -90.0, unit: .degrees))
}
} else {
if (pictureOrientation == "portrait") {
profilePicture = profilePicture?.rotated(by: Measurement(value: 90.0, unit: .degrees))
}
}
self.buttonProfilePicture.setImage(profilePicture, for: .normal)
self.buttonProfilePicture.imageView?.contentMode = .scaleAspectFill
})
From my own personal experience (and asking virtually the same question a year ago), I've found that when you save an image using UIImagePNGRepresentation, it doesn't actually store the orientation data for that specific image. You should use UIImageJPEGRepresentation when you're having orientation issues. JPEG uses the exif format that specifies the orientation for an image, whereas PNG apparently does not. Your issue should be resolved if you save your image using UIImageJPEGRepresentation
Swift 5 - Update
This worked for me, just apply this on your UIImage before uploading it.
extension UIImage {
func fixedOrientation() -> UIImage? {
guard imageOrientation != UIImage.Orientation.up else {
// This is default orientation, don't need to do anything
return self.copy() as? UIImage
}
guard let cgImage = self.cgImage else {
// CGImage is not available
return nil
}
guard let colorSpace = cgImage.colorSpace, let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
return nil // Not able to create CGContext
}
var transform: CGAffineTransform = CGAffineTransform.identity
switch imageOrientation {
case .down, .downMirrored:
transform = transform.translatedBy(x: size.width, y: size.height)
transform = transform.rotated(by: CGFloat.pi)
case .left, .leftMirrored:
transform = transform.translatedBy(x: size.width, y: 0)
transform = transform.rotated(by: CGFloat.pi / 2.0)
case .right, .rightMirrored:
transform = transform.translatedBy(x: 0, y: size.height)
transform = transform.rotated(by: CGFloat.pi / -2.0)
case .up, .upMirrored:
break
#unknown default:
break
}
// Flip image one more time if needed to, this is to prevent flipped image
switch imageOrientation {
case .upMirrored, .downMirrored:
transform = transform.translatedBy(x: size.width, y: 0)
transform = transform.scaledBy(x: -1, y: 1)
case .leftMirrored, .rightMirrored:
transform = transform.translatedBy(x: size.height, y: 0)
transform = transform.scaledBy(x: -1, y: 1)
case .up, .down, .left, .right:
break
#unknown default:
break
}
ctx.concatenate(transform)
switch imageOrientation {
case .left, .leftMirrored, .right, .rightMirrored:
ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
default:
ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
break
}
guard let newCGImage = ctx.makeImage() else { return nil }
return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up)
}
}
Just an update, UIImageJPEGRepresentation has changed to jpegData in the recent versions of xcode.
jpegData(compressionQuality: 1.0) 1.0 being high quality and 0 being low quality.