簡體   English   中英

iOS:從照片庫中選擇一個GIF,轉換為NSData以用於multipart / form-data

[英]iOS: Select a GIF from the photo library, convert to NSData for use in multipart/form-data

我的代碼目前正在使用什么:

我從照片庫中選擇了JPG或PNG(使用標准的ImagePicker方法),並使用以下方法將該圖像轉換為NSData:

self.myImageData = UIImageJPEGRepresentation(myImage, 0.9); 

然后我使用multipart / form-data將其發布到服務器。

我現在想要為GIF做同樣的事情,同時保留原始的GIF數據(以便動畫GIF進入圖書館,恢復出來仍然是動畫)。

在didFinishPickingMediaWithInfo中,我可以使用原始GIF的URL

self.myGIFURL = [info objectForKey:UIImagePickerControllerReferenceURL]. 

這是一個可能讓我得到的例子:

資產庫://asset/asset.GIF ID = 1000000034&EXT = GIF

以下是我現在嘗試將此GIF推送到NSData的兩種方法,每次myImageData顯示(null)。

我試過使用initWithContentsOfURL:

NSData *dataFromGIFURL = [[NSData alloc] initWithContentsOfURL: myGIFURL];
self.myImageData = dataFromGIFURL;
[dataFromGIFURL release];

然后我嘗試將NSURL轉換為initWithContentsOfFile的字符串:

NSString *stringFromURL = [NSString stringWithFormat:@"%@", myGIFURL];
NSData *dataFromGIFURL = [[NSData alloc] initWithContentsOfFile: stringFromURL];
self.myImageData = dataFromGIFURL;
[dataFromGIFURL release];

有什么建議? 謝謝。

UIImagePickerControllerReferenceURL鍵在iOS 4.1之前不會出現。 因此,我在你的問題中暗示,使用AssetsLibrary框架是很好的,該框架僅在4.0版本的iOS中出現。 在這種情況下,您可以使用以下內容:

- (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];
        }
    ];
}

因此,您創建了一個ALAssetsLibrary,要求它找到指定了URL的資產(它理解assets-library:// URL方案),然后當您獲得資產時,您將獲取其默認表示並使用它來為您提供字節。 它們將是實際的磁盤上字節,來自磁帶庫的資產的默認表示形式是磁盤形式。

例如,選擇我從Google圖像中隨機抓取的特定GIF,從連接到該代理的代理的圖像選擇器中獲取輸出:

2011-03-03 23:17:37.451 IPTest [1199:307]資產大小,以字節為單位:174960

2011-03-03 23:17:37.459 IPTest [1199:307]前四個字節:47(G)49(I)46(F)38(8)

這就是標准GIF標題的開頭。 選擇PNG或JPG可以識別PNG和JPG標頭的前四個字節。

編輯:完成這個想法,顯然你可以使用ALAssetRepresentation將描述文件的所有字節讀入一個適當的malloc'd C數組,然后使用NSData +(id)dataWithBytes:length :(或者更可能的是,+ dataWithBytesNoCopy: length:freeWhenDone :)將其包裝成NSData。

這是一個使用較新的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
                }
            }];
        }
    }
}

這是使用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更新:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM