Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
341 views
in Technique[技术] by (71.8m points)

iphone - 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:

self.myImageData = UIImageJPEGRepresentation(myImage, 0.9); 

which I then post to a server using 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).

In didFinishPickingMediaWithInfo, I am able to get the URL of the original GIF using

self.myGIFURL = [info objectForKey:UIImagePickerControllerReferenceURL]. 

Here's one example of what that might get me:

assets-library://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).

I've tried to use initWithContentsOfURL:

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

Then I tried converting the NSURL to a string for initWithContentsOfFile:

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

Any suggestions? Thanks.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The UIImagePickerControllerReferenceURL key doesn't appear until 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. 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. 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:

2011-03-03 23:17:37.451 IPTest[1199:307] size of asset in bytes: 174960

2011-03-03 23:17:37.459 IPTest[1199:307] first four bytes: 47 (G) 49 (I) 46 (F) 38 (8)

So that's the beginning of the standard GIF header. Picking PNGs or JPGs gives the recognisable first four bytes of the PNG and JPG headers.

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...