I'm trying to set a background image for a CCButton and make sure it stretches or minimizes to the exact size of the CCButton:
-(void)setBackgroundSpriteFrame: (NSString*)spriteFrameFileName
{
NSString* fullFileName = [NSString stringWithFormat:#"%#.png", spriteFrameFileName];
CCSpriteFrame *spriteFrame = [CCSpriteFrame frameWithImageNamed:fullFileName];
[super setBackgroundSpriteFrame:spriteFrame forState:CCControlStateNormal];
double scaleValue = self.contentSize.height / spriteFrame.rect.size.height;
[self.background setScale:scaleValue];
self.fileName = spriteFrameFileName;
}
This method resides inside a class that inherits from CCButton.
The problem is that I see the background image but it is squeezed in a weird way (see image) and not minimized\stretched to the size of the button.
Please note that the image and the button are squares so no need to scale X\Y separately, and also note that the CCButton is generated with SprtieBuilder and not by code.
'Weird look':
Original look:
Thanks
Thanks 'YvesLeBorg' for trying to help, I managed to solve this issue.
I'm posting the code that helped me.
Hope it will help others.
NSString* fullFileName = [NSString stringWithFormat:#"%#.png", spriteFrameFileName];
CCTexture *texture = [CCTexture textureWithFile:fullFileName];
texture.contentScale = 2.0;
[super setBackgroundSpriteFrame:[texture createSpriteFrame] forState:CCControlStateNormal];
[self setScale:0.40];
self.fileName = spriteFrameFileName;
Have not enough reputation to comment, so please excuse to write an answer instead.
When I encountered the same problem I found a net solution on the cocos2d forum (no link, sry). Summarizing it - there is no need to scale the image separately. But one shall follow 2 rules:
1) the image should be at least same size than the element (CCButton) and
2) not forget to explicitly set the forState:CCControlStateNormal
the usage of contentScale as you did is not needed in that case.
Related
I'm trying to have the AVSpeechSynthesizer read the user's text selection in a UITextView. It works quite well when I double-tap a word but whenever I try to select more than one word, the AVSpeechSynthesizer starts speaking words in a weird way. Is there a way to prevent this behaviour or to retrieve the user's text selection only when they release the selecting finger ?
Any help would be greatly appreciated.
Here is what I do :
-(void) textViewDidChangeSelection:(UITextView *)textView{
NSRange r = textView.selectedRange;
if (!(r.length == 0)) {
NSString *selText = [self.entryTextField2.text substringWithRange:r];
AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:selText];
[utterance setRate:0.5f];
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:self.selectedSpeakerLanguage];
[self.synthesizer speakUtterance:utterance];
}
}
I think I should have done it the Apple way from the start or at least the IOS way. Reading the selectedRange directly from textViewDidChangeSelection: is definitely not a good idea. You need to use a [UIMenuController sharedMenuController] to present a UIMenuItem that triggers the readSelection method instead.
I have an animated GIF successfully loaded into an NSData or NSBitmapImageRep object. Reference for NSBitmapImageRep
I've figured how to return data like the number of frames in that gif using:
NSNumber *frames = [bitmapRep valueForProperty:#"NSImageFrameCount"];
However, I'm a bit confused as to how I can actually access that frame as its own object.
I think one of these two methods will help, but I'm not actually sure how they'll get the individual frame for me.
+ representationOfImageRepsInArray:usingType:properties:
– representationUsingType:properties:
Any help appreciated. Thanks
I've figured how to return data like the number of frames in that gif using:
NSNumber *frames = [bitmapRep valueForProperty:#"NSImageFrameCount"];
However, I'm a bit confused as to how I can actually access that frame as its own object.
To have access to a special frame indexOfFrame ( 0 <= indexOfFrame < [frames intValue] ) you only need to set the NSImageCurrentFrame and you are done. There is no need to use CG-functions or make copies of frames. You can stay in the object oriented Cocoa world. A small example shows the duration of all GIF frames:
NSNumber *frames = [bitmapRep valueForProperty:#"NSImageFrameCount"];
if( frames!=nil ){ // bitmapRep is a Gif imageRep
for( NSUInteger i=0; i<[frames intValue]; i++ ){
[bitmapRep setProperty:NSImageCurrentFrame
withValue:[NSNumber numberWithUnsignedInt:i] ];
NSLog(#"%2d duration=%#",
i, [bitmapRep valueForProperty:NSImageCurrentFrameDuration] );
}
}
Another example: write all frames of a GIF image as PNG files to the filesystem:
NSNumber *frames = [bitmapRep valueForProperty:#"NSImageFrameCount"];
if( frames!=nil ){ // bitmapRep is a Gif imageRep
for( NSUInteger i=0; i<[frames intValue]; i++ ){
[bitmapRep setProperty:NSImageCurrentFrame
withValue:[NSNumber numberWithUnsignedInt:i] ];
NSData *repData = [bitmapRep representationUsingType:NSPNGFileType
properties:nil];
[repData writeToFile:
[NSString stringWithFormat:#"/tmp/gif_%02d.png", i ] atomically:YES];
}
}
I've figured how to return data like the number of frames in that gif using:
NSNumber *frames = [bitmapRep valueForProperty:#"NSImageFrameCount"];
However, I'm a bit confused as to how I can actually access that frame as its own object.
As far as I know, you can't—not from an NSBitmapImageRep.
Instead, create a CGImageSource from the GIF data, and use CGImageSourceCreateImageAtIndex to extract each frame (preferably as you need it).
Alternatively, you might try setting the NSImageCurrentFrame property. If you need a rep for each frame, make as many copies as there are frames (minus one, since you have the original), and set each rep's current frame to a different number. But I haven't tried that, so I'm not sure it will actually work.
Basically, NSBitmapImageRep's GIF support is weird, so you should just use CGImageSource.
I think one of these two methods will help, but I'm not actually sure how they'll get the individual frame for me.
+ representationOfImageRepsInArray:usingType:properties:
– representationUsingType:properties:
No, those methods are for serializing an image (or image rep). They're for writing data out, not reading it in. (Notice what constants those methods expect in their type parameters.)
If you want to have a look at some working source code for a GIF decoder for iOS (works for MacOSX too) then you can find it AVGIF89A2MvidResourceLoader.m at github. The approach is to use the ImageIO framework and call CGImageSourceCreateWithData() along with CGImageSourceCreateImageAtIndex() to get access to the Nth gif image in the file. But, there are some tricky details related to detecting if a transparent pixel appears in the GIF and how to write the results to a file to avoid running out of memory if the GIF is really long that might not be obvious.
I am using 150 images in a sequence for animation .
Here is my code.
NSMutableArray *arrImages =[[NSMutableArray alloc]initWithCapacity:0];
for(int i = 0; i <=158; i++)
{
UIImage* image = [UIImage imageNamed:[NSString stringWithFormat:#"baby%05d.jpg",i]];
[arrImages addObject:image];
}
babyimage.animationImages = arrImages;
[arrImages release];
babyimage.animationDuration=6.15;
[babyimage startAnimating];
but it is taking too much memory.After playing it for 1 minute it shows memory warnings in console. and then crashed.i have reduced images resolution also and i can't make it less then 150 for better quality.
Is there any better way to do this animation without memory issue.
Thanks a lot
plz help ...
Instead of
[UIImage imageNamed:[NSString stringWithFormat:#"baby%05d.jpg",i]]
use
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"baby%05d.jpg",i] ofType:nil]]
Reason is imageNames caches image and does not release until it release memory warning
Edit
Also, don't store entire image into array, just save image name if you want or don't save anything. This will also take much memory.
I am unaware as to what the animation is you haven't specified it. But if I were doing the code, I would follow the following algorithm.
This is assuming there's only one image shown at a particular time but during transition, you will end up having two convolving in a way.
procedureAnimate:
photo_1 = allocate(file_address_array[i++])
while i < MAX_PHOTOS
photo_2 = allocate(file_address_array[i++])
photo_3 = allocate(file_address_array[i++])
perform_animation(photo_1, photo_2)
release(photo_1)
photo_1 = photo_2
photo_2 = photo_3
release(last_two)
I not sure if this is the_perfect_way of doing such a thing. But this will be a lot more efficient.
(May be there's something terribly wrong with the alloc/release login but this is consistent with my working at 5.14 AM in the morning). Let me know if this doesn't work.
i am trying to set texture with this :
[[self setSpriteByTag] setTexture:[[CCTextureCache sharedTextureCache] addImage:[NSString stringWithFormat:#"%#0001.png",face]]];
when [self setSpriteByTag] return a sprite face is an image string, and they both ok because i have logged them.
this sprite is a child of a page in ccscrolayer :
one page of the layer pages :
CCLayer *page1 = [[CCLayer alloc] init];
BACK.position=ccp(screenSize.width/2,screenSize.height/2);
[page1 addChild:BACK];
when i was trying to change BACK's image , with the command i wrote here.
what happen is that i see a white screen.
i have check that the image is in my assets .
what could be the problem ?
the facr that i change a sprite that is a child of a page ?
edit :
this is the function that gives me the sprite BACK:
-(CCSprite*)setSpriteByTag
{
int currentPage=[scroller currentScreen];
[globals sharedGlobals].currentPageG=currentPage; //move to touch ended?
currentPage=currentPage+1;
//NSLog(#"PAGE:%d",currentPage);
if(currentPage==1)
{[globals sharedGlobals].WhatFace =#"BeastFace"; return BACK;}
else if(currentPage==2)
{[globals sharedGlobals].WhatFace =#"BlueFace"; return BACK1;}
else if(currentPage==3)
It gets white only in case when image is not present in the resources.. I checked running same code.. It works fine.. If I put wrong name of the image which is not present.. It changes to white... Please check for the image
[NSString stringWithFormat:#"%#0001.png",face]
M sure problem is in the image name.. :)
[NSString stringWithFormat:#"%#0001.png",face]
Your filenames will have to have the format "xxxxx0001.png". Assuming the face variable is the string "BeastFace" then the filename to load will be "BeastFace0001.png".
So far the obvious but keep in mind that the file "Beastface0001.png" will not load on the device, and neither will "beastface0001.png" because iOS devices use a case-sensitive file system. It will work on the iOS Simulator though.
I have a panning gesture that pans across a series of images. I'm not sure how to correctly manage the memory for this, after panning for a certain length of time, I'm getting crashes.
animImage is a UIImageView;
Here is how it works:
- (IBAction) panAnim:(UIPanGestureRecognizer *)sender{
CGPoint translate = [sender translationInView:sliderView];
if (translate.x >= lastPoint) {
difference = translate.x - lastPoint;
[self forwardAnim:difference];
} else {
difference = lastPoint - translate.x;
[self backwardAnim:difference];
}
lastPoint = translate.x;
}
-(void)forwardAnim:(CGFloat)speed{
NSInteger newFrame = currentFrame+speed;
currentFrame = newFrame;
if (currentFrame>=totalFrames) {
currentFrame=0;
}
NSString *newImagePath = [NSString stringWithFormat:#"%#", [currentAnimation objectAtIndex:currentFrame]];
animImage.image = [UIImage imageNamed:newImagePath];
}
-(void)backwardAnim:(CGFloat)speed{
NSInteger newFrame = currentFrame-speed;
currentFrame = newFrame;
if (currentFrame<0) {
currentFrame=(totalFrames-1);
}
NSString *newImagePath = [NSString stringWithFormat:#"%#", [currentAnimation objectAtIndex:currentFrame]];
animImage.image = [UIImage imageNamed:newImagePath];
}
The animation detects position of the translate and calculates what 'frame' the animation should be at and then swaps out the image.
I'm getting a very smooth animation for this but obviously I'm causing a crash because I'm not managing the memory correctly. I'm getting Memory Warnings and then crashes - but only when I've been scrolling through the images for a while.
I need to figure out a way to pre-load 100 images at a time, so I can only keep the memory of 100 images. It's strange because the images are opened and closed properly in the IO Output in Instruments.
Thanks for your help!
Cheers, D
+[UIImageView imageNamed:] caches the images it loads, so it's not surprising that your memory usage keeps increasing. You might try changing those +imageNamed: calls to +imageWithContentsOfFile: instead. That may hurt your animation performance, but I suspect you'll see memory usage drop significantly.
A memory warning doesn't mean that a crash is imminent. It'd help if you'd post the details of the crash. Looking at the crash log, you should be able to identify a line in your code that leads to the crash -- it may be a few frames from the top of the stack. Find that line, put a breakpoint a line or two before it, and step through the code imagining what could happen on each line that might cause a problem -- failed allocation, bad value, etc.
BTW, your 25kB image files likely expand to something much larger in memory.