Saturday 15 March 2014

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



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

through this question , answer i've got working means of detecting when arbitrarily rotated image isn't outside cropping rect.

the next step figure out how correctly adjust it's containing scroll view zoom ensure there no empty spaces within cropping rect. clarify, want enlarge (zoom in) image; crop rect should remain un-transformed.

the layout hierarchy looks this:

containing uiscrollview uiimageview (this gets arbitrarily rotated) crop rect overlay view

... uiimageview can zoomed , panned within scrollview.

there 4 gesture events occur need accounted for:

pan gesture (done): accomplished detecting if it's been panned incorrectly , resets contentoffset. rotation cgaffinetransform scroll view zoom adjustment of cropping rect overlay frame

as far can tell, should able utilize same logic 2, 3, , 4 adjust zoomscale of scroll view create image fit properly.

how calculate zoom ratio necessary create rotated image fit within crop rect?

to improve illustrate i'm trying accomplish, here's illustration of wrong size:

i need calculate zoom ratio necessary create this:

here's code i've got far using oluseyi's solution below. works when rotation angle minor (e.g. less 1 radian), on , goes wonky.

cgrect visiblerect = [_scrollview convertrect:_scrollview.bounds toview:_imageview]; cgrect croprect = _croprectview.frame; cgfloat rotationangle = fabs(self.rotationangle); cgfloat = 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 - happens lot } else { // woo! fixed } _diddetectbadrotation = no; }];

note i'm using autolayout makes frames , bounds goofy.

assume image rectangle (blue in diagram) , crop rectangle (red) have same aspect ratio , center. when rotated, image rectangle has bounding rectangle (green) want crop scaled (effectively, scaling downwards image).

to scale effectively, need know dimensions of new bounding rectangle , utilize scale factor fits crop rect it. dimensions of bounding rectangle rather obviously

(a + b) x (c + d)

notice each segment a, b, c, d either adjacent or opposite side of right triangle formed bounding rect , 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 simply

max(crop_rect_width / (a + b), crop_rect_height / (c + d))

here's reference diagram:

ios objective-c uiscrollview cgaffinetransform

No comments:

Post a Comment