Comparing image URLs - iphone

Hi I got a set of codes here, which compares images' URL. This was from a library. An multiple imagepicker,
I know that in these codes, that the otherUrls are the images picked, while the selfUrls are the one that the photolibrary/camera roll contains.
Can someone please help me, on making this a shortcut, to not compare to every single URLs, to just skip to it, or fast comparing. Hope someone could help me. cause when it compares to all the selfUrls, it crashes. due to too much picture.
- (BOOL)isEqual:(id)other
{
if (other == self)
return YES;
if (!other || ![other isKindOfClass:[self class]])
return NO;
ALAsset *otherAsset = (ALAsset *)other;
NSDictionary *selfUrls = [self valueForProperty:ALAssetPropertyURLs];
NSDictionary *otherUrls = [otherAsset valueForProperty:ALAssetPropertyURLs];
return [selfUrls isEqualToDictionary:otherUrls];
}

From what I understand of your question this is fairly simple. I won't write the exact code for you to do it but will give you some pointers.
First off we need to find what the format of the camera roll URL looks like (so we know which ones to skip over).
So to do this create a simple call to launch the camera roll. It will have a delegate method didFinishPickingMediaWithInfo that we will use. It returns the information associated with the image you selected. We can pull the URL of the image easily.
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
[self dismissModalViewControllerAnimated:YES];
//Get the image url
NSURL *assetURL = [info objectForKey:UIImagePickerControllerReferenceURL];
//Convert url to string
NSString *urlString = [url absoluteString];
//Print it out
NSLog(#"Our string format = %#", urlString);
}
Now that we know what the format of the camera roll URL. What you can do know is look and say, "Ok, the first 10 characters of each URL pulled from the camera roll is the same". When you loop through checking your URLs, check the first 10 characters. If they differ from the camera roll format then you know its not from the camera roll (mouthful).
Hope this helps.

Related

Get the name of an image taken from camera/photo library

I am having an issue with getting the name of an image that is taken from the photo library or camera. I have successfully picked the image but I want to send the picked image as an email attachment using MFMailComposeViewController. The problem is that the MFMailComposeViewController required a specific name of the image. I have used the following code to get the image name, and it always returning "assest.JPG" and that is not working with MFMailComposeViewController
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo{
[imageView setImage:image];
image_ = image;
image_ = [UIImage imageNamed:#"file.jpg"];
NSURL *imagePath = [editingInfo objectForKey:#"UIImagePickerControllerReferenceURL"];
imageName = [imagePath lastPathComponent];
NSLog(#"%#",imageName);
[self dismissModalViewControllerAnimated:YES];
if (CAMORLIB == 1) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image:didFinishSavingWithError:contextInfo:), nil);
}}
is there is any other way to deal with this issue?
Thanks,
Mohammed
Your code here:
image_ = image;
image_ = [UIImage imageNamed:#"file.jpg"];
doesn't make sense, as it assigns to image_ twice. The UIImage method -imageNamed:(NSString*)name tries to load a file named file.jpg from disk.
The reason your MFMailComposeViewController doesn't work is that the above code results in image_ being nil because [UIImage imageNamed:#"filename"] doesn't find a file named that (and as a result returns nil)
Attaching to mail
When attaching an image to a MFMailComposeViewController, you tell it what filename you want the image to have, along with the image's data:
NSData* myData = UIImageJPEGRepresentation(image, .70f);
[picker addAttachmentData:myData mimeType:#"image/jpg" fileName:#"desiredfilename.jpg"];
Here, image is a UIImage and #"desiredfilename.jpg" is the filename you want the image to appear to have in the email.
Pulling an image from the Assets Library only gives you the guid url of the item.
There is no real construct of names in the Assets Library. The photo library has a few properties but they are as follows
ALAssetPropertyType
ALAssetPropertyLocation
ALAssetPropertyDuration
ALAssetPropertyOrientation
ALAssetPropertyDate
all of which can be found in AssetsLibrary.framework\ALAsset.h
to put a name for images I gather from there, I usually put
[NSString stringWithFormat:"Image%#.png",imageNumber]
where image number incremented as I add images.
Hope that helps

App works fine on 4S, but crashes on 3G, because of SIGABRT

When the user starts the app for the first time he gets a pop up and has to save an image. It works on the simulator and on the 4S. But when I start it with my 3G it gives me a SIGABRT error as soon as I chose a picture. I assume its because of the size of the picture which is too pick and therefore claiming all of the ram - But that is rather weird, because I make it much smaller. Here is the code:
- (void)viewDidLoad
{
[super viewDidLoad];
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"bild"] == nil) {
picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:picker animated:YES];
}
}
- (void)imagePickerController:(UIImagePickerController *) Picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
double compressionRatio=1;
NSData *imageData=UIImageJPEGRepresentation([info objectForKey:#"bild"],compressionRatio);
while ([imageData length]>5000) {
compressionRatio=compressionRatio*0.20;
imageData=UIImageJPEGRepresentation([info objectForKey:#"bild"],compressionRatio);
}
UIImage *yourUIImage;
yourUIImage = [info objectForKey:UIImagePickerControllerOriginalImage];
imageData = [NSKeyedArchiver archivedDataWithRootObject:yourUIImage];
[[NSUserDefaults standardUserDefaults] setObject:imageData forKey:#"bild"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self dismissModalViewControllerAnimated:YES];
}
I get the SIGABRT error at this line imageData = [NSKeyedArchiver archivedDataWithRootObject:yourUIImage];
Should I use another method to resize the image? Or should I save it as a local file and retrieve it everytime the app starts? (If its possible)
You are using NSCoding to archive an UIImage into a NSData object.
Before iOS5 UIImage didn't implement the methods for NSCoding. You simply can't use archivedDataWithRootObject: with UIImages before iOS5.
That's why you get an exception on the iPhone 3G.
This is just a very educated guess because I can't confirm that with documentation or a test on a device but there are a lot of questions and forum posts around that ask how to implement NSCoding on UIImage.
and this whole block of code isn't called at all because [info objectForKey:#"bild"] will return nil. The info dictionary does not contain an object for the key bild.
Documentation for UIImagePickerControllerDelegate_Protocol contains a List of valid keys
NSData *imageData=UIImageJPEGRepresentation([info objectForKey:#"bild"],compressionRatio);
while ([imageData length]>5000) {
compressionRatio=compressionRatio*0.20;
imageData=UIImageJPEGRepresentation([info objectForKey:#"bild"],compressionRatio);
}
you probably want to use something like that:
NSData *data;
if ([[UIImage class] conformsToProtocol:#protocol(NSCoding)]) {
// >= iOS5
data = [NSKeyedArchiver archivedDataWithRootObject:image];
// save so you know it's an archived UIImage object
}
else {
// < iOS5
data = /* your UIImageJPEGRepresentation method but this time with the key UIImagePickerControllerOriginalImage instead of "bild" */
// save so you know it's raw JPEG data
}
Edit: Another error is probably that you're looking for an object for the key "bild" within the info dictionary you're passed from the image picker controller. It will have no such key. You should pass the key UIImagePickerControllerOriginalImage to get at the image instead.
--
You're not throwing away the old imageData. If your problem is high memory consumption, you'll have to do away with the image data as you progressively shrink the image.
Additionally, an image may be too big anyway to fit within 5000 bytes. Your current code doesn't handle this gracefully. Eventually, the compression ratio will grow beyond 1.0 at which point the function will probably throw an exception.
I'd suggest resizing the image before trying to compress it heavily.
No matter how you make the image data smaller, your current code keeps all the old copies around until the next time the autorelease pool is drained. Since the data returned from UIImageJPEGRepresentation is autoreleased, you may try using an inline autorelease pool around every loop iteration to drain the data immediately.
If the SIGABRT is consistently happening at imageData = [NSKeyedArchiver archivedDataWithRootObject:yourUIImage]; then my feeling would be that it is likely to be that specific line, rather than a memory issue.
UIImage never used to conform to NSCoding, but the current docs say that it does. It could be that the 3G, which will be limited to iOS 4.2.1 is using a non-conformant version and so crashes when you try to archive, whereas the 4S on iOS 5 uses the new conformant version.
Try adding a category for NSCoding to UIImage and then rerun on the 3G. Example at http://iphonedevelopment.blogspot.com/2009/03/uiimage-and-nscoding.html

Saving multiple images to camera roll, only saved a few

Im attempting to save some images to a camera roll, all the images are in a array.
if (buttonIndex == 1) {
int done = 0;
NSMutableArray *copyOfImages = [[NSMutableArray alloc]initWithArray:saveImagesToArray];
while (!done == 1){
if (copyOfImages.count == 0) {
done = 1;
}
if (copyOfImages.count > 0){
[copyOfImages removeLastObject];
}
UIImage *image = [[UIImage alloc]init];
image = [copyOfImages lastObject];
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
}
because i dont know how many images there can be i use a while loop
Im testing this with 8 images, the array shows a count of 8 so thats good.
When i try saving the images this comes up in the console.
-[NSKeyedUnarchiver initForReadingWithData:]: data is NULL
Out of the 8 images im trying, only 5 show up in the camera roll.
Any help would be great.
Thanks :)
Why are you calling [copyOfImages removeLastObject]?
Every time you go through that look are you destroying the last object, which is strange because you haven't added it to the roll yet. Take out that line and see if you look works.
Also, rather than using a for loop, use the following pattern:
for (id object in array) {
// do something with object
}
This will enumerate though the objects in the array, stopping when it reaches the end. Just be sure not to modify the array while you are doing this.
I had this same issue and I resolved it by ensuring that the images are saved sequentially. I think there may be some kind of race condition going on.
Basically, I did:
UIImageWriteToSavedPhotosAlbum([self.images objectAtIndex:self.currentIndex], self,
#selector(image:didFinishSavingWithError:contextInfo:), nil);
Then in image:didFinishSavingWithError:contextInfo:, I increment currentIndex and try the next image, if there are any left.
This has worked for me in every case so far.
I had the same exact problem. No matter how much pictures i added to the share activityController, maximum of 5 were saved.
i have found that the problem was to send the real UIImage and not URL:
NSMutableArray *activityItems = [[NSMutableArray alloc] init];
for(UIImage *image in imagesArray) {
[activityItems addObject:image];
}
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
To expand on Bill's answer, UIImageWriteToSavedPhotosAlbum seems to do its writing on some unknown thread asynchronously - but also there is some hidden limit to the number of images it can write at once. You can even tease out write busy-type errors if you dig in deep.
Tons more info here:
Objective-C: UIImageWriteToSavedPhotosAlbum() + asynchronous = problems
I also agree with Bill that serializing your writes is the only reasonable/reliable answer
I have seen.

Detect whether an UIImage is PNG or JPEG?

Currently doing my first steps with iPhone development through MonoTouch, I am playing with an UIImage that I read from the photo library.
What I want to achieve is to get the raw byte array (byte[]) of the image.
I know that there are the UIImageJPEGRepresentation and UIImagePNGRepresentation wrappers in MonoTouch. I also know how to use them. What I don't know is:
How do I decide which of these two functions to call?
I.e. if the original image is a JPEG image, I do not want to get it as an PNG but also as a JPEG, and vice versa.
Is there a way to do this, or am I missing some points on this?
Once you have a UIImage, it is capable of producing either a JPEG or PNG using UIImageJPEGRepresentation or UIImagePNGRepresentation. The format of the original image is only important when the UIImage is being created from it (decides which CFImage provider to load it).
If it's important to your app or algorithm to ensure you save it as the original format, I think you have to maintain that info to use when your writing it. I double checked and couldn't find anything that advertised what format it came from.
Are you going to change the image through UIImageView or does the image stay unchanged in your experience? If it's not changed and you just need the UI to select the image, could you get to file bytes? For example, if you showed the images just to select and then you upload them to a server or something, the UIImage could only be for viewing and selecting and if your data structure remembers which file it came from, you could get the bits back off disk and upload. If your changing the file in the view, then you or the user needs to decide the output (and if jpeg the quality) of the image.
PREPARE
typedef NS_ENUM(NSInteger, DownloadImageType) {
DownloadImageTypePng,
DownloadImageTypeJpg
};
#property (assign, nonatomic) DownloadImageType imageType;
DETECT
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *compareString = [[info objectForKey:UIImagePickerControllerReferenceURL] absoluteString];
NSRange pngRange = [compareString rangeOfString:#"PNG" options:NSBackwardsSearch];
if (pngRange.location != NSNotFound) {
compareString = [compareString substringFromIndex:pngRange.location];
self.imageType = DownloadImageTypePng;
NSLog(#"%#", compareString);
} else {
NSLog(#"Not PNG");
}
NSRange jpgRange = [compareString rangeOfString:#"JPG" options:NSBackwardsSearch];
if (jpgRange.location != NSNotFound) {
compareString = [compareString substringFromIndex:jpgRange.location];
self.imageType = DownloadImageTypeJpg;
NSLog(#"%#", compareString);
} else {
NSLog(#"Not JPG");
}
}
USE
if (self.imageType == DownloadImageTypePng) {
} else if (self.imageType == DownloadImageTypeJpg) {
}

save images to photo library, but sometimes can not work correctly

I used the codes below to save images to photo librabry
for(int i=0;i<[imageNameArray count];i++)
{
NSMutableString *sss=[[NSMutableString alloc] initWithString: myAppPath];
[sss appendString:#"/"] ;
[sss appendString: [NSString stringWithFormat:#"%#",[imageNameArray objectAtIndex:i] ] ] ;
UIImage *image = [[[UIImage alloc] initWithContentsOfFile:sss]autorelease];
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
[sss release];
}
but sometimes, it can not save images correctly, I found that in photo library, there are one or more black blocks replace the saved images in thumbnail mode, but if I click the black blocks, the original images can display correctly.
Is there anyone met the same problem?
Welcome any comment
Thanks
interdev
It could be a problem that you're saving the images in quick succession, and as a result, the save calls are overlapping. (It takes longer to write an image to the disk than it does to return from the function).
As far as I understand the save image function is asynchronous, and allows a delegate/call back to be registered (in the places where you're passing nil).
You should probably wait until one image has finished writing until you start another.
You can engineer this using the delegate and callbacks. To make it better for the user and to give them an idea of whats happening, you can display a progress bar and other information such as "1/3 images saved" etc.
Edit:
For a better context, I looked up the documentation:
The UIImageWriteToSavedPhotosAlbum function is declared as such:
void UIImageWriteToSavedPhotosAlbum (
UIImage *image,
id completionTarget,
SEL completionSelector,
void *contextInfo
);
you should set the completionTarget (likely to be self) and the completionSelector which should have the following signature:
- (void) image: (UIImage *) image
didFinishSavingWithError: (NSError *) error
contextInfo: (void *) contextInfo;
In the completion selector, you can perform the logic of whether or not you need to perform another save, and update your 'progress' UI.