I am building an iOS app that is to have a full screen ImagePickerController, with the resulting image that is captured to be the same that is shown in the ImagePickerController View. This is my current relevant code:
To create and transform the ImagePickerController:
self.imagePicker = [[UIImagePickerController alloc] init];
self.imagePicker.delegate = self;
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
// set the aspect ratio of the camera
float heightRatio = 4.0f / 3.0f;
// calculate the height of the camera based on the screen width
float cameraHeight = floorf(screenSize.width * heightRatio);
// calculate the ratio that the camera height needs to be scaled by
float scale = ceilf((screenSize.height / cameraHeight) * 10.0) / 10.0;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
self.imagePicker.showsCameraControls = NO;
[self.imagePicker setCameraOverlayView:cameraView];
// move the controller to the center of the screen
self.imagePicker.cameraViewTransform = CGAffineTransformMakeTranslation(0, (screenSize.height - cameraHeight) / 2.0);
// concatenate the scale transform
self.imagePicker.cameraViewTransform = CGAffineTransformScale(self.imagePicker.cameraViewTransform, scale, scale);
}
Once the image captured, here is the code I am using to redraw the captured image to match the Preview:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
self.image = [info objectForKey:UIImagePickerControllerOriginalImage];
self.image = [self croppedImage:self.image];
- (UIImage *) croppedImage: (UIImage *)image{
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
// set the aspect ratio of the camera
float heightRatio = 4.0f / 3.0f;
// calculate the height of the camera based on the screen width
float cameraHeight = floorf(screenSize.width * heightRatio);
// calculate the ratio that the camera height needs to be scaled by
float scale = ceilf((screenSize.height / cameraHeight) * 10.0) / 10.0;
CGSize originalImageSize = [image size];
CGSize newImageSize = CGSizeMake(floorf(originalImageSize.width / scale)* 3/4, floorf(originalImageSize.height / scale)* 3/4);
CGRect newImageRect = CGRectMake((originalImageSize.width - newImageSize.width)/2.0, (originalImageSize.height - newImageSize.height)/2.0, newImageSize.width, newImageSize.height);
return [image croppedImage:newImageRect];
}
So my problem is that my CroppedImage method is not calculating correctly, as the resulting image seems to be more "zoomed in" than needed. Not really sure what is wrong in the calculation.
Note - this app is to intended to scale properly on all iPhones - Portrait mode only. I am currently testing on iPhone 6.
In case this helps anybody - on my device i was able to fix it by switching
CGSize newImageSize = CGSizeMake(floorf(originalImageSize.width / scale)* 3/4, floorf(originalImageSize.height / scale)* 3/4);
to
CGSize newImageSize = CGSizeMake(floorf(originalImageSize.width / scale), floorf(originalImageSize.height / scale)* 4/3);
only the height/scale needed to by be multiplied and by 4/3, not 3/4. I have not tested this on any other devices yet. Just figured this might help anybody running into the same thing.
Related
I'm using PEPhotoCropEditor library in one of my iOS project. I able to having constant aspect ratio (1:1) with following code.
- (void)openEditor {
PECropViewController *controller = [[PECropViewController alloc] init];
controller.delegate = self;
controller.image = self.imageView.image;
UIImage *image = self.imageView.image;
CGFloat width = image.size.width;
CGFloat height = image.size.height;
CGFloat length = MIN(width, height);
CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
controller.imageCropRect = CGRectMake((width - length) / 2,
(height - length) / 2,
length,
length);
// Restricted to a square aspect ratio
controller.keepingCropAspectRatio = YES;
controller.cropAspectRatio = 1.0;
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
[self presentViewController:navigationController animated:YES completion:NULL];
}
But then I needed to have aspect ratio (height:width) of (1:3) instead of (1:1).
controller.cropAspectRatio = 1.0f / 3.0f;
I tried above and nothing happened. Still having same aspect ratio. Then I change below code too.
controller.imageCropRect = CGRectMake((width - length) / 2,
(height - length) / 2,
length * 3,
length);
Again nothing happened. After commenting above I hard coded the value like below.
controller.imageCropRect = CGRectMake(0.0f, 0.0f, 300.0f, 100.0f);
Then the cropping area displayed correctly but when resizing that aria will lead to destroy the crop aspect ratio (1:3)
Any idea how to remain aspect ratio (1:3) till all editing process complete?
Set this in ViewdidAppear in PECropViewController.m
self.cropAspectRatio = 1.0f;
self.keepingCropAspectRatio = YES;
And pass value to function setKeepingAspectRatio in PECropRectView.m
- (void)setKeepingAspectRatio:(BOOL)keepingAspectRatio
{
_keepingAspectRatio = keepingAspectRatio;
if (self.keepingAspectRatio) {
CGFloat width = CGRectGetWidth(self.bounds);
CGFloat height = CGRectGetHeight(self.bounds);
self.fixedAspectRatio = your_fixed_aspect_ratio_value;//fminf(width / height, height / width);
}
}
you will get expected result.
I'm using Parse.com to build a simple app. I want to know if there is any way to make the imageView size fixed (for example 30x30px) and round the corners of the image?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
//-------------------------------------------------------------------------------------------------------------------------------------------------
{
PFTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
PFUser *user = users[indexPath.row];
cell.textLabel.text = user[PF_USER_FULLNAME];
PFImageView *imageView = [[PFImageView alloc] init];
[imageView setBackgroundColor:[UIColor clearColor]];
cell.imageView.image = [UIImage imageNamed:#"tab_profile.png"]; // placeholder image
cell.imageView.file = (PFFile *)user[PF_USER_THUMBNAIL]; // remote image
[cell.imageView loadInBackground];
return cell;
}
Please help with any advice, I'm new to Xcode and Parse SDK...
1)
2)
This is what I usually use to get a circle on an imageView:
Crop (not resize) the image to make it a square. The method below resizes the image to whatever size you pass as a CGSize:
(UIImage *)squareImageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
{
double ratio;
double delta;
CGPoint offset;
//make a new square size, that is the resized imaged width
CGSize sz = CGSizeMake(newSize.width, newSize.width);
//figure out if the picture is landscape or portrait, then
//calculate scale factor and offset
if (image.size.width > image.size.height)
{
ratio = newSize.width / image.size.width;
delta = (ratio*image.size.width - ratio*image.size.height);
offset = CGPointMake(delta/2, 0);
} else {
ratio = newSize.width / image.size.height;
delta = (ratio*image.size.height - ratio*image.size.width);
offset = CGPointMake(0, delta/2);
}
//make the final clipping rect based on the calculated values
CGRect clipRect = CGRectMake(-offset.x, -offset.y,
(ratio * image.size.width) + delta,
(ratio * image.size.height) + delta);
//start a new context, with scale factor 0.0 so retina displays get
//high quality image
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(sz, YES, 0.0);
} else {
UIGraphicsBeginImageContext(sz);
}
UIRectClip(clipRect);
[image drawInRect:clipRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Then, call the method just created, and apply the corner radius (in this case it will be a circle):
imageView.image = [self squareImageWithImage:imageNormal scaledToSize:CGSizeMake(50, 50)]; // assuming you want a 50x50px image
// convert imageview to circle
imageView.layer.cornerRadius = cell.imageView.frame.size.width / 2;
imageView.clipsToBounds = YES;
You can reduce the amount of the cornerRadius to something else with this same call.
This is how I do it:
Image with fix size
If it's possible use Storyboard and create 2 size constraints for the PFImageView with the 30 px value, but if the project doesn't uses size classes it should work without constraints, just set the proper size for the image. If you experience shape changes you could play with View Mode also.
TooManyEduardos's solution for the rounded image is correct, if you don't want circle just play with the numbers.
//1
imageView.layer.cornerRadius = cell.imageView.frame.size.width / 2;
//2
imageView.layer.cornerRadius = cell.imageView.frame.size.width / 4;
//3
imageView.layer.cornerRadius = cell.imageView.frame.size.width / 6;
//4
imageView.layer.cornerRadius = cell.imageView.frame.size.width / 8;
I am using an UIImagePickerView to grab photos from the camera or camera roll. When the user 'picks' an image, I'm inserting the image onto an UIImageView, which is nested in a UIScrollView to allow pinch/pan. I have an overlay above the image view which represents the area to which the image will be cropped (just like when UIImagePickerView's .allowEditing property is YES).
The Apple-provided "allowEditing" capability also has the same problem I'm seeing with my code (which I why I tried to write it myself in the first place, and I need custom shapes in the overlay). The problem is that I can't seem to find a good way to allow the user to pan around over ALL the image. There are always portions of the image which can't be placed in the crop window. It's always content around the edges (maybe the outside 10%) of the image, which cannot be panned into the crop window.
In the above photo, the brown area at the top and bottom are the scroll view's background color. The image view is sized to the image.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// Calculate what height/width we'll need for our UIImageView.
CGSize screenSize = [UIScreen mainScreen].bounds.size;
float width = 0.0f, height = 0.0f;
if (image.size.width > image.size.height) {
width = screenSize.width;
height = image.size.height / (image.size.width/screenSize.width);
} else {
height = screenSize.height;
width = image.size.width / (image.size.height/screenSize.height);
}
if (width > screenSize.width) {
height /= (width/screenSize.width);
width = screenSize.width;
}
if (height > screenSize.height) {
width /= (height/screenSize.height);
height = screenSize.height;
}
// Update the image view to the size of the image and center it.
// Image view is a subview of the scroll view.
imageView.frame = CGRectMake((screenSize.width - width) / 2, (screenSize.height - height) / 2, width, height);
imageView.image = image;
// Setup our scrollview so we can scroll and pinch zoom the image!
imageScrollView.contentSize = CGSizeMake(screenSize.width, screenSize.height);
// Close the picker.
[[picker presentingViewController] dismissViewControllerAnimated:YES completion:NULL];
}
I've considered monitoring scroll position and zoom level of the scroll view and disallow a side of the image to pass into the crop "sweet spot" of the image. This seems like over-engineering, however.
Does anyone know of a way to accomplish this?
I'm a moron. What a difference a good night's sleep can make ;-) Hopefully, it will help someone in the future.
Setting the correct scroll view contentSize and contentInset did the trick. The working code is below.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// Change the frame of the image view so that it fits the image!
CGSize screenSize = [UIScreen mainScreen].bounds.size;
float width = 0.0f, height = 0.0f;
if (image.size.width > image.size.height) {
width = screenSize.width;
height = image.size.height / (image.size.width/screenSize.width);
} else {
height = screenSize.height;
width = image.size.width / (image.size.height/screenSize.height);
}
// Make sure the new height and width aren't bigger than the screen
if (width > screenSize.width) {
height /= (width/screenSize.width);
width = screenSize.width;
}
if (height > screenSize.height) {
width /= (height/screenSize.height);
height = screenSize.height;
}
CGRect overlayRect = cropOverlay.windowRect;
imageView.frame = CGRectMake((screenSize.width - width) / 2, (screenSize.height - height) / 2, width, height);
imageView.image = image;
// Setup our scrollview so we can scroll and pinch zoom the image!
imageScrollView.contentSize = imageView.frame.size;
imageScrollView.contentInset = UIEdgeInsetsMake(overlayRect.origin.y - imageView.frame.origin.y,
overlayRect.origin.x,
overlayRect.origin.y + imageView.frame.origin.y,
screenSize.width - (overlayRect.origin.x + overlayRect.size.width));
// Dismiss the camera's VC
[[picker presentingViewController] dismissViewControllerAnimated:YES completion:NULL];
}
The scrollview and image view are set up like this:
imageScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
imageScrollView.showsHorizontalScrollIndicator = NO;
imageScrollView.showsVerticalScrollIndicator = NO;
imageScrollView.backgroundColor = [UIColor blackColor];
imageScrollView.userInteractionEnabled = YES;
imageScrollView.delegate = self;
imageScrollView.minimumZoomScale = MINIMUM_SCALE;
imageScrollView.maximumZoomScale = MAXIMUM_SCALE;
[self.view addSubview:imageScrollView];
imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.backgroundColor = [UIColor grayColor]; // I had this set to gray so I could see if/when it didn't align properly in the scroll view. You'll likely want to change it to black
[imageScrollView addSubview:imageView];
Edit 3-21-14 Newer, fancier, better implementation of the method that calculates where to place the image in the screen and scrollview. So what's better? This new implementation will check for any image that is being set into the scrollview which is SMALLER in width or height, and adjust the frame of the image view such that it expands to be at least as wide or tall as the overlay rect, so you don't ever have to worry about your user selecting an image that isn't optimal for your overlay. Yay!
- (void)imagePickerController:(UIImagePickerController *)pickerUsed didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// Change the frame of the image view so that it fits the image!
CGSize screenSize = [UIScreen mainScreen].bounds.size;
float width = 0.0f, height = 0.0f;
if (image.size.width > image.size.height) {
width = screenSize.width;
height = image.size.height / (image.size.width/screenSize.width);
} else {
height = screenSize.height;
width = image.size.width / (image.size.height/screenSize.height);
}
CGRect overlayRect = cropOverlay.windowRect;
// We should check the the width and height are at least as big as our overlay window
if (width < overlayRect.size.width) {
float ratio = overlayRect.size.width / width;
width *= ratio;
height *= ratio;
}
if (height < overlayRect.size.height) {
float ratio = overlayRect.size.height / height;
height *= ratio;
width *= ratio;
}
CGRect imageViewFrame = CGRectMake((screenSize.width - width) / 2, (screenSize.height - height) / 2, width, height);
imageView.frame = imageViewFrame;
imageView.image = image;
// Setup our scrollview so we can scroll and pinch zoom the image!
imageScrollView.contentSize = imageView.frame.size;
imageScrollView.contentInset = UIEdgeInsetsMake(overlayRect.origin.y - imageView.frame.origin.y,
(imageViewFrame.origin.x * -1) + overlayRect.origin.x,
overlayRect.origin.y + imageView.frame.origin.y,
imageViewFrame.origin.x + (screenSize.width - (overlayRect.origin.x + overlayRect.size.width)));
// Calculate the REAL minimum zoom scale!
float minZoomScale = 1 - MIN(fabsf(fabsf(imageView.frame.size.width) - fabsf(overlayRect.size.width)) / imageView.frame.size.width,
fabsf(fabsf(imageView.frame.size.height) - fabsf(overlayRect.size.height)) / imageView.frame.size.height);
imageScrollView.minimumZoomScale = minZoomScale;
// Dismiss the camera's VC
[[picker presentingViewController] dismissViewControllerAnimated:YES completion:NULL];
}
I'm trying to make the camera preview take up part of my view, rather than the entire screen. Is this even possible? Do I have to use something like the AV Foundation Framework to do this? I am new to iOS development, so any guidance would be greatly appreciated! Thanks!
Yes, you need to use AVFoundation for that. In the past some people (including myself) have tried to use UIImagePickerController instead (by replacing its view property with a custom view), but it doesn't work in iOS 7 (or at least will never work as you expect). Specifying a custom preview was never a documented feature of UIImagePickerController to begin with, so no big surprise.
Try this code to maintain your resultant image in same size. Its working well for me.
Step 1: First create IBOutlet for UIImageview.
Step 2: Add custom method into your imagePickerController.
-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = info[UIImagePickerControllerMediaType];
[self dismissViewControllerAnimated:YES completion:nil];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
OriginalImage=info[UIImagePickerControllerOriginalImage];
image = info[UIImagePickerControllerOriginalImage];
//------Additional method placed here----
imageview.image = image; // additional method
[self resizeImage];
//---------
if (_newMedia)
UIImageWriteToSavedPhotosAlbum(image,self,#selector(image:finishedSavingWithError:contextInfo:),nil);
}
else if ([mediaType isEqualToString:(NSString *)kUTTypeMovie])
{
// Code here to support video if enabled
}
}
Step 3: Custom method to resize images on camera preview
//---- Resize the original image ----------------------
-(void)resizeImage
{
UIImage *resizeImage = imageview.image;
float width = 320;
float height = 320;
CGSize newSize = CGSizeMake(320,320);
UIGraphicsBeginImageContextWithOptions(newSize,NO,0.0);
CGRect rect = CGRectMake(0, 0, width, height);
float widthRatio = resizeImage.size.width / width;
float heightRatio = resizeImage.size.height / height;
float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;
width = resizeImage.size.width / divisor;
height = resizeImage.size.height / divisor;
rect.size.width = width;
rect.size.height = height;
//indent in case of width or height difference
float offset = (width - height) / 2;
if (offset > 0) {
rect.origin.y = offset;
}
else {
rect.origin.x = -offset;
}
[resizeImage drawInRect: rect];
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
imageview.image = smallImage;
imageview.contentMode = UIViewContentModeScaleAspectFit;
}
I am interested in using a custom overlay for the UIImagePickerController for camera controls that take the entire screen, very similar to what the default Camera app does when switched to the video function.
I have referenced several questions here on SO on this topic, particularly this one, as well as the Apple example on how to use a custom overlay for the UIImagePickerController, but none of them have been able to produce a successful, full-screen result with iOS 7.
So far, this is what the camera UI looks like with the custom overlay (without any buttons):
Note that there is a black bar in the bottom of the screen. I noticed that I could get the black bar removed if I change the cameraAspectRatio to 1, but this distorts the camera zoom as it then has a very zoomed in view. Is there a way to have full screen without either distorting the zoom too much (I understand that a small bit is necessary), and also remove the black bar?
Here is my code that configures the custom overlay:
{
self.imagePickerController.showsCameraControls = NO;
[[NSBundle mainBundle] loadNibNamed:#"overlayView" owner:self options:nil];
self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
self.imagePickerController.cameraOverlayView = self.overlayView;
self.overlayView = nil;
// Device's screen size (ignoring rotation intentionally):
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
float imageWidth = floorf(screenSize.width * cameraAspectRatio);
float scale = ceilf((screenSize.height / imageWidth) * 10.0) / 10.0;
self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);
}
Update:
An additional issue that I noticed is, the picture that is shown in camera preview is always smaller and has less details than the picture that is saved when the method [self.imagePickerController takePicture]. To illustrate:
This is what the keyboard looks like in the camera preview with the black bar below (sorry its a bit shaky):
However, note that the actual captured image in the preview panel has a lot more details as shown here, especially towards the top, as well as both left and right.
My question is, how would be able to set my camera preview so that what the user sees in preview is exactly the image that it will capture and could be shown to them afterwards? Thanks!
Update 2
Here is the entire code in viewDidLoad that sets up the camera controls.
- (void)viewDidLoad
{
[super viewDidLoad];
//Appearance configuration
self.navigationItem.hidesBackButton = YES;
//UIImagePickerController initialization and setup
self.imagePickerController = [[UIImagePickerController alloc] init];
self.imagePickerController.delegate = self;
self.imagePickerController.allowsEditing = NO;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
self.imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; //if there is a camera avaliable
} else {
self.imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;//otherwise go to the folder
}
self.imagePickerController.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeImage, nil];
if (self.imagePickerController.sourceType == UIImagePickerControllerSourceTypeCamera)
{
self.imagePickerController.showsCameraControls = NO;
[[NSBundle mainBundle] loadNibNamed:#"overlayView" owner:self options:nil];
self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
self.imagePickerController.cameraOverlayView = self.overlayView;
self.overlayView = nil;
// Device's screen size (ignoring rotation intentionally):
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
int heightOffset = 0;
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0"))
{
heightOffset = 120; //whole screen :)
}
float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
float imageWidth = floorf(screenSize.width * cameraAspectRatio);
float scale = ceilf(((screenSize.height + heightOffset) / imageWidth) * 10.0) / 10.0;
self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);
}
}
And in viewWillAppear, I call the image picker view:
BOOL modalPresent = (BOOL)(self.presentedViewController);
//Present the Camera UIImagePicker if no image is taken
if (!appDelegate.imageStorageDictionary[#"picture1"]){
if (modalPresent == NO){ //checks if the UIImagePickerController is modally active
[self presentViewController:self.imagePickerController animated:NO completion:nil];
}
}
After many attempts, this is what worked for me with many thanks to other people's suggestions. The following facts were very helpful to know and keep in mind:
The camera's points resolution is 426 * 320. In order for the camera preview's height to be stretched to the phone's screen height of 568, it needs to be multiplied by a factor of 1.3333 when using CGAffineTransformScale.
Note that the below are hard coded with various numbers based on the iPhone 5's screen resolution in points. They could be improved by using such objects such as screen.height, screen.width and other variables to make it applicable to iPhone 4/4s dimensions as well.
self.imagePickerController.showsCameraControls = NO;
[[NSBundle mainBundle] loadNibNamed:#"overlayView" owner:self options:nil];
self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
self.imagePickerController.cameraOverlayView = self.overlayView;
self.overlayView = nil;
//For iphone 5+
//Camera is 426 * 320. Screen height is 568. Multiply by 1.333 in 5 inch to fill vertical
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, 71.0); //This slots the preview exactly in the middle of the screen by moving it down 71 points
self.imagePickerController.cameraViewTransform = translate;
CGAffineTransform scale = CGAffineTransformScale(translate, 1.333333, 1.333333);
self.imagePickerController.cameraViewTransform = scale;
In Swift
var picker: UIImagePickerController = UIImagePickerController();
picker.sourceType = UIImagePickerControllerSourceType.Camera;
picker.showsCameraControls = false;
var screenBounds: CGSize = UIScreen.mainScreen().bounds.size;
var scale = screenBounds.height / screenBounds.width;
picker.cameraViewTransform = CGAffineTransformScale(picker.cameraViewTransform, scale, scale);
Make sure that you account for 20px status bar change in iOS7. If you are facing a 20px black screen at bottom of the screen then this will be your issue. You can check that whether the app is running in ios7 or not by one of these preprocessors
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
And you can make following changes to your code and see if it works
{
self.imagePickerController.showsCameraControls = NO;
[[NSBundle mainBundle] loadNibNamed:#"overlayView" owner:self options:nil];
self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
self.imagePickerController.cameraOverlayView = self.overlayView;
self.overlayView = nil;
// Device's screen size (ignoring rotation intentionally):
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
int heightOffset = 0;
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0"))
{
heightOffset = 20;
}
float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
float imageWidth = floorf(screenSize.width * cameraAspectRatio);
float scale = ceilf(((screenSize.height + heightOffset) / imageWidth) * 10.0) / 10.0;
self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);
}
Please let me know if it works. I haven't coded it to test.
Because the screen aspect ratio is different than the 4/3 ratio of the camera itself, you need (as you mentioned) to slightly crop the edges in order to have the image extend to the bottom.
In order to do that, you need to have the width be wide enough so that the height can be the full screen. So, your image width and height must be:
float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
float imageWidth = screenSize.height / cameraAspectRatio;
You'll also probably want the view presenting the camera image to be that width that extends off both sides of the screen.
There is a way easier method to get your overlay fullscreen at least tested in iOS 9.
let view = ... your overlayView
let bounds = UIScreen.mainScreen().bounds
view.center = CGPoint(x: bounds.midX, y: bounds.midY)
view.bounds = bounds
self.imagePicker.cameraOverlayView = view
I don't know why you use screen size. Just try this simple code:
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera])
{
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
controller.sourceType = UIImagePickerControllerSourceTypeCamera;
controller.allowsEditing = NO;
controller.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:
UIImagePickerControllerSourceTypeCamera];
controller.delegate = self;
[self presentViewController:controller animated:NO completion:^{}];
}
Try this code to maintain your resultant image in custom size. I got result by using custom method for getting resultant image as custom size.
First create IBOutlet for UIImageview.
-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = info[UIImagePickerControllerMediaType];
[self dismissViewControllerAnimated:YES completion:nil];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
OriginalImage=info[UIImagePickerControllerOriginalImage];
image = info[UIImagePickerControllerOriginalImage];
//----------------------------------------
imageview.image = image; //------------- additional method for custom image size
self resizeImage];
//-----------------------------------------
if (_newMedia)
UIImageWriteToSavedPhotosAlbum(image,self,#selector(image:finishedSavingWithError:contextInfo:),nil);
}
else if ([mediaType isEqualToString:(NSString *)kUTTypeMovie])
{
// Code here to support video if enabled
}
}
//---- Resize the original image by using custom method----------------------
-(void)resizeImage
{
UIImage *resizeImage = imageview.image;
float width = 320;
float height = 320;
CGSize newSize = CGSizeMake(320,320);
UIGraphicsBeginImageContextWithOptions(newSize,NO,0.0);
CGRect rect = CGRectMake(0, 0, width, height);
float widthRatio = resizeImage.size.width / width;
float heightRatio = resizeImage.size.height / height;
float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;
width = resizeImage.size.width / divisor;
height = resizeImage.size.height / divisor;
rect.size.width = width;
rect.size.height = height;
//indent in case of width or height difference
float offset = (width - height) / 2;
if (offset > 0) {
rect.origin.y = offset;
}
else {
rect.origin.x = -offset;
}
[resizeImage drawInRect: rect];
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
imageview.image = smallImage;
imageview.contentMode = UIViewContentModeScaleAspectFit;
}
To solve a similar problem, I instantiated a ViewController from storyboard and used the controller's view as camera overlay.
I don't know if it's what you're looking for, but i used the following code:
UIImagePickerController *globalPicker = [[UIImagePickerController alloc] init];
globalPicker.delegate = self;
globalPicker.sourceType = UIImagePickerControllerSourceTypeCamera;controller=[self.storyboard instantiateViewControllerWithIdentifier:#"myVC"];
overlayView = controller.view;
UIView *cameraView=[[UIView alloc] initWithFrame:self.view.bounds];
[cameraView addSubview:overlayView];
[globalPicker setCameraOverlayView:cameraView];
Try this code, it works fine for me
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraUI.showsCameraControls = NO;
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
float cameraAspectRatio = 4.0 / 3.0;
float imageHeight = floorf(screenSize.width * cameraAspectRatio);
float scale = screenSize.height / imageHeight;
float trans = (screenSize.height - imageHeight)/2;
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, trans);
CGAffineTransform final = CGAffineTransformScale(translate, scale, scale);
cameraUI.cameraViewTransform = final
;
cameraUI.delegate = self;
[self presentViewController:cameraUI animated:YES completion:nil];
This code assumes that the aspect of the original camera preview area is 4:3.