Connection between UIGraphicsGetImageFromCurrentImageContext and drawInrect - iphone

I have found the following code to resize an UIImage:
CGSize newSize = CGSizeMake(self.image.size.width*0.25, self.image.size.height*0.25);
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[self.image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
but there are some couple of things I don't understand.
First I'm trying to resize the original image to 25% of the original size - but this method resizes it to 50% of the original size. Why?
What is the connection between drawInRect and UIGraphicsGetImageFromCurrentImageContext. As I see it, the UIGraphicsGetImageFromCurrentImageContext is overwriting the current image making the call to drawInRect redundant.
I would be grateful if someone could help me understand what's going on in details.
Thanks in advance.

first , because it's retina screen, you should set the scale to 1.0 , or it just x2
UIGraphicsBeginImageContextWithOptions(newSize, NO, 1.0);
if you call UIGraphicsBeginImageContext , any paint work will result in the Context you specific
the drawInRect in your code paint the image to the context, it's not redundant
or you can remove it, you get a empty image
finally, you can get a merged UIImage from the context
UIGraphicsGetImageFromCurrentImageContext();
just get a UIImage From What you have done(on context)
if you don't set the image back , it's won't change anything
self.image = UIGraphicsGetImageFromCurrentImageContext();

Related

CGContextDrawImage renders blurry text and images

I'm rendering PDF content into a UIView and I'm seeing that the text provided by the PDF is blurry when zoomed.
The way I'm rendering the text is as follows
CGSize size = CGSizeMake(96, 9); // These numbers come from the PDF
NSString* text = #"Text to render";
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
[text drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
This UIImage has the correct size and when I inspect it via XCode it is crisp.
When I call CGContextDrawImage below
CGRect widgetRect = CGRectMake(0,0,180,90);
CGContextDrawImage(mainContext, size, image.CGImage);
The result is blurry.
Notes:
The mainContext above has it's origin lower left so that's why I render text into a separate context and draw an image.
The UIView has a contentScaleFactor of 3 and the mainContext has a size to match that scale.
I looked at CGContextDrawImage draws large images very blurry and it doesn't address my problem.
I can't reproduce this problem outside my app in it's own.
This last part shows me that the problem is somewhere in the app code so I' hoping for hints and ideas about where to look in the rendering pipeline and how to debug.
EDIT:
Updated the calll to CGContextDrawImage to use the correct size.

Image quality problems when UILabel is rescaled and rasterized

I have some problems in rescaling the content of a UILabel object when it is stored as an image. Since the rendered image has to be bigger than the original UILabel, I have computed the scale imageScale needed to rescale the original image and saved it into a CGSize variable. In the following, I will explain the adopted (and failing) approaches.
Code used for rendering the image
The following code is used for rendering the extracted image on the canvas.
[labelImage drawInRect:CGRectMake(xCoordinate/imageScale.width,
yCoordinate/imageScale.height,
newSize.width,
newSize.height)
blendMode:kCGBlendModeNormal alpha:0.8];
where the variable newSize is computed as follows:
newSize.width = originalWidth/imageScale.width;
newSize.height = originalHeight/imageScale.height
Approach 1
I extracted the label using the following code:
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[[label layer] renderInContext: UIGraphicsGetCurrentContext()];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
where label is the UILabel variable and newSize is the size that the rescaled image should have (see above for details).
However, I obtain the following image, which is obviously failing, since the content is very little and not centered:
Approach 2
I extracted the label using the following code:
UIGraphicsBeginImageContextWithOptions([label bounds].size, NO, 0.0);
[[label layer] renderInContext: UIGraphicsGetCurrentContext()];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
However, since I am using the original image size in order to extract the image, the effect I obtain is the following:
As you can notice, the text in the balloon has not a high resolution, and thus it is not visualized properly.
The question
How to correct one of the two approaches so as to visualize in high resolution the image?
Seems like you just need to set appropriate scale for the generated image.
This is the function:
void UIGraphicsBeginImageContextWithOptions(
CGSize size,
BOOL opaque,
CGFloat scale
);
You set scale as 0.0. Try replacing it with [UIScreen mainScreen].scale.

pixelated iphone UIImageView

I've been having issues rendering images with the UIImageView class. The pixelation seems to occur mostly on the edges of the image I am trying to show.
I have tried changing the property 'Render with edge antialiasing' to no avail.
The image files contain images that are larger than what will appear on the screen.
It seems to be royally messing with the quality of the image and then displaying it. I tried to post images here, but StackOverflow is denying me that privilege. So here's a link to what's going on.
http://i.imgur.com/QpUOTOF.png
The sun in this image is the problem I'm speaking of. Any ideas?
On-the-fly image resizing is quick and of low quality. For bundled images, it is worth the extra bundle space to include downsized versions. For downloaded images, you can achieve better results by resizing with Core Graphics into a new UIImage before you set the image property.
CGSize newSize = CGSizeMake(newWidth, newHeight);
UIGraphicsBeginImageContextWithOptions(newSize, // context size
NO, // opaque?
0); // image scale. 0 means "device screen scale"
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
[bigImage drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Use following method use for get specific hight and width with image
+ (UIImage*)resizeImage:(UIImage*)image withWidth:(int)width withHeight:(int)height
{
CGSize newSize = CGSizeMake(width, height);
float widthRatio = newSize.width/image.size.width;
float heightRatio = newSize.height/image.size.height;
if(widthRatio > heightRatio)
{
newSize=CGSizeMake(image.size.width*heightRatio,image.size.height*heightRatio);
}
else
{
newSize=CGSizeMake(image.size.width*widthRatio,image.size.height*widthRatio);
}
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
This method return NewImage, with specific size that you specified.
How big is your image and what is the size of the imageView? Don't rely on UIImageView to scale it down for you. You probably need to resize it manually. This would also be a bit more memory efficient.
I use categories like these:
>>>github link <<<
to do image resizing.
This also gives you some other nice function for rounded corners etc.
Also keep in mind, that you need a transparent border at the edge of an image if you want to rotate it to avoid aliasing.

<Error>: CGBitmapContextCreate: unsupported parameter combination vs. lower resolution image

- (UIImage *)roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize {
// If the image does not have an alpha layer, add one
UIImage *image = [self imageWithAlpha];
// Build a context that's the same dimensions as the new size
CGBitmapInfo info = CGImageGetBitmapInfo(image.CGImage);
CGContextRef context = CGBitmapContextCreate(NULL,
image.size.width,
image.size.height,
CGImageGetBitsPerComponent(image.CGImage),
0,
CGImageGetColorSpace(image.CGImage),
CGImageGetBitmapInfo(image.CGImage));
// Create a clipping path with rounded corners
CGContextBeginPath(context);
[self addRoundedRectToPath:CGRectMake(borderSize, borderSize, image.size.width - borderSize * 2, image.size.height - borderSize * 2)
context:context
ovalWidth:cornerSize
ovalHeight:cornerSize];
CGContextClosePath(context);
CGContextClip(context);
// Draw the image to the context; the clipping path will make anything outside the rounded rect transparent
CGContextDrawImage(context, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage);
// Create a CGImage from the context
CGImageRef clippedImage = CGBitmapContextCreateImage(context);
CGContextRelease(context);
// Create a UIImage from the CGImage
UIImage *roundedImage = [UIImage imageWithCGImage:clippedImage];
CGImageRelease(clippedImage);
return roundedImage;
}
I have the method above and am adding rounded corners to Twitter profile images. For most of the images this works awesome. There are a few that cause the following error to occur:
: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 32 bits/pixel; 3-component color space; kCGImageAlphaLast; 96 bytes/row.
I have done some debugging and it looks like the only difference from the images causing errors and the ones that are not is the parameter, CGImageGetBitmapInfo(image.CGImage), when creating the context. This throws the error and results in the context being null. I tried setting the last parameter to kCGImageAlphaPremultipliedLast to no avail either. The image is drawn this time but with much less quality. Is there a way to get a higher quality image on par with the rest of them? The path to the image is via Twitter so not sure if they have different ones you can pull.
I have seen the other questions regarding this error too. None of have solved this issue. I saw this post but the errored images are completely blurry after that. And casting the width and height to NSInteger also didn't work. Below is a screenshot of the two profile images and their quality as well. The first one is causing the error.
Does anyone have any idea what the issue is here?
Thanks a ton. This has been killing me.
iOS does not support kCGImageAlphaLast. You need to use kCGImageAlphaPremultipliedLast.
You also need to handle the scale of your initial image. Your current code doesn't, so it downsamples the image if its scale is 2.0.
You can write the entire function more simply by using UIKit functions and classes. UIKit will take care of the scale for you; you just have to pass in the original image's scale when you ask it to create the graphics context.
- (UIImage *)roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize {
// If the image does not have an alpha layer, add one
UIImage *image = [self imageWithAlpha];
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale); {
CGRect imageRect = (CGRect){ CGPointZero, image.size };
CGRect borderRect = CGRectInset(imageRect, borderSize, borderSize);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:borderRect
byRoundingCorners:UIRectCornerAllCorners
cornerRadii:CGSizeMake(cornerSize, cornerSize)];
[path addClip];
[image drawAtPoint:CGPointZero];
}
UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return roundedImage;
}
If your imageWithAlpha method itself creates a UIImage from another UIImage, it needs to propagate the scale also.

Using CGContext to display a sprite sheet iPhone

So I have a spritesheet in png format, and have already worked out the coordinates for what I want to display. I'm trying to create a method that will return a UIImage when passed the location information on the spritesheet. I'm just not sure how to use the CGContext stuff along with the the coordinates to return an UIImage.
I was looking to CGContextClipToRect because I think that is the way to do it, but I just can't seem to get it to work.
Something like this
CGSize size = CGSizeMake(xSize, ySize);
UIGraphicsBeginImageContext(size);
//CGContextClipToRect(spriteSheet.size, imageRect);
[spriteSheet drawAtPoint:CGPointMake(xPos, yPos)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
returns only what is in the size Context. I need to be able to "move" this size window around the spritesheet if that makes sense.
Any help would be appreciated.
Thanks,
Mike
I think the call you want to use is CGImageCreateWithImageInRect
newImage = [UIImage imageWithCGImage:CGImageCreateWithImageInRect( [spriteSheet CGImage] , imageRect )];
you need to think of your co-ordinates backwards. The CGSize is fixed. Translate your xPos,yPos so that your sprite appears under the window.