I am using following code to make an image oval shape.
UIImage * fooImage = image;
CGRect imageRect = CGRectMake(0, 0, 291, 130);
UIGraphicsBeginImageContextWithOptions(imageRect.size,NO,0.0);
// create a bezier path defining rounded corners
UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0.0, 0.0, CGRectGetWidth(img_blank.frame), CGRectGetHeight(img_blank.frame))];
// use this path for clipping in the implicit context
[path addClip];
// draw the image into the implicit context
[fooImage drawInRect:imageRect];
// save the clipped image from the implicit context into an image
UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
img_blank.image=maskedImage;
Here image_blank is the UIImage which I am using, if image with greater width and less height comes then it will not strech. If I change the values, I won't get an oval shape that fits my UIImageview(img_blank).
This issue is that your rect size and your image size don't match.
When you:
[fooImage drawInRect:imageRect];
the image will be drawn skewed into that rectangle, which you've defined as CGRectMake(0, 0, 291, 130);
To get it to work, you need to create a second rectangle that expands the oval's rectangle to match the image'a width/height ratio. You can then use this second rectangle to draw the image so that the image will aspect-fill the oval.
This is some pseudo code that I've used in the past for similar problems:
// get the size of the image that we want to scale
CGSize imageSize = imageToDraw.size;
// get the size of the canvas we're trying to fill
CGSize canvasSize = imageRect.size;
// we need to see how the ratio of image width & height compare to the canvas
CGFloat horizontalRatio = canvasSize.width / imageSize.width;
CGFloat verticalRatio = canvasSize.height / imageSize.height;
// pick the ratio that requires the most scaling
CGFloat ratio = MAX(horizontalRatio, verticalRatio); //AspectFill
// calculate the size that we should draw the image so that it could fill
// the entire canvas with an aspect-fill rule
CGSize aspectFillSize = CGSizeMake(imageSize.width * ratio, imageSize.height * ratio);
// now draw the image, centering it and filling the canvas
[imageToDraw drawInRect:CGRectMake((canvasSize.width-aspectFillSize.width)/2,
(canvasSize.height-aspectFillSize.height)/2,
aspectFillSize.width,
aspectFillSize.height)];
Related
I am Rotating an UIImage According to a scale value.My Scale And Rotation are working well but the problem is after rotating uiimage , the image size (width & Height) is decreasing. Any idea how to solve the issue?
Image before Rotation
Image After Rotation
The code i am using :
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.image.size.width, self.image.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(self.lastContentOffset/5);
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, 5.0);
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-self.image.size.width/2 , -self.image.size.height/2 , self.image.size.width, self.image.size.height), \[self.rotatedImage CGImage\]);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.rotatedImage = newImage;
Lets assume your image was HxH in size. After 45 degrees (M_PI/2 radians) rotation its going to be sqrt(2)*H x sqrt(2)*H in size. So you need bigger context in order to fit rotated image. Otherwise the corners of an image will be cut off. Also you will need bigger UIImageView in order to fit bigger image. Otherwise it's going to be autoscaled to the UIImageView size.
I am going through 19th chapter of Big Nerd Ranch, iOS textbook and can not understand several parts of the function that takes in a big image and creates a thumbnail out of it. Have a look:
- (void)setThumbnailFromImage:(UIImage *)image
{
CGSize origImageSize = image.size;
// The rectangle of the thumbnail
CGRect newRect = CGRectMake(0, 0, 40, 40);
// Figure out a scaling ratio to make sure we maintain the same aspect ratio
float ratio = MAX(newRect.size.width / origImageSize.width,
newRect.size.height / origImageSize.height);
// Create a transparent bitmap context with a scaling factor
// equal to that of the screen
UIGraphicsBeginImageContextWithOptions(newRect.size, NO, 0.0);
// Create a path that is a rounded rectangle
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:newRect
cornerRadius:5.0];
// Make all subsequent drawing clip to this rounded rectangle
[path addClip];
// Center the image in the thumbnail rectangle
CGRect projectRect;
projectRect.size.width = ratio * origImageSize.width;
projectRect.size.height = ratio * origImageSize.height;
projectRect.origin.x = (newRect.size.width - projectRect.size.width) / 2.0;
projectRect.origin.y = (newRect.size.height - projectRect.size.height) / 2.0;
[image drawInRect:projectRect];
// Get the image from the image context; keep it as our thumbnail
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
self.thumbnail = smallImage;
// Cleanup image context resources; we're done
UIGraphicsEndImageContext();
}
From my understanding we are getting the MAX of the two ratios and then we put a smaller edge of the original image equal to newRect's edge (which is 40 in our case), the other edge seemingly should stick out of the newRect since the edge would be larger than the edge of newRect, when we UIGraphicsGetImageFromCurrentImageContext(). That's my vague 'understanding'.
Could anyone please explain what is this whole code doing in a detailed way, especially, the centering part? If you know some tutorials that might be relevant, it would also be great.
I just took or added to the previous comments and tried to explain each part more clearly. You seemed to get the basic idea, so I hope this helps solidify everything.
- (void)setThumbnailFromImage:(UIImage *)image
{
CGSize origImageSize = image.size;
//Create new rectangle of your desired size
CGRect newRect = CGRectMake(0, 0, 40, 40);
//Divide both the width and the height by the width and height of the original image to get the proper ratio.
//Take whichever one is greater so that the converted image isn't distorted through incorrect scaling.
float ratio = MAX(newRect.size.width / origImageSize.width,
newRect.size.height / origImageSize.height);
// Create a transparent bitmap context with a scaling factor
// equal to that of the screen
// Basically everything within this builds the image
UIGraphicsBeginImageContextWithOptions(newRect.size, NO, 0.0);
// Create a path that is a rounded rectangle -- essentially a frame for the new image
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:newRect
cornerRadius:5.0];
// Applying path
[path addClip];
// Center the image in the thumbnail rectangle
CGRect projectRect;
// Scale the image with previously determined ratio
projectRect.size.width = ratio * origImageSize.width;
projectRect.size.height = ratio * origImageSize.height;
// I believe the anchor point of the new image is (0.5, 0.5), so here he is setting the position to be in the middle
// Half of the width and height added to whatever origin you have (in this case 0) will give the proper coordinates
projectRect.origin.x = (newRect.size.width - projectRect.size.width) / 2.0;
projectRect.origin.y = (newRect.size.height - projectRect.size.height) / 2.0;
// Add the scaled image
[image drawInRect:projectRect];
// Retrieving the image that has been created and saving it in memory
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
self.thumbnail = smallImage;
// Cleanup image context resources; we're done
UIGraphicsEndImageContext();
}
I want to draw a image at angle. I have one ImageView with contect mode Aspect to fit. Also I have one dragView which user can move and rotate on the View. I have moved the dragView with CGAffineTransformMakeRotation
Both the ImageView and dragView is added on the main (self) view.
I have done the following code.
It has two problem
I dont know how to save image at angle that i can get from the CGAffineTransformMakeRotation
dragView is not placed currently on the image. it has some variation in the x and y position.
-(void)btnSaveClicked{
UIGraphicsBeginImageContextWithOptions(imgView.image.size, NO, 0.0); // create context as the image size
UIImage *dragImage = [self imageWithView:dragView]; // convert image from the dragView
[imgView.image drawInRect:CGRectMake(0, 0, imgView.image.size.width, imgView.image.size.height)]; // draw main image
CGSize size = imageDraw.size;
float factor = imgView.image.size.width / imgView.frame.size.width;
if (factor < imgView.image.size.height / imgView.frame.size.height) {
factor = imgView.image.size.height / imgView.frame.size.height;
}
CGRect rect = CGRectMake(self.view.frame.size.width/2-size.width/factor/2, self.view.frame.size.height/2-size.height/factor/2, size.width/factor, size.height/factor);
CGPoint point = CGPointMake((dragView.frame.origin.x+10-rect.origin.x)*factor,(dragView.frame.origin.y+10 - rect.origin.y)*factor);
[dragImage drawAtPoint:point blendMode:kCGBlendModeNormal alpha:1.0]; // draw the dragImnage but the point is wrong
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
imgView.image = newImage;
}
Sample Project : https://github.com/SunnyShah407/WaterMark/tree/master
Is it possible to scale an image inside a UIView without changing the UIView's bounds? (That is, while still clipping the image to the UIView's bounds, even as the image scales larger than the UIView.)
I found some code on a different SO post that scales the image in a UIView:
view.transform = CGAffineTransformScale(CGAffineTransformIdentity, _scale, _scale);
However, this seems to affect the view's bounds -- making them larger -- so that the UIView's drawing now stomps over other nearby UIViews as its contents grow larger. Can I make its contents scale larger, while keeping the clipping bounds the same?
The easiest way to scale image is to use UIImageView by setting its contentMode property.
If you have to use UIView to show the image, you may try to redraw the image in UIView.
1.subclass UIView
2.draw your image in drawRect
//the followed code draw the origin size of the image
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[_yourImage drawAtPoint:CGPointMake(0,0)];
}
//if you want to draw as much as the size of the image, you should calculate the rect that the image draws into
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[_yourImage drawInRect:_rectToDraw];
}
- (void)setYourImage:(UIImage *)yourImage
{
_yourImage = yourImage;
CGFloat imageWidth = yourImage.size.width;
CGFloat imageHeight = yourImage.size.height;
CGFloat scaleW = imageWidth / self.bounds.size.width;
CGFloat scaleH = imageHeight / self.bounds.size.height;
CGFloat max = scaleW > scaleH ? scaleW : scaleH;
_rectToDraw = CGRectMake(0, 0, imageWidth * max, imageHeight * max);
}
A CALayer can do it, and a UIImageView can do it. Can I directly display an image with aspect-fit with Core Graphics? The UIImage drawInRect does not allow me to set the resize mechanism.
If you're already linking AVFoundation, an aspect-fit function is provided in that framework:
CGRect AVMakeRectWithAspectRatioInsideRect(CGSize aspectRatio, CGRect boundingRect);
For instance, to scale an image to fit:
UIImage *image = …;
CRect targetBounds = self.layer.bounds;
// fit the image, preserving its aspect ratio, into our target bounds
CGRect imageRect = AVMakeRectWithAspectRatioInsideRect(image.size,
targetBounds);
// draw the image
CGContextDrawImage(context, imageRect, image.CGImage);
You need to do the math yourself. For example:
// desired maximum width/height of your image
UIImage *image = self.imageToDraw;
CGRect imageRect = CGRectMake(10, 10, 42, 42); // desired x/y coords, with maximum width/height
// calculate resize ratio, and apply to rect
CGFloat ratio = MIN(imageRect.size.width / image.size.width, imageRect.size.height / image.size.height);
imageRect.size.width = imageRect.size.width * ratio;
imageRect.size.height = imageRect.size.height * ratio;
// draw the image
CGContextDrawImage(context, imageRect, image.CGImage);
Alternatively, you can embed a UIImageView as a subview of your view, which gives you easy to use options for this. For similar ease of use but better performance, you can embed a layer containing the image in your view's layer. Either of these approaches would be worthy of a separate question, if you choose to go down that route.
Of course you can. It'll draw the image in whatever rect you pass. So just pass an aspect-fitted rect. Sure, you have to do a little bit of math yourself, but that's pretty easy.
here's the solution
CGSize imageSize = yourImage.size;
CGSize viewSize = CGSizeMake(450, 340); // size in which you want to draw
float hfactor = imageSize.width / viewSize.width;
float vfactor = imageSize.height / viewSize.height;
float factor = fmax(hfactor, vfactor);
// Divide the size by the greater of the vertical or horizontal shrinkage factor
float newWidth = imageSize.width / factor;
float newHeight = imageSize.height / factor;
CGRect newRect = CGRectMake(xOffset,yOffset, newWidth, newHeight);
[image drawInRect:newRect];
-- courtesy https://stackoverflow.com/a/1703210