Camera Overlay not in the center - ios

I am trying to add an overlay to this UIImagePickerController instance but the result is the overlay off center.
I have created a simple red square (300x300 pt) to exemplify the problem and serve as an overlay and added that to the camera overlay, using this:
CGRect bounds = [[UIScreen mainScreen] bounds];
UIView *containerOverlay = [[UIView alloc] initWithFrame:bounds];
UIImage *overlay = [UIImage imageNamed:#"red"];
UIImageView *overlayView = [[UIImageView alloc] initWithImage:overlay];
CGFloat midX = CGRectGetMidX(bounds);
CGFloat midY = CGRectGetMidY(bounds);
CGPoint center = CGPointMake(midX, midY);
overlayView.center = center;
[containerOverlay addSubview:overlayView];
[_camera setCameraOverlayView:containerOverlay];
this is what is shown on the live preview... completely off the vertical center.
amazingly, when I take the picture and iOS shows me the picture already taken, the overlay is magically centered...
How do I center the overlay on the live camera?

Well the overlay is y-centered to the screen bounds right?
Which is what you are doing here:
CGFloat midX = CGRectGetMidX(bounds);
CGFloat midY = CGRectGetMidY(bounds);
If you want the overlay aligned to the actual image rect you need to offset the bottom black bar (it's not the same height as the top black bar).

Related

Calculating Visible CGRect to crop a UIImageView [duplicate]

This question already has answers here:
How to crop a UIImageView to a new UIImage in 'aspect fill' mode?
(2 answers)
Closed 4 years ago.
I have a UIView. There is a UIImageView inside that UIView. UIImageView doesn't comply to autolayout constraints. Parent UIView's bounds are clipped.
Now content mode of UIImageView is Aspect Fill, but the size of UIImageView is always calculated and set to size of UIImage that is being rendered. So UIImageView's size will always be equal to size of UIImage.
Now UIImageView can be positioned. It has a pan gesture applied to it. UIImageView is being moved within the parent UIView based on requirement of user.
My task is to crop the UIImage of UIImageView to the visible viewport of parent UIVIew only. Core Cropping the image is not issue but finding the visible rect is.
My solution which is not working was to convert frame of parent UIView and child UIImageView to window screen. Then find the intersection of new converted frames. But this is not working. There should be some simple mathematics behind this which I am not able to come up successfully.
This is my code so far.
CGRect imgFrame = [_pageImageView convertRect:_pageImageView.frame toView:nil];
CGRect viewportFrame = [_viewportView convertRect: _viewportView.frame toView:nil];
CGRect visibleRect = CGRectIntersection(imgFrame, viewportFrame);
CGImageRef imageRef = CGImageCreateWithImageInRect([_pageImageView.image CGImage], visibleRect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
My objective is to find the visible rect that is visible through clipped parent UIVIew, then crop the UIImageView based on that visible rect. Important note: UIImageView can be positioned and moved within parent UIView.
EDIT: I can't use UIScrollView for cropping as used in many other discussions for my internal reasons.
You can place the image view inside the UIScrollView instead of UIView which make the pan gesture work easier.
I have the scrollview have the UIImageView
- (CGRect)imageCropRect
{
CGSize imageSize = self.image.size;
CGSize contentSize = self.contentSize;
CGRect cropBoxFrame = self.frame;
CGPoint contentOffset = self.contentOffset;
UIEdgeInsets edgeInsets = self.contentInset;
CGRect frame = CGRectZero;
frame.origin.x = floor((contentOffset.x + edgeInsets.left) * (imageSize.width / contentSize.width));
frame.origin.x = MAX(0, frame.origin.x);
frame.origin.y = floor((contentOffset.y + edgeInsets.top) * (imageSize.height / contentSize.height));
frame.origin.y = MAX(0, frame.origin.y);
frame.size.width = ceil(cropBoxFrame.size.width * (imageSize.width / contentSize.width));
frame.size.width = MIN(imageSize.width, frame.size.width);
frame.size.height = ceil(cropBoxFrame.size.height * (imageSize.height / contentSize.height));
frame.size.height = MIN(imageSize.height, frame.size.height);
return frame;
}

Expand and compress the circle on pinch in and pinch out in ios

I have code to draw a circle in ios
int size = 60
int radius = size/2;
self.tapSelectionView = [[UIView alloc] initWithFrame:CGRectMake(longPressedPoint.x - radius, longPressedPoint.y - radius, size, size)];
self.tapSelectionView.layer.cornerRadius = radius;
self.tapSelectionView.layer.borderColor = [UIColor greenColor].CGColor;
self.tapSelectionView.backgroundColor = [UIColor clearColor];
self.tapSelectionView.layer.borderWidth = 2;
[self.view addSubview:self.tapSelectionView];
CGPoint centerOfOriginalFrame = CGPointMake(self.tapSelectionView.frame.origin.x + radius, self.tapSelectionView.frame.origin.y + radius);
centerOfDrawnCircle = centerOfOriginalFrame;
and now I want to make this circle to expand and compress on pinch in and pinch out gestures in ios.Could anyone please help me on how to get this, i'm new to ios development.
Just add pinch gesture to your circle i.e on tapSelectionView
on pinch gesture action:- set CGAfflineTransform to your tapSelectionView i.e transform scale to expand(zoom out) and (zoom in)
If you need example code you can surely see this link

Zoom a rotated image inside scroll view to fit (fill) frame of overlay rect

Through this question and answer I've now got a working means of detecting when an arbitrarily rotated image isn't completely outside a cropping rect.
The next step is to figure out how to correctly adjust it's containing scroll view zoom to ensure that there are no empty spaces inside the cropping rect. To clarify, I want to enlarge (zoom in) the image; the crop rect should remain un-transformed.
The layout hierarchy looks like this:
containing UIScrollView
UIImageView (this gets arbitrarily rotated)
crop rect overlay view
... where the UIImageView can also be zoomed and panned inside the scrollView.
There are 4 gesture events that occur that need to be accounted for:
Pan gesture (done): accomplished by detecting if it's been panned incorrectly and resets the contentOffset.
Rotation CGAffineTransform
Scroll view zoom
Adjustment of the cropping rect overlay frame
As far as I can tell, I should be able to use the same logic for 2, 3, and 4 to adjust the zoomScale of the scroll view to make the image fit properly.
How do I properly calculate the zoom ratio necessary to make the rotated image fit perfectly inside the crop rect?
To better illustrate what I'm trying to accomplish, here's an example of the incorrect size:
I need to calculate the zoom ratio necessary to make it look like this:
Here's the code I've got so far using Oluseyi's solution below. It works when the rotation angle is minor (e.g. less than 1 radian), but anything over that and it goes really wonky.
CGRect visibleRect = [_scrollView convertRect:_scrollView.bounds toView:_imageView];
CGRect cropRect = _cropRectView.frame;
CGFloat rotationAngle = fabs(self.rotationAngle);
CGFloat a = visibleRect.size.height * sinf(rotationAngle);
CGFloat b = visibleRect.size.width * cosf(rotationAngle);
CGFloat c = visibleRect.size.height * cosf(rotationAngle);
CGFloat d = visibleRect.size.width * sinf(rotationAngle);
CGFloat zoomDiff = MAX(cropRect.size.width / (a + b), cropRect.size.height / (c + d));
CGFloat newZoomScale = (zoomDiff > 1) ? zoomDiff : 1.0 / zoomDiff;
[UIView animateWithDuration:0.2
delay:0.05
options:NO
animations:^{
[self centerToCropRect:[self convertRect:cropRect toView:self.zoomingView]];
_scrollView.zoomScale = _scrollView.zoomScale * newZoomScale;
} completion:^(BOOL finished) {
if (![self rotatedView:_imageView containsViewCompletely:_cropRectView])
{
// Damn, it's still broken - this happens a lot
}
else
{
// Woo! Fixed
}
_didDetectBadRotation = NO;
}];
Note I'm using AutoLayout which makes frames and bounds goofy.
Assume your image rectangle (blue in the diagram) and crop rectangle (red) have the same aspect ratio and center. When rotated, the image rectangle now has a bounding rectangle (green) which is what you want your crop scaled to (effectively, by scaling down the image).
To scale effectively, you need to know the dimensions of the new bounding rectangle and use a scale factor that fits the crop rect into it. The dimensions of the bounding rectangle are rather obviously
(a + b) x (c + d)
Notice that each segment a, b, c, d is either the adjacent or opposite side of a right triangle formed by the bounding rect and the rotated image rect.
a = image_rect_height * sin(rotation_angle)
b = image_rect_width * cos(rotation_angle)
c = image_rect_width * sin(rotation_angle)
d = image_rect_height * cos(rotation_angle)
Your scale factor is simply
MAX(crop_rect_width / (a + b), crop_rect_height / (c + d))
Here's a reference diagram:
Fill frame of overlay rect:
For a square crop you need to know new bounds of the rotated image which will fill the crop view.
Let's take a look at the reference diagram:
You need to find the altitude of a right triangle (the image number 2). Both altitudes are equal.
CGFloat sinAlpha = sin(alpha);
CGFloat cosAlpha = cos(alpha);
CGFloat hypotenuse = /* calculate */;
CGFloat altitude = hypotenuse * sinAlpha * cosAlpha;
Then you need to calculate the new width for the rotated image and the desired scale factor as follows:
CGFloat newWidth = previousWidth + altitude * 2;
CGFloat scale = newWidth / previousWidth;
I have implemented this method here.
I will answer using sample code, but basically this problem becomes really easy, if you will think in rotated view coordinate system.
UIView* container = [[UIView alloc] initWithFrame:CGRectMake(80, 200, 100, 100)];
container.backgroundColor = [UIColor blueColor];
UIView* content2 = [[UIView alloc] initWithFrame:CGRectMake(-50, -50, 150, 150)];
content2.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:0.5];
[container addSubview:content2];
[self.view setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:container];
[container.layer setSublayerTransform:CATransform3DMakeRotation(M_PI / 8.0, 0, 0, 1)];
//And now the calculations
CGRect containerFrameInContentCoordinates = [content2 convertRect:container.bounds fromView:container];
CGRect unionBounds = CGRectUnion(content2.bounds, containerFrameInContentCoordinates);
CGFloat midX = CGRectGetMidX(content2.bounds);
CGFloat midY = CGRectGetMidY(content2.bounds);
CGFloat scaleX1 = (-1 * CGRectGetMinX(unionBounds) + midX) / midX;
CGFloat scaleX2 = (CGRectGetMaxX(unionBounds) - midX) / midX;
CGFloat scaleY1 = (-1 * CGRectGetMinY(unionBounds) + midY) / midY;
CGFloat scaleY2 = (CGRectGetMaxY(unionBounds) - midY) / midY;
CGFloat scaleX = MAX(scaleX1, scaleX2);
CGFloat scaleY = MAX(scaleY1, scaleY2);
CGFloat scale = MAX(scaleX, scaleY);
content2.transform = CGAffineTransformScale(content2.transform, scale, scale);

Rotate CAEmitterCell content based on Animation Direction

Using CAEmitterLayer and Cell to show particles that have direction sensitive content image (an arrow).
Want the content (arrow image) to point in the direction the cell is moving.
Here is code for having all the arrows move from outside edge toward center. How to rotate image so the image points in direction of movement:
emitterLayer = [CAEmitterLayer layer];
emitterLayer.emitterPosition = self.view.center;
emitterLayer.emitterSize = self.view.bounds.size;
emitterLayer.emitterMode = kCAEmitterLayerOutline;
emitterLayer.emitterShape = kCAEmitterLayerRectangle;
CAEmitterCell* arrow = [CAEmitterCell emitterCell];
arrow.birthRate = 10;
arrow.velocity = 100;
arrow.emissionLatitude = M_PI;
arrow.scale = 0.5;
arrow.lifetime = 2;
arrow.contents = (id) [[UIImage imageNamed:#"arrowOutline.png"] CGImage];
emitterLayer.emitterCells = #[arrow];
[self.view.layer addSublayer:emitterLayer];
How to get the content image to adjust based on direction of cell movement?
Ended up using 4 different CAEmitterLayers one for each direction where emitterPosition is each edge of the screen and emitterSize is length of given edge.
If there is better solution please share.

UIImageView not centered after rotation

I manually add an UIImageView to my UIView and center it, this works fine, but after rotating the device, the UIImageView isn't centered anymore (it's moved to the lower left). How can I fix this?
logoView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"wi-fi-sticker.png"]];
logoView.center = self.view.center;
[self.view addSubview:logoView];
Regards,
Sascha
I was able to center mine correctly every time using something like this
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration:{
CGRect screen = [[UIScreen mainScreen] bounds];
float pos_y, pos_x;
pos_y = UIDeviceOrientationIsLandscape(toInterfaceOrientation) ? screen.size.width/2 : screen.size.height/2;
pos_x = UIDeviceOrientationIsLandscape(toInterfaceOrientation) ? screen.size.height/2 : screen.size.width/2;
myImageView.center = CGPointMake(pos_x, pos_y);
}

Resources