I have a CGPath shaped like an arrow that I am drawing in the CGContext of my current view. I would like to generate a miniature version (thumbnail) of the arrow to add it as an Image to a UITableView showing all selected arrows.
I am succeeding to downscale a picture of the full context which leaves the arrow smaller than it should be. Ideally I would like to crop the image of the full context to the bounds of the arrow. However, I was not yet successful. Any leads? Thanks for the help!
Here are a picture of the full view containing an arrow and another picture of the thumbnail I am generating.
Ideally the thumbnail above would be cropped to contain the arrow only - not the full context.
The code I use is the follwoing:
- (UIImage*) imageForObject:(id<GraphicalObject>) object
inRect:(CGRect)rect {
UIImage *image = [UIImage new];
CGRect objectBounds = [object objectBounds];
UIGraphicsBeginImageContext(self.view.frame.size);//objectBounds.size);
CGContextRef context =UIGraphicsGetCurrentContext();
[object drawInContext:context];
//doesn't work
CGContextClipToRect(context, objectBounds);
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
The CGRect called objectBounds has two components, an origin and a size. In order the draw the object correctly as a thumbnail, the code needs to scale the image (to get the size right) and translate the image (to move the origin to {0,0}). So the code looks like this
- (UIImage *)getThumbnailOfSize:(CGSize)size forObject:(UIBezierPath *)object
{
// to maintain the aspect ratio, we need to compute the scale
// factors for x and y, and then use the smaller of the two
CGFloat xscale = size.width / object.bounds.size.width;
CGFloat yscale = size.height / object.bounds.size.height;
CGFloat scale = (xscale < yscale) ? xscale : yscale;
// start a graphics context with the thumbnail size
UIGraphicsBeginImageContext( size );
CGContextRef context = UIGraphicsGetCurrentContext();
// here's where we scale and translate to make the image fit
CGContextScaleCTM( context, scale, scale );
CGContextTranslateCTM( context, -object.bounds.origin.x, -object.bounds.origin.y );
// draw the object and get the resulting image
[object stroke];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Related
I have a collection view in which the cell we place image from gallery. On a cell there is a button which rotate an image when we click it. Now when I click the image it rotates the image but when I send it to the server it does not goes in the rotated angle as I selected, it goes as it is coming from gallery or camera. When I select an image from gallery it gives this in an array of image ,
III (
"<UIImage: 0x608000299b90>, {1000, 624}"
)
and in path of image array it comes this,
FFF is(
"/Users/Apple/Library/Developer/CoreSimulator/Devices/23D54E17-36FB-4397-BA5E-09A05EB0EBF3/data/Containers/Data/Application/C1D07D05-11B3-4D49-8D91-884FC3DA1A06/Documents/E7IME.png"
)
Now i want to store the the rotated condition of image and send it to server with same rotated condition. but when i click the button nothing comes in console and just image rotates.
You have to rotate the image itself and saving that state, try below:
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
-(UIImage *)rotateImage:(UIImage*)src byRadian:(CGFloat)radian
{
CGRect rect = CGRectApplyAffineTransform(CGRectMake(0,0, src.size.width, src.size.height), CGAffineTransformMakeRotation(radian));
CGSize rotatedSize = rect.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, radian);
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-src.size.width / 2, -src.size.height / 2, src.size.width, src.size.height), [src CGImage]);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Usage:
UIImage *rotatedImage = [self rotateImage:[UIImage imageNamed:#"urImageName"] byRadian:DEGREES_TO_RADIANS(90)];
[self.image setImage:rotatedImage];
Note: you have then to send the rotatedImage.
Answer is inspired from: https://stackoverflow.com/a/20860719/4004429
You can save your modified image (imageView) in the gallery with
UIImageWriteToSavedPhotosAlbum(imageView, nil, nil, nil);
The sequence of nil is the completion block, you can read the usage here.
I would like to rotate a UIImage from file (a jpeg on the file system) a computed amount of radians, but I would like to rotate it around a point in the image, as well as keep the original size of the image (with transparent gaps in the image where image data no longer exists, as well as cropping image data that has moved outside of the original frame). I would like to then store and display the resulting UIImage. I haven't found any resources for this task, any help would be much appreciated!
The closest thing I have found so far (with some slight modifications) is as follows:
-(UIImage*)rotateImage:(UIImage*)image aroundPoint:(CGPoint)point radians:(float)radians newSize:(CGRect)newSize
{
CGRect imageRect = { point, image.size };
UIGraphicsBeginImageContext(image.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, imageRect.origin.x, imageRect.origin.y);
CGContextRotateCTM(context, radians);
CGContextTranslateCTM(context, -imageRect.origin.x, -imageRect.origin.y);
CGContextDrawImage(context, (CGRect){ CGPointZero, imageRect.size }, [image CGImage]);
UIImage *returnImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return returnImg;
}
Unfortunately, this rotates the image incorrectly (in my tests, somewhere in the neighborhood of 180 degrees more than desired).
to rotate that UIImage image, lets say 90 degrees, you can easily do:
imageView.transform = CGAffineTransformMakeRotation(M_PI/2);
to rotate it multiple times you can use:
UIView animateKeyframesWithDuration method
and to anchor it to some point you can use:
[image.layer setAnchorPoint:CGPointMake(....)];
Hi,
I want to rotate my UIImageView without moving the whole "png". No code is only to test what happens
_fanImage.transform = CGAffineTransformMakeRotation(45);
It turns but the whole image moves. What can I do that this doesn't happen ?
You can try something like this.. You should rotate the UIImage rather than UIImageView.
- (UIImage *)imageWithTransform:(CGAffineTransform)transform {
CGRect rect = CGRectMake(0, 0, self.size.height, self.size.width);
CGImageRef imageRef = self.CGImage;
// Build a context that's the same dimensions as the new size
CGContextRef bitmap = CGBitmapContextCreate(NULL,
self.size.width,
self.size.height,
CGImageGetBitsPerComponent(imageRef),
0,
CGImageGetColorSpace(imageRef),
CGImageGetBitmapInfo(imageRef));
// Rotate and/or flip the image if required by its orientation
CGContextConcatCTM(bitmap, transform);
// Draw into the context; this scales the image
CGContextDrawImage(bitmap, rect, imageRef);
// Get the resized image from the context and a UIImage
CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
// Clean up
CGContextRelease(bitmap);
CGImageRelease(newImageRef);
return newImage;
}
I think you mean that you want your image view to rotate around it's center point. Is that right? If so, that's what a view should do by default.
You should do a search on "Translating, Scaling, and Rotating Views" in Xcode and read the resulting article.
Note that all of iOS's angles are specified in radians, not degrees.
Your sample images aren't really helpful, since we can't see the frame that the image view is drawn into. It's almost impossible to tell what your image views are doing and what they are supposed to be doing instead based on the pictures you linked from your dropbox.
A full 360 degrees is 2pi.
You should use
CGFloat degrees = 45;
CGFloat radians = degrees/180*M_PI;
_fanImage.transform = CGAffineTransformMakeRotation(radians);
That will fix the rotation amount for your code, but probably not the rotation position.
It looks like I might've potentially found an answer to one of my earlier problems and would be happy to post the solution on SO though I first need to confirm it works properly.
The problem is it seems to be - most of the time, though not always. I've isolated the problematic code - it's a method I created whose purpose is to return a UIImage of what is currently visible on the device's screen. It looks like this:
+ (UIImage *)getImageVisibleOnScreenWith: (CGRect) boundingRect rotationAngle: (CGFloat) angle scalingRatio: (CGFloat) scale entireImageView: (UIImageView *) imageView actualVisibleView: (UIView *) visibleView {
// Create a graphics context the size of the bounding rectangle
UIGraphicsBeginImageContext(boundingRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// Rotate and translate the context
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformTranslate(transform, boundingRect.size.width/2, boundingRect.size.height/2);
transform = CGAffineTransformRotate(transform, angle);
transform = CGAffineTransformScale(transform, scale, -scale);
CGContextConcatCTM(context, transform);
// Draw the image into the context
CGContextDrawImage(context, CGRectMake(-imageView.image.size.width/2, -imageView.image.size.height/2, imageView.image.size.width, imageView.image.size.height), imageView.image.CGImage);
// Get an image from the context
UIImage *viewImage = [UIImage imageWithCGImage: CGBitmapContextCreateImage(context)];
// Clean up
UIGraphicsEndImageContext();
// Get the image currently on the screen (it's an intersection of specific UIImageViews)
CGRect visibleImageRect = CGRectIntersection(imageView.frame, visibleView.frame);
UIImage *visibleImage = (__bridge UIImage *)(CGImageCreateWithImageInRect((__bridge CGImageRef)(viewImage), visibleImageRect));
return visibleImage;
}
I pass on the result of this method to another one and noticed it sometimes returns nil - for no apparent reason, well at least I couldn't find any.
As usual, any ideas and help will be appreciated; also let me know if you need to see more code or if there's anything unclear as to what the purpose it is.
So I have some copypasta way to create a PNG file and it's working splendidly, however, when going to print this PNG it appears kind of "blurry" like a low resolution image. Is there any way to create the PNG with a higher pixel depth?
Here's my current code:
- (UIImage*) renderScrollViewToImage
{
UIImage* image = nil;
UIGraphicsBeginImageContext(self.scrollView.contentSize);
{
CGPoint savedContentOffset = self.scrollView.contentOffset;
CGRect savedFrame = self.scrollView.frame;
self.scrollView.contentOffset = CGPointZero;
self.scrollView.frame = CGRectMake(0, 0, _scrollView.contentSize.width, _scrollView.contentSize.height);
[self.scrollView.layer renderInContext: UIGraphicsGetCurrentContext()];
image = UIGraphicsGetImageFromCurrentImageContext();
_scrollView.contentOffset = savedContentOffset;
_scrollView.frame = savedFrame;
}
UIGraphicsEndImageContext();
if (image != nil) {
return image;
}
return nil;
}
try replacing:
UIGraphicsBeginImageContext(self.scrollView.contentSize);
with
UIGraphicsBeginImageContextWithOptions(self.scrollView.contentSize, NO, 0.0);
which will take into account retina scaling. docs:
UIGraphicsBeginImageContextWithOptions
Creates a bitmap-based graphics context with the specified options.
void UIGraphicsBeginImageContextWithOptions(
CGSize size,
BOOL opaque,
CGFloat scale
);
Parameters
size
The size (measured in points) of the new bitmap context. This represents the size of the image returned by the UIGraphicsGetImageFromCurrentImageContext function. To get the size of the bitmap in pixels, you must multiply the width and height values by the value in the scale parameter.
opaque
A Boolean flag indicating whether the bitmap is opaque. If you know the bitmap is fully opaque, specify YES to ignore the alpha channel and optimize the bitmap’s storage. Specifying NO means that the bitmap must include an alpha channel to handle any partially transparent pixels.
scale
The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.