I am building a photo app for iPhone which allows the user to take a photo with the camera or grab one from the Camera Roll, then pan and zoom this image as needed in a UIScrollView. The user then taps a button to save the image. I am having trouble with the key method that returns the exact center of the visible area of an imageview embedded in the scrollview. I need this method to allow for variations in the dimensions of the device screen (i.e., iPhone 4 vs 5), as well as for variations in the size, aspect ratio and zoom scale of the source image.
As an example, I need to get this to work for the following:
- iPhone 5 with screen dimensions that are 320 X 568
- Scrollview frame size of 320 X 568
- An image with dimensions 380 width and 284 height
- Zoom scale of 3.0
Alternatively, I also need for it to work for this:
- iPhone 4 with screen dimensions of 320 X 480
- Scrollview frame size of 320 X 480
- An image with dimensions 640 width and 1048 height
- Zoom scale of 1.3
The following is my current code, which tries to account for variations in the screen's dimensions and the image's dimensions, but it does not work for both iPhone 4 and 5, and for all types of images, such as those in portrait or landscape format. Is there a simpler way to get the center point of the visible portion of a scrollview? I need a clearer understanding of how to interpret and manipulate the properties of a view, such as the bounds.origin and bounds.size and use content size and zoom scale in the scrollview.
I have looked at various questions that are similar but none of these seem to account adequately for all variations in device or image aspect ratio or size. Any help would be greatly appreciated!
Similar questions
How can I determine the area currently visible in a scrollview and determine the center?
Getting the right coordinates of the visible part of a UIImage inside of UIScrollView
- (CGPoint)centerOfVisibleFrame:(UIImage *)image inScrollView:(UIScrollView *)scrollView
{
CGPoint frameCenter;
CGFloat zoomScale = scrollView.zoomScale;
// First determine the dimensions of the device
CGSize deviceFrameSize = [UIScreen mainScreen].bounds.size;
// Need to determine the scale factor for adjusting the image to full width/full height
CGFloat imageDeviceAspectFitScale;
// Compare the aspect ratio (height / width) of the device to the aspect ratio of the image
CGFloat deviceAspectRatio = deviceFrameSize.height / deviceFrameSize.width;
CGFloat imageAspectRatio = image.size.height / image.size.width;
// If the device's aspect ratio is greater than the image aspect ratio
if (deviceAspectRatio > imageAspectRatio)
{
// Set the imageDeviceAspectFitScale for full width
imageDeviceAspectFitScale = image.size.width / deviceFrameSize.width;
}
// Otherwise the image's aspect ratio is greater than the device aspect ratio
else
{
// Set the imageDeviceAspectFitScale for full height
imageDeviceAspectFitScale = image.size.height / deviceFrameSize.height;
}
// Create the frame for the image at full width or full height
CGSize imageAspectFitSize;
imageAspectFitSize.width = image.size.width / imageDeviceAspectFitScale;
imageAspectFitSize.height = image.size.height / imageDeviceAspectFitScale;
// Calculate the vertical and horizontal offset to adjust the coordinates of the
// image center to account for greater device height or device width
CGFloat verticalOffset = deviceFrameSize.height - imageAspectFitSize.height;
CGFloat horizontalOffset = deviceFrameSize.width - imageAspectFitSize.width;
if (self.debug) NSLog(@"verticalOffset = %f horizontalOffset = %f", verticalOffset, horizontalOffset);
if (self.debug) NSLog(@"image.size.width: %f image.size.height: %f", image.size.width, image.size.height);
if (self.debug) NSLog(@"scrollView.frame.size w: %f h: %f", scrollView.frame.size.width, scrollView.frame.size.height);
if (self.debug) NSLog(@"scrollView.bounds.size.width: %f scrollView.bounds.size.height: %f",
scrollView.bounds.size.width, scrollView.bounds.size.height);
if (self.debug) NSLog(@"scrollView.contentSize w=%f h=%f", scrollView.contentSize.width, scrollView.contentSize.height);
// imageRect represents the coordinate space for the image, adjusted for zoom scale
CGRect imageRect;
// First use the visible frame's origin to determine the top left corner of the visible rectangle
imageRect.origin.x = scrollView.contentOffset.x;
imageRect.origin.y = scrollView.contentOffset.y;
if (self.debug) NSLog(@"imageRect.origin x = %f y = %f", imageRect.origin.x, imageRect.origin.y);
// Adjust the image rect for zoom - Multiply by zoom scale
imageRect.size.width = image.size.width * zoomScale;
imageRect.size.height = image.size.height * zoomScale;
if (self.debug) NSLog(@"Zoomed imageRect.size width = %f height = %f", imageRect.size.width, imageRect.size.height);
// Then scale the image down to fit into the device frame
// Divide by the image device aspect fit scale
imageRect.size.width = imageRect.size.width / imageDeviceAspectFitScale;
imageRect.size.height = imageRect.size.height / imageDeviceAspectFitScale;
if (self.debug) NSLog(@"CVF Aspect fit imageRect.size width = %f height = %f", imageRect.size.width, imageRect.size.height);
// Then calculate the frame center by using the x and y dimensions of the DEVICE frame
frameCenter.x = imageRect.origin.x + (deviceFrameSize.width / 2);
frameCenter.y = imageRect.origin.y + (deviceFrameSize.height / 2);
// Scale back to original image dimensions from zoom
frameCenter.x = frameCenter.x / zoomScale;
frameCenter.y = frameCenter.y / zoomScale;
if (self.debug) NSLog(@"frameCenter.x = %f frameCenter.y = %f", frameCenter.x, frameCenter.y);
// Scale back up for the aspect fit scale
frameCenter.x = frameCenter.x * imageDeviceAspectFitScale;
frameCenter.y = frameCenter.y * imageDeviceAspectFitScale;
// Correct the coordinates for horizontal and vertical offset
frameCenter.x = frameCenter.x - (horizontalOffset);
frameCenter.y = frameCenter.y - (verticalOffset);
if (self.debug) NSLog(@"CVF frameCenter.x = %f frameCenter.y = %f", frameCenter.x, frameCenter.y);
return frameCenter;
}