I develop an application in which i process the image using its pixels but in that image processing it takes a lot of time. Therefore i want to crop UIImage (Only middle part of image i.e. removing/croping bordered part of image).I have the develop code are,
- (NSInteger) processImage1: (UIImage*) image
{
CGFloat width = image.size.width;
CGFloat height = image.size.height;
struct pixel* pixels = (struct pixel*) calloc(1, image.size.width * image.size.height * sizeof(struct pixel));
if (pixels != nil)
{
// Create a new bitmap
CGContextRef context = CGBitmapContextCreate(
(void*) pixels,
image.size.width,
image.size.height,
8,
image.size.width * 4,
CGImageGetColorSpace(image.CGImage),
kCGImageAlphaPremultipliedLast
);
if (context != NULL)
{
// Draw the image in the bitmap
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, image.size.width, image.size.height), image.CGImage);
NSUInteger numberOfPixels = image.size.width * image.size.height;
NSMutableArray *numberOfPixelsArray = [[[NSMutableArray alloc] initWithCapacity:numberOfPixelsArray] autorelease];
}
How i take(croping outside bordered) the middle part of UIImage?????????
Try something like this:
CGImageRef imageRef = CGImageCreateWithImageInRect([largeImage CGImage], cropRect);
image = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
Note: cropRect is smaller rectangle with middle part of the image...
I was looking for a way to get an arbitrary rectangular crop (ie., sub-image) of a UIImage.
Most of the solutions I tried do not work if the orientation of the image is anything but UIImageOrientationUp.
For example:
http://www.hive05.com/2008/11/crop-an-image-using-the-iphone-sdk/
Typically if you use your iPhone camera, you will have other orientations like UIImageOrientationLeft, and you will not get a correct crop with the above. This is because of the use of CGImageRef/CGContextDrawImage which differ in the coordinate system with respect to UIImage.
The code below uses UI* methods (no CGImageRef), and I have tested this with up/down/left/right oriented images, and it seems to work great.
// get sub image
- (UIImage*) getSubImageFrom: (UIImage*) img WithRect: (CGRect) rect {
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// translated rectangle for drawing sub image
CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, img.size.width, img.size.height);
// clip to the bounds of the image context
// not strictly necessary as it will get clipped anyway?
CGContextClipToRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height));
// draw image
[img drawInRect:drawRect];
// grab image
UIImage* subImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return subImage;
}
Because I needed it just now, here is M-V 's code in Swift 4:
func imageWithImage(image: UIImage, croppedTo rect: CGRect) -> UIImage {
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
let drawRect = CGRect(x: -rect.origin.x, y: -rect.origin.y,
width: image.size.width, height: image.size.height)
context?.clip(to: CGRect(x: 0, y: 0,
width: rect.size.width, height: rect.size.height))
image.draw(in: drawRect)
let subImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return subImage!
}
It would ultimately be faster, with a lot less image creation from sprite atlases, if you could set not only the image for a UIImageView, but also the top-left offset to display within that UIImage. Maybe this is possible. It would certainly eliminate a lot of effort!
Meanwhile, I created these useful functions in a utility class that I use in my apps. It creates a UIImage from part of another UIImage, with options to rotate, scale, and flip using standard UIImageOrientation values to specify. The pixel scaling is preserved from the original image.
My app creates a lot of UIImages during initialization, and this necessarily takes time. But some images aren't needed until a certain tab is selected. To give the appearance of quicker load I could create them in a separate thread spawned at startup, then just wait till it's done when that tab is selected.
This code is also posted at Most efficient way to draw part of an image in iOS
+ (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)aperture {
return [ChordCalcController imageByCropping:imageToCrop toRect:aperture withOrientation:UIImageOrientationUp];
}
// Draw a full image into a crop-sized area and offset to produce a cropped, rotated image
+ (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)aperture withOrientation:(UIImageOrientation)orientation {
// convert y coordinate to origin bottom-left
CGFloat orgY = aperture.origin.y + aperture.size.height - imageToCrop.size.height,
orgX = -aperture.origin.x,
scaleX = 1.0,
scaleY = 1.0,
rot = 0.0;
CGSize size;
switch (orientation) {
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
size = CGSizeMake(aperture.size.height, aperture.size.width);
break;
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
case UIImageOrientationUp:
case UIImageOrientationUpMirrored:
size = aperture.size;
break;
default:
assert(NO);
return nil;
}
switch (orientation) {
case UIImageOrientationRight:
rot = 1.0 * M_PI / 2.0;
orgY -= aperture.size.height;
break;
case UIImageOrientationRightMirrored:
rot = 1.0 * M_PI / 2.0;
scaleY = -1.0;
break;
case UIImageOrientationDown:
scaleX = scaleY = -1.0;
orgX -= aperture.size.width;
orgY -= aperture.size.height;
break;
case UIImageOrientationDownMirrored:
orgY -= aperture.size.height;
scaleY = -1.0;
break;
case UIImageOrientationLeft:
rot = 3.0 * M_PI / 2.0;
orgX -= aperture.size.height;
break;
case UIImageOrientationLeftMirrored:
rot = 3.0 * M_PI / 2.0;
orgY -= aperture.size.height;
orgX -= aperture.size.width;
scaleY = -1.0;
break;
case UIImageOrientationUp:
break;
case UIImageOrientationUpMirrored:
orgX -= aperture.size.width;
scaleX = -1.0;
break;
}
// set the draw rect to pan the image to the right spot
CGRect drawRect = CGRectMake(orgX, orgY, imageToCrop.size.width, imageToCrop.size.height);
// create a context for the new image
UIGraphicsBeginImageContextWithOptions(size, NO, imageToCrop.scale);
CGContextRef gc = UIGraphicsGetCurrentContext();
// apply rotation and scaling
CGContextRotateCTM(gc, rot);
CGContextScaleCTM(gc, scaleX, scaleY);
// draw the image to our clipped context using the offset rect
CGContextDrawImage(gc, drawRect, imageToCrop.CGImage);
// pull the image from our cropped context
UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();
// pop the context to get back to the default
UIGraphicsEndImageContext();
// Note: this is autoreleased
return cropped;
}
#Very small/simple Swift 5 version,
You shouldn't mix UI and CG objects, they sometimes have very different coordinate spaces. This can make you sad.
Note 👉 : self.draw(at:)
#inlinable private prefix func - (right: CGPoint) -> CGPoint
{
return CGPoint(x: -right.x, y: -right.y)
}
extension UIImage
{
public func cropped(to cropRect: CGRect) -> UIImage?
{
let renderer = UIGraphicsImageRenderer(size: cropRect.size)
return renderer.image
{
_ in
self.draw(at: -cropRect.origin)
}
}
}
Using the function
CGContextClipToRect(context, CGRectMake(0, 0, size.width, size.height));
Here's an example code, used for a different purpose but clips ok.
- (UIImage *)aspectFillToSize:(CGSize)size
{
CGFloat imgAspect = self.size.width / self.size.height;
CGFloat sizeAspect = size.width/size.height;
CGSize scaledSize;
if (sizeAspect > imgAspect) { // increase width, crop height
scaledSize = CGSizeMake(size.width, size.width / imgAspect);
} else { // increase height, crop width
scaledSize = CGSizeMake(size.height * imgAspect, size.height);
}
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClipToRect(context, CGRectMake(0, 0, size.width, size.height));
[self drawInRect:CGRectMake(0.0f, 0.0f, scaledSize.width, scaledSize.height)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
If you want a portrait crop down the center of every photo.
Use #M-V solution, & replace cropRect.
CGFloat height = imageTaken.size.height;
CGFloat width = imageTaken.size.width;
CGFloat newWidth = height * 9 / 16;
CGFloat newX = abs((width - newWidth)) / 2;
CGRect cropRect = CGRectMake(newX,0, newWidth ,height);
I wanted to be able to crop from a region based on an aspect ratio, and scale to a size based on a outer bounding extent. Here is my variation:
import AVFoundation
import ImageIO
class Image {
class func crop(image:UIImage, source:CGRect, aspect:CGSize, outputExtent:CGSize) -> UIImage {
let sourceRect = AVMakeRectWithAspectRatioInsideRect(aspect, source)
let targetRect = AVMakeRectWithAspectRatioInsideRect(aspect, CGRect(origin: CGPointZero, size: outputExtent))
let opaque = true, deviceScale:CGFloat = 0.0 // use scale of device's main screen
UIGraphicsBeginImageContextWithOptions(targetRect.size, opaque, deviceScale)
let scale = max(
targetRect.size.width / sourceRect.size.width,
targetRect.size.height / sourceRect.size.height)
let drawRect = CGRect(origin: -sourceRect.origin * scale, size: image.size * scale)
image.drawInRect(drawRect)
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return scaledImage
}
}
There are a couple things that I found confusing, the separate concerns of cropping and resizing. Cropping is handled with the origin of the rect that you pass to drawInRect, and scaling is handled by the size portion. In my case, I needed to relate the size of the cropping rect on the source, to my output rect of the same aspect ratio. The scale factor is then output / input, and this needs to be applied to the drawRect (passed to drawInRect).
One caveat is that this approach effectively assumes that the image you are drawing is larger than the image context. I have not tested this, but I think you can use this code to handle cropping / zooming, but explicitly defining the scale parameter to be the aforementioned scale parameter. By default, UIKit applies a multiplier based on the screen resolution.
Finally, it should be noted that this UIKit approach is higher level than CoreGraphics / Quartz and Core Image approaches, and seems to handle image orientation issues. It is also worth mentioning that it is pretty fast, second to ImageIO, according to this post here: http://nshipster.com/image-resizing/
Related
I want to create a new UIImage from another one which is turned to 45° (at its bottom left corner, clockwise). The space around the old image would be filled white or so. In the image I uploaded, the old image would be the blue one and the new image would be the actual image I linked, including the white parts.
Played a little bit in playground with Swift and here is my solution:
func rotateImage(image: UIImage!, var rotationDegree: CGFloat) -> UIImage {
// 180 degress = 540 degrees, that's why we calculate modulo
rotationDegree = rotationDegree % 360
// If degree is negative, then calculate positive
if rotationDegree < 0.0 {
rotationDegree = 360 + rotationDegree
}
// Get image size
let size = image.size
let width = size.width
let height = size.height
// Get degree which we will use for calculation
var calcDegree = rotationDegree
if calcDegree > 90 {
calcDegree = 90 - calcDegree % 90
}
// Calculate new size
let newWidth = width * CGFloat(cosf(Float(calcDegree.degreesToRadians))) + height * CGFloat(sinf(Float(calcDegree.degreesToRadians)))
let newHeight = width * CGFloat(sinf(Float(calcDegree.degreesToRadians))) + height * CGFloat(cosf(Float(calcDegree.degreesToRadians)))
let newSize = CGSize(width: newWidth, height: newHeight)
// Create context using new size, make it opaque, use screen scale
UIGraphicsBeginImageContextWithOptions(newSize, true, UIScreen.mainScreen().scale)
// Get context variable
let context = UIGraphicsGetCurrentContext()
// Set fill color to white (or any other)
// If no color needed, then set opaque to false when initialize context
CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
CGContextFillRect(context, CGRect(origin: CGPointZero, size: newSize))
// Rotate context and draw image
CGContextTranslateCTM(context, newSize.width * 0.5, newSize.height * 0.5)
CGContextRotateCTM(context, rotationDegree.degreesToRadians);
CGContextTranslateCTM(context, newSize.width * -0.5, newSize.height * -0.5)
image.drawAtPoint(CGPoint(x: (newSize.width - size.width) / 2.0, y: (newSize.height - size.height) / 2.0))
// Get image from context
let returnImage = UIGraphicsGetImageFromCurrentImageContext()
// End graphics context
UIGraphicsEndImageContext()
return returnImage
}
Do not forget to include this extension:
extension CGFloat {
var degreesToRadians : CGFloat {
return self * CGFloat(M_PI) / 180.0
}
}
I would recommend to go threw this answer to better understand how I calculated newSize after image is rotated.
If you just want to change the way an image is displayed, transform the image view that displays it.
If you really want a new rotated image, redraw the image in a transformed graphics context.
If you just want to rotate the UIImageView used to display the image, you could do this:
#define DegreesToRadians(x) ((x) * M_PI / 180.0) //put this at the top of your file
imageView.transform = CGAffineTransformMakeRotation(DegreesToRadians(45));
But if you want to rotate the actual image, do something like this:
- (UIImage *)image:(UIImage *)image rotatedByDegrees:(CGFloat)degrees
{
// calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
// Create the bitmap context
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
// Move the origin to the middle of the image so we will rotate and scale around the center.
CGContextTranslateCTM(bitmap, rotatedSize.width / 2, rotatedSize.height / 2);
// // Rotate the image context
CGContextRotateCTM(bitmap, DegreesToRadians(degrees));
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-image.size.width / 2, -image.size.height / 2, image.size.width, image.size.height), [image CGImage]);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Above code adapted from this answer by The Lion https://stackoverflow.com/a/11667808/1757960
Help, Im new to ios programming, I want to rotate may UIImage but I dont want the edges to be cut or loose some part of the image.
this is my code:
double angle = M_PI * 10/ 180; CGSize s = {image.size.width, image.size.height}; UIGraphicsBeginImageContext(s); CGContextRef ctx = UIGraphicsGetCurrentContext();
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformTranslate(transform, image.size.width/2, image.size.height/2);
transform = CGAffineTransformRotate(transform, angle);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
CGContextConcatCTM(ctx, transform);
CGContextDrawImage(ctx,CGRectMake(-[image size].width/2,-[image size].height/2,image.size.width, image.size.height),image.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(newImage, nil, nil, nil);
The image is rotating but the size of the frame does not change because of that some of the image has been cut.
OUTPUT:https://fbcdn-sphotos-e-a.akamaihd.net/hphotos-ak-xpf1/t1.0-9/1555286_761679470521535_1800180000235265553_n.jpg
EXPECTED OUTPUT: https://fbcdn-photos-g-a.akamaihd.net/hphotos-ak-xfa1/t1.0-0/10314770_761675840521898_6536715783383115855_a.jpg
Please help me thank you.
This might be what you are searching for.
Just copy the following code at the end of the .m file (after the #end) in which you want to rotate an image.
#interface UIImage (RotationMethods)
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees;
#end
#implementation UIImage (RotationMethods)
static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees
{
// calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
// Create the bitmap context
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
// Move the origin to the middle of the image so we will rotate and scale around the center.
CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
// // Rotate the image context
CGContextRotateCTM(bitmap, DegreesToRadians(degrees));
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Then rotate your image like in the example below:
CGFloat degrees = 90;
yourImage = [yourImage imageRotatedByDegrees:degrees];
I've got the following function, previous to iOS 7 & XCode 5 it worked as expected. The function takes an image and a cropSize. The image is the one to be cropped to a specified size, which is defined by CGSize cropSize. The purpose of the function is to crop the image to a certain size and then return the cropped image.
- (UIImage *) cropImage:(UIImage *)originalImage cropSize:(CGSize)cropSize
{
//calculate scale factor to go between cropframe and original image
float SF = originalImage.size.width / cropSize.width;
//find the centre x,y coordinates of image
float centreX = originalImage.size.width / 2;
float centreY = originalImage.size.height / 2;
//calculate crop parameters
float cropX = centreX - ((cropSize.width / 2) * SF);
float cropY = centreY - ((cropSize.height / 2) * SF);
CGRect cropRect = CGRectMake(cropX, cropY, (cropSize.width *SF), (cropSize.height * SF));
CGImageRef imageRef = CGImageCreateWithImageInRect([originalImage CGImage], cropRect);
//keep orientation if landscape
UIImage *newImage;
if (originalImage.size.width > originalImage.size.height || originalImage.size.width == originalImage.size.height) {
newImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:originalImage.imageOrientation];
}
else
{
newImage = [UIImage imageWithCGImage:imageRef];
}
CGImageRelease(imageRef);
//Now want to scale down cropped image!
//want to multiply frames by 2 to get retina resolution
CGRect scaledImgRect = CGRectMake(0, 0, (cropSize.width * 2), (cropSize.height * 2));
UIGraphicsBeginImageContextWithOptions(scaledImgRect.size, NO, [UIScreen mainScreen].scale);
[newImage drawInRect:scaledImgRect];
UIImage *scaledNewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledNewImage;
}
The problem is that it all works fine in with a UIImage that is passed in that is in landscape orientation, the image is cropped as expected, however if the image passed in was taken in portrait, then the resulting image (the cropped result in scaledNewImage) is rotated 90 degrees on its side, which I don't want.
It is as if the portrait image is being worked on as if it's in landscape - and so the function cropped what should be a portrait orientated image in landscape instead of portrait.
This isn't so apparent if the crop area is square, however if the area to be cropped is a landscape rectangle then it's cropping it along the length of the portrait rather than the width. Hope I'm making sense!
This issue didn't occur prior to iOS 7 & XCode 5.. so I'm not sure exactly what's changed. Any help appreciated, thanks.
Solved this issue with the help of an answer here: https://stackoverflow.com/a/14712184/521653
- (UIImage *) cropImage:(UIImage *)originalImage cropSize:(CGSize)cropSize
{
NSLog(#"original image orientation:%d",originalImage.imageOrientation);
//calculate scale factor to go between cropframe and original image
float SF = originalImage.size.width / cropSize.width;
//find the centre x,y coordinates of image
float centreX = originalImage.size.width / 2;
float centreY = originalImage.size.height / 2;
//calculate crop parameters
float cropX = centreX - ((cropSize.width / 2) * SF);
float cropY = centreY - ((cropSize.height / 2) * SF);
CGRect cropRect = CGRectMake(cropX, cropY, (cropSize.width *SF), (cropSize.height * SF));
CGAffineTransform rectTransform;
switch (originalImage.imageOrientation)
{
case UIImageOrientationLeft:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(M_PI_2), 0, -originalImage.size.height);
break;
case UIImageOrientationRight:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(-M_PI_2), -originalImage.size.width, 0);
break;
case UIImageOrientationDown:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(-M_PI), -originalImage.size.width, -originalImage.size.height);
break;
default:
rectTransform = CGAffineTransformIdentity;
};
rectTransform = CGAffineTransformScale(rectTransform, originalImage.scale, originalImage.scale);
CGImageRef imageRef = CGImageCreateWithImageInRect([originalImage CGImage], CGRectApplyAffineTransform(cropRect, rectTransform));
UIImage *result = [UIImage imageWithCGImage:imageRef scale:originalImage.scale orientation:originalImage.imageOrientation];
CGImageRelease(imageRef);
//return result;
//Now want to scale down cropped image!
//want to multiply frames by 2 to get retina resolution
CGRect scaledImgRect = CGRectMake(0, 0, (cropSize.width * 2), (cropSize.height * 2));
UIGraphicsBeginImageContextWithOptions(scaledImgRect.size, NO, [UIScreen mainScreen].scale);
[result drawInRect:scaledImgRect];
UIImage *scaledNewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledNewImage;
}
That's the updated method there. I implemented the code from the answer linked into my method and it solves the issues. Strange that I didn't have these before iOS 7!
In IOS How can I crop a rectangular image to square letterbox so that it maintains the original aspect ratio and the remaining spaces are filled with black. E.g. the "pad" strategy that transloadit uses to crop/resize their images.
http://transloadit.com/docs/image-resize
For anyone who stumbles onto this question and many more like it without a clear answer, I have written a neat little category that accomplishes this at the model level by modifying the UIImage directly rather than just modifying the view. Simply use this method the returned image will be letterboxed to a square shape, regardless of which side is longer.
- (UIImage *) letterboxedImageIfNecessary
{
CGFloat width = self.size.width;
CGFloat height = self.size.height;
// no letterboxing needed, already a square
if(width == height)
{
return self;
}
// find the larger side
CGFloat squareSize = MAX(width,height);
UIGraphicsBeginImageContext(CGSizeMake(squareSize, squareSize));
// draw black background
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextFillRect(context, CGRectMake(0, 0, squareSize, squareSize));
// draw image in the middle
[self drawInRect:CGRectMake((squareSize - width) / 2, (squareSize - height) / 2, width, height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Just for convenience - heres a swift rewrite of #Dima's answer:
import UIKit
extension UIImage
{
func letterboxImage() -> UIImage
{
let width = self.size.width
let height = self.size.height
// no letterboxing needed, already a square
if(width == height)
{
return self
}
// find the larger side
let squareSize = max(width, height)
UIGraphicsBeginImageContext(CGSizeMake(squareSize, squareSize))
// draw black background
let context = UIGraphicsGetCurrentContext()
CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0)
CGContextFillRect(context, CGRectMake(0, 0, squareSize, squareSize))
// draw image in the middle
self.drawInRect(CGRectMake((squareSize-width) / 2, (squareSize - height) / 2, width, height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
You have to set contentMode of the UIImageView with UIViewContentModeScaleAspectFit. You can also find this option for UIImageView if you use storyboard.
The set the backgroundColor of UIImageView to black (or other color of your choice).
I'am doing an app something like this: You load a photo and you put images over it, like balloons, etc..
When I try to merge one of this over images with only resize it works fine. Like 10px more than it should be but no problem.
The problem comes when you rotate the image [UIImageView] it appears much bigger that the image its, I try allot of things and nothing. I leave the code. I hope someone could help.
Note: The image size its inside UIImageView, then multiplied it by the scale of the main image
- (UIImage *)mergeImage:(UIImageView *)mainImage withImageView:(UIImageView *)imageView {
UIImage *temp = imageView.image;
UIImage *tempMain = mainImage.image;
CGFloat mainScale = [self imageViewScaleFactor:mainImage];
CGFloat tempScale = 1/mainScale;
NSLog(#"%f", tempScale);
//Rotate UIIMAGE
UIGraphicsBeginImageContext(temp.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformTranslate(transform, temp.size.width/2, temp.size.height/2);
CGFloat angle = atan2(imageView.transform.b, imageView.transform.a);
transform = CGAffineTransformRotate(transform, angle);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
CGContextConcatCTM(ctx, transform);
// Draw the image into the context
CGContextDrawImage(ctx, CGRectMake(-temp.size.width/2, -temp.size.height/2, temp.size.width, temp.size.height), temp.CGImage);
// Get an image from the context
temp = [UIImage imageWithCGImage: CGBitmapContextCreateImage(ctx)];
NSLog(#"%f %f %f", mainScale, mainImage.frame.size.width, mainImage.frame.size.height);
UIGraphicsBeginImageContextWithOptions(tempMain.size, NO, 1.0f);
//Get imageView size & position
NSLog(#"%f %f %f %f", imageView.frame.origin.x, imageView.frame.origin.y, imageView.frame.size.width, imageView.frame.size.height);
CGFloat offsetX = 0;
CGFloat offsetY = -44;
if (tempMain.size.height > tempMain.size.width) {
offsetX = ((tempMain.size.width * mainScale) - 320)/2;
}else{
offsetY = ((tempMain.size.height * mainScale) - 416)/2;
offsetY -= 44;
}
CGFloat imageViewX = (imageView.frame.origin.x + offsetX) * tempScale;
CGFloat imageViewY = (imageView.frame.origin.y + offsetY) * tempScale;
CGFloat imageViewW = imageView.frame.size.width * tempScale;
CGFloat imageViewH = imageView.frame.size.height * tempScale;
CGRect tempRect = CGRectMake(imageViewX, imageViewY, imageViewW, imageViewH);
[tempMain drawAtPoint:CGPointZero];
[temp drawInRect:tempRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Thanks
This is the solution that works for me
Merging a previosly rotated by gesture UIImageView with another one. WYS is not WYG
I just take a photo to the main screen and then crop it to the size of the photo, its faster, and clean. and the resolution it ok if the apps runs in retina in a normal device isn't too good. And you need to prepare that code to work in retina & non-retina