I'm building an app using the UIImagePickerController and a custom Overlay. What is does is comparing two images (before image and after image). I am using a custom overlay with the before image when taking the after photo(please see the image attached).
iPhone 5 - ios7
iPhone 4 - iOS7 (When taking the image)
iPhone 4 - iOS 7 (After taking the photo)
See the size difference between iPhone 4 and iPhone 5 camera view.
Application works fine with iPhone 5 screen size(Both ios 6 and ios7). But iPhone 4/4s screen size, it works fine ONLY with iOS6. The issue is with iphone 4/4s(ios7 ONLY), Camera view takes full screen.
That means, you can notice
iPhone 5 camera view size ~ 320*427 (iOS 6 and iOS 7)
iPhone 4 camera view size ~ 320*427 (iOS 6)
BUT
iPhone 4 camera view size ~ 320*480 (iOS 7).
After the image is taken, it fitted to the actual size of 320*427. Because of this issue, I cannot align before image with camera view on iPhone 4 iOS7 (because its screeches to 320*480).
Does anyone faces this strange issue. I tried almost everything, but NO luck. Any ideas please???
This is my piece code for loading the camera view with custom before photo overlay.
- (void)loadCameraWithImage
{
if (!isLoadedOnce)
{
isLoadedOnce = YES;
UIImagePickerController *cameraView = [[UIImagePickerController alloc] init];
cameraView.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraView.wantsFullScreenLayout = NO;
if ([self respondsToSelector:#selector(setEdgesForExtendedLayout:)]) {
[self setEdgesForExtendedLayout:UIRectEdgeNone];
}
// crop before image
UIImage *imgTmpCropped = [self imageByCropping:imgBefore toRect:CGRectMake(0, 0, imgBefore.size.width/2, imgBefore.size.height)];
UIImage *overleyImage = [[UIImage alloc] initWithCGImage: imgTmpCropped.CGImage
scale: [UIScreen mainScreen].scale
orientation: UIImageOrientationDownMirrored];
UIImageView *crosshairView;
UIImageView *beforeView;
CGFloat screenHieght = [UIScreen mainScreen].bounds.size.height;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
//overleyImage = [UIImage imageNamed:#"overlay_ipad.png"];
crosshairView = [[UIImageView alloc] initWithImage:overleyImage];
crosshairView.frame = CGRectMake(0, 0, 768, 1024);
[crosshairView setUserInteractionEnabled:YES];
crosshairView.backgroundColor = [UIColor clearColor];
beforeView = [[UIImageView alloc] initWithImage:overleyImage];
beforeView.frame = CGRectMake(0, 0, 384, 1024);
beforeView.alpha = 0.5;
beforeView.contentMode = UIViewContentModeScaleAspectFill;
}
else {
//overleyImage = [UIImage imageNamed:#"overleyImageAfter.png"];
crosshairView = [[UIImageView alloc] init];
beforeView = [[UIImageView alloc] initWithImage:overleyImage];
if(screenHieght>500){
crosshairView.frame = CGRectMake(0, 60, 320, 480);
beforeView.frame = CGRectMake(0, 70, 160, 427);
}
else{
if([[[UIDevice currentDevice] systemVersion] floatValue] <7.0){
crosshairView.frame = CGRectMake(0, 0, 320, 480);
beforeView.frame = CGRectMake(0, 0, 160, 427);
}
else{
crosshairView.frame = CGRectMake(0, 0, 320, 480);
beforeView.frame = CGRectMake(0, 0, 160, 480);
}
}
[crosshairView setUserInteractionEnabled:YES];
crosshairView.backgroundColor = [UIColor clearColor];
beforeView.alpha = 0.5;
beforeView.contentMode = UIViewContentModeScaleToFill;
}
//[crosshairView addSubview:beforeView];
//set our custom overlay view
cameraView.cameraOverlayView = beforeView;
cameraView.delegate = (id)self;
cameraView.showsCameraControls = YES;
cameraView.navigationBarHidden = YES;
cameraView.toolbarHidden = YES;
[cameraView setHidesBottomBarWhenPushed:YES];
[self.view.window.rootViewController presentViewController:cameraView animated:YES completion:nil];
isLoadedOnce = NO;
}
}
TL;DR
Camera's preview has the same aspect ratio in every device (4:3), screens don't. Asume the preview will have that specific aspect ratio and that it will be placed in a specific position on the screen. Draw your overlay inside that area.
Longer:
We faced the same issue. (Our use case is taking pictures of credit cards with an overlay with the same size as a card). The main problem is that the camera preview's proportions are always the same (4:3) in every device but different phones have different screen proportions (iPhone 4s vs iPhone 5, for example) so the preview's need to be fitted differently and that makes putting an overlay and cropping that very difficult.
Our solution was (the code is somewhat messy and hacky, sorry):
// Adjust camera preview to be a little bit more centered instead of adjusted to the top
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
float cameraAspectRatio = 4.0 / 3.0;
float imageHeight = screenSize.width * cameraAspectRatio;
float verticalAdjustment;
if (screenSize.height - imageHeight <= 54.0f) {
verticalAdjustment = 0;
} else {
verticalAdjustment = (screenSize.height - imageHeight) / 2.0f;
verticalAdjustment /= 2.0f; // A little bit upper than centered
}
CGAffineTransform transform = self.cameraController.cameraViewTransform;
transform.ty += verticalAdjustment;
self.cameraController.cameraViewTransform = transform;
CGRect previewFrame = CGRectMake(0, verticalAdjustment, screenSize.width, imageHeight);
CardPhotoView *overlayView = [[CardPhotoView alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, screenSize.height) widthPercentageOfCamera:self.widthPercentageOfCamera previewFrame:previewFrame];
self.overlayView = overlayView;
self.overlayView.delegate = self;
self.overlayView.useViewport = YES;
[self.overlayView setCameraReady:NO];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(cameraIsReady:) name:AVCaptureSessionDidStartRunningNotification object:nil];
self.cameraController.showsCameraControls = NO;
self.cameraController.navigationBarHidden = YES;
self.cameraController.toolbarHidden = YES;
self.cameraController.cameraOverlayView = self.overlayView;
[self presentViewController:self.cameraController animated:NO completion:nil];
Explanation:
self.cameraController is a UIImagePickerController. CardPhotoView is a view subclass that draws the overlay, it takes the preview frame to know exactly where the preview will be positioned (some devices will have black bars on top and bottom, some won't). It also takes a width percentage to add a little padding to the cropping window.
Also, we have hidden all default camera controls and we have implemented some buttons that will do the work for us. Those buttons are added in the CardPhotoView class and they are drawn taking into account where the preview frame is.
Related
I am creating an app with a simple UIImageview and scroll view for zooming.
Everything is perfect on my iPhone5/s. However, when I test the app on the iPhone 4S it does not work correctly. When I use a modal to pop the image full screen, the image is half way off the screen.
Again, this ONLY happens on the 4S and not the 5.
I tried changing the anchor points, forcing sizing but nothing works
Also, after I change my orientation from portrait to land scape and back, it goes back into "position"
I am also using constraints as my scrollview is horizontal and vertical center in my main view and the image view is horizontal vertical center in the scroll view.
Thank you in advance.
some relevant code:
image = [UIImage imageNamed:self.myImage];
[self.scrollView setTranslatesAutoresizingMaskIntoConstraints:YES];
[self.imageView setTranslatesAutoresizingMaskIntoConstraints:YES];
[self.myView setTranslatesAutoresizingMaskIntoConstraints:YES];
[im setBackgroundColor:[UIColor blackColor]];
im.contentMode = UIViewContentModeScaleAspectFit;
[self.scrollView setZoomScale:self.scrollView.minimumZoomScale
animated:YES];
NSLog(#"%F",img.size.height);
CGFloat imgheight = image.size.height;
CGFloat imgwidth = image.size. width;
CGSize imageSize = [self currentScreenBoundsDependOnOrientation];
self.scrollView.frame = CGRectMake(0,
0,
imageSize.width,
imageSize.height);
self.imageView.frame = CGRectMake(0,
0,
imageSize.width,
imageSize.height);
dan = true;
self.scrollView.delegate = self;
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleDoubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
[self.scrollView addGestureRecognizer:doubleTap];
self.scrollView.minimumZoomScale = 1;
self.scrollView.maximumZoomScale = 2.4;
self.scrollView.scrollEnabled = YES;
self.scrollView.zoomScale = self.scrollView.minimumZoomScale;
I want to add rounded corners image on my UIView, so I made two of my images 12x12px rounded corners.
I want to know how best to add my view taking into account that he must align automatically in portrait and landscape mode in the bottom of the total screen!
This is what I did now, but that does not work:
CGSize result = [[UIScreen mainScreen] bounds].size;
self.brcLeft = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, result.height-12.0, 12.0, 12.0)];
self.brcLeft.image = [UIImage imageNamed:#"brc-left"];
[self.view addSubview:brcLeft];
self.brcRight = [[UIImageView alloc] initWithFrame:CGRectMake(result.width-12.0, result.height-12, 12.0, 12.0)];
self.brcRight.image = [UIImage imageNamed:#"brc-right"];
[self.view addSubview:brcRight];
For setting your views to both orientation at the bottom of the screen do this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
CGRect screenFrame = [[UIScreen mainScreen] bounds];
[self.brcLeft setFrame:CGRectMake(0.0, screenFrame.size.height - self.brcLeft.frame.size.height , 12.0, 12.0)];
[self.brcRight setFrame:CGRectMake(result.width-12.0, screenFrame.size.height - self.brcRight.frame.size.height , 12.0, 12.0)];
return YES;
}
and for rounded Corners:
#import <QuartzCore/QuartzCore.h>
write this in your viewDidLoad
self.brcLeft.layer.cornerRadius = 2;
self.brcLeft.layer.masksToBounds = YES;
self.brcRight.layer.cornerRadius = 2;
self.brcRight.layer.masksToBounds = YES;
I have an application which has a fullscreen UIScrollView, and within it there are seven images. The images are also meant to be full screen, and the scroll view is set to enable pagination.
I have a method which either creates or moves the image views:
-(void)rebuildImageView{
// set up images
float screenW = self.view.bounds.size.width;
float screenH = self.view.bounds.size.height;
int numImgs = self.soundNames.count;
self.mainScrollView.contentSize = CGSizeMake(screenW * numImgs, screenH);
for(int i=0; i<numImgs; i++){
UIImageView* imageView = (UIImageView*)[self.mainScrollView viewWithTag:i+100];
if(imageView == nil){
imageView = [[UIImageView alloc] init];
imageView.tag = i+100;
[self.mainScrollView addSubview:imageView];
imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"image%d.jpg",i]];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
[imageView release];
}
imageView.frame = CGRectMake(i * screenW, 0, screenW, screenH);
}
// scroll to the current one
[self.mainScrollView scrollRectToVisible:CGRectMake(self.currentSound*screenW, 0, screenW, screenH) animated:YES];
}
I also have this on the view controller:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[UIView animateWithDuration:duration animations:^{
[self rebuildImageView];
}];
}
This code works fine when I autorotate while image 0 is being shown, but when I'm on image 7, you can briefly see most of image 6 when rotating. This video shows what's happening:
http://www.youtube.com/watch?v=1O3jOcTgVP8
Is there a better method I should use to reconfigure the scroll view and images when rotating the device?
Any frame changes put in the willAnimateRotationToInterfaceOrientation:duration method should automatically animate. So you could try removing it from the block?
Personally, I've had a lot more luck with this type of thing subclassing UIScrollView and putting the equivalent layout subview frame code in an override of the layoutSubviews method (don't forget to call super or you might end up with misplaced scroll bars).
I am using the code from http://www.cocos2d-iphone.org/forum/topic/6889 to add a UIView to the screen in a Cocos2d game. It works great in non-retina resolution (everything is positioned correctly), but in retina resolution the UIView is placed in a different location. The code I am using to add the view to the game is basically the same as the code from the website:
UIView *myView = [[[UIView alloc] init] autorelease];
myView.backgroundColor = [UIColor redColor];
CCUIViewWrapper *wrapper = [CCUIViewWrapper wrapperForUIView:myView];
wrapper.contentSize = CGSizeMake(100, 100);
wrapper.position = ccp(50,50);
[self addChild:wrapper];
The view appears 50px from the bottom and left corner in non retina and 0px from left and 100px up in retina.
The positioning for the wrapper in retina mode is ccp(320,0). No idea why, but it works.
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)] == YES && [[UIScreen mainScreen] scale] == 2.00) {
wrapper.position = ccp(320,0); //Retina
} else {
wrapper.position = ccp(160,240); //Normal
}
The CCUIViewWrapper (at least in the form from the forum thread) does not use CC_CONTENT_SCALE_FACTOR(). That means it's not compatible with Retina displays.
You may be able to get around this by supplying properly scaled size and position, this may or may not work:
wrapper.contentSize = CGSizeMake(100 * CC_CONTENT_SCALE_FACTOR(),
100 * CC_CONTENT_SCALE_FACTOR());
wrapper.position = ccp(50 * CC_CONTENT_SCALE_FACTOR(),
50 * CC_CONTENT_SCALE_FACTOR());
I have a bug in a Universal iOS app that does not display the camera view in the iPad frame. The view is offset to the left. The view sits perfectly in an iPhone, but not on iPad. The original code was written 2 years ago and I am wondering if there has been a change in iOS that is now missing from this section of code.
Here is what I have at the moment;
self.preview = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
AVCaptureConnection *avcc = [self.preview connection];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
[avcc setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
else
[avcc setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
CGRect rect = [[[self view] layer] bounds];
[self.preview setBounds:CGRectMake(0, 0, rect.size.height, rect.size.width)];
[self.preview setPosition:CGPointMake(CGRectGetMidY(rect), CGRectGetMidX(rect))];
self.preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
As per the problem , what I can suggest just add this line in viewDidLayoutSubviews() if your project support Auto Layout .
Code:-
{
CGRect bounds=self.view.layer.bounds;
self.preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
self.preview.bounds=bounds;
self.preview.position=CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
}