iphone UIImagePickerController और मौजूदा फ़ोटो से EXIF डेटा निकालने




cocoa-touch gps (15)

क्या कोई विशिष्ट कारण है कि आप छवि से स्थान डेटा निकालना चाहते हैं? कोरलोकेशन ढांचे का उपयोग करके अलग-अलग स्थान प्राप्त करने का विकल्प हो सकता है। यदि यह केवल आपको आवश्यक भूगोल है, तो यह आपको कुछ सिरदर्द बचा सकता है।

यह अच्छी तरह से जाना जाता है कि UIImagePickerController चयन के बाद फोटो के मेटाडेटा को वापस नहीं करता है। हालांकि, ऐप स्टोर (मोबाइल फ़ोटोज़, पिक्सेलपिप) में कुछ ऐप्स मूल फ़ाइलों और उनके भीतर संग्रहीत EXIF ​​डेटा को पढ़ने में सक्षम होते हैं, जिससे ऐप को चयनित फ़ोटो से जिओडाटा निकालने में सक्षम बनाता है।

वे मूल फ़ाइल को / निजी / var / मोबाइल / मीडिया / डीसीआईएम / 100APPLE / फ़ोल्डर से पढ़कर और EXIF ​​लाइब्रेरी के माध्यम से इसे चलाकर ऐसा करते हैं।

हालांकि, मैं UIImagePickerController से डिस्क पर एक फ़ाइल में लौटाई गई तस्वीर से मेल खाने का एक तरीका नहीं निकाल सकता। मैंने फ़ाइल आकारों की खोज की है, लेकिन मूल फ़ाइल एक जेपीईजी है, जबकि लौटाई गई छवि कच्ची यूआईएममेज है, जिससे छवि के फ़ाइल आकार को जानना असंभव हो गया है।

मैं हैश की एक टेबल बनाने और प्रत्येक छवि के पहले एक्स पिक्सेल के खिलाफ मिलान करने पर विचार कर रहा हूं। हालांकि यह शीर्ष पर थोड़ा सा लगता है, और शायद काफी धीमी है।

कोई सुझाव?


यह आईओएस 5 (बीटा 4) और कैमरा रोल के साथ काम करता है (आपको .h में ब्लॉक के लिए टाइप defs की आवश्यकता है):

#import <Photos/Photos.h>

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

    NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
    PHFetchResult *fetchResult = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];
    PHAsset *asset = fetchResult.firstObject;

    //All you need is
    //asset.location.coordinate.latitude
    //asset.location.coordinate.longitude

    //Other useful properties of PHAsset
    //asset.favorite
    //asset.modificationDate
    //asset.creationDate
}

मैं इस पर काम करने के लिए थोड़ी देर बिताता हूं, जिसके लिए मुझे एक आवेदन के लिए अनुबंधित किया गया था। असल में एपीआई वर्तमान में खड़ा है क्योंकि यह संभव नहीं है। मूल समस्या UIImage क्लास अभिविन्यास को छोड़कर सभी EXIF ​​डेटा STRIPS है। कैमरा रोल में सहेजने के लिए यह फ़ंक्शन भी इस डेटा को स्ट्रिप्स करता है। तो मूल रूप से किसी भी अतिरिक्त EXIF ​​डेटा को पकड़ने और बनाए रखने का एकमात्र तरीका यह है कि इसे अपने एप्लिकेशन में एक निजी "कैमरा रोल" में सहेज लें। मैंने इस बग को सेब के साथ भी दायर किया है और ऐप समीक्षक प्रतिनिधि की आवश्यकता पर जोर दिया है जिसके साथ हम संपर्क में हैं। उम्मीद है कि किसी दिन वे इसे जोड़ देंगे .. अन्यथा यह जीईओ टैगिंग पूरी तरह से बेकार है क्योंकि यह केवल "स्टॉक" कैमरा एप्लिकेशन में काम करता है।

नोट ऐप स्टोर पर कुछ एप्लिकेशन इस के आसपास हैक । जीईओ डेटा को बचाने के लिए, जो मैंने पाया है, सीधे कैमरे रोल तक पहुंच रहा है और सीधे फोटो सहेज रहा है। हालांकि यह केवल कैमरा रोल / सहेजी गई तस्वीरों के साथ काम करता है और शेष फोटो लाइब्रेरी नहीं। आपके कंप्यूटर से आपके फोन पर "सिंक" की गई तस्वीरों में अभिविन्यास को छोड़कर सभी EXIF ​​डेटा हैं।

मैं अभी भी समझ नहीं पा रहा हूं कि उन अनुप्रयोगों को क्यों स्वीकृत किया गया था (वे कैमरे रोल से भी हटा दें) और हमारे आवेदन जो कि उनमें से कोई भी अभी भी वापस नहीं रखा जा रहा है।


ऐसा लगता है कि UIImagePickerControllerMediaURL द्वारा प्राप्त तस्वीर में एक्फिफ़ टैग बिल्कुल नहीं हैं


मेरे पास एक समान सवाल था जहां मैं सिर्फ एक तस्वीर लेना चाहता था और उपरोक्त में से कोई भी मेरी समस्या को सरल तरीके से हल करने के लिए प्रकट नहीं होता है (उदाहरण के लिए कोई बाहरी पुस्तकालय नहीं), तो यहां वह सभी डेटा है जो मैं पा सकता हूं जिसे आप निकाल सकते हैं पिकर के साथ इसे चुनने के बाद एक छवि से:

mediaType=public.image
originalImage=<UIImage: 0x7fb38e00e870> size {1280, 850} orientation 0 scale 1.000000
editedImage=<UIImage: 0x7fb38e09e1e0> size {640, 424} orientation 0 scale 1.000000
cropRect=NSRect: {{0, 0}, {1280, 848}}
mediaUrl=(null)
referenceUrl=assets-library://asset/asset.JPG?id=AC072879-DA36-4A56-8A04-4D467C878877&ext=JPG
mediaMetadata=(null)
type=ALAssetTypePhoto
location=(null)
duration=ALErrorInvalidProperty
assetUrl=assets-library://asset/asset.JPG?id=AC072879-DA36-4A56-8A04-4D467C878877&ext=JPG
orientation=0
date=2014-07-14 04:28:18 +0000
representations=(
    "public.jpeg"
)
urls={
    "public.jpeg" = "assets-library://asset/asset.JPG?id=AC072879-DA36-4A56-8A04-4D467C878877&ext=JPG";
}

तो जब आप कोई छवि चुनते हैं, तो आपको ऐसा लगता है जो इस तरह दिखता है (तिथि सहित!):

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

    // Try to get the original file.
    NSURL *originalFile = [info objectForKey:UIImagePickerControllerMediaURL];
    if (originalFile) {
        NSData *fileData = [NSData dataWithContentsOfURL:originalFile];
    }
}

वैसे भी, उम्मीद है कि कुछ और बचाता है।


फ़ाइल फ़ाइल को मूल फ़ाइल में प्राप्त करने के लिए UIImagePickerControllerMediaURL शब्दकोश कुंजी का उपयोग करें। दस्तावेज़ीकरण के बावजूद, आप फोटो के लिए फ़ाइल यूआरएल और न केवल फिल्में प्राप्त कर सकते हैं।

 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
      let url = info[UIImagePickerControllerReferenceURL] as? URL
            if url != nil {

                let fetchResult = PHAsset.fetchAssets(withALAssetURLs: [url!], options: nil)
                let asset = fetchResult.firstObject
                print(asset?.location?.coordinate.latitude)
                print(asset?.creationDate)
            }
    }

ऐसा करने का शरारती तरीका UIImagePickerViewController के विचारों को पार करना है और प्रतिनिधि कॉलबैक में चयनित छवि को चुनना है।

 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { id thumbnailView = [[[[[[[[[[picker.view subviews] objectAtIndex:0] subviews] objectAtIndex:0] subviews] objectAtIndex:0] subviews] objectAtIndex:0] subviews] objectAtIndex:0]; NSString *fullSizePath = [[[thumbnailView selectedPhoto] fileGroup] pathForFullSizeImage]; NSString *thumbnailPath = [[[thumbnailView selectedPhoto] fileGroup] pathForThumbnailFile]; NSLog(@"%@ and %@", fullSizePath, thumbnailPath); } 

इससे आपको पूर्ण आकार की छवि का मार्ग मिल जाएगा, जिसे आप अपनी पसंद के EXIF ​​लाइब्रेरी के साथ खोल सकते हैं।

लेकिन, यह एक निजी एपीआई कहता है और यदि आप इस ऐप को सबमिट करते हैं तो इन विधि नामों को ऐप्पल द्वारा पता लगाया जाएगा । तो ऐसा मत करो, ठीक है?


क्या आपने इस आईफोन लाइब्रेरी को देखा है?

http://code.google.com/p/iphone-exif/

मेरी तरफ से कोशिश करूँगा। मैं उस चित्र से जीपीएस (जियोटैग) निर्देशांक प्राप्त करना चाहता हूं जो UIImagePickerController के साथ लिया गया है: /

एक गहरी नजर के बाद, यह लाइब्रेरी एनएसडीटा जानकारी को इनपुट के रूप में लेती है और यूआईएममेज पिकर कंट्रोलर स्नैपशॉट लेने के बाद यूआईएममेज लौटाता है। सिद्धांत रूप में, यदि हम UIImage के लिए UIkit श्रेणी से चयनित का उपयोग करते हैं

NSData * UIImageJPEGRepresentation (
   UIImage *image,
   CGFloat compressionQuality
);

फिर हम UIImage को NSData इंस्टेंस में परिवर्तित कर सकते हैं और फिर इसे आईफोन एक्सिफ़ लाइब्रेरी के साथ उपयोग कर सकते हैं।

अद्यतन करें:
मैंने ऊपर वर्णित पुस्तकालय को एक परीक्षण दिया और ऐसा लगता है कि यह काम करता है। हालांकि, EXIF ​​प्रारूप और लाइब्रेरी में उच्च स्तरीय एपीआई की कमी के बारे में मेरे सीमित knwoledge के कारण, मैं EXIF ​​टैग के लिए मान प्राप्त करने का प्रबंधन नहीं करता हूं। यदि आप में से कोई भी आगे जा सकता है तो यहां मेरा कोड है:


#import "EXFJpeg.h"

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
    NSLog(@"image picked %@ with info %@", image, editingInfo);
    NSData* jpegData = UIImageJPEGRepresentation (image,0.5);
    EXFJpeg* jpegScanner = [[EXFJpeg alloc] init];
    [jpegScanner scanImageData: jpegData];
    EXFMetaData* exifData = jpegScanner.exifMetaData;
    EXFJFIF* jfif = jpegScanner.jfif;
    EXFTag* tagDefinition = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_DateTime]];
    //EXFTag* latitudeDef = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_GPSLatitude]];
    //EXFTag* longitudeDef = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_GPSLongitude]];
    id latitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLatitude]];
    id longitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLongitude]];
    id datetime = [exifData tagValue:[NSNumber numberWithInt:EXIF_DateTime]];
    id t = [exifData tagValue:[NSNumber numberWithInt:EXIF_Model]];
....
....

टैग परिभाषा को पुनर्प्राप्त करना ठीक है, लेकिन सभी टैग मान nil लौटाते हैं :(

यदि आप लाइब्रेरी को आज़माकर देखना चाहते हैं, तो आपको इसे चलाने के लिए एक वैश्विक चर परिभाषित करने की आवश्यकता है (जैसा कि दस्तावेज़ में समझाया गया है लेकिन hum ..: /)

BOOL gLogging = FALSE;

अद्यतन 2
यहां जवाब दें: आईफोन - एक फोटो से स्थान की जानकारी का उपयोग करें UIImage मेटा जानकारी को समाहित नहीं करता है , इसलिए हम अटक गए हैं: निश्चित रूप से, इस इंटरफ़ेस के माध्यम से कोई EXIF ​​जानकारी नहीं दी जाएगी।

अंतिम अद्यतन
ठीक है, मैं इसे पिकर द्वारा लौटाए गए चित्रों को कम से कम जियोटैग करने के लिए काम करने में कामयाब रहा।
UIImagePickerController को ट्रिगर करने से पहले, वर्तमान कॉलेशन पुनर्प्राप्त करने के लिए CLLocationManager का उपयोग करना आपके ऊपर निर्भर है
एक बार आपके पास हो जाने के बाद, आप इस विधि का उपयोग कर सकते हैं जो क्लाउलोकेशन से UIImage को geotag करने के लिए exif-iPhone लाइब्रेरी का उपयोग करता है:

-(void) imagePickerController:(UIImagePickerController *)picker 
           didFinishPickingMediaWithInfo:(NSDictionary *)info
{
  NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
  if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
    NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
    if (url) {
      ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset) {
      CLLocation *location = [myasset valueForProperty:ALAssetPropertyLocation];
      // location contains lat/long, timestamp, etc
      // extracting the image is more tricky and 5.x beta ALAssetRepresentation has bugs!
    };
    ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror) {
      NSLog(@"cant get image - %@", [myerror localizedDescription]);
    };
    ALAssetsLibrary *assetsLib = [[ALAssetsLibrary alloc] init];
    [assetsLib assetForURL:url resultBlock:resultblock failureBlock:failureblock];
  }
}


iOS 8 में एक तरीका है

किसी भी तृतीय पक्ष EXIF लाइब्रेरी का उपयोग किए बिना

// Inside whatever implements UIImagePickerControllerDelegate
@import AssetsLibrary;

// ... your other code here ...

@implementation MYImagePickerDelegate

- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    NSString *mediaType = info[UIImagePickerControllerMediaType];
    UIImage *originalImage = info[UIImagePickerControllerOriginalImage];
    UIImage *editedImage = info[UIImagePickerControllerEditedImage];
    NSValue *cropRect = info[UIImagePickerControllerCropRect];
    NSURL *mediaUrl = info[UIImagePickerControllerMediaURL];
    NSURL *referenceUrl = info[UIImagePickerControllerReferenceURL];
    NSDictionary *mediaMetadata = info[UIImagePickerControllerMediaMetadata];

    NSLog(@"mediaType=%@", mediaType);
    NSLog(@"originalImage=%@", originalImage);
    NSLog(@"editedImage=%@", editedImage);
    NSLog(@"cropRect=%@", cropRect);
    NSLog(@"mediaUrl=%@", mediaUrl);
    NSLog(@"referenceUrl=%@", referenceUrl);
    NSLog(@"mediaMetadata=%@", mediaMetadata);

    if (!referenceUrl) {
        NSLog(@"Media did not have reference URL.");
    } else {
        ALAssetsLibrary *assetsLib = [[ALAssetsLibrary alloc] init];
        [assetsLib assetForURL:referenceUrl
                   resultBlock:^(ALAsset *asset) {
                       NSString *type = 
                           [asset valueForProperty:ALAssetPropertyType];
                       CLLocation *location = 
                           [asset valueForProperty:ALAssetPropertyLocation];
                       NSNumber *duration = 
                           [asset valueForProperty:ALAssetPropertyDuration];
                       NSNumber *orientation = 
                           [asset valueForProperty:ALAssetPropertyOrientation];
                       NSDate *date = 
                           [asset valueForProperty:ALAssetPropertyDate];
                       NSArray *representations = 
                           [asset valueForProperty:ALAssetPropertyRepresentations];
                       NSDictionary *urls = 
                           [asset valueForProperty:ALAssetPropertyURLs];
                       NSURL *assetUrl = 
                           [asset valueForProperty:ALAssetPropertyAssetURL];

                       NSLog(@"type=%@", type);
                       NSLog(@"location=%@", location);
                       NSLog(@"duration=%@", duration);
                       NSLog(@"assetUrl=%@", assetUrl);
                       NSLog(@"orientation=%@", orientation);
                       NSLog(@"date=%@", date);
                       NSLog(@"representations=%@", representations);
                       NSLog(@"urls=%@", urls);
                   }
                  failureBlock:^(NSError *error) {
                      NSLog(@"Failed to get asset: %@", error);
                  }];
    }

    [picker dismissViewControllerAnimated:YES
                               completion:nil];
}

@end

मैं कैमरा रोल छवियों के लिए इसका उपयोग कर रहा हूँ

import AssetsLibrary

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

    if picker.sourceType == UIImagePickerControllerSourceType.photoLibrary,
        let url = info[UIImagePickerControllerReferenceURL] as? URL {

        let assetLibrary = ALAssetsLibrary()
        assetLibrary.asset(for: url, resultBlock: { (asset) in
            if let asset = asset {
                let assetRep: ALAssetRepresentation = asset.defaultRepresentation()
                let metaData: NSDictionary = assetRep.metadata() as NSDictionary
                print(metaData)
            }
        }, failureBlock: { (error) in
            print(error!)
        })
    }

}

यह स्पष्ट रूप से काम करता है अगर छवि में जीपीएस मेटा सूचनाएं हैं

आशा करता हूँ की ये काम करेगा


आईओएस 8 के लिए और बाद में आप फोटो फ्रेमवर्क का उपयोग कर सकते हैं

- (BOOL)writeCGImageToCameraRoll:(CGImageRef)cgImage withMetadata:(NSDictionary *)metadata
{

   NSDictionary *Exif = [metadata objectForKey:@"Exif"];   // Add this line

}

ऐप्पल ने आईओएस 4 में एक छवि I / O फ्रेमवर्क जोड़ा है जिसका उपयोग चित्रों से EXIF ​​डेटा पढ़ने के लिए किया जा सकता है। मुझे नहीं पता कि UIImagePickerController हालांकि एम्बेडेड EXIF ​​डेटा के साथ एक तस्वीर देता है।

संपादित करें: आईओएस 4 में आप UIImagePickerControllerMediaMetadata कुंजी के मूल्य को हथियाने के द्वारा EXII डेटा प्राप्त कर सकते हैं जो UIImagePickerControllerDelegate प्रतिनिधि को पास की जाने वाली जानकारी शब्दकोश में है।


आईओएस 10 के लिए - स्विफ्ट 3

पिकर के कॉलबैक में एक info निर्देश है जहां metadata साथ एक कुंजी metadata : UIImagePickerControllerMediaMetadata


आप UIImagePickerController और निर्देशिका में प्रत्येक छवि द्वारा लौटाए गए छवि डेटा को हश करने में सक्षम हो सकते हैं और उनकी तुलना कर सकते हैं।


बस एक विचार है, लेकिन क्या आपने GitHub पर थ्री 20 प्रोजेक्ट में TTPhotoViewController को आजमाया है?

यह एक छवि पिकर प्रदान करता है जो कई स्रोतों से पढ़ सकता है। आप इसे UIImagePickerController के विकल्प के रूप में उपयोग करने में सक्षम हो सकते हैं, या स्रोत आपको एक सुराग दे सकता है कि आपको आवश्यक जानकारी कैसे प्राप्त करें।





exif