• iOS 拍照中加入GPS和具体地理位置


    最近有一个需求,要求用手机拍个照片,并切需要拍摄时间,拍摄gps,拍摄具体街道信息。

    首先要感谢PhotoGPSdemo的作者,你可以到这里下载demo http://www.cocoachina.com/bbs/read.php?tid=130501

    以前,总认为jpg就是包含了像素信息的2进制文件,其实,jpg中还可以包含许多起它的信息,只不过我们平常用查看jpg属性时,系统没有给我们把信息全部显示出来而已!

    在iOS中,提供了一组函数来操作jpg的这些额外的信息,你需要#import <ImageIO/ImageIO.h>才能使用他们。

    首先,需要注意的是,UIImage对象中是没有这些信息的,它仅仅包含图像本身,jpg才包含这些信息,请不要弄混。

    先看看怎么从jpg图片中取得各种额外信息,代码如下

    - (IBAction)test
    {
        NSString * home = NSHomeDirectory();
        NSData *data = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@"%@/Documents/xx.jpg",home]];
        
        CGImageSourceRef imgSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
        
        CFDictionaryRef metaDataDicRef = CGImageSourceCopyPropertiesAtIndex(imgSource,0,nil);
        NSLog(@"cfdictionary %@",(__bridge NSDictionary *)metaDataDicRef);
        
        NSDictionary *dic = (__bridge NSDictionary *)metaDataDicRef;
        
        NSDictionary *exifDic = [dic objectForKey:(NSString *)kCGImagePropertyExifDictionary];
        
        NSString *location = [exifDic objectForKey:(NSString *)kCGImagePropertyExifCameraOwnerName];
        NSLog(@"location is %@",location);
        
        NSString *DateTimeOriginal = [exifDic objectForKey:(NSString *)kCGImagePropertyExifDateTimeOriginal];
        NSLog(@"time is %@",DateTimeOriginal);
        
        CFRelease(metaDataDicRef);
        CFRelease(imgSource);
    }

    首先,需要用到CGImageSourceRef类,不能用UIImage类型(需要验证。。。),这种CGImageSourceRef类型可以通过函数取出jpg的额外数据,这些数据叫做metaData,翻译过来就是元数据。得到的metaData是以字典形式返回的,其中的key是固定的,具体声明见下方

    CFStringRef kCGImagePropertyTIFFDictionary;
    CFStringRef kCGImagePropertyGIFDictionary;
    CFStringRef kCGImagePropertyJFIFDictionary;
    CFStringRef kCGImagePropertyExifDictionary;
    CFStringRef kCGImagePropertyPNGDictionary;
    CFStringRef kCGImagePropertyIPTCDictionary;
    CFStringRef kCGImagePropertyGPSDictionary;
    CFStringRef kCGImagePropertyRawDictionary;
    CFStringRef kCGImagePropertyCIFFDictionary;
    CFStringRef kCGImageProperty8BIMDictionary;
    CFStringRef kCGImagePropertyDNGDictionary;
    CFStringRef kCGImagePropertyExifAuxDictionary;

    这些key中,有许多key对应的对象还是一个字典,比如kCGImagePropertyExifDictionary所对应的对象包含一下key值

    const CFStringRef kCGImagePropertyExifExposureTime;
    const CFStringRef kCGImagePropertyExifFNumber;
    const CFStringRef kCGImagePropertyExifExposureProgram;
    const CFStringRef kCGImagePropertyExifSpectralSensitivity;
    const CFStringRef kCGImagePropertyExifISOSpeedRatings;
    const CFStringRef kCGImagePropertyExifOECF;
    const CFStringRef kCGImagePropertyExifVersion;
    const CFStringRef kCGImagePropertyExifDateTimeOriginal;
    const CFStringRef kCGImagePropertyExifDateTimeDigitized;
    const CFStringRef kCGImagePropertyExifComponentsConfiguration;
    const CFStringRef kCGImagePropertyExifCompressedBitsPerPixel;
    const CFStringRef kCGImagePropertyExifShutterSpeedValue;
    const CFStringRef kCGImagePropertyExifApertureValue;
    const CFStringRef kCGImagePropertyExifBrightnessValue;
    const CFStringRef kCGImagePropertyExifExposureBiasValue;
    const CFStringRef kCGImagePropertyExifMaxApertureValue;
    const CFStringRef kCGImagePropertyExifSubjectDistance;
    const CFStringRef kCGImagePropertyExifMeteringMode;
    const CFStringRef kCGImagePropertyExifLightSource;
    const CFStringRef kCGImagePropertyExifFlash;
    const CFStringRef kCGImagePropertyExifFocalLength;
    const CFStringRef kCGImagePropertyExifSubjectArea;
    const CFStringRef kCGImagePropertyExifMakerNote;
    const CFStringRef kCGImagePropertyExifUserComment;
    const CFStringRef kCGImagePropertyExifSubsecTime;
    const CFStringRef kCGImagePropertyExifSubsecTimeOrginal;
    const CFStringRef kCGImagePropertyExifSubsecTimeDigitized;
    const CFStringRef kCGImagePropertyExifFlashPixVersion;
    const CFStringRef kCGImagePropertyExifColorSpace;
    const CFStringRef kCGImagePropertyExifPixelXDimension;
    const CFStringRef kCGImagePropertyExifPixelYDimension;
    const CFStringRef kCGImagePropertyExifRelatedSoundFile;
    const CFStringRef kCGImagePropertyExifFlashEnergy;
    const CFStringRef kCGImagePropertyExifSpatialFrequencyResponse;
    const CFStringRef kCGImagePropertyExifFocalPlaneXResolution;
    const CFStringRef kCGImagePropertyExifFocalPlaneYResolution;
    const CFStringRef kCGImagePropertyExifFocalPlaneResolutionUnit;
    const CFStringRef kCGImagePropertyExifSubjectLocation;
    const CFStringRef kCGImagePropertyExifExposureIndex;
    const CFStringRef kCGImagePropertyExifSensingMethod;
    const CFStringRef kCGImagePropertyExifFileSource;
    const CFStringRef kCGImagePropertyExifSceneType;
    const CFStringRef kCGImagePropertyExifCFAPattern;
    const CFStringRef kCGImagePropertyExifCustomRendered;
    const CFStringRef kCGImagePropertyExifExposureMode;
    const CFStringRef kCGImagePropertyExifWhiteBalance;
    const CFStringRef kCGImagePropertyExifDigitalZoomRatio;
    const CFStringRef kCGImagePropertyExifFocalLenIn35mmFilm;
    const CFStringRef kCGImagePropertyExifSceneCaptureType;
    const CFStringRef kCGImagePropertyExifGainControl;
    const CFStringRef kCGImagePropertyExifContrast;
    const CFStringRef kCGImagePropertyExifSaturation;
    const CFStringRef kCGImagePropertyExifSharpness;
    const CFStringRef kCGImagePropertyExifDeviceSettingDescription;
    const CFStringRef kCGImagePropertyExifSubjectDistRange;
    const CFStringRef kCGImagePropertyExifImageUniqueID;
    const CFStringRef kCGImagePropertyExifGamma;
    const CFStringRef kCGImagePropertyExifCameraOwnerName;
    const CFStringRef kCGImagePropertyExifBodySerialNumber;
    const CFStringRef kCGImagePropertyExifLensSpecification;
    const CFStringRef kCGImagePropertyExifLensMake;
    const CFStringRef kCGImagePropertyExifLensModel;
    const CFStringRef kCGImagePropertyExifLensSerialNumber;

    这里的每一个key都有具体的含义,代表了jpg的一些信息。这些key和key的值时有严格的格式限定的,你用了自己定义的key或者不符合规则的值,是不能正确地写入jpg文件的(待会要提到如何写入metaData信息)。


    如何用UIImagePickerController拍摄照片后加入信息呢?用这个控件拍照后,默认生成的metaData信息较少,只有拍摄时间等几个信息,没有gps信息,更没有街道信息,我们需要手动加入。

    
    

    #pragma mark - UIImagePickerControllerDelegate

    
    
    
    
    

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

    
    

    {

    
    

        _mediaInfo =[NSMutableDictionarydictionaryWithDictionary:info];

    
    

        

    
    

        if (!_locationManager) {

    
    

            _locationManager = [[CLLocationManager alloc]init];

    
    

            [_locationManagersetDelegate:self];

    
    

            [_locationManagersetDistanceFilter:kCLDistanceFilterNone];

    
    

            [_locationManagersetDesiredAccuracy:kCLLocationAccuracyBest];

    
    

        }

    
    

        [_locationManagerstartUpdatingLocation];

    
    

        

    
    

        [picker dismissViewControllerAnimated:YEScompletion:^

    
    

         {

    
    

             

    
    

         }];

    
    

    }

    
    
    
    
    

    #pragma mark CLLocationManagerDelegate

    
    

    - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{

    
    

        [manager stopUpdatingLocation];

    
    

        

    
    

        UIImage *originalImage= (UIImage *) [_mediaInfoobjectForKey:UIImagePickerControllerOriginalImage];

    
    

        NSData *imageNSData = UIImageJPEGRepresentation(originalImage,1);

    
    

        

    
    

        CGImageSourceRef imgSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageNSData, NULL);

    
    

        //this is the type of image (e.g., public.jpeg)

    
    

        CFStringRef UTI = CGImageSourceGetType(imgSource);

    
    

        

    
    

        //this will be the data CGImageDestinationRef will write into

    
    

        NSMutableData *newImageData = [NSMutableDatadata];

    
    

        CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge  CFMutableDataRef)newImageData, UTI, 1, NULL);

    
    

        

    
    

        if(!destination)

    
    

        {

    
    

            NSLog(@"***Could not create image destination ***");

    
    

            return;

    
    

        }

    
    

        

    
    

        //get original metadata

    
    

        NSDictionary *dict = [_mediaInfoobjectForKey:UIImagePickerControllerMediaMetadata];

    
    

        NSMutableDictionary *metadata = [NSMutableDictionarydictionaryWithDictionary:dict];

    
    

        

    
    

        //set gps info into metadata,we need a dictionary

    
    

        NSDictionary * gpsDict=[newLocation GPSDictionary];

    
    

        if (metadata && gpsDict) {

    
    

            [metadata setValue:gpsDict forKey:(NSString*)kCGImagePropertyGPSDictionary];

    
    

        }

    
    

        

    
    

        //get location detail by CLGeocoder, this needs wifi

    
    

        CLGeocoder *geocoder = [[CLGeocoder alloc] init];

    
    

        [geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error){

    
    

            if(error != nil)

    
    

            {

    
    

                NSLog(@"CLGeocoder error :%@ ",error);

    
    

            }

    
    

            else//if we can get place info ,we set it into meteData dic with kCGImagePropertyExifCameraOwnerName key

    
    

            {

    
    

                if(placemarks.count > 0)

    
    

                {

    
    

                    CLPlacemark *placemark = [placemarks objectAtIndex:0];

    
    

                    NSMutableDictionary *eifDic = (NSMutableDictionary *)[metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary];

    
    

                    [eifDic setObject:placemark.nameforKey:(NSString *)kCGImagePropertyExifCameraOwnerName];

    
    

                }

    
    

            }

    
    

            

    
    

            //add the image contained in the image source to the destination, overidding the old metadata with our modified metadata

    
    

            CGImageDestinationAddImageFromSource(destination, imgSource, 0, (__bridge  CFDictionaryRef) metadata);

    
    

            

    
    

            BOOL success = NO;

    
    

            success = CGImageDestinationFinalize(destination);

    
    

            

    
    

            if(!success) {

    
    

                NSLog(@"***Could not create data from image destination ***");

    
    

                return ;

    
    

            }

    
    

            

    
    

            CFRelease(imgSource);

    
    

            CFRelease(destination);

    
    

            

    
    

            [self sendData:newImageData];

    
    

            [self writeTest:newImageData];

    
    

            

    
    

        }];

    
    

        

    
    

        

    
    

    }

    
    
    
     

    @implementation CLLocation (GPSDictionary)

    -(NSDictionary*)GPSDictionary{

        NSDateFormatter *formatter  = [[NSDateFormatteralloc] init];

        [formatter setDateFormat:@"hh:mm:ss.SS"];

        

        CLLocation *location=self;

        NSDictionary *gpsDict   = [NSDictionarydictionaryWithObjectsAndKeys:

                                   [NSNumbernumberWithFloat:fabs(location.coordinate.latitude)], kCGImagePropertyGPSLatitude,

                                   ((location.coordinate.latitude >= 0) ? @"N" : @"S"), kCGImagePropertyGPSLatitudeRef,

                                   [NSNumbernumberWithFloat:fabs(location.coordinate.longitude)], kCGImagePropertyGPSLongitude,

                                   ((location.coordinate.longitude >= 0) ? @"E" : @"W"), kCGImagePropertyGPSLongitudeRef,

                                   [formatter stringFromDate:[location timestamp]], kCGImagePropertyGPSTimeStamp,

                                   nil];

        NSLog(@"gpsDict i %@",gpsDict);

        

        return gpsDict;

    }

    @end

     

    上面代码需要手动改改,它的最终目的就是用 CGImageDestinationAddImageFromSource(destination, imgSource, 0, (__bridge CFDictionaryRef) metadata);函数用新的metaData信息生成新的jpg数据。

    其中gps数据用了系统自定义的key值写入,街道信息没有找到合适的key,就冒用了kCGImagePropertyExifCameraOwnerName这个key。

  • 相关阅读:
    html5之服务器推送事件
    浅谈js之this对象
    浅谈js之事件处理
    浅谈js之ajax
    浅谈js之事件流
    浅谈js之闭包
    浅谈JS引用类型之Array类型
    关于window.onload的一些小理解
    web渗透测试中WAF绕过讲解(二)基于HTTP协议绕过
    web渗透测试中WAF绕过讲解(一)
  • 原文地址:https://www.cnblogs.com/breezemist/p/3568562.html
Copyright © 2020-2023  润新知