I'm working on an iPhone app that can create pictures and post them to Facebook and Instagram.
The correct size for Facebook photos seems to be 350x350, and indeed this code creates a 350x350 image exactly how I want:
-(UIImage *)createImage {
UIImageView *v = [[UIImageView alloc] initWithFrame:CGRectMake(0, screenHeight/2-349, 349, 349)];
v.image = [UIImage imageNamed:#"backgroundForFacebook.png"]; //"backgroundForFacebook.png" is 349x349.
//This code adds some text to the image.
CGSize dimensions = CGSizeMake(screenWidth, screenHeight);
CGSize imageSize = [self.ghhaiku.text sizeWithFont:[UIFont fontWithName:#"Georgia"
size:mediumFontSize]
constrainedToSize:dimensions lineBreakMode:0];
int textHeight = imageSize.height+16;
UITextView *tv = [self createTextViewForDisplay:self.ghhaiku.text];
tv.frame = CGRectMake((screenWidth/2)-(self.textWidth/2),s creenHeight/3.5,
self.textWidth/2 + screenWidth/2, textHeight*2);
[v addSubview:tv];
//End of text-adding code
CGRect newRect = CGRectMake(0, screenHeight/2-349, 349, 349);
UIGraphicsBeginImageContext(newRect.size);
[[v layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *myImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[v removeFromSuperview];
return myImage;
}
But when I use the same code to create an Instagram image, which needs to be 612x612, I get the text only, no background image:
-(UIImage *)createImageForInstagram {
UIImageView *v = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 612, 612)];
v.image = [UIImage imageNamed:#"backgroundForInstagram.png"]; //"backgroundForInstagram.png" is 612x612.
//...text-adding code...
CGRect newRect = CGRectMake(0, 0, 612, 612);
UIGraphicsBeginImageContext(newRect.size);
[[v layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *myImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[v removeFromSuperview];
return myImage;
}
What am I doing wrong, and how do I fix it?
(While I'm at it, I'll also say that I'm very new to using graphic contexts, so if there's any awkwardness in the code I'd appreciate your pointing it out.)
EDIT: Now I've reduced the two methods to one, and this time I don't even get the text. Argh!
-(UIImage *)addTextToImage:(UIImage *)myImage withFontSize:(int)sz {
NSString *string=self.displayHaikuTextView.text;
NSString *myWatermarkText = [string stringByAppendingString:#"\n\n\t--haiku.com"];
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:[UIFont fontWithName:#"Georgia"
size:sz],
NSFontAttributeName,
nil];
NSAttributedString *attString = [[NSAttributedString alloc] initWithString:myWatermarkText attributes:attrs];
UIGraphicsBeginImageContextWithOptions(myImage.size,NO,1.0);
[myImage drawAtPoint: CGPointZero];
NSString *longestLine = ghv.listOfLines[1];
CGSize sizeOfLongestLine = [longestLine sizeWithFont:[UIFont fontWithName:#"Georgia" size:sz]];
CGSize siz = CGSizeMake(sizeOfLongestLine.width, sizeOfLongestLine.height*5);
[attString drawAtPoint: CGPointMake(myImage.size.width/2 - siz.width/2, myImage.size.height/2-siz.height/2)];
myImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return myImage;
}
When I pass the arguments [UIImage imageNamed:"backgroundForFacebook.png"] (an image 349x349) and 12, everything is fine. I get the picture. When I pass the arguments [UIImage imageNamed:"backgroundForInstagram.png"] (an image 612x612) and 24, nothing doing.
Right now I'm just putting the text on the smaller image (#"backgroundForFacebook.png") and then resizing it, but that makes the text blurry, which I don't like.
EDIT: Just to cover the basics, here are images of 1) the method in which I call this method (to check the spelling) and 2) the Supporting Files and the Build Phases (to show the image is actually there). I also tried assigning longestLine a non-variable NSString. No luck. :(
FURTHER EDIT: Okay, logging the size and scale of the images as I go during addTextToImage: above, here's what I get for the smaller image, the one that's working:
2013-02-04 22:24:09.588 GayHaikuTabbed[38144:c07] 349.000000, 349.000000, 1.000000
And here's what I get for the larger image--it's a doozy.
Feb 4 22:20:36 Joels-MacBook-Air.local GayHaikuTabbed[38007] <Error>: CGContextGetFontRenderingStyle: invalid context 0x0
Feb 4 22:20:36 Joels-MacBook-Air.local GayHaikuTabbed[38007] <Error>: CGContextSetFillColorWithColor: invalid context 0x0
//About thirty more of these.
Feb 4 22:20:36 Joels-MacBook-Air.local GayHaikuTabbed[38007] <Error>: CGBitmapContextCreate: unsupported parameter combination: 0 integer bits/component; 0 bits/pixel; 0-component color space; kCGImageAlphaNoneSkipLast; 2448 bytes/row.
Feb 4 22:20:36 Joels-MacBook-Air.local GayHaikuTabbed[38007] <Error>: CGContextDrawImage: invalid context 0x0
Feb 4 22:20:36 Joels-MacBook-Air.local GayHaikuTabbed[38007] <Error>: CGBitmapContextCreateImage: invalid context 0x0
Step through the code. After you create myImage, go into the console and look at myImage.size and myImage.scale. Multiply the size numbers by the scale.
If your background image is Retina-quality, your image is actually 1224 x 1224.
From the UIImage docs:
You should avoid creating UIImage objects that are greater than 1024 x
1024 in size. Besides the large amount of memory such an image would
consume, you may run into problems when using the image as a texture
in OpenGL ES or when drawing the image to a view or layer. This size
restriction does not apply if you are performing code-based
manipulations, such as resizing an image larger than 1024 x 1024
pixels by drawing it to a bitmap-backed graphics context. In fact, you
may need to resize an image in this manner (or break it into several
smaller images) in order to draw it to one of your views.
If your image is actually 612 pixels (not points) but your code is rendering it as 1224 pixels, you can just change the scale property to 1.0.
If your image is actually 1224 pixels, you'll need to do something else, like
put your code on a bitmap-backed graphics context (i.e., calling UIGraphicsBeginImageContext around the offending code)
displaying a smaller version to the user
However, if your image is for Instagram, it should not be 1224 x 1224 :-)
Update: I noticed your app is haiku-related, so here is the answer in haiku format:
Big UIImage?
Bitmap-backed graphics context
Or shrink to 612
i always back up to the obvious questions:
is your image actually properly called/spelled backgroundForInstagram.png?
have you properly added it to your project?
when added, did it copied to the device in the copy steps of the build phases?
what's in the ghv at the time of the call in the edited code?
what's in item[1] of ghv.lines at the time of that rendering?
these are the things i would look at in terms of debugging this code.
Try This
-(UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
//UIGraphicsBeginImageContext(newSize);
UIGraphicsBeginImageContextWithOptions(newSize, NO, 10.0);// 10.0 means 10 time bigger
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Related
I have a simple method that I'm using to resize images. I need to create 2200 x 2200 px images and upload them to a server. I have a working solution but I it doesn't works properly. I think there's something wrong where I set the size for the image because the result is bigger then 10 MB.
- (void) uploadImage {
NSData *imageData = UIImageJPEGRepresentation([self resizeImage:self.uploadImg.image reSize:CGSizeMake(2200, 2200)], 1.0);
...
}
- (UIImage*)resizeImage:(UIImage*)aImage reSize:(CGSize)newSize
{
UIGraphicsBeginImageContextWithOptions(newSize, YES, [UIScreen mainScreen].scale);
[aImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Is it a right implementation? The CGSizeMake(2200, 2200) is equal to 2200x2200 pixel? If yes, what indicates the 10MB+ file size? It shouldn't be bigger then 1-2MB.
I have a UIImage that I'm loading into one of my app's views. It is a 10.7 MB image, but when it loads in the app, the app's resource usage suddenly jumps by 50 MB. Why does it do this? Shouldn't memory used increase by only about 10.7MB? I am certain that loading the image is what causes the jump in memory usage because I tried commenting these lines out and the memory usage went back to around 8 MB. Here's how I load the image:
UIImage *image = [UIImage imageNamed:#"background.jpg"];
self.backgroundImageView = [[UIImageView alloc] initWithImage:image];
[self.view addSubview:self.backgroundImageView];
If there is no way to decrease the memory used by this image, is there a way to force it to deallocate when I want it to? I'm using ARC.
No, it should not be 10.7MB. The 10.7MB is the compressed size of the image.
The image loaded in to the UIImage object is a decoded image.
For each pixel in the image 4 bytes (R,G,B and Alpha) are used, therefore you can calculate the memory size, height x width x 4 = total bytes in memory.
So the moment you loaded the image into memory it will take up lots of memory, and since a UIImageView is used to present the image and as a subview the images is kept in memory.
You should try and change the size of the image to match the size of the iOS screen size.
As #rckoenes said
Don't show the images with high file size.
You need to resize the image before you display it.
UIImage *image = [UIImage imageNamed:#"background.jpg"];
self.backgroundImageView =[self imageWithImage:display scaledToSize:CGSizeMake(20, 20)];//Give your CGSize of the UIImageView.
[self.view addSubview:self.backgroundImageView];
-(UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
//UIGraphicsBeginImageContext(newSize);
// In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
// Pass 1.0 to force exact pixel size.
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
You can do one thing. if you can afford 50 MB for this image. If this image with 10 mb size is that much critical to your application then. you can release it just after its use to keep memory usage in control.
As you are using ARC there is no option for release but you can do this
#autoreleasepool {
UIImage *image = [UIImage imageNamed:#"background.jpg"];
self.backgroundImageView = [[UIImageView alloc] initWithImage:image];
[self.view addSubview:self.backgroundImageView];
}
using autoreleasepool it will be sure that after this autoreleasepool{} block memory for fat image will be deallocated. making your device RAM happy again.
Hope it helps !
UIImageView *cellimage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0 , 107, 70)];
The above statement i am sure will make appropriate sizes in both retina resolution devices and standard ones..that is a frame of 107 x 70 pixels on standard and 214 x 140 on retina.
What i want to know is if the below UIGraphicsGetImageFromCurrentImageContext does the same too.. image will be 67 x 67 for standard and 124 x 124 for retina versions?
CGSize imagesize = CGSizeMake(67, 67);
UIGraphicsBeginImageContext(imagesize);
NSLog(#" Converting ");
[image drawInRect:CGRectMake(0,0,imagesize.width,imagesize.height)];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if not can anyone tell me how to differentiate between models.?
Thanks
You need to use UIGraphicsBeginImageContextWithOptions instead of UIGraphicsBeginImageContext, so that you can specify the scale factor of the image. This will use the scale factor of the device's main screen:
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
This will use the scale factor of the screen containing cellImage, if cellImage is on a screen:
UIGraphicsBeginImageContextWithOptions(imageSize, NO, cellImage.window.screen.scale);
This will hardcode the scale factor:
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 2);
After successfully using UIView’s new drawViewHierarchyInRect:afterScreenUpdates: method introduced in iOS 7 to obtain an image representation (via UIGraphicsGetImageFromCurrentImageContext()) for blurring my app also needed to obtain just a portion of a view. I managed to get it in the following manner:
UIImage *image;
CGSize blurredImageSize = [_blurImageView frame].size;
UIGraphicsBeginImageContextWithOptions(blurredImageSize, YES, .0f);
[aView drawViewHierarchyInRect: [aView bounds] afterScreenUpdates: YES];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
This lets me retrieve aView’s content following _blurImageView’s frame.
Now, however, I would need to obtain a portion of aView, but this time this portion would be “inside”. Below is an image representing what I would like to achieve.
I have already tried creating a new graphics context and setting its size to the portion’s size (red box) and calling aView to draw in the rect that represents the red box’s frame (of course its superview’s frame being equal to aView’s) but the image obtained is all black (empty).
After a lot of tweaking I managed to find something that did the job, however I heavily doubt this is the way to go.
Here’s my [edited-for-Stack Overflow] code that works:
- (UIImage *) imageOfPortionOfABiggerView
{
UIView *bigViewToExtractFrom;
UIImage *image;
UIImage *wholeImage;
CGImageRef _image;
CGRect imageToExtractFrame;
CGFloat screenScale = [[UIScreen mainScreen] scale];
// have to scale the rect due to (I suppose) the screen's scale for Core Graphics.
imageToExtractFrame = CGRectApplyAffineTransform(imageToExtractFrame, CGAffineTransformMakeScale(screenScale, screenScale));
UIGraphicsBeginImageContextWithOptions([bigViewToExtractFrom bounds].size, YES, screenScale);
[bigViewToExtractFrom drawViewHierarchyInRect: [bigViewToExtractFrom bounds] afterScreenUpdates: NO];
wholeImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// obtain a CGImage[Ref] from another CGImage, this lets me specify the rect to extract.
// However since the image is from a UIView which are all at 2x scale (retina) if you specify a rect in points CGImage will not take the screen's scale into consideration and will process the rect in pixels. You'll end up with an image from the wrong rect and half the size.
_image = CGImageCreateWithImageInRect([wholeImage CGImage], imageToExtractFrame);
wholeImage = nil;
// have to specify the image's scale due to CGImage not taking the screen's scale into consideration.
image = [UIImage imageWithCGImage: _image scale: screenScale orientation: UIImageOrientationUp];
CGImageRelease(_image);
return image;
}
I hope this will help anyone that stumped upon my issue. Feel free to improve my snippet.
Thanks
This question already has answers here:
The simplest way to resize an UIImage?
(34 answers)
Closed 9 years ago.
I've created a UIImageView which contains an image with a high resolution. The problem is that the resolution of that image is too high to put into the imageView. The size of the imageView is 92 x 91 (so it's small). It contains an UIImage, whose resolution is too high so it looks ugly in the UIImageView.
So how can I reduce the resolution of that UIImage?
My code for the UIImageView:
UIImageView *myImageView = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:pngFilePath]];
myImageView.frame = CGRectMake(212.0, 27, 92,91);
have a look at this
https://stackoverflow.com/a/2658801
This will help you to resize your image according to your need
Add method to your code and call like this
UIImage *myImage =[UIImage imageWithContentsOfFile:pngFilePath];
UIImage *newImage =[UIImage imageWithImage:myImage scaledToSize:CGSizeMake(92,91)];
You can resize an image using this method that returns a resized image :
-(UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
// Here pass new size you need
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Hope it helps you.
try with this
myImageView.contentMode = UIViewContentModeScaleToFill;
You need to downsize the image, which will reduce the resolution, make it easier to store. I actually wrote a class (building on some stuff from SO) that does just that. It's on my github, take a look:
https://github.com/pavlovonline/UIImageResizer
the main method is
-(UIImage*)resizeImage:(UIImage*)image toSize:(CGFloat)size
so you give this method the size to which you want to downsize your image. If the height is greater than the width, it will auto-calculate the middle and give you a perfectly centered square. Same for width being greater than height. If you need an image that is not square, make your own adjustments.
so you'll get back a downsized UIImage which you can then put into your UIImageView. Save some memory too.