6

I'm trying to adapt THIS question to work with a retina display. Here's how I figured out how to work with retina graphics for UIGraphicsBeginImageContext.

if (UIGraphicsBeginImageContextWithOptions != NULL)
{
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.0f);
}
else
{
    UIGraphicsBeginImageContext(self.view.bounds.size);
}

However, when I use it the image looks really huge and doesn't scale down to fit the display. Any ideas how I can tell it to resize the captured image to fit the boxes? (Please refer to the other question to understand what I mean).

Community
  • 1
  • 1
sudo rm -rf
  • 29,408
  • 19
  • 102
  • 161

3 Answers3

12

I've written this code to perform exactly the same thing described in the other post. It works on any iOS device with at least iOS 3.1.

_launcherView is the view that need to be photographed

CGFloat scale = 1.0;
if([[UIScreen mainScreen]respondsToSelector:@selector(scale)]) {        
    CGFloat tmp = [[UIScreen mainScreen]scale];
    if (tmp > 1.5) {
        scale = 2.0;    
    }
} 

if(scale > 1.5) {
    UIGraphicsBeginImageContextWithOptions(_launcherView.frame.size, NO, scale);
} else {
    UIGraphicsBeginImageContext(_launcherView.frame.size);
}

[_launcherView.layer renderInContext:UIGraphicsGetCurrentContext()];

UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

CGRect upRect = CGRectMake(0, 0, _launcherView.frame.size.width*scale, (diff - offset)*scale);
CGImageRef imageRefUp = CGImageCreateWithImageInRect([screenshot CGImage], upRect);
[self.screenshot1 setFrame:CGRectMake(0, 0, screenshot1.frame.size.width, diff - offset)];
[screenshot1 setContentMode:UIViewContentModeTop];
UIImage * img1 = [UIImage imageWithCGImage:imageRefUp];
[self.screenshot1 setBackgroundImage:img1 forState:UIControlStateNormal];
CGImageRelease(imageRefUp);

CGRect downRect = CGRectMake(0, (diff - offset)*scale, _launcherView.frame.size.width*scale, (screenshot.size.height - diff + offset)*scale);
CGImageRef imageRefDown = CGImageCreateWithImageInRect([screenshot CGImage], downRect);
[self.screenshot2 setFrame:CGRectMake(0, screenshot1.frame.size.height ,  screenshot2.frame.size.width, _launcherView.frame.size.height - screenshot1.frame.size.height)];
[screenshot2 setContentMode:UIViewContentModeTop];
UIImage * img2 = [UIImage imageWithCGImage:imageRefDown];
[self.screenshot2 setBackgroundImage:img2 forState:UIControlStateNormal];
CGImageRelease(imageRefDown);
MacTeo
  • 2,656
  • 1
  • 20
  • 23
  • Thanks! I don't have access to my machine ATM, but I'll try it as soon as I can and will accept it as answer. – sudo rm -rf Feb 28 '11 at 22:00
  • If you have any problem please tell me, but i'm sure it will be easily adapted to fit your needs. – MacTeo Feb 28 '11 at 22:03
  • Works quite nicely, thanks! I'm just wondering if this could be done with `UIImage`s instead of `UIButton`s. I dislike the "click" effect that the buttons force. – sudo rm -rf Mar 01 '11 at 04:06
  • Oh never mind, I can just use `screenshot1.adjustsImageWhenHighlighted = NO;` :) – sudo rm -rf Mar 01 '11 at 04:14
  • Exactly, the button is useful to close the folder – MacTeo Mar 01 '11 at 06:43
  • What the @#$@# - this answer is not only incomplete but if you use this code it has nothing but compile problems - variables are not even defined! – Sam B Apr 19 '13 at 16:24
  • If you look at the code is was written for iOS 3.1: four years ago... It is obvious that now has problems. – MacTeo Apr 21 '13 at 10:01
0

According to this session, iOS Memory Deep Dive, we had better use ImageIO to downscale images.

  • Memory use is related to the dimensions of the images, not the file size.
  • UIGraphicsBeginImageContextWithOptions always uses SRGB rendering-format, which use 4 bytes per pixel.
  • A image have load -> decode -> render 3 phases.

For the following image, if you use UIGraphicsBeginImageContextWithOptions we only need 590KB to load a image, while we need 2048 pixels x 1536 pixels x 4 bytes per pixel = 10MB when decoding enter image description here

while UIGraphicsImageRenderer, introduced in iOS 10, will automatically pick the best graphic format in iOS12. It means, you will save 75% of memory by replacing UIGraphicsBeginImageContextWithOptions with UIGraphicsImageRenderer if you don't need SRGB.

let url = NSURL(fileURLWithPath: filePath)

func resize() =

let imgSource = CGImageSourceCreateWithURL(url, nil)
if let imageSource = imgSource {
    let options: [NSString: Any] = [
        kCGImageSourceThumbnailMaxPixelSize: 100,
        kCGImageSourceCreateThumbnailFromImageAlways: true
    ]
    let scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)
}

I took some notes here for this session.

RY_ Zheng
  • 3,041
  • 29
  • 36
-2
- (UIImage *)getNewimage{
    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
Bhumit Mehta
  • 16,278
  • 11
  • 50
  • 64