[英]iOS: Select a GIF from the photo library, convert to NSData for use in multipart/form-data
What's currently working in my code: 我的代码目前正在使用什么:
I select a JPG or PNG from the Photo Library (using standard ImagePicker methods), and convert that image to NSData using: 我从照片库中选择了JPG或PNG(使用标准的ImagePicker方法),并使用以下方法将该图像转换为NSData:
self.myImageData = UIImageJPEGRepresentation(myImage, 0.9);
which I then post to a server using multipart/form-data. 然后我使用multipart / form-data将其发布到服务器。
I now want to do the same for a GIF, while retaining the original GIF data (so that an animated GIF going into the library, comes back out still animating). 我现在想要为GIF做同样的事情,同时保留原始的GIF数据(以便动画GIF进入图书馆,恢复出来仍然是动画)。
In didFinishPickingMediaWithInfo, I am able to get the URL of the original GIF using 在didFinishPickingMediaWithInfo中,我可以使用原始GIF的URL
self.myGIFURL = [info objectForKey:UIImagePickerControllerReferenceURL].
Here's one example of what that might get me: 这是一个可能让我得到的例子:
assets-library://asset/asset.GIF?id=1000000034&ext=GIF
资产库://asset/asset.GIF ID = 1000000034&EXT = GIF
Here are two ways I've tried now to push this GIF into NSData, and each time I myImageData shows (null). 以下是我现在尝试将此GIF推送到NSData的两种方法,每次myImageData显示(null)。
I've tried to use initWithContentsOfURL: 我试过使用initWithContentsOfURL:
NSData *dataFromGIFURL = [[NSData alloc] initWithContentsOfURL: myGIFURL];
self.myImageData = dataFromGIFURL;
[dataFromGIFURL release];
Then I tried converting the NSURL to a string for initWithContentsOfFile: 然后我尝试将NSURL转换为initWithContentsOfFile的字符串:
NSString *stringFromURL = [NSString stringWithFormat:@"%@", myGIFURL];
NSData *dataFromGIFURL = [[NSData alloc] initWithContentsOfFile: stringFromURL];
self.myImageData = dataFromGIFURL;
[dataFromGIFURL release];
Any suggestions? 有什么建议? Thanks.
谢谢。
The UIImagePickerControllerReferenceURL key doesn't appear until iOS 4.1. UIImagePickerControllerReferenceURL键在iOS 4.1之前不会出现。 I therefore take it as implicit in your question that it's fine to use the AssetsLibrary framework, which appeared in iOS only at 4.0.
因此,我在你的问题中暗示,使用AssetsLibrary框架是很好的,该框架仅在4.0版本的iOS中出现。 In which case, you can use the following:
在这种情况下,您可以使用以下内容:
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL]
resultBlock:^(ALAsset *asset)
{
ALAssetRepresentation *representation = [asset defaultRepresentation];
NSLog(@"size of asset in bytes: %d", [representation size]);
unsigned char bytes[4];
[representation getBytes:bytes fromOffset:0 length:4 error:nil];
NSLog(@"first four bytes: %02x (%c) %02x (%c) %02x (%c) %02x (%c)",
bytes[0], bytes[0],
bytes[1], bytes[1],
bytes[2], bytes[2],
bytes[3], bytes[3]);
[library autorelease];
}
failureBlock:^(NSError *error)
{
NSLog(@"couldn't get asset: %@", error);
[library autorelease];
}
];
}
So, you create an ALAssetsLibrary, ask it to find you the asset with the URL specified (it understands the assets-library:// URL scheme), then when you get the asset you grab its default representation and use that to feed you the bytes. 因此,您创建了一个ALAssetsLibrary,要求它找到指定了URL的资产(它理解assets-library:// URL方案),然后当您获得资产时,您将获取其默认表示并使用它来为您提供字节。 They'll be the actual on-disk bytes, the default representation for an asset from the library being its on-disk form.
它们将是实际的磁盘上字节,来自磁带库的资产的默认表示形式是磁盘形式。
For example, selecting a particular GIF I grabbed at random from Google images, from an image picker wired up to a delegate with that method in it gives me the output: 例如,选择我从Google图像中随机抓取的特定GIF,从连接到该代理的代理的图像选择器中获取输出:
2011-03-03 23:17:37.451 IPTest[1199:307] size of asset in bytes: 174960
2011-03-03 23:17:37.451 IPTest [1199:307]资产大小,以字节为单位:174960
2011-03-03 23:17:37.459 IPTest[1199:307] first four bytes: 47 (G) 49 (I) 46 (F) 38 (8)
2011-03-03 23:17:37.459 IPTest [1199:307]前四个字节:47(G)49(I)46(F)38(8)
So that's the beginning of the standard GIF header. 这就是标准GIF标题的开头。 Picking PNGs or JPGs gives the recognisable first four bytes of the PNG and JPG headers.
选择PNG或JPG可以识别PNG和JPG标头的前四个字节。
EDIT: to finish the thought, obviously you can use ALAssetRepresentation to read all of the bytes describing the file into a suitably malloc'd C array, then use NSData +(id)dataWithBytes:length: (or, more likely, +dataWithBytesNoCopy:length:freeWhenDone:) to wrap that into an NSData. 编辑:完成这个想法,显然你可以使用ALAssetRepresentation将描述文件的所有字节读入一个适当的malloc'd C数组,然后使用NSData +(id)dataWithBytes:length :(或者更可能的是,+ dataWithBytesNoCopy: length:freeWhenDone :)将其包装成NSData。
Here's a version that uses the newer Photos framework: 这是一个使用较新的Photos框架的版本:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSURL * refUrl = [info objectForKey:UIImagePickerControllerReferenceURL];
if (refUrl) {
PHAsset * asset = [[PHAsset fetchAssetsWithALAssetURLs:@[refUrl] options:nil] lastObject];
if (asset) {
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.synchronous = YES;
options.networkAccessAllowed = NO;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
NSNumber * isError = [info objectForKey:PHImageErrorKey];
NSNumber * isCloud = [info objectForKey:PHImageResultIsInCloudKey];
if ([isError boolValue] || [isCloud boolValue] || ! imageData) {
// fail
} else {
// success, data is in imageData
}
}];
}
}
}
Here's Eli's version using Swift 3: 这是使用Swift 3的Eli版本:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
guard let imageURL = info[UIImagePickerControllerReferenceURL] as? URL else { return }
guard let asset = PHAsset.fetchAssets(withALAssetURLs: [imageURL], options: nil).lastObject else { return }
if picker.sourceType == .photoLibrary || picker.sourceType == .savedPhotosAlbum {
let options = PHImageRequestOptions()
options.isSynchronous = true
options.isNetworkAccessAllowed = false
options.deliveryMode = .highQualityFormat
PHImageManager.default().requestImageData(for: asset, options: options) { data, uti, orientation, info in
guard let info = info else { return }
if let error = info[PHImageErrorKey] as? Error {
log.error("Cannot fetch data for GIF image: \(error)")
return
}
if let isInCould = info[PHImageResultIsInCloudKey] as? Bool, isInCould {
log.error("Cannot fetch data from cloud. Option for network access not set.")
return
}
// do something with data (it is a Data object)
}
} else {
// do something with media taken via camera
}
}
Swift 4 update: Swift 4更新:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let mediaType = info[UIImagePickerControllerMediaType] as! CFString
let assetPath = info[UIImagePickerControllerReferenceURL] as! URL
self.dismiss(animated: true, completion: nil)
switch mediaType {
case kUTTypeImage, kUTTypeLivePhoto, kUTTypeGIF:
if let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
if (assetPath.absoluteString.hasSuffix("GIF")) || (assetPath.absoluteString.hasSuffix("gif")){
print("GIF")
let options = PHImageRequestOptions()
options.isSynchronous = true
options.isNetworkAccessAllowed = false
options.deliveryMode = .highQualityFormat
guard let asset = PHAsset.fetchAssets(withALAssetURLs: [assetPath], options: nil).lastObject else { return }
PHImageManager.default().requestImageData(for: asset, options: options) { data, uti, orientation, info in
guard let info = info else { return }
if let error = info[PHImageErrorKey] as? Error {
print("Cannot fetch data for GIF image: \(error)")
return
}
if let isInCould = info[PHImageResultIsInCloudKey] as? Bool, isInCould {
print("Cannot fetch data from cloud. Option for network access not set.")
return
}
if let gifImageData = data {
// do something with data (it is a Data object)
}
}
} else {
// this is the basic image
}
}
case kUTTypeMovie:
if let videoURL = info[UIImagePickerControllerMediaURL] as? URL {
// using video type
}
default:
print("Others")
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.