Here is my code...
CCSprite *u = [CCSprite spriteWithFile:#"1_S.png" rect:CGRectMake(0, 0, 27, 27)];
u.position = ccp((45.7*i+45.7*(i+1))/2, 467);
u.tag = i;
[self addChild:u];
and in my resource folder i have 2 image files named
1_S.png
and
1_S#2x.png
.As i read the the doc
https://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/SupportingResolutionIndependence/SupportingResolutionIndependence.html#//apple_ref/doc/uid/TP40007072-CH10
i think when i run this code in iPhone 4 the image named
1_S#2x.png
should load...but it isn't.....the first image is loaded.....why?? IS THIS ANY VERSION PROBLEM???
there is a bug in the OS4 code preventing retina display from working with cocos2d
See this link regarding issue 910:
http://www.cocos2d-iphone.org/wiki/doku.php/release_notes:0_99_4#
Issue #910 is still open.
The workaround is to edit CCTextureCache.m and make the following changes:
//# work around for issue #910
#if 0 // <---- change it to #if 1
UIImage *image = [UIImage imageNamed:path];
tex = [ [CCTexture2D alloc] initWithImage: image ];
#else
// prevents overloading the autorelease pool
UIImage *image = [ [UIImage alloc] initWithContentsOfFile: fullpath ];
tex = [ [CCTexture2D alloc] initWithImage: image ];
[image release];
#endif //
Again, issue #910 is not a cocos2d bug, but an iOS4 bug. ”#2x” images are not loaded if you use UIImage initWithContentOffile (but the documentation says it should work). So the work around is to use UIImage imageNamed, but it is not enabled by default because it will consume much more memory.
Related
The code to render a MKMapView to an UIImage no longer works in iOS 7. It returns an empty image with nothing but the word "Legal" at the bottom and a black compass on the top right. The map itself is missing. Below is my code:
UIGraphicsBeginImageContext(map.bounds.size);
[map.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Map is an IBOutlet that points to a MKMapView. Is there any way to render a MKMapView correctly in iOS 7?
From this SO post:
You can use MKMapSnapshotter and grab the image from the resulting MKMapSnapshot. See the discussion of it WWDC 2013 session video, Putting Map Kit in Perspective.
For example:
MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
options.region = self.mapView.region;
options.scale = [UIScreen mainScreen].scale;
options.size = self.mapView.frame.size;
MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
UIImage *image = snapshot.image;
NSData *data = UIImagePNGRepresentation(image);
[data writeToFile:[self snapshotFilename] atomically:YES];
}];
Having said that, the renderInContext solution still works for me. There are notes about only doing that in the main queue in iOS7, but it still seems to work. But MKMapSnapshotter seems like the more appropriate solution for iOS7.
I am using Grand Central Dispatch to queue a task to capture a UIView as an image. Everything is working fine with this except that the image capturing running on a queue is taking quite a long time.
Is there any way to speed this up or improve my technique. Here is the code to capture and scale the image, which is then set to a UIImageView's image for displaying.
(void)captureScrollViewImageForLayoverView
{
// capture big map image
CGSize size = mainView.bounds.size;
UIGraphicsBeginImageContext(size);
[[mainView layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// scale map
size = myLocationOverlay.bounds.size;
UIGraphicsBeginImageContext(size);
[newImage drawInRect:CGRectMake(0,0,size.width,size.height)];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
myLocationOverlay.imageMap.image = scaledImage;
}
And Here is the code that is queueing the task.
...
mapImageDrawQueue = dispatch_queue_create("mapImage.drawQueue", NULL);
(void)captureScrollViewImageForLayoverViewWrapper {
// multithreaded approach to draw map
dispatch_async(mapImageDrawQueue, ^{ [self captureScrollViewImageForLayoverView]; });
}
I used to load images at queue in my app with same issue you mentioned. I checked official programming guide, remembered it told that it can't guarantee the queue run immediately after you call it. So I used NSThread do the job, and it's working well:
NSThread* myThread = [[NSThread alloc] initWithTarget:self
selector:#selector(captureScrollViewImageForLayoverView)
object:nil];
[myThread start];
Remember add these lines to the function captureScrollViewImageForLayoverView:
At top : NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
At end : [pool release];
Check this doc to know more - Threading Programming Guide
Hope it helps.
In my code I stretch the size of an image to a specified size. The code works fine so far.
I got the problem that "UIGraphicsBeginImageContext ()" does not release the memory of the new image. So, the memory is full after about 10 minutes and the app is terminated by IOS.
Does anyone have a solution to this problem?
- (CCSprite *)createStretchedSignFromString:(NSString *)string withMaxSize:(CGSize)maxSize withImage:(UIImage *)signImage
{
// Create a new image that will be stretched with 10 px cap on each side
UIImage *stretchableSignImage = [signImage stretchableImageWithLeftCapWidth:10 topCapHeight:10];
// Set size for new image
CGSize newImageSize = CGSizeMake(260.f, 78.0f);
// Create new graphics context with size of the answer string and some cap
UIGraphicsBeginImageContext(newImageSize);
// Stretch image to the size of the answer string
[stretchableSignImage drawInRect:CGRectMake(0.0f, 0.0f, newImageSize.width, newImageSize.height)];
// Create new image from the context
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
// End graphics context
UIGraphicsEndImageContext();
// Create new texture from the stretched
CCTexture2D *tex = [[CCTexture2D alloc] initWithImage:resizedImage];
CCSprite *spriteWithTex = [CCSprite spriteWithTexture:tex];
[[CCTextureCache sharedTextureCache] removeTexture:tex];
[tex release];
// Return new sprite for the sign with the texture
return spriteWithTex;
}
Called by this code:
// Create image from image path
UIImage *targetSignImage = [UIImage imageWithContentsOfFile:targetSignFileName];
// Create new sprite for the sign with the texture
CCSprite *plainSign = [self createStretchedSignFromString:answerString withMaxSize:CGSizeMake(260.0f, 78.0f) withImage:targetSignImage];
Thank you so far.
I've found the solution to my problem.
First of all, the code shown above is correct and without leaks.
The problem was caused by the removal of the sprite that has planSign as child. The sprite is removed by a timer that runs on a different thread, so on an others NSAutoreleasePool.
[timerClass removeTarget:targetWithSign] released an empty pool.
[timerClass performSelectorOnMainThread:#selector(removeTarget:) withObject:targetWithSign waitUntilDone:NO]; released the correct pool, which contains the target sprite and its child plainSign.
Thanks to SAKrisT and stigi for your suggestions.
I have an animated image which works great. It consists of 180 high quality images and it plays fine and loops continuously. My problem is that the first time I load the view containing these images it takes a long time to load. Every subsequent time after that it loads immediately as I am assuming that the images have been cached or preloaded!!! I come from a flash background and as I am sure you aware preloaders are as common as muck so I don't feel this should be difficult to find but after countless googling I cannot find any good examples on preloading or any articles on why there is a delay and what to do about it.
So my question(s) is this:
Is there a checkbox in the info.plist to preload all my images at the start of the app?
How can you preload images and are there any simple example projects that I could look at?
Is this the best way to implement what is essentially a video but has been output to a png sequence?
Is there another method as viewDidLoad does not work as I expect it to do. It traces "FINISHED LOADING IMAGES" (see code below) but the view does not show for a second or two after the images have been loaded so if the view does not show until the images have loaded then neither will the UIActivityIndicatorView which is also in the same view.
How do you do event listening in objective c?
Below is the code in the viewDidLoad which I believe is fairly standard:
Any help is greatly appreciated as I am banging my head on a brick wall on something that seems so basic in ui development. Help :)
- (void)viewDidLoad {
[super viewDidLoad];
imageArray = [[NSMutableArray alloc] initWithCapacity:IMAGE_COUNT];
NSLog(#"START LOADING IMAGES");
// Build array of images, cycling through image names
for (int i = 0; i < IMAGE_COUNT; i++){
[imageArray addObject:[UIImage imageNamed: [NSString stringWithFormat:#"Main_%d.png", i]]];
}
animatedImages = [[UIImageView alloc] initWithFrame:CGRectMake(0,20,IMAGE_WIDTH, IMAGE_HEIGHT)];
animatedImages.animationImages = [NSArray arrayWithArray:imageArray];
animatedImages.animationDuration = 6.0;
animatedImages.animationRepeatCount = 0;
[self.view addSubview:animatedImages];
animatedImages.startAnimating;
[animatedImages release];
NSLog(#"FINISH LOADING IMAGES");
}
Cheers
M
In case someone finds this question, I have an answer, which is to pre-render the images like this.
NSMutableArray *menuanimationImages = [[NSMutableArray alloc] init];
for (int aniCount = 1; aniCount < 21; aniCount++) {
NSString *fileLocation = [[NSBundle mainBundle] pathForResource: [NSString stringWithFormat: #"bg%i", aniCount + 1] ofType: #"png"];
// here is the code to load and pre-render the image
UIImage *frameImage = [UIImage imageWithContentsOfFile: fileLocation];
UIGraphicsBeginImageContext(frameImage.size);
CGRect rect = CGRectMake(0, 0, frameImage.size.width, frameImage.size.height);
[frameImage drawInRect:rect];
UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// then add the resulting image to the array
[menuanimationImages addObject:renderedImage];
}
settingsBackground.animationImages = menuanimationImages;
I have tried multiple other methods of pre-loading images, and this is the only thing I've found that works.
My problem is that the first time I load the view containing these images it takes a long time to load. Every subsequent time after that it loads immediately as I am assuming that the images have been cached or preloaded
you are right at this point ...... as you are using method imageNamed: for this method document quotes.....
This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.
so in my opinion, rather than doing following stuff in viewDidLoad, you should do it earlier where delay is of not considerable......
for (int i = 0; i < IMAGE_COUNT; i++)
{
[imageArray addObject:[UIImage imageNamed: [NSString stringWithFormat:#"Main_%d.png", i]]];
}
another approach
- (void)spinLayer:(CALayer *)inLayer duration:(CFTimeInterval)inDuration
direction:(int)direction
{
CABasicAnimation* rotationAnimation;
// Rotate about the z axis
rotationAnimation =
[CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
// Rotate 360 degress, in direction specified
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 * direction];
// Perform the rotation over this many seconds
rotationAnimation.duration = inDuration;
rotationAnimation.repeatCount = 100;
//rotationAnimation.
// Set the pacing of the animation
//rotationAnimation.timingFunction =
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
// Add animation to the layer and make it so
[inLayer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
}
this method will help in animation call it as follow(I am assuming that you are putting above method in same class where you have imageView.
[self spinLayer:yourImageView.layer duration:5.0
direction:<-1 or 1 for anti clockwise or clockwise spin>];
remember just set only one image to that imageView(which you wish to animate.
thanks,
I'm trying to add more than 10 pictures on ScrollView.
NSUInteger i;
for (i = 1; i <= numberOfImage; i++)
{
NSString *imageName = [NSString stringWithFormat:#"d%dimage%d.png", imageSection, i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView addSubview:imageView];
[imageView release];
}
This code is from Apple example and it works fine. But if the variable 'i' is bigger than 10, 'UIImage *image' is empty. The imageName seems to correct. But I don't know why it does not load image. Does anybody sees the problem??
And one more thing. If I do like that, does iOS controls memory automatically? I mean it's kind of wasting memory if all (more than 10) images are loaded on memory even they are not displayed. I've heard that iOS loads images only displayed on screen and free images those are not displayed. Is that right?
Thanks for reading.
UIimage imageNamed: does cache file contents. I recommend you to use UIImage +imageWithContentsOfFile: that doesn't cache at all in such situation.
You have to make sure the images have the correct name (like 0dimage11.jpg) and are added to the XCode project.
You probably have to set the contentSize accordingly.
IOS will not do that magic memory management thing unless you are using a CATiledLayer based UIView.
If UIImage is not created, it because the name does not refer to an image in the resource folder and you should have an exception.
You need to have the correct file names. You said you think the file names are correct.
NSLog(#"Loop %d: d%dimage%d.png", i,imageSection, i]);
Log out the file names so you can see what the names actually are. Place that line in your loop.
NSUInteger i;
for (i = 1; i <= numberOfImage; i++)
{
NSString *imageName = [NSString stringWithFormat:#"d%dimage%d.png", imageSection, i];
NSLog(#"Loop %d: d%dimage%d.png", i,imageSection, i]);
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView addSubview:imageView];
[imageView release];
}
Then monitor the filenames in the debugger and see if those image files exist, and in the same directory where Apple put their image files.
Hey,Its not good way to load 10 images at once.All things you have done correct and still you'r image display empty then please check log may be there is memory warning.You can you apple's sample code photoscroller. It will do all thing that you want and also manages good memory.there are two method one is using CATieldLayer and another one directly load images. I recommended you to use method that uses CATieldLayer.
Sorry guys. This is turned out to be my fault. well, not exactly MY fault. Designers throw me many files with wrong filenames like d1imgae11.png... Anyway tips from all you guys gave me different view to see the problem and I got another hint about not to cache images. Thanks.