I'm not sure I did understand that very well in the Apple doc. I'm considering using CATiledLayer to display a JPEG image. However, I only have an entire JPEG file at my disposal and no small tiles. Is it still possible to use a CATiledLayer and let it "tile" the JPEG?
Thanks!
No. You will have to tile them yourself, unfortunately. The WWDC 2010 videos on Core Animation discuss how to do this and in their sample code, they demonstrate how to use a CATileLayer when the tiles already exist.
Correction
I meant to say watch the Scroll View session. It's session 104 "Designing Apps with Scroll Views"
You may use This for making CATileLayer with image and Zoom functionality in scrollview.
- (void)viewDidLoad
{
[super viewDidLoad];
// You do not need to and must not autorelease [NSBundle mainBundle]
NSString *path = [[NSBundle mainBundle] pathForResource:#"img" ofType:#"jpg"];
NSData *data = [NSData dataWithContentsOfFile:path];
image = [UIImage imageWithData:data];
// CGRect pageRect = CGRectMake(0, 0, 1600, 2400);
CGRect pageRect = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
CATiledLayer *tiledLayer = [CATiledLayer layer];
tiledLayer.delegate = self;
tiledLayer.tileSize = CGSizeMake(256.0, 256.0);
tiledLayer.levelsOfDetail = 5; // was 1000, which makes no sense. Each level of detail is a power of 2.
tiledLayer.levelsOfDetailBias = 5; // was 1000, which also makes no sense.
// Do not change the tiledLayer.frame.
tiledLayer.bounds = pageRect; // I think you meant bounds instead of frame.
// Flip the image vertically.
tiledLayer.transform = CATransform3DMakeScale(1.0f, -1.0F, 1.0f);
myContentView = [[UIView alloc] initWithFrame:CGRectMake(500,400,image.size.width,image.size.height)];
[myContentView.layer addSublayer:tiledLayer];
// UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
scrollView=[[UIScrollView alloc]initWithFrame:CGRectMake(10, 10, 300, 400)];
scrollView.backgroundColor = [UIColor whiteColor];
// [scrollView setContentSize:CGSizeMake(image.size.width,image.size.height)];
[scrollView setContentSize:image.size];
scrollView.maximumZoomScale = 32; // = 2 ^ 5
scrollView.delegate = self;
// scrollView.contentSize = pageRect.size;
[scrollView addSubview:myContentView];
[self.view addSubview:scrollView];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return myContentView;
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"img" ofType:#"jpg"];
NSData *data = [NSData dataWithContentsOfFile:path];
image = [UIImage imageWithData:data];
CGRect imageRect = CGRectMake (0.0, 0.0, image.size.width, image.size.height);
CGContextDrawImage (context, imageRect, [image CGImage]);
}
The easier way is to just downscale the image until it fits (I think devices support up to 2044x2044 or so). You can create subimages of a CGImage with CGImageCreateWithImageInRect()
Related
I have the following method which takes some CAShapeLayers and converts them into a UIImage. The UIImage is used in a cell for a UITableView (much like the photos app when you select a photo from one of your libraries). This method is called from within a GCD block:
-(UIImage*) imageAtIndex:(NSUInteger)index
{
Graphic *graphic = [[Graphic graphicWithType:index]retain];
CALayer *layer = [[CALayer alloc] init];
layer.bounds = CGRectMake(0,0, graphic.size.width, graphic.size.height);
layer.shouldRasterize = YES;
layer.anchorPoint = CGPointZero;
layer.position = CGPointMake(0, 0);
for (int i = 0; i < [graphic.shapeLayers count]; i++)
{
[layer addSublayer:[graphic.shapeLayers objectAtIndex:i]];
}
CGFloat largestDimension = MAX(graphic.size.width, graphic.size.height);
CGFloat maxDimension = self.thumbnailDimension;
CGFloat multiplicationFactor = maxDimension / largestDimension;
CGSize graphicThumbnailSize = CGSizeMake(multiplicationFactor * graphic.size.width, multiplicationFactor * graphic.size.height);
layer.sublayerTransform = CATransform3DScale(layer.sublayerTransform, graphicThumbnailSize.width / graphic.size.width, graphicThumbnailSize.height / graphic.size.height, 1);
layer.bounds = CGRectMake(0,0, graphicThumbnailSize.width, graphicThumbnailSize.height);
UIGraphicsBeginImageContextWithOptions(layer.bounds.size, NO, 0);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = [UIGraphicsGetImageFromCurrentImageContext() retain];
UIGraphicsEndImageContext();
[layer release];
[graphic release];
return [image autorelease];
}
For whatever reason, when I'm scrolling the UITableView and loading the images in, it is stuttering a little bit. I know the GCD code is fine because it's worked previously so it appears something in this code is causing the stuttering. Does anyone know what that could be? Is CAAnimation not thread safe? Or does anyone know a better way to take a bunch of CAShapeLayers and convert them into a UIImage?
In the end I believe:
[layer renderInContext:UIGraphicsGetCurrentContext()];
Cannot be done on a separate thread, so I had to do the following:
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
//draw the mutable paths of the CAShapeLayers to the context
UIImage *image = [UIGraphicsGetImageFromCurrentImageContext() retain];
UIGraphicsEndImageContext();
There is a great example of this (where I learned to do it) in the WWDC2012 video "Building Concurrent User Interfaces on iOS"
I am creating thumbnails and showing those thumbnails in gridView(using AQgridView). Thumbnails shown in gridView is too blurry and is not what I want. I am attached my code. Please help.
Here is my code:-
- (void)viewDidLoad
{
[super viewDidLoad];
imageArray = [[NSMutableArray alloc] init];
self.gridView = [[AQGridView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
self.gridView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
self.gridView.autoresizesSubviews = YES;
self.gridView.delegate = self;
self.gridView.dataSource = self;
[self.view addSubview:gridView];
[self makeThumbs];
// Do any additional setup after loading the view from its nib.
}
///////////Making thumb from PDF file///////////////
-(void)makeThumbs{
NSString* finalPath = [[NSBundle mainBundle] pathForResource:#"Maths" ofType:#"pdf" inDirectory:nil];
NSURL* pdfFileUrl = [NSURL fileURLWithPath:finalPath];
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((__bridge CFURLRef)pdfFileUrl);
CGPDFPageRef page;
CGRect aRect = CGRectMake(0, 0, 70, 100); // thumbnail size
UIGraphicsBeginImageContext(aRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
NSUInteger totalNum = CGPDFDocumentGetNumberOfPages(pdf);
for(int i = 0; i < totalNum; i++ ) {
UIImage* thumbnailImage;
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, aRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetGrayFillColor(context, 1.0, 1.0);
CGContextFillRect(context, aRect);
// Grab the first PDF page
page = CGPDFDocumentGetPage(pdf, i + 1);
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFMediaBox, aRect, 0, true);
// And apply the transform.
CGContextConcatCTM(context, pdfTransform);
CGContextDrawPDFPage(context, page);
// Create the new UIImage from the context
thumbnailImage = UIGraphicsGetImageFromCurrentImageContext();
//Use thumbnailImage (e.g. drawing, saving it to a file, etc)
CGContextRestoreGState(context);
[imageArray addObject:thumbnailImage];
}
NSLog(#"image array count is %d",[imageArray count]);
if ([imageArray count]>0) {
[self.gridView reloadData];
}
UIGraphicsEndImageContext();
CGPDFDocumentRelease(pdf);
}
Here image showing blurry thumbnails that are created on iPad Simulator
Try using UIGraphicsBeginImageContextWithOptions passing 0.0 as scale (to use the screen scale).
So I have UIScrollView. I download img from web server and add subview to uiscrollview. I'm doing this asynchronious. It downloads pictures very well but it just doesn't display them. I need to tap on the screen and move a little bit and after that the pictures appears... Is it a way do display them by the code? thanks
myWidth = [[UIScreen mainScreen] bounds].size.width;
customBtnWidth = myWidth - 30;
NSData * imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString: pictureUrl]];
UIImage *img = [[UIImage alloc]initWithData:imageData];
UIImageView *imgView = [[UIImageView alloc] initWithImage:img];
imgView.frame = CGRectMake( x*customBtnWidth, self.videoView.bounds.size.height ,customBtnWidth,customBtnWidth);
imgView.center = CGPointMake(15+ customBtnWidth /2 + x * customBtnWidth + x*30, customBtnWidth / 2);
[self.scrollView addSubview:imgView];
//
//[self.scrollView motionBegan:UIEventSubtypeNone withEvent:UIEventSubtypeNone];
scrollView.contentSize = CGSizeMake(self.photosView.bounds.size.width+ number*customBtnWidth, customBtnWidth );
//[self.scrollView setNeedsDisplay];
//[self.scrollView bringSubviewToFront:imgView];
[imageData release];
[img release];
[imgView release];
I see that you have already tried [self.scrollView setNeedsDisplay]; but its commented out. Did that not work?
You can also try setting scrollView's contentMode to UIViewContentModeRedraw like self.scrollView.contentMode = UIViewContentModeRedraw; while initializing the scrollView and check if that solves it.
I'm trying to create a UIImage from an image context and set that as the contents of a CALayer (the image will end up split up and spread across multiple CALayers). The only problem is, it doesn't seem to be aligning correctly - it's offset by 30 pixels or so.
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
number = 1;
background = [UIImage imageNamed:#"numberBackground.png"];
// draw images
UIGraphicsBeginImageContext(CGSizeMake(background.size.width, background.size.height));
[background drawAtPoint:CGPointMake(0, 0)];
NSString *numberString = [[NSString alloc] initWithString:[NSString stringWithFormat:#"%d", number]];
[[UIColor whiteColor] set];
[numberString drawAtPoint:CGPointMake(0, 0) withFont:[UIFont fontWithName:#"HelveticaNeue" size:128]];
UIImage *front = [UIGraphicsGetImageFromCurrentImageContext() retain];
UIGraphicsEndImageContext();
// top layer
topLayer = [CALayer layer];
[topLayer setContents:(id)front.CGImage];
[topLayer setContentsGravity:#"kCAGravityTop"];
[topLayer setFrame:CGRectMake(0, 0, background.size.width, background.size.height / 2)];
[topLayer setAnchorPoint:CGPointMake(0, 1)];
[topLayer setPosition:CGPointMake(0, background.size.height / 2)];
[topLayer setMasksToBounds:NO];
[topLayer setBackgroundColor:[UIColor lightGrayColor].CGColor];
[self.layer addSublayer:topLayer];
}
return self;
}
I don't have enough reputation points to post an image yet, but here's how the layer renders, as well as how it should render and the full image: link text
Found my mistake - setContentsGravity should take the built-in string constant kCAGravityTop, not my NSString literal #"kCAGravityTop".
Here is the problem... I am using CA Tiled Layer to display a large jpg. The view loads okay, and when I go to scroll around, it works fine. However, as soon as I zoom in or out once, it scrolls to the top left (to the anchor point) and will not scroll at all. The zooming works fine, but I just cannot scroll.
Here is my code:
#import <QuartzCore/QuartzCore.h>
#import "PracticeViewController.h"
#implementation practiceViewController
//#synthesize image;
- (void)viewDidLoad
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"H-5" ofType:#"jpg"];
NSData *data = [NSData dataWithContentsOfFile:path];
image = [UIImage imageWithData:data];
CGRect pageRect = CGRectMake(0, 0, image.size.width, image.size.height);
CATiledLayer *tiledLayer = [CATiledLayer layer];
tiledLayer.anchorPoint = CGPointMake(0.0f, 1.0f);
tiledLayer.delegate = self;
tiledLayer.tileSize = CGSizeMake(1000, 1000);
tiledLayer.levelsOfDetail = 6;
tiledLayer.levelsOfDetailBias = 0;
tiledLayer.bounds = pageRect;
tiledLayer.transform = CATransform3DMakeScale(1.0f, -1.0f, 0.3f);
myContentView = [[UIView alloc] initWithFrame:self.view.bounds];
[myContentView.layer addSublayer:tiledLayer];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
scrollView.delegate = self;
scrollView.contentSize = pageRect.size;
scrollView.minimumZoomScale = .2;
scrollView.maximumZoomScale = 1;
[scrollView addSubview:myContentView];
[self.view addSubview:scrollView];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return myContentView;
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"H-5" ofType:#"jpg"];
NSData *data = [NSData dataWithContentsOfFile:path];
image = [UIImage imageWithData:data];
CGRect imageRect = CGRectMake (0.0, 0.0, image.size.width, image.size.height);
CGContextDrawImage (ctx, imageRect, [image CGImage]);
}
#end
See the above listed question