iOS UIImage: set image orientation without rotating the image itself - ios

I am using AVCapture+camera portrait mode to capture an image. when I display the captured image, it is fine--looks fine. But when I convert to jpeg representation and then convert to base64 string to server and server stored it, it is "rotated" already.
So I checked the image orientation before sending to server: it is UIImageOrientation.Right(so is there any way to capture an image using portrait mode but the captured image orientation is up? well, I doubt that after some digging). After the server got the image, it did not do anything, just ignored the metadata about orientation I guess.
since the image I captured looks fine, I want just preserve how the image look like. However, I want to set the image orientation to be up. if I just set the image orientation, the image does not look right anymore.
So is there a way to set the orientation without causing the image to be rotated or after setting the orientation to be up, how to I keep the orientation but rotate the actual image to make it look right?

- (UIImage *)removeRotationForImage:(UIImage*)image {
if (image.imageOrientation == UIImageOrientationUp) return image;
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
[image drawInRect:(CGRect){0, 0, image.size}];
UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return normalizedImage;
}

swift version of oldrinmendez answer
func removeRotationForImage(image: UIImage) -> UIImage {
if image.imageOrientation == UIImageOrientation.Up {
return image
}
UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
image.drawInRect(CGRect(origin: CGPoint(x: 0, y: 0), size: image.size))
let normalizedImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return normalizedImage
}

Related

UIImage size doubled when converted to CGImage?

I am trying to crop part of an image taken with the iPhone's camera via the cropping(to:) method on a CGImage but I am encountering a weird phenomenon where my UIImage's dimensions are doubled when converted with .cgImage which, obviously, prevents me from doing what I want.
The flow is:
Picture is taken with the camera and goes into a full-screen imageContainerView
A "screenshot" of this imageContainerView is made with a UIView extension, effectively resizing the image to the container's dimensions
imageContainerView's .image is set to now be the "screenshot"
let croppedImage = imageContainerView.renderToImage()
imageContainerView.image = croppedImage
print(imageContainerView.image!.size) //yields (320.0, 568.0)
print(imageContainerView.image!.cgImage!.width, imageContainerView.image!.cgImage!.height) //yields (640, 1136) ??
extension UIView {
func renderToImage(afterScreenUpdates: Bool = false) -> UIImage {
let rendererFormat = UIGraphicsImageRendererFormat.default()
rendererFormat.opaque = isOpaque
let renderer = UIGraphicsImageRenderer(size: bounds.size, format: rendererFormat)
let snapshotImage = renderer.image { _ in
drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
}
return snapshotImage
}
}
I have been wandering around here with no success so far and would gladly appreciate a pointer or a suggestion on how/why the image size is suddenly doubled.
Thanks in advance.
This is because print(imageContainerView.image!.size) prints the size of the image object in points and print(imageContainerView.image!.cgImage!.width, imageContainerView.image!.cgImage!.height) print the size of the actual image in pixels.
On iPhone you are using there are 2 pixels for evert point in both horizontal and vertical. The UIImage scale property will give you the factor which in your case will be 2.
See this link iPhone Resolutions

MPMediaItemArtwork init(image:) deprecated in iOS 10.0

Apple has deprecated init(image:) method in MPMediaItemArtwork in iOS 10.
What is the new alternative.
the class shows interface shows method below to be available in the new OS version
public init(boundsSize: CGSize, requestHandler: #escaping (CGSize) -> UIImage)
Anyone know how to use it?
Also question 2, part of the previous question: Does showing now playing metadata on the lock-screen and control-center using MPNowPlayingInfoCenter work in the simulator?
You can use the following code:
let image = UIImage(named: "logo")!
let artwork = MPMediaItemArtwork.init(boundsSize: image.size, requestHandler: { (size) -> UIImage in
return image
})
And, yes, "now playing" metadata shows on the control center in the simulator.
I was wondering the same and ended up finding Apple's explanation for this.
They say we shouldn't do any expensive resizing operations on the image when handler is requested, but instead simply return the closely matching image out of ones already available to you.
The following WWDC 2017 video is where they mention it. It's about tvOS, but at least we get some insight. Starts at 07:20: https://developer.apple.com/videos/play/wwdc2017/251/?time=440
I saw this just now and I'm confused too, but I guess this is the right way:
self.remoteArtwork = [[MPMediaItemArtwork alloc] initWithBoundsSize:CGSizeMake(600, 600) requestHandler:^UIImage * _Nonnull(CGSize size) {
UIImage *lockScreenArtworkApp = [UIImage imageNamed:#"lockScreenLogo"];
return [self.manager resizeImageWithImage:lockScreenArtworkApp scaledToSize:size];
}];
The method - in my case in a singleton "Manager"-Class
- (UIImage *)resizeImageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
//UIGraphicsBeginImageContext(newSize);
// In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
// Pass 1.0 to force exact pixel size.
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Minimum code:
MPMediaItemArtwork(boundsSize: image.size) { _ in image }

Take Screenshot of Textfield in swift?

Am making an iOS application which captures screenshot of a textview filled with some image. The problem is that the screen shot captures the entire screen.
How do I take screen shot of UITextView using Swift?
The following worked for me
UIGraphicsBeginImageContextWithOptions(self.textField.bounds.size, false, 0);
self.textField.drawViewHierarchyInRect(self.textField.bounds, afterScreenUpdates: true)
let copied = UIGraphicsGetImageFromCurrentImageContext();
imageView.image = copied
UIGraphicsEndImageContext();
You can save any view as image by using drawViewHierarchyInRect method
UIGraphicsBeginImageContextWithOptions(self.textView.bounds.size, false, 0);
self.textText.drawViewHierarchyInRect(CGRectMake(0, 0, self.textView.frame.size.width, self.textView.frame.size.height),afterScreenUpdates:true)
var screenShot:UIImage = UIGraphicsGetImageFromCurrentImageContext();
All answers are good but missing is scale which is necessary in context.
Use UIView's drawViewHierarchyInRect mehtod to capture screen.
//Use screen scale for better images
let screenScale = UIScreen.mainScreen().scale;
//create context
UIGraphicsBeginImageContextWithOptions(yourView.bounds.size, false, screenScale);
//use view for drawing
yourView.drawViewHierarchyInRect(yourView.bounds, afterScreenUpdates: true)
//get captured image
let capturedImage = UIGraphicsGetImageFromCurrentImageContext();
//last dump context
UIGraphicsEndImageContext();
Another sloution : use UIView's layer's renderInContext
//Use screen scale for better images
let screenScale = UIScreen.mainScreen().scale;
//create context
UIGraphicsBeginImageContextWithOptions(yourView.bounds.size, false, screenScale);
//use view for drawing
yourView.layer.renderInContext(UIGraphicsGetCurrentContext())
//get captured image
let capturedImage = UIGraphicsGetImageFromCurrentImageContext();
//last dump context
UIGraphicsEndImageContext();

iOS: renderInContext and Landscape orientation issue

I'm trying to save the currently shown views on my iOS device for a certain app, and this is working properly. But I've got a problem as soon as I'm trying to save a UIImageView in Landscape orientation.
See the following image that describes my problem:
I'm using Auto layout for this app, and it runs on both iPhone and iPad. It seems like the ImageView is always saved as shown in portrait mode, and I'm a little bit stuck right now.
This is the code I use:
CGSize frameSize = self.view.frame.size;
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
frameSize = CGSizeMake(self.view.frame.size.height, self.view.frame.size.width);
}
UIGraphicsBeginImageContextWithOptions(frameSize, NO, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGFloat scale = CGRectGetWidth(self.view.frame) / CGRectGetWidth(self.view.bounds);
CGContextScaleCTM(ctx, scale, scale);
[self.view.layer renderInContext:ctx];
[self.delegate photoSaved:UIGraphicsGetImageFromCurrentImageContext()];
UIGraphicsEndImageContext();
Looking forward to your help!
I still have no idea what your exact issue is but using your screenshot code makes a bit strange image (not rotated or anything though, just too small). Can you try this code instead please.
+ (UIImage *)imageFromView:(UIView *)view {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, .0f);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
Other then that you must understand there is a huge difference between UIImage and CGImage as the UIImage includes the orientation while CGImage does not. When dealing with image transformations it is usually with the CGImage and getting its width or height will discard the orientation. That means a CGImage will have flipped dimensions when its orientation is not up (UIImageOrientationUp). But usually when dealing with such images you create a CGImage from the context and then use [UIImage imageWithCGImage:ref scale:1.0f orientation:originalOrientation]. Only if you wish to explicitly rotate the image so it has no orientation (being UIImageOrientationUp) you need to rotate and translate the image and draw it onto the context.
Anyway, this orientation issues are quite fixed by now, UIImagePNGRepresentation respects the orientation and you have an image constructor from the CGImage already written above which is what used to be missing in the past if I remember correctly.

iOS render image in context not working as expected in landscape orientation

The code below seems to work well to render an image from a view at retina resolution. The problem is it does not seem to work while my device is in landscape orientation. It returns an image rotated 90 degrees.
Do I need to add options for image or context orientation?
CGSize panelRect = CGSizeMake(selectedPanelView.frame.size.width, selectedPanelView.frame.size.height);
UIGraphicsBeginImageContextWithOptions(panelRect, 1, 2);
[[selectedPanelView layer] renderInContext:UIGraphicsGetCurrentContext()];
renderedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
The problem seems to be fixed by using: UIImage imageWithCGImage:scale:orientation: as below.
UIImage *renderedImageWithOrientation = [UIImage imageWithCGImage:renderedImage.CGImage scale:1 orientation:0];
I run this after rendering the image, then I add the image to the imageView.

Resources