I used the codes below to rotate an UIImage
double angle = -90;
NSData *imageData = [NSData dataWithContentsOfFile:sss];
UIImage *image =[UIImage imageWithData:imageData];
CGSize s = {image.size.width, image.size.height};
UIGraphicsBeginImageContext(s);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, 0,image.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextRotateCTM(ctx, 2*M_PI*angle/360);
CGContextDrawImage(ctx,CGRectMake(0,0,image.size.width, image.size.height),image.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[myUIImageView setImage:newImage];
but nothing displays on myUIImageView.
If there is anything wrong?
Welcome any comment
Thanks
interdev
If you're going to be rotating the image 90 degrees, you should swap the width and height when you create the image context:
CGSize s = {image.size.height, image.size.width};
This way, there's enough space to draw the fully-transformed image. Attempting to draw an image into a rectangle which exceeds the bounds of a graphics context will just result in nothing being drawn.
P.S. I recommend using a CGBitmapContext instead of UIGraphicsBeginImageContext(), as the former is thread-safe, which means you'd be able to do your image manipulations on a background thread if you so chose.
Related
I am capturing CGRect with following code. But the resulting image is not the image what i want. Image has some transparent background. What to do for removing transparent background as suggesting the picture.
- (UIImage *)captureScreenInRect:(CGRect)captureFrame {
CALayer *layer;
layer = imageScrollview.layer;
UIGraphicsBeginImageContext(imageScrollview.bounds.size);
CGContextClipToRect (UIGraphicsGetCurrentContext(),captureFrame);
\[layer renderInContext:UIGraphicsGetCurrentContext()\];
UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenImage;
}
Translate your context so that its origin matches your captureFrame:
UIGraphicsBeginImageContext(imageScrollview.bounds.size);
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(c, -captureFrame.origin.x, -captureFrame.origin.y);
[imageScrollView.layer renderInContext:c];
UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
(written from memory, untested)
Additionally clipping the context is not necessary as the image is already clipped by the image context's bounds.
Try this one
CGRect cropRect = CGRectMake(imageScrollview.frame.origin.x+15, imageScrollview.frame.origin.y+15, WIDTH, HEIGHT);
I am working on creating an image gallery which has thumbnails in different sizes. I want to convert these rectangle thumbnails to square size so that all of them could appear similar in size. I dont mind cropping it from extended portion but I am not sure how to do it. can anyone please help me?
Thanks
Pankaj
You need to use the image in rect method passing in the image and the required bounds...
CGImageRef imageRef = CGImageCreateWithImageInRect([anImage CGImage], requiredBounds);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
I have added this to a UIImage category (UIImage+Resize) in the following post, you can download the source code as well - Categories example
Well if you use an UIImageView to display your images (wich I am more than sure that you do) you can set it's contentMode property to UIViewContentModeScaleAspectFill. This should 'crop' your image to the boundaries of your UIImageView. In case your image will go out of the boundaries of the UIImageView make sure clipsToBounds is also set to YES.
Let me know if that helps.
I'm using the next method. The input are the UIImage to scale and the size of the UIImageView's frame where the UIImage is. It works when the frame's height and width are equal.
One important thing: I keep the image's ratio. I don't expand the image to cover the full square. If you want to do it you have to change the 'drawInRect' line for [self drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; and remove the if-else.
- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
CGFloat scaleRatio;
if (image.size.width > image.size.height) {
scaleRatio = image.size.height/image.size.width;
}else{
scaleRatio = image.size.width/image.size.height;
}
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(scaleRatio, scaleRatio);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextConcatCTM(context, scaleTransform);
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
if (image.size.width > image.size.height) {
[image drawInRect:CGRectMake(0, (newSize.height/2)-(newSize.height*scaleRatio/2), newSize.width, newSize.height*scaleRatio)];
}else{
[image drawInRect:CGRectMake((newSize.width/2)-(newSize.width*scaleRatio/2), 0, newSize.width*scaleRatio, newSize.height)];
}
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
I want to know, how can I erase a custom rect (with, for example, an UIView in IB or something else) of an UIImageView in order to display an other UIImageView positioned underneath.
I didn't manage to do it using some response in the forum...
This will clear a rect in an image:
- (UIImage *)clearRect:(CGRect)rect inImage:(UIImage *)image {
if (UIGraphicsBeginImageContextWithOptions != NULL)
UIGraphicsBeginImageContextWithOptions([image size], NO, 0.0);
else
UIGraphicsBeginImageContext([image size]);
CGContextRef context = UIGraphicsGetCurrentContext();
[image drawInRect:CGRectMake(0.0, 0.0, [image size].width, [image size].height)];
CGContextClearRect(context, rect);
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
Just load your image and clear the rects before assigning it to the image view:
UIImage *image = [UIImage imageNamed:#"Image.png"];
UIImage *maskedImage = [self clearRect:CGRectMake(10.0, 10.0, 50.0, 50.0) inImage:image];
[imageView setImage:maskedImage];
probably not the best solution but you can do the other way and take the 4 parts around the rect separately and combine them afterwards without the inner rect. You would repeat this as long as you have rect's to crop out.
You cannot clear the UIImageView itself because this just draws the UIImage. So you have erase the rect in the UIImage. Create a bitmap context, draw the image into it. Erase the part you want to "see through" with CGContextClearRect. When create a new new image from the bitmap context.
I created a masked image using a function form an iphone blog:
UIImage *imgToSave = [self maskImage:[UIImage imageNamed:#"pic.jpg"] withMask:[UIImage imageNamed:#"sd-face-mask.png"]];
Looks good in a UIImageView
UIImageView *imgView = [[UIImageView alloc] initWithImage:imgToSave];
imgView.center = CGPointMake(160.0f, 140.0f);
[self.view addSubview:imgView];
UIImagePNGRepresentation to save to disk:
[UIImagePNGRepresentation(imgToSave) writeToFile:[self findUniqueSavePath] atomically:YES];
UIImagePNGRepresentation returns NSData of an image that looks different.
The output is inverse image mask.
The area that was cut out in the app is now visible in the file.
The area that was visible in the app is now removed. Visibility is opposite.
My mask is designed to remove everything but the face area in the picture. The UIImage looks right in the app but after I save it on disk, the file looks opposite. The face is removed but everything else this there.
Please let me know if you can help!
In quartz you cam mask either by an image mask (black let through and white blocks), or a normal image (white let through and black blocks) which is the opposite. It seems for some reason saving is treating the image mask as a normal image to mask with. One thought is to render to a bitmap context and then create an image to be saved from that.
I had the exact same issue, when I saved the file it was one way, but the image returned in memory was the exact opposite.
The culprit & the solution was UIImagePNGRepresentation(). It fixes the in-app image before saving it to disk, so I just inserted that function as the last step in creating the masked image and returning that.
This may not be the most elegant solution, but it works. I copied some code from my app and condensed it, not sure if this code below works as is, but if not, its close... maybe just some typos.
Enjoy. :)
// MyImageHelperObj.h
#interface MyImageHelperObj : NSObject
+ (UIImage *) createGrayScaleImage:(UIImage*)originalImage;
+ (UIImage *) createMaskedImageWithSize:(CGSize)newSize sourceImage:(UIImage *)sourceImage maskImage:(UIImage *)maskImage;
#end
// MyImageHelperObj.m
#import <QuartzCore/QuartzCore.h>
#import "MyImageHelperObj.h"
#implementation MyImageHelperObj
+ (UIImage *) createMaskedImageWithSize:(CGSize)newSize sourceImage:(UIImage *)sourceImage maskImage:(UIImage *)maskImage;
{
// create image size rect
CGRect newRect = CGRectZero;
newRect.size = newSize;
// draw source image
UIGraphicsBeginImageContextWithOptions(newRect.size, NO, 0.0f);
[sourceImage drawInRect:newRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// draw mask image
[maskImage drawInRect:newRect blendMode:kCGBlendModeNormal alpha:1.0f];
maskImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// create grayscale version of mask image to make the "image mask"
UIImage *grayScaleMaskImage = [MyImageHelperObj createGrayScaleImage:maskImage];
CGFloat width = CGImageGetWidth(grayScaleMaskImage.CGImage);
CGFloat height = CGImageGetHeight(grayScaleMaskImage.CGImage);
CGFloat bitsPerPixel = CGImageGetBitsPerPixel(grayScaleMaskImage.CGImage);
CGFloat bytesPerRow = CGImageGetBytesPerRow(grayScaleMaskImage.CGImage);
CGDataProviderRef providerRef = CGImageGetDataProvider(grayScaleMaskImage.CGImage);
CGImageRef imageMask = CGImageMaskCreate(width, height, 8, bitsPerPixel, bytesPerRow, providerRef, NULL, false);
CGImageRef maskedImage = CGImageCreateWithMask(newImage.CGImage, imageMask);
CGImageRelease(imageMask);
newImage = [UIImage imageWithCGImage:maskedImage];
CGImageRelease(maskedImage);
return [UIImage imageWithData:UIImagePNGRepresentation(newImage)];
}
+ (UIImage *) createGrayScaleImage:(UIImage*)originalImage;
{
//create gray device colorspace.
CGColorSpaceRef space = CGColorSpaceCreateDeviceGray();
//create 8-bit bimap context without alpha channel.
CGContextRef bitmapContext = CGBitmapContextCreate(NULL, originalImage.size.width, originalImage.size.height, 8, 0, space, kCGImageAlphaNone);
CGColorSpaceRelease(space);
//Draw image.
CGRect bounds = CGRectMake(0.0, 0.0, originalImage.size.width, originalImage.size.height);
CGContextDrawImage(bitmapContext, bounds, originalImage.CGImage);
//Get image from bimap context.
CGImageRef grayScaleImage = CGBitmapContextCreateImage(bitmapContext);
CGContextRelease(bitmapContext);
//image is inverted. UIImage inverts orientation while converting CGImage to UIImage.
UIImage* image = [UIImage imageWithCGImage:grayScaleImage];
CGImageRelease(grayScaleImage);
return image;
}
#end
I'm using the following code to crop and create a new UIImage out of a bigger one. I've isolated the issue to be with the function CGImageCreateWithImageInRect() which seem to not set some CGImage property the way I want. :-) The problem is that a call to function UIImagePNGRepresentation() fails returning a nil.
CGImageRef origRef = [stillView.image CGImage];
CGImageRef cgCrop = CGImageCreateWithImageInRect( origRef, theRect);
UIImage *imgCrop = [UIImage imageWithCGImage:cgCrop];
...
NSData *data = UIImagePNGRepresentation ( imgCrop);
-- libpng error: No IDATs written into file
Any idea what might wrong or alternative for cropping a rect out of UIImage?
I had the same problem, but only when testing compatibility on iOS 3.2. On 4.2 it works fine.
In the end I found this http://www.hive05.com/2008/11/crop-an-image-using-the-iphone-sdk/ which works on both, albeit a little more verbose!
I converted this into a category on UIImage:
UIImage+Crop.h
#interface UIImage (Crop)
- (UIImage*) imageByCroppingToRect:(CGRect)rect;
#end
UIImage+Crop.m
#implementation UIImage (Crop)
- (UIImage*) imageByCroppingToRect:(CGRect)rect
{
//create a context to do our clipping in
UIGraphicsBeginImageContext(rect.size);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
//create a rect with the size we want to crop the image to
//the X and Y here are zero so we start at the beginning of our
//newly created context
CGRect clippedRect = CGRectMake(0, 0, rect.size.width, rect.size.height);
CGContextClipToRect( currentContext, clippedRect);
//create a rect equivalent to the full size of the image
//offset the rect by the X and Y we want to start the crop
//from in order to cut off anything before them
CGRect drawRect = CGRectMake(rect.origin.x * -1,
rect.origin.y * -1,
self.size.width,
self.size.height);
//draw the image to our clipped context using our offset rect
CGContextTranslateCTM(currentContext, 0.0, rect.size.height);
CGContextScaleCTM(currentContext, 1.0, -1.0);
CGContextDrawImage(currentContext, drawRect, self.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;
}
#end
In a PNG there are various chunks present, some containing palette info, some actual image data and some other information, it's a very interesting standard. The IDAT chunk is the bit that actually contains the image data. If there's no "IDAT written into file" then libpng has had some issue creating a PNG from the input data.
I don't know exactly what your stillView.image is, but what happens when you pass your code a CGImageRef that is certainly valid? What are the actual values in theRect? If your theRect is beyond the bounds of the image then the cgCrop you're trying to use to make the UIImage could easily be nil - or not nil, but containing no image or an image with width and height 0, giving libpng nothing to work with.
It seems the solution you are trying should work, but I recommend to use this:
CGImageRef image = [stillView.image CGImage];
CGRect cropZone;
size_t cWitdh = cropZone.size.width;
size_t cHeight = cropZone.size.height;
size_t bitsPerComponent = CGImageGetBitsPerComponent(image);
size_t bytesPerRow = CGImageGetBytesPerRow(image) / CGImageGetWidth(image) * cWidth;
//Now we build a Context with those dimensions.
CGContextRef context = CGBitmapContextCreate(nil, cWitdh, cHeight, bitsPerComponent, bytesPerRow, CGColorSpaceCreateDeviceRGB(), CGImageGetBitmapInfo(image));
CGContextDrawImage(context, cropZone, image);
CGImageRef result = CGBitmapContextCreateImage(context);
UIImage * cropUIImage = [[UIImage alloc] initWithCGImage:tmp];
CGContextRelease(context);
CGImageRelease(mergeResult);
NSData * imgData = UIImagePNGRepresentation ( cropUIImage);
UIImage *croppedImage = [self imageByCropping:yourImageView.image toRect:heredefineyourRect];
CGSize size = CGSizeMake(croppedImage.size.height, croppedImage.size.width);
UIGraphicsBeginImageContext(size);
CGPoint pointImg1 = CGPointMake(0,0);
[croppedImage drawAtPoint:pointImg1 ];
[[UIImage imageNamed:yourImagenameDefine] drawInRect:CGRectMake(0,532, 150,80) ];//here define your Reactangle
UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
croppedImage = result;
yourCropImageView.image=croppedImage;
[yourCropImageView.image retain];