Mapping CGContext and Retina

guys this is my code:

- (void) renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx { //background CGContextSetFillColorWithColor(ctx, [[UIColor colorWithRed:((float)238 / 255.0f) green:((float)233 / 255.0f) blue:((float)215 / 255.0f) alpha:1] CGColor]); CGContextFillRect(ctx, CGRectInset(leavesView.bounds, 0, 0)); //text CGContextSetTextDrawingMode(ctx, kCGTextFill); CGContextSetTextMatrix(ctx, CGAffineTransformMake(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)); CGContextSetFillColorWithColor(ctx, [[UIColor blackColor] CGColor]); UIGraphicsPushContext(ctx); CGContextSaveGState(ctx); CGContextTranslateCTM(ctx, 0.1f, leavesView.bounds.size.height); CGContextScaleCTM(ctx, 1.0f, -1.0f); CGRect textRect = CGRectMake(5, 5, leavesView.bounds.size.width-10, leavesView.bounds.size.height-10); if (pages.count > 0 && pages.count-1 >= index) { [[pages objectAtIndex:index] drawInRect:textRect withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentLeft]; } CGContextRestoreGState(ctx); UIGraphicsPopContext(); } 

It works great on iPhone 2G, 3G, 3GS, but I have problems on newer models.

In the text of the retina, an attempt is made not to double the resolution, as in the standard.

Do you have any ideas?

+6
source share
4 answers

Try setting the contentScale variable of the layers as follows:

 layer.contentsScale = [UIScreen mainScreen].scale; 

This should make the code adapted to display the retina / nontrina.

+16
source

It looks like you are using a Leaves project on git. I had the same problem in my project and it was solved as follows.

First, you need to determine the size and scale of the original Core Graphics context created in imageForPageIndex: in LeavesCache.m according to the screen scale of the devices. Be sure to also scale the CGContextClipToRect.

 - (CGImageRef) imageForPageIndex:(NSUInteger)pageIndex { CGFloat scale = [[UIScreen mainScreen] scale]; // we need to size the graphics context according to the device scale CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate(NULL, pageSize.width*scale, pageSize.height*scale, 8, /* bits per component*/ pageSize.width*scale * 4, /* bytes per row */ colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(colorSpace); CGContextClipToRect(context, CGRectMake(0, 0, pageSize.width*scale, pageSize.height*scale)); CGContextScaleCTM(context, scale, scale); [dataSource renderPageAtIndex:pageIndex inContext:context]; CGImageRef image = CGBitmapContextCreateImage(context); CGContextRelease(context); [UIImage imageWithCGImage:image]; CGImageRelease(image); return image; } 

Then, in setUpLayers in LeavesView.m, you need to apply the device screen scale to each CALayer that is initialized. As Brad Larson wrote in a similar question :

By default, your CALayer does not transmit its Quartz content at a higher resolution of the Retina screen. You can enable this using the following code:

 layer.contentsScale = [[UIScreen mainScreen] scale]; 

So, here are the first few lines from setUpLayers in LeavesView.m, where I apply device scale to topPage CALayer. You will need to do this for all CALayers and CAGradientLayers initialized in setUpLayers:

 - (void) setUpLayers { // Set the backgound image of the leave view to the book page UIColor *background = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"open_book_page_turn.png"]]; self.clipsToBounds = YES; topPage = [[CALayer alloc] init]; topPage.contentsScale = [[UIScreen mainScreen] scale]; // We need to apply the device display scale to each layer topPage.masksToBounds = YES; topPage.contentsGravity = kCAGravityLeft; topPage.backgroundColor = [[UIColor whiteColor] CGColor]; topPage.backgroundColor = [background CGColor]; ... } 
+3
source

You can simply set the scale when starting the context.

 + (UIImage *)imageWithView:(UIView *)view { UIGraphicsBeginImageContextWithOptions([view bounds].size, NO, [[UIScreen mainScreen] scale]); [[view layer] renderInContext:UIGraphicsGetCurrentContext()]; UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return result; } 
+2
source

For Swift 3

 func getImageFromContext() -> UIImage{ UIGraphicsBeginImageContextWithOptions(self.frame.size, false, UIScreen.main.scale) self.drawHierarchy(in: self.bounds, afterScreenUpdates: true) self.layer.render(in: UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image! } 
0
source

Source: https://habr.com/ru/post/903980/


All Articles