Encontrar el cuadrado centrado más grande de un paisaje o un retrato UIImage y escalarlo a un tamaño

Necesito encontrar el cuadrado centrado más grande de un retrato o una image de paisaje escalada a un tamaño. Por ejemplo, si obtengo una image de tamaño 1200×800 y necesito que el cuadrado centrado quede networkingucido al tamaño 300×300.

Encontré una respuesta sobre esta pregunta sobre stackoverflow que se ha copydo ampliamente. Sin embargo, esa respuesta es incorrecta, por lo tanto, desea publicar la respuesta correcta, que es la siguiente:

+ (UIImage*) cropBiggestCentenetworkingSquareImageFromImage:(UIImage*)image withSide:(CGFloat)side { // Get size of current image CGSize size = [image size]; if( size.width == size.height && size.width == side){ return image; } CGSize newSize = CGSizeMake(side, side); 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.height / image.size.height; delta = ratio*(image.size.width - image.size.height); offset = CGPointMake(delta/2, 0); } else { ratio = newSize.width / image.size.width; delta = ratio*(image.size.height - 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), (ratio * image.size.height)); //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; } 

La respuesta incorrecta que encontré anteriormente es la siguiente:

 + (UIImage*) cropBiggestCentenetworkingSquareImageFromImage:(UIImage*)image withSide:(CGFloat)side { // Get size of current image CGSize size = [image size]; if( size.width == size.height && size.width == side){ return image; } CGSize newSize = CGSizeMake(side, side); 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; } 

El problema con este código es que no se recorta correctamente.

Ambos códigos pueden probarse en la siguiente image: https://s3.amazonaws.com/anandprakash/ImageWithPixelGrid.jpg

Corregir algo genera la siguiente image en la url base anterior: https://s3.amazonaws.com/anandprakash/ScreenshotCorrectAlgo.png

Wrong Algo genera la siguiente image en la url base anterior: note el 50px adicional en el ancho de cada lado. https://s3.amazonaws.com/anandprakash/ScreenshotWrongAlgo.png

La misma respuesta anterior que una extensión Swift en UIImage:

 private extension UIImage { func cropBiggestCentenetworkingSquareImage(withSide side: CGFloat) -> UIImage { if self.size.height == side && self.size.width == side { return self } let newSize = CGSizeMake(side, side) let ratio: CGFloat let delta: CGFloat let offset: CGPoint if self.size.width > self.size.height { ratio = newSize.height / self.size.height delta = ratio * (self.size.width - self.size.height) offset = CGPointMake(delta / 2, 0) } else { ratio = newSize.width / self.size.width delta = ratio * (self.size.height - self.size.width) offset = CGPointMake(0, delta / 2) } let clipRect = CGRectMake(-offset.x, -offset.y, ratio * self.size.width, ratio * self.size.height) if UIScreen.mainScreen().respondsToSelector(#selector(NSDecimalNumberBehaviors.scale)) { UIGraphicsBeginImageContextWithOptions(newSize, true, 0.0) } else { UIGraphicsBeginImageContext(newSize); } UIRectClip(clipRect) self.drawInRect(clipRect) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage } }