I have a class variable imageView of class UIImageView and a button.
The array of images is loaded from the Gallery by using Assets.
When the loading of all images is done, I show the first image:
- (void)showImage
{
if ([images count] > 0)
[self.imageView setImage:[images objectAtIndex:0]];
currentPage = 0;
}
Everything is good so far,
But when I tap the button with following action:
- (IBAction)buttonNext:(id)sender {
NSLog(#"images array %#", images );
if (currentPage < [images count]-1)
{
NSLog(#"next currentPage %d %d %#",currentPage, [images count],[images objectAtIndex:currentPage])
currentPage++;
[self.imageView setImage:[images objectAtIndex:currentPage]];
}
}
no image replacement takes place. The imageView stucks the previous image.
I debugged the array of images:
images array (
"<UIImage: 0xb38cec0>",
"<UIImage: 0xb0f8280>",
"<UIImage: 0xb063360>",
"<UIImage: 0xb0660a0>"
)
EDIT
The code which loads the images:
-(void)loadImage:(NSString*)url
{
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
if (iref) {
UIImage *largeImage = [UIImage imageWithCGImage:iref];
CGSize size=CGSizeMake(400, 500);//set the width and height
UIGraphicsBeginImageContext(size);
[largeImage drawInRect:CGRectMake(0,0,size.width,size.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
//here is the scaled image which has been changed to the size specified
UIGraphicsEndImageContext();
[images addObject:newImage];
if ([images count] == [pages count])
[self showImage];
}
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror)
{
NSLog(#"Can't get image - %#",[myerror localizedDescription]);
};
NSURL *asseturl = [NSURL URLWithString:url];
[assetslibrary assetForURL:asseturl
resultBlock:resultblock
failureBlock:failureblock];
}
- (void)viewWillAppear:(BOOL)animated
for(NSDictionary* a in pages)
{
if ([a objectForKey:#"iospath"] != nil)
[self loadImage:[document objectForKey:#"iospath"]];
}
pages is an array loaded in viewDidLoad. The images are there. Why I can not show'em?
Regards
Related
I have tried a lot of solutions provided on other questions which were same as mine but nothing could help me much.
Let me tell you what am I doing. I have a collection view. In that I will display some images which will be captured by camera. I am capturing multiple pictures at a time. All the pictures which I have taken, the address of those images will first save into database and then those images will be displayed in collection view.
Now what happens, when I click 40-50 images at a time, the app is crashed and xcode displays a message something like "app is terminating due to memory pressure". Also I am getting too many memory warnings in logs but actually I was neglecting them.
First I am writing code for taking multiple pictures-
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
//Get Image URL from Library
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
NSURL *urlPath = [info valueForKey:UIImagePickerControllerReferenceURL];
if (segmentControl.selectedSegmentIndex != 1) {
[picker dismissViewControllerAnimated:YES completion:nil];
}
if (segmentControl.selectedSegmentIndex == 2) {
[self insertPicToDB:urlPath];
}else{
__block NSURL *url;
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
// Request to save the image to camera roll
[library writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
} else {
url = assetURL;
[self insertPicToDB:url];
}
}];
}
}
}
}
After while taking each picture, I am saving image url in db and then at the same time trying to reload the collection view as well.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Cell";
collectionCell = (CollectionCell *)[_collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
collectionCell.imageView = (UIImageView*)[collectionCell viewWithTag:100];
collectionCell.imageView.image = [UIImage imageNamed:#"placeholder.png"];
NSString *fileURL = [[recipeImages[indexPath.section] objectAtIndex:indexPath.item] objectForKey:#"FileUrl"];
collectionCell.imagURL = fileURL;
if ([fileURL hasPrefix:#"assets-library"]) {
[self getImageFromURL:[NSURL URLWithString:fileURL] :indexPath];
}else{
fileURL = [NSString stringWithFormat:#"%#/uploads/thumbnail/%#",[[HttpClient sharedInstance]getBaseURLString],[[fileURL componentsSeparatedByString:#"\\"]lastObject]];
[collectionCell.imageView setImageWithURL:[NSURL URLWithString:fileURL] placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
}
return collectionCell;
}
So the condition is, I will keep clicking the pictures and the pictures will be saving in background.
And the definition of method "getImageFromURL" is-
-(void)getImageFromURL:(NSURL*)yourUrl :(NSIndexPath*)indexPath{
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
ALAssetRepresentation *rep = [myasset defaultRepresentation];
#autoreleasepool {
CGImageRef iref = [rep fullScreenImage];
if (iref) {
UIImage *image = [UIImage imageWithCGImage:iref];
dispatch_async(dispatch_get_main_queue(), ^{
collectionCell = (CollectionCell*)[_collectionView cellForItemAtIndexPath:indexPath];
if (collectionCell) {
NSData *imageData = UIImageJPEGRepresentation(image, 0.1);
UIImage *compressedImage = [UIImage imageWithData:imageData];
collectionCell.imageView.image = compressedImage;
}else{
collectionCell.imageView.image = nil;
}
[collectionCell.imageView setNeedsDisplay];
[collectionCell setNeedsDisplay];
});
iref = nil;
}
}
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror)
{
NSLog(#"Can't get image - %#",[myerror localizedDescription]);
};
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:yourUrl
resultBlock:resultblock
failureBlock:failureblock];
}
I am also trying to compress the images while fetching in collection view. So I don't think that it is crashing because of collection view. What can be the reason? Is it because of I am using ALAssetsLibrary or something else?
I was debugging it in iPhone 4S with iOS version 7.1.1.
Thanks in advance.
Just downloaded the ELCImagePicker and I am now getting this warning in ELCImagePickerController.m
Implicit conversion from enumeration type 'ALAssetOrientation' (aka 'enum ALAssetOrientation) to different enumeration type 'UIImageOrientation' (aka 'UIImageOrientation')
The code throwing the warning is:
orientation = [assetRep orientation];
Here is the full function if it is more revealing:
- (void)selectedAssets:(NSArray *)assets
{
NSMutableArray *returnArray = [[NSMutableArray alloc] init];
for(ELCAsset *elcasset in assets) {
ALAsset *asset = elcasset.asset;
id obj = [asset valueForProperty:ALAssetPropertyType];
if (!obj) {
continue;
}
NSMutableDictionary *workingDictionary = [[NSMutableDictionary alloc] init];
CLLocation* wgs84Location = [asset valueForProperty:ALAssetPropertyLocation];
if (wgs84Location) {
[workingDictionary setObject:wgs84Location forKey:ALAssetPropertyLocation];
}
[workingDictionary setObject:obj forKey:UIImagePickerControllerMediaType];
//This method returns nil for assets from a shared photo stream that are not yet available locally. If the asset becomes available in the future, an ALAssetsLibraryChangedNotification notification is posted.
ALAssetRepresentation *assetRep = [asset defaultRepresentation];
if(assetRep != nil) {
if (_returnsImage) {
CGImageRef imgRef = nil;
//defaultRepresentation returns image as it appears in photo picker, rotated and sized,
//so use UIImageOrientationUp when creating our image below.
UIImageOrientation orientation = UIImageOrientationUp;
if (_returnsOriginalImage) {
imgRef = [assetRep fullResolutionImage];
orientation = [assetRep orientation];
} else {
imgRef = [assetRep fullScreenImage];
}
UIImage *img = [UIImage imageWithCGImage:imgRef
scale:1.0f
orientation:orientation];
[workingDictionary setObject:img forKey:UIImagePickerControllerOriginalImage];
}
[workingDictionary setObject:[[asset valueForProperty:ALAssetPropertyURLs] valueForKey:[[[asset valueForProperty:ALAssetPropertyURLs] allKeys] objectAtIndex:0]] forKey:UIImagePickerControllerReferenceURL];
[returnArray addObject:workingDictionary];
}
}
if (_imagePickerDelegate != nil && [_imagePickerDelegate respondsToSelector:#selector(elcImagePickerController:didFinishPickingMediaWithInfo:)]) {
[_imagePickerDelegate performSelector:#selector(elcImagePickerController:didFinishPickingMediaWithInfo:) withObject:self withObject:returnArray];
} else {
[self popToRootViewControllerAnimated:NO];
}
}
To get rid of this warning I updated this piece of code:
if (_returnsOriginalImage) {
imgRef = [assetRep fullResolutionImage];
orientation = [assetRep orientation];
} else {
imgRef = [assetRep fullScreenImage];
}
To the following:
if (_returnsOriginalImage) {
imgRef = [assetRep fullResolutionImage];
NSNumber *orientationValue = [asset valueForProperty:#"ALAssetPropertyOrientation"];
if (orientationValue != nil) {
orientation = [orientationValue intValue];
}
} else {
imgRef = [assetRep fullScreenImage];
}
I'm working on a simple puzzle game that use an image as background of the board game.
Everything works fine, but there are a little thing bothering me. When I take a photo from camera I can save it on my Photo Library but I don't know where it was saved, I mean, what is the exactly URL of my photo.
Here is the code where I save photos:
- (void) imagePickerController:(UIImagePickerController *) picker didFinishPickingMediaWithInfo:(NSDictionary *) info
{
NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
UIImage *originalImage, *editedImage, *imageToSave;
// Handle a still image capture
if (CFStringCompare ((CFStringRef) mediaType, kUTTypeImage, 0) == kCFCompareEqualTo) {
editedImage = (UIImage *) [info objectForKey:UIImagePickerControllerEditedImage];
originalImage = (UIImage *) [info objectForKey:UIImagePickerControllerOriginalImage];
if (editedImage) {
imageToSave = editedImage;
} else {
imageToSave = originalImage;
}
CGRect bounds;
bounds.origin = CGPointZero;
bounds.size = imageToSave.size;
[scrollView setContentSize:bounds.size];
[scrollView setContentOffset:bounds.origin];
[imageView setFrame:bounds];
imageView.image = imageToSave;
if ([info objectForKey:#"UIImagePickerControllerReferenceURL"] == nil) {
// Save the new image (original or edited) to the Camera Roll
ALAssetsLibrary *al = [[ALAssetsLibrary alloc] init];
ALAssetOrientation orientation; //= [[[info objectForKey:#"UIImagePickerControllerMediaMetadata"] objectForKey:#"Orientation"] integerValue];
NSString *infoOrientation = [[info objectForKey:#"UIImagePickerControllerMediaMetadata"] objectForKey:#"Orientation"];
switch ([infoOrientation integerValue]) {
case 3:
orientation = ALAssetOrientationUp;
break;
case 6:
orientation = ALAssetOrientationRight;
break;
default:
orientation = ALAssetOrientationDown;
break;
}
[al writeImageToSavedPhotosAlbum:[imageToSave CGImage] orientation:orientation completionBlock:^(NSURL *assetURL, NSError *error) {
if (error == nil) {
NSLog(#"saved");
savedImageCam = assetURL;
} else {
NSLog(#"error");
}
}];
} else {
NSLog(#"URL from saved image: %#", savedImageCam);
NSLog(#"URL from photo image: %#", [info objectForKey:#"UIImagePickerControllerReferenceURL"]);
}
}
// Handle a movie capture
if (CFStringCompare ((CFStringRef) mediaType, kUTTypeMovie, 0) == kCFCompareEqualTo) {
NSString *moviePath = (NSString *)[[info objectForKey:UIImagePickerControllerMediaURL] path];
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum (moviePath)) {
UISaveVideoAtPathToSavedPhotosAlbum (moviePath, nil, nil, nil);
}
}
[self dismissViewControllerAnimated:YES completion:nil];
}
The call method UIImageWriteToSavedPhotosAlbum doesn't return the URL, and the instance variable info just bring the URL if I call the Photo Library directly not through of camera.
Anybody knows how can I fix it?
Don't use UIImageWriteToSavedPhotosAlbum. Instead, use the ALAssetsLibrary and writeImageToSavedPhotosAlbum:orientation:completionBlock:. The completionBlock then gives you access to the asset URL that you can use to get the image again in the future.
So I'm building an app that the user takes pictures of themselves, it saves them to the camera roll, and I'm saving references to the asset URLs to display them in the app. At first this model seemed to work fine, but as I took more and more pictures it started receiving memory warnings and eventually crashed. Is there a better way to approach this?
This is how I load up the saved photos at the launch of the app (which freezes the app for up to 10 seconds depending on how many are being loaded):
- (void) loadPhotosArray
{
_photos = [[NSMutableArray alloc] init];
NSData* data = [[NSUserDefaults standardUserDefaults] objectForKey: #"savedImages"];
if (data)
{
NSArray* storedUrls = [[NSArray alloc] initWithArray: [NSKeyedUnarchiver unarchiveObjectWithData: data]];
// reverse array
NSArray* urls = [[storedUrls reverseObjectEnumerator] allObjects];
for (NSURL* assetUrl in urls)
{
// Block to handle image handling success
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
if (iref) {
UIImage* tempImage = [UIImage imageWithCGImage:iref];
UIImage* image = [[UIImage alloc] initWithCGImage: tempImage.CGImage scale: 1.0 orientation: UIImageOrientationRight];
// Set image in imageView
[_photos addObject: image];
[[NSNotificationCenter defaultCenter] postNotificationName: #"PhotosChanged" object: self];
}
};
// Handles failure of getting image
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror)
{
NSLog(#"Can't get image - %#",[myerror localizedDescription]);
};
// Load image then call appropriate block
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL: assetUrl
resultBlock: resultblock
failureBlock: failureblock];
}
}
else
{
NSLog(#"Photo storage is empty");
}
}
And saving photos:
- (void) addImageToPhotos: (UIImage*)image
{
// Store image at front of array
NSMutableArray* temp = [[NSMutableArray alloc] initWithObjects: image, nil];
// load rest of images onto temp array
for (UIImage* image in _photos)
{
[temp addObject: image];
}
_photos = nil;
_photos = [[NSMutableArray alloc] initWithArray: temp];
// [self.photos addObject: image];
[[NSNotificationCenter defaultCenter] postNotificationName: #"PhotosChanged" object: self.photos];
// save to cache
ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
[library saveImage: image toAlbum: #kAlbumeName withCompletionBlock:^(NSError *error) {
if (error)
{
NSLog(#"Error saving");
}
}];
}
I think have 2 methods to optimize this problem.
U should just save image name string instead of saving UIImage object, then when need to display the image, use pagination to display image according to saved image name string.
U should use multi-thread to deal with this long time task, recommend u to use gcd to load image name string.
Everything is working fine with FBProfilePictureView but I need to get that picture from FBProfilePictureView and turn it into an UIImage.
How should I do it?
I tried using this:
UIGraphicsBeginImageContext(self.profilePictureView.frame.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.TestPictureOutlet.image = viewImage;
But this doesnt work for my solution.
FBProfilePictureView is a UIView, this UIView contains a UIImageView, that is your image, you can get the UIImage from that UIImageView:
profilePictureView is a FBProfilePictureView
UIImage *image = nil;
for (NSObject *obj in [profilePictureView subviews]) {
if ([obj isMemberOfClass:[UIImageView class]]) {
UIImageView *objImg = (UIImageView *)obj;
image = objImg.image;
break;
}
}
EDIT: add another way more quickly but do the same thing
__block UIImage *image = nil;
[self.view.subviews enumerateObjectsUsingBlock:^(NSObject *obj, NSUInteger idx, BOOL *stop) {
if ([obj isMemberOfClass:[UIImageView class]]) {
UIImageView *objImg = (UIImageView *)obj;
image = objImg.image;
*stop = YES;
}
}];
Above both mentioned solutions work fine to get UIImage object out from FBProfilePictureView.
Only thing is, You need to put some delay before to get image from FBProfilePictureView.
Like:
[FBRequest requestForMe] startWithCompletionHandler:
^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
if (!error) {
myNameLbl.text = user.name;
profileDP.profileID = user.id;
//NOTE THIS LINE WHICH DOES THE MAGIC
[self performSelector:#selector(getUserImageFromFBView) withObject:nil afterDelay:1.0];
}];
- (void)getUserImageFromFBView{
UIImage *img = nil;
//1 - Solution to get UIImage obj
for (NSObject *obj in [profileDP subviews]) {
if ([obj isMemberOfClass:[UIImageView class]]) {
UIImageView *objImg = (UIImageView *)obj;
img = objImg.image;
break;
}
}
//2 - Solution to get UIImage obj
// UIGraphicsBeginImageContext(profileDP.frame.size);
// [profileDP.layer renderInContext:UIGraphicsGetCurrentContext()];
// img = UIGraphicsGetImageFromCurrentImageContext();
// UIGraphicsEndImageContext();
//Here I'm setting image and it works 100% for me.
testImgv.image = img;
}
Regards!
Aamir Ali -
iOS Apps Developer
#Time Group (TGD)
Here the solution.
steps:
Make sure that you assigned the FB user id to object of class
"FBProfilePictureView" in my case this class object is
"userPictureImageView"
-(void)saveFBUserImage
{
CGSize imageSize = self.userPictureImageView.frame.size;
UIGraphicsBeginImageContext(imageSize);
CGContextRef imageContext = UIGraphicsGetCurrentContext();
[self.userPictureImageView.layer renderInContext: imageContext];
UIImage* viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *imageData = UIImageJPEGRepresentation(viewImage,1);
UIImage * img = [UIImage imageWithData:imageData];
NSString *filePath = <specify your path here>;
CGSize size = img.size;
if(size.height > 50)
size.height = 50;
if(size.width > 50)
size.width = 50;
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
CGSize size2 = rect.size;
UIGraphicsBeginImageContext(size2);
[img drawInRect:rect];
img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *newImageData = UIImageJPEGRepresentation(img, 1.0);
[newImageData writeToFile:filePath atomically:YES];
}
That's it. :-)
I have found above solutions to be quite working but here is updated code which i found it more easy going.
#property FBSDKProfilePictureView *pictureView;
if ([FBSDKAccessToken currentAccessToken]) {
self.pictureView=[[FBSDKProfilePictureView alloc]init];
[self.pictureView setProfileID:#"me"];
[self.pictureView setPreservesSuperviewLayoutMargins:YES];
[self.pictureView setPictureMode:FBSDKProfilePictureModeNormal];
[self.pictureView setNeedsImageUpdate];
[self performSelector:#selector(getUserImageFromFBView) withObject:nil afterDelay:1.0];
}
-(void) getUserImageFromFBView
{
UIImage *image = nil;
for (NSObject *obj in [self.pictureView subviews]) {
if ([obj isMemberOfClass:[UIImageView class]]) {
UIImageView *objImg = (UIImageView *)obj;
image = objImg.image;
break;
}
}
[self.profilePic setImage:image forState:UIControlStateNormal];
}
Hope this helps. Here i have put 1 second delay to wait for the profile picture to load.