I'm working working on an iPhone application for uploading video files to a specific platform, and one feature I would really love is to be able to present, say, ten different thumbnails for the same video for the user to pick from.
The problem is, that ALAsset only provides a thumbnail method, which just returns the default thumbnail. I have read through the ALAssetRepresentation and ALAsset documentation and I can't seem to find a way to get a thumbnail for a specific timestamp.
I guess one option would be to use something along the lines of libav to get thumbnails but that seems a little "over the top" for something like this. Can anyone help me on this one?
Best regards,
Nick
i think this will help you , and
you can also see through this prompt
Video File thumbnail timestamp missing in ALAsset
{
if ([theAsset valueForProperty:ALAssetPropertyType] == ALAssetTypeVideo) {
// Black semi-transparent background at the bottom of the item
CGRect containerFrame = CGRectMake(0, frame.size.height - AGIPC_ITEM_HEIGHT, frame.size.width, AGIPC_ITEM_HEIGHT);
UIView *containerForMovieInfo = [[[UIView alloc] initWithFrame:containerFrame] autorelease];
containerForMovieInfo.backgroundColor = [UIColor blackColor];
containerForMovieInfo.alpha = 0.7f;
// Movie icon on left side
CGRect movieFrame = CGRectMake(4, 60, 26, 15);
UIImageView *movieImageView = [[[UIImageView alloc] initWithFrame:movieFrame] autorelease];
if (IS_IPAD()) {
movieImageView.image = [UIImage imageNamed:#"AGIPC-Movie-iPad"];
} else {
movieImageView.image = [UIImage imageNamed:#"AGIPC-Movie-iPhone"];
}
[containerForMovieInfo addSubview:movieImageView];
// Movie duration on right side
if ([theAsset valueForProperty:ALAssetPropertyDuration] != ALErrorInvalidProperty) {
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateFormat:#"mm:ss"];
CGRect durationFrame = CGRectMake(frame.size.width - 26 - 4, 60, 26, 15);
UILabel *durationView = [[[UILabel alloc] initWithFrame:durationFrame] autorelease];
durationView.backgroundColor = [UIColor clearColor];
durationView.textColor = [UIColor whiteColor];
durationView.text = [formatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:[[theAsset valueForProperty:ALAssetPropertyDuration] doubleValue]]];
durationView.font = [UIFont systemFontOfSize:10];
[containerForMovieInfo addSubview:durationView];
}
[self addSubview:containerForMovieInfo];
}
}
last but not least, you must creat the image of the camera on your own.
// Get URL from ALAsset* asset:
NSURL* assetURL = [asset valueForProperty:ALAssetPropertyAssetURL];
// Create AVURLAsset using this URL (assetOptions is optional):
NSDictionary* assetOptions = nil;
// assetOptions = #{AVURLAssetPreferPreciseDurationAndTimingKey : #(YES)};
AVAsset* avAsset = [[AVURLAsset alloc] initWithURL:assetURL options:assetOptions];
// Create generator:
AVAssetImageGenerator* generator = [[AVAssetImageGenerator alloc] initWithAsset:avAsset];
generator.appliesPreferredTrackTransform = YES;
// Create array with CMTimes of thumbnails using your own logic.
// (Use +(NSValue*)valueWithCMTime:(CMTime)time to add CMTime in array).
NSArray* times = [self generateThumbnailTimesForVideo:avAsset];
// Generate thumbnail images asynchronously:
[generator generateCGImagesAsynchronouslyForTimes:times
completionHandler:^(CMTime requestedTime,
CGImageRef image,
CMTime actualTime,
AVAssetImageGeneratorResult result,
NSError* error)
{
// This block is performed for each CMTime in times array.
UIImage* thumbnail = [[UIImage alloc] initWithCGImage:image];
}
];
Synchronous method to get thumbnail at any time is
// PS: SYNC method:
CGImageRef imgRef = [generator copyCGImageAtTime:time actualTime:NULL error:&error];
UIImage* thumbnail = [[UIImage alloc] initWithCGImage:image];
Related
How is that change of textView frame makes it's text after pdf export unselectable? It's simple rasterized with horible compression. If I export textView and don't change the frame I got perfect vectors.
I've view with textView and I export the pdf with content of textView like this:
- (void) generatePDFWithFilename:(NSString *)filename
{
// Creates a mutable data object for updating with binary data, like a byte array
NSMutableData *pdfData = [NSMutableData data];
// pdf view
_pdfView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 612, 792)];
// adding subview - for easier positioning
CGRect tempFrame;
UIView *tempView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, _pdfView.bounds.size.width - 20, _pdfView.bounds.size.height - 20)];
tempView.backgroundColor = [UIColor redColor];
_pdfView.backgroundColor = [UIColor lightGrayColor];
[_pdfView addSubview:tempView];
UITextView *pdfDescriptionTextView = [[UITextView alloc] initWithFrame:CGRectZero];
pdfDescriptionTextView = _workDescriptionTextView;
[tempView addSubview:pdfDescriptionTextView];
// pdfDescriptionTextView.center = CGPointMake(50, 200); // working - vector data are preserved
tempFrame = pdfDescriptionTextView.frame;
tempFrame.origin = CGPointMake(100, 100);
tempFrame.size = CGSizeMake(tempView.bounds.size.width - 40, pdfDescriptionTextView.contentSize.height);
pdfDescriptionTextView.frame = tempFrame;
pdfDescriptionTextView.backgroundColor = [UIColor greenColor];
UIGraphicsBeginPDFContextToData(pdfData, CGRectZero, nil);
UIGraphicsBeginPDFPageWithInfo(_pdfView.bounds, nil);
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
[_pdfView.layer renderInContext:pdfContext];
// remove PDF rendering context
UIGraphicsEndPDFContext();
// Retrieves the document directories from the iOS device
NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString* documentDirectory = [documentDirectories objectAtIndex:0];
NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:filename];
// instructs the mutable data object to write its context to a file on disk
BOOL success = [pdfData writeToFile:documentDirectoryFilename atomically:YES];
if(success)
{
[self sendEmailWithData:pdfData];
}
}
just change its editing mode.....
pdfDescriptionTextView.editable = FALSE;
After this the user will not be able to change the text anymore
In my app, I use UIImageView and UIScrollView to show a lot of images (every time there are about 20 images and every image is about 600px*500px and size is about 600kb).
I use this code to accomplish this function:
// Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[UIImage alloc]initWithData:[NSData dataWithContentsOfFile:filePath]];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
imageData = nil;
iv = nil;
iv.image = nil;
filePath = nil;
[imageData release];
[filePath release];
[iv release];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
But every time I initialize this function, the memory will increase about 5MB. Actually I release UIImageView, UIimage and UIScrollView (vi.image=nil, [vi release]) but it doesn't work, the allocated memory is not getting released. BTW, I used my friend's code first vi.image = nil then vi = nil; but the pictures are not getting displayed on scrollview.
The main problem, as I see it, is that you're setting your local variables to nil and then you proceed to try to use those local variables in methods like release and the like, but because they've been set to nil, those methods now do nothing, and the objects with the +1 retainCount (or now +2 because you've added them to your view) are never released.
Thus, I'd suggest the following:
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[UIImage alloc]initWithData:[NSData dataWithContentsOfFile:filePath]];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
// Don't set these to nil, or else subsequent release statements do nothing!
// These statements are actually not necessary because they refer to local
// variables so you don't need to worry about dangling pointers. Make sure
// you're not confusing the purpose of setting a pointer to nil in ARC to
// what you're doing in your non-ARC code.
//
// imageData = nil;
// iv = nil;
// You don't want to set this to nil because if iv is not nil, your image
// will be removed from your imageview. So, not only is this not needed,
// but it's undesired.
//
// iv.image = nil;
// This statement is not necessary for the same reason you don't do it
// to imageData or iv, either. This is probably even worse, though, because
// filePath is not a variable that you initialized via alloc. You should
// only be releasing things you created with alloc (or new, copy, mutableCopy,
// for which you issued a retain statement).
//
// filePath = nil;
[imageData release];
// filePath is a +0 retainCount already, so don't release. You only release
// those items for which you increased retainCount (e.g. via new, copy,
// mutableCopy, or alloc or anything you manually retained).
//
// [filePath release];
[iv release];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
Thus, your code would be simplified (and corrected) to probably just be:
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
[imageData release];
[iv release];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
Or you could further simplify your code through the use of autorelease:
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)] autorelease];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]] autorelease];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
By the way, the statement (with autorelease):
UIImage *imageData = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]] autorelease];
could probably be simplified to:
UIImage *imageData = [UIImage imageWithContentsOfFile:filePath];
This gives you a UIImage, with a +0 retainCount (i.e. you don't have to release it) from your file.
So, a few final observations:
You really should probably review and study the Advanced Memory Management Programming Guide. It's dense reading if you're new to memory management, but mastery of these concepts (especially in non-ARC code) is critical.
If you haven't, I'd encourage you to run your code through the static analyzer ("Product" - "Analyze" or shift+command+B). I'd be surprised if many (if not most) of these issues wouldn't have been identified for you by the analyzer. You should have zero warnings when you run your code through the analyzer.
If you want to take this to the next level, you might want to be far more conservative about your memory management. The governing principle would be a system design that only loads the images that are needed at the UI at any given time, which involves not only calvinBhai's excellent suggestion of lazy loading of images (i.e. don't load images into memory until your UI really needs them), but also a pro-active releasing images once they've scrolled off the screen. Maybe you don't need to worry about it in your app, because you're only dealing with 20 images at a time, but if any of your portfolios/galleries expanded to 100 or 1000 images, the idea of keeping all of those in memory at any given time is just a bad idea. This is a more advanced concept, so maybe you should focus on the basic memory management problems of your existing code first, but longer term, you might want to contemplate lazy loading and pro-active releasing of images.
If memory is your concern,
try lazy loading the images = Load the visible image, the next and previous image. You dont have to have all images added to your klpscrollview.
Once you figure out lazy loading the images onto your scrollview, then you can think of fixing the images not showing on your scrollview.
Easier would be to search for "lazy load uiimage uiscrollview"
Actually i want to display iamge in UIImageView ...tat image names are getting from my database..so how to display image from getting string in an array in iphone
use this methods
UIImageView *imageView = [UIImageView alloc] initWithFrame:CGRectMake(0,0,320,480)];
imageView.animationImages = animationImages ;
imageView.animationRepeatCount = 2;
imageView.animationDuration= 4.0;
[imageView startAnimating];
animationImages is an Array containig UIImage Objects.
NSString *imageNameStr = [NSString stringWithFormat:#"%#",[imageNameArray objectAtIndex:index]];
UIImageView *myImage;
myImage=[[UIImageView alloc]initWithFrame:CGRectMake(00.0, 00.0, 320.0, 480.0)];
myImage.backgroundColor=[UIColor clearColor];
myImage.image=[UIImage imageNamed:imageNameStr];
[self.view addSubview:myImage];
hope it Help To you
You can use the following code.
NSString *str = [NSString stringWithFormat:#"%#",[arr_ArrayName objectAtIndex:index]];
NSString *path = [[ NSBundle mainBundle] pathForResource:str ofType:#"png"];
UIImage *temp = [UIImage imageWithContentsOfFile:path];
yourImageView.image = temp;
Pass the index value as an integer which image from array you want to display.
Edit:
Declare one integer temp in your view will appear. Set it's value to 0. temp = 0;
Then, inside your button action please write the below mentioned code:
-(void)buttonClick
{
NSString *selectedItem =[NSString stringWithFormat:#"%#",[colors objectAtIndex:temp]];
NSString *wrdstr = [[ NSBundle mainBundle] pathForResource:selectedItem ofType:#"png"];
UIImage *temp = [UIImage imageWithContentsOfFile:wrdstr];
imgshow.image = temp;
if(temp <= [colors count])
temp = temp + 1;
}
I am working on displaying several Images in a scrollview loaded from a MapServer which returns an image of showing a map.
So what I did is I have created 4 UIImageViews, put them in a NSMutableDictionary.
Then when scrolling to the desirable Image it will initiate to load the data from the url asynchronous.
so first I display an UIActivityIndicatorView, then it will load the data and at the end hide the UIActivityIndicatorView and display the UIImageView.
everything is working more or less fine, apart that it takes sooo long until the image displays, allthough the image is not that big and I have a log text indicating that the end of the function arrived... this log message appears immediately but the image still does not show...
If I call the URL by the Webbrowser the image is shown immediately as well.
below you see my piece of code.
- (void) loadSRGImage:(int) page {
UIImageView *currentSRGMap = (UIImageView *)[srgMaps objectForKey:[NSString stringWithFormat:#"image_%i", page]];
UIActivityIndicatorView *currentLoading = (UIActivityIndicatorView *)[srgMaps objectForKey:[NSString stringWithFormat:#"loading_%i", page]];
// if the image has been loaded already, do not load again
if ( currentSRGMap.image != nil ) return;
if ( page > 1 ) {
MKCoordinateSpan currentSpan;
currentSpan.latitudeDelta = [[[srgMaps objectForKey:[NSString stringWithFormat:#"span_%i", page]] objectForKey:#"lat"] floatValue];
currentSpan.longitudeDelta = [[[srgMaps objectForKey:[NSString stringWithFormat:#"span_%i", page]] objectForKey:#"lon"] floatValue];
region.span = currentSpan;
region.center = mapV.region.center;
[mapV setRegion:region animated:TRUE];
//[mapV regionThatFits:region];
}
srgLegende.hidden = NO;
currentSRGMap.hidden = YES;
currentLoading.hidden = NO;
[currentLoading startAnimating];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage:)
object:[NSString stringWithFormat:#"%i", page]];
[queue addOperation:operation];
[operation release];
}
- (void) loadImage:(NSInvocationOperation *) operation {
NSString *imgStr = [#"image_" stringByAppendingString:(NSString *)operation];
NSString *loadStr = [#"loading_" stringByAppendingString:(NSString *)operation];
WGS84ToCH1903 *converter = [[WGS84ToCH1903 alloc] init];
CLLocationCoordinate2D coord1 = [mapV convertPoint:mapV.bounds.origin toCoordinateFromView:mapV];
CLLocationCoordinate2D coord2 = [mapV convertPoint:CGPointMake(mapV.bounds.size.width, mapV.bounds.size.height) toCoordinateFromView:mapV];
int x1 = [converter WGStoCHx:coord1.longitude withLat:coord1.latitude];
int y1 = [converter WGStoCHy:coord1.longitude withLat:coord1.latitude];
int x2 = [converter WGStoCHx:coord2.longitude withLat:coord2.latitude];
int y2 = [converter WGStoCHy:coord2.longitude withLat:coord2.latitude];
NSString *URL = [NSString stringWithFormat:#"http://map.ssatr.ch/mapserv?mode=map&map=import/dab/maps/dab_online.map&mapext=%i+%i+%i+%i&mapsize=320+372&layers=DAB_Radio_Top_Two", y1, x1, y2, x2];
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:URL]];
UIImage* image = [[UIImage alloc] initWithData:imageData];
[imageData release];
UIImageView *currentSRGMap = (UIImageView *)[srgMaps objectForKey:imgStr];
UIActivityIndicatorView *currentLoading = (UIActivityIndicatorView *)[srgMaps objectForKey:loadStr];
currentSRGMap.hidden = NO;
currentLoading.hidden = YES;
[currentLoading stopAnimating];
[currentSRGMap setImage:image]; //UIImageView
[image release];
NSLog(#"finished loading image: %#", URL);
}
I had a similar thing in my app, and i used the SDWebImage from https://github.com/rs/SDWebImage. This has a category written over UIImageView. You need to mention a placeholder image and a url to the UIImageView. It will display the image once it is downloaded and also maintains a cache of the downloaded images, hence avoiding multiple server calls.
I have an animation of a menu background that is 21 frames. I load them into memory using the below code in the view's viewDidLoad method.
NSMutableArray *menuanimationImages = [[NSMutableArray alloc] init];
for( int aniCount = 0; aniCount < 21; aniCount++ )
{
NSString *fileLocation = [[NSBundle mainBundle] pathForResource: [NSString stringWithFormat: #"bg%i", aniCount + 1] ofType: #"png"];
NSData *imageData = [NSData dataWithContentsOfFile: fileLocation];
[menuanimationImages addObject: [UIImage imageWithData:imageData]];
}
settingsBackground.animationImages = menuanimationImages;
Unfortunately, doing [settingsBackground startAnimating]; doesn't work in the viewDidLoad method. Is there some way to preload the animation so there isn't a 1-3 second delay on first run?
I wouldn't normally recommend using imageNamed and relying on the in-built caching mechanisms. You'll find a lot of discussion on this if you search, but also it won't necessarily pre-render your images anyway.
I use the following code to pre-load and pre-render images so there is no delay when animating the first time through.
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 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();
[menuanimationImages addObject:renderedImage];
}
settingsBackground.animationImages = menuanimationImages;
The problem with each of these answers is that the suggested "fix" is to preload all your image data into memory. That can and will result in crashes if your images are too big or there are too many images, see my answer for uiimage-animation-causing-app-to-crash-memory-leaks for more detailed info. The real fix is that you need to decompress the images but not hold them all in memory. Or, you can use a movie format that already does the decompression for all frames in one step, so that changing from frame to frame is not a costly operation.
The animationImages property of UIImageView requires an array of UIImage objects, not an array of NSData objects.
You may also want to set the duration and repeatCount, even though they have default values.
Example:
if (!self.idleView.animationImages) {
self.idleView.animationImages = [NSArray arrayWithObjects:[UIImage imageNamed:#"idle1.png"],
[UIImage imageNamed:#"idle2.png"],
[UIImage imageNamed:#"idle3.png"],
[UIImage imageNamed:#"idle4.png"],
[UIImage imageNamed:#"idle5.png"],
[UIImage imageNamed:#"idle6.png"],
[UIImage imageNamed:#"idle7.png"],
[UIImage imageNamed:#"idle8.png"],
[UIImage imageNamed:#"idle9.png"],
[UIImage imageNamed:#"idle10.png"],
[UIImage imageNamed:#"idle11.png"],
[UIImage imageNamed:#"idle12.png"],
[UIImage imageNamed:#"idle13.png"],
[UIImage imageNamed:#"idle14.png"],
[UIImage imageNamed:#"idle15.png"],
[UIImage imageNamed:#"idle16.png"],
[UIImage imageNamed:#"idle17.png"],
[UIImage imageNamed:#"idle18.png"],
[UIImage imageNamed:#"idle19.png"],
[UIImage imageNamed:#"idle20.png"]
, nil];
}
self.idleView.animationRepeatCount = 0;
self.idleView.animationDuration = 2.0;
[self.view addSubview:self.idleView];
[self.view sendSubviewToBack:self.idleView];
[self.idleView startAnimating];
Try the following code, normally you should have no delays. Also this code is simpler :
NSMutableArray *menuanimationImages = [[NSMutableArray alloc] initWithCapacity:21];
NSString *imageName;
for( int aniCount = 1; aniCount < 21; aniCount++ )
{
imageName = [NSString stringWithFormat:#"bg%d.png", aniCount];
[menuanimationImages addObject:[UIImage imageNamed:imageName]];
}
settingsBackground.animationImages = menuanimationImages;
// all frames will execute in 2 seconds
settingsBackground.animationDuration = 2.0;
// repeat the annimation forever
settingsBackground.animationRepeatCount = 0;
// start animating
[settingsBackground startAnimating];