媒体层图形技术之ImageIO 学习笔记

本文介绍如何使用Image I/O框架解码GIF动画,包括获取每一帧的信息及延迟时间,并演示如何逐步加载图像数据。此外,还介绍了如何创建和使用ImageSources与ImageDestinations。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.ImageIo --解码gif动画 
解码代码:
void getFrameInfo(CFURLRef url, NSMutableArray *frames, NSMutableArray *delayTimes, CGFloat *totalTime,CGFloat *gifWidth, CGFloat *gifHeight)
{
    CGImageSourceRef gifSource = CGImageSourceCreateWithURL(url, NULL);
    
    // get frame count
    size_t frameCount = CGImageSourceGetCount(gifSource);
    for (size_t i = 0; i < frameCount; ++i) {
        // get each frame
        CGImageRef frame = CGImageSourceCreateImageAtIndex(gifSource, i, NULL);
        [frames addObject:(id)frame];
        CGImageRelease(frame);
        
        // get gif info with each frame
        NSDictionary *dict = (NSDictionary*)CGImageSourceCopyPropertiesAtIndex(gifSource, i, NULL);
        NSLog(@"kCGImagePropertyGIFDictionary %@", [dict valueForKey:(NSString*)kCGImagePropertyGIFDictionary]);
        
        // get gif size
        if (gifWidth != NULL && gifHeight != NULL) {
            *gifWidth = [[dict valueForKey:(NSString*)kCGImagePropertyPixelWidth] floatValue];
            *gifHeight = [[dict valueForKey:(NSString*)kCGImagePropertyPixelHeight] floatValue];
        }
        
        // kCGImagePropertyGIFDictionary中kCGImagePropertyGIFDelayTime,kCGImagePropertyGIFUnclampedDelayTime值是一样的
        NSDictionary *gifDict = [dict valueForKey:(NSString*)kCGImagePropertyGIFDictionary];
        [delayTimes addObject:[gifDict valueForKey:(NSString*)kCGImagePropertyGIFDelayTime]];
        
        if (totalTime) {
            *totalTime = *totalTime + [[gifDict valueForKey:(NSString*)kCGImagePropertyGIFDelayTime] floatValue];
        }
    }
}

动画播放:
- (void)startGif
{
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
    
    NSMutableArray *times = [NSMutableArray arrayWithCapacity:3];
    CGFloat currentTime = 0;
    int count = _frameDelayTimes.count;
    for (int i = 0; i < count; ++i) {
        [times addObject:[NSNumber numberWithFloat:(currentTime / _totalTime)]];
        currentTime += [[_frameDelayTimes objectAtIndex:i] floatValue];
    }
    [animation setKeyTimes:times];
    
    NSMutableArray *images = [NSMutableArray arrayWithCapacity:3];
    for (int i = 0; i < count; ++i) {
        [images addObject:[_frames objectAtIndex:i]];
    }
    
    [animation setValues:images];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
    animation.duration = _totalTime;
    animation.delegate = self;
    animation.repeatCount = 5;
    
    [self.layer addAnimation:animation forKey:@"gifAnimation"];
}
一、基本的Image I/O使用
原文出去: http://supershll.blog.163.com/blog/static/37070436201298111139748/
Image I/O框架提供了不透明数据类型来读取图像数据和写图像数据到一个目的地(CGImageSourceRef和CGImageDestinationRef)。它支持很多图像格式,包括标准web格式、搞动态范围图像,和原始相机数据。Image I/O还有许多其他特性:
1)mac平台上的最快的图像解码和编码。
2)逐步加载图片的能力。
3)支持图像元数据。
4)缓存效果。
你可以通过下面的对象来创建image source和image destination:
1)URLs:即CFURLRef对象。
2)Core Foundation对象:CFDataRef和CFmutableDataRef。
3)Quartz data consumer(CGDataConsumerRef)和data provider(CGDataProviderRef)对象。

1、使用Image I/O框架:  #import <ImageIO/ImageIO.h>
2、支持的图像格式:例如JPEG、JPEG2000、RAW、TIFF、BMP、PNG。在不同的平台不是所有的格式都支持。你可以调用下列函数来获得支持的格式:
1)CGImageSourceCopyTypeIdentifiers:返回同一类型修饰符的数组,表示支持的图像源。
2)CGImageDestinationCopyTypeIdentifiers:返回支持的目的地的Uniform Type Identifiers(UTIs)。

你可以使用CFShow函数来打印结果。
CFArrayRef mySourceTypes = CGImageSourceCopyTypeIdentifiers();
CFShow(mySourceTypes);
CFArrayRef myDestinationTypes = CGImageDestinationCopyTypeIdentifiers();
CFShow(myDestinationTypes);
一般格式是com.apple.pict,public.jpeg,public.tiff等。

二、创建和使用Image Sources
1、从一个Image Source创建一个Image:
myImage = CGImageSourceCreateImageAtIndex(myImageSource,0,NULL);
下面的例子显示了如何从一个路径中创建一个image source然后提取出image。当你创建一个image source时,你可以提供一个提示作为image source file的格式。
当你从image source中创建image时,你必须指定一个index,并且可以提供一个属性字典来指定一些事情,如是否创建一个缩略图或是否允许缓存。CGImageSource Reference和CGImageProperties Reference提供了键和期待的数据类型的列表。
你需要提供一个index值,因为一些image file 格式允许多个image存在于一个source file中。对于只有一个image的image source,传递0就可以了。你可以通过函数CGImageSourceGetCount来获得image source file中包含的image的数量。
例子:
CGImageRef MyCreateCGImageFromFile (NSString* path)
{
    // Get the URL for the pathname passed to the function.
    NSURL *url = [NSURL fileURLWithPath:path];
    CGImageRef        myImage = NULL;
    CGImageSourceRef  myImageSource;
    CFDictionaryRef   myOptions = NULL;
    CFStringRef       myKeys[2];
    CFTypeRef         myValues[2];

    // Set up options if you want them. The options here are for
    // caching the image in a decoded form and for using floating-point
    // values if the image format supports them.
    myKeys[0] = kCGImageSourceShouldCache;
    myValues[0] = (CFTypeRef)kCFBooleanTrue;
    myKeys[1] = kCGImageSourceShouldAllowFloat;
    myValues[1] = (CFTypeRef)kCFBooleanTrue;
    // Create the dictionary
    myOptions = CFDictionaryCreate(NULL, (const void **) myKeys,
                   (const void **) myValues, 2,
                   &kCFTypeDictionaryKeyCallBacks,
                   & kCFTypeDictionaryValueCallBacks);
    // Create an image source from the URL.
    myImageSource = CGImageSourceCreateWithURL((CFURLRef)url, myOptions);
    CFRelease(myOptions);
    // Make sure the image source exists before continuing
    if (myImageSource == NULL){
        fprintf(stderr, "Image source is NULL.");
        return  NULL;
    }
    // Create an image from the first item in the image source.
    myImage = CGImageSourceCreateImageAtIndex(myImageSource,
                                           0,
                                           NULL);
 
    CFRelease(myImageSource);
    // Make sure the image exists before continuing
    if (myImage == NULL){
         fprintf(stderr, "Image not created from image source.");
         return NULL;
    }
 
    return myImage;
}

2、从一个Image Source中创建一个缩略图
 myThumbnailImage = CGImageSourceCreateThumbnailAtIndex(myImageSource,0, myOptions);
一些image source file包含缩略图。如果缩略图没有准备好,Image I/O给你一些选项来创建他们。你还可以指定一个最大的缩略图尺寸和是否应用一个transform到缩略图上。
例子:
CGImageRef MyCreateThumbnailImageFromData (NSData * data, int imageSize)
{
    CGImageRef        myThumbnailImage = NULL;
    CGImageSourceRef  myImageSource;
    CFDictionaryRef   myOptions = NULL;
    CFStringRef       myKeys[3];
    CFTypeRef         myValues[3];
    CFNumberRef       thumbnailSize;
 
   // Create an image source from NSData; no options.
   myImageSource = CGImageSourceCreateWithData((CFDataRef)data,
                                               NULL);
   // Make sure the image source exists before continuing.
   if (myImageSource == NULL){
        fprintf(stderr, "Image source is NULL.");
        return  NULL;
   }
 
   // Package the integer as a  CFNumber object. Using CFTypes allows you
   // to more easily create the options dictionary later.
   thumbnailSize = CFNumberCreate(NULL, kCFNumberIntType, &imageSize);
 
   // Set up the thumbnail options.
   myKeys[0] = kCGImageSourceCreateThumbnailWithTransform;
   myValues[0] = (CFTypeRef)kCFBooleanTrue;
   myKeys[1] = kCGImageSourceCreateThumbnailFromImageIfAbsent;
   myValues[1] = (CFTypeRef)kCFBooleanTrue;
   myKeys[2] = kCGImageSourceThumbnailMaxPixelSize;
   myValues[2] = (CFTypeRef)thumbnailSize;
 
   myOptions = CFDictionaryCreate(NULL, (const void **) myKeys,
                   (const void **) myValues, 2,
                   &kCFTypeDictionaryKeyCallBacks,
                   & kCFTypeDictionaryValueCallBacks);
 
  // Create the thumbnail image using the specified options.
  myThumbnailImage = CGImageSourceCreateThumbnailAtIndex(myImageSource,
                                          0,
                                          myOptions);
  // Release the options dictionary and the image source
  // when you no longer need them.
  CFRelease(thumbnailSize);
  CFRelease(myOptions);
  CFRelease(myImageSource);
 
   // Make sure the thumbnail image exists before continuing.
   if (myThumbnailImage == NULL){
         fprintf(stderr, "Thumbnail image not created from image source.");
         return NULL;
   }
 
   return myThumbnailImage;
}

- (void)updateImage
{
    _imageV.image = _webImage.image;
    
    NSData *data = UIImagePNGRepresentation(_webImage.image);
    CGImageRef  imageRef = [self thumbnailCreateWithData:data imageSize:0.5];
    UIImage * iamge = [UIImage imageWithCGImage:imageRef];
    self.thumbnailImage.image = iamge;
      CFRelease(imageRef);
}

-(CGImageRef)thumbnailCreateWithData:data imageSize:(int)imageSize
{
    
    CGImageRef        myThumbnailImage = NULL;
    CGImageSourceRef  myImageSource;
    CFDictionaryRef   myOptions = NULL;
    CFStringRef       myKeys[3];
    CFTypeRef         myValues[3];
    CFNumberRef       thumbnailSize;
    
    // Create an image source from NSData; no options.
    myImageSource = CGImageSourceCreateWithData((CFDataRef)data,
                                                NULL);
    // Make sure the image source exists before continuing.
    if (myImageSource == NULL){
        fprintf(stderr, "Image source is NULL.");
        return  NULL;
    }
    
    // Package the integer as a  CFNumber object. Using CFTypes allows you
    // to more easily create the options dictionary later.
    thumbnailSize = CFNumberCreate(NULL, kCFNumberIntType, &imageSize);
    
    // Set up the thumbnail options.
    myKeys[0] = kCGImageSourceCreateThumbnailWithTransform;
    myValues[0] = (CFTypeRef)kCFBooleanTrue;
    myKeys[1] = kCGImageSourceCreateThumbnailFromImageIfAbsent;
    myValues[1] = (CFTypeRef)kCFBooleanTrue;
    myKeys[2] = kCGImageSourceThumbnailMaxPixelSize;
    myValues[2] = (CFTypeRef)thumbnailSize;
    
    myOptions = CFDictionaryCreate(NULL, (const void **) myKeys,
                                   (const void **) myValues, 2,
                                   &kCFTypeDictionaryKeyCallBacks,
                                   & kCFTypeDictionaryValueCallBacks);
   
    CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)data, nil);
    CGImageRef thumbnail  = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, myOptions);
    CFRelease(imageSource);
    CFRelease(myOptions);
    
    return thumbnail;
}


3、逐步地加载一幅图像:
_incrementallyImgSource = CGImageSourceCreateIncremental(NULL);
CGImageSourceUpdateData(_incrementallyImgSource, (CFDataRef)_recieveData, _isLoadFinished);
如果你有一个很大的图像,或者正在从网络上加载图像数据,你或许就想创建一个incremental image source,然后你就可以一点点地加载图像数据。你需要执行下面的步骤:
1)创建一个CFData对象来累积图像数据。
2)创建一个incremental image source,通过调用函数CGImageSourceCreateIncremental。
3)添加image data到CFData对象。
4)调用函数CGImageSourceUpdateData,传递CFData对象和一个布尔值(bool数据类型)来指定是否data 参数包含了整个图像,或只是图像数据的一部分。在任意一种情况下,data参数都必须包含当前所有的图像数据。
5)如果你已经累积了足够的图像数据,就通过函数CGImageSourceCreateImageAtIndex,来绘制部分图像,然后release掉。
6)检查你是否已经有了所有的数据,通过函数CGImageSourceGetStatusAtIndex。如果图像完成了,函数返回kCGImageStatusComplete。如果没有完成,就重复3-4步,直到其完成。
7)释放incremental image source。
代码:
- (id)initWithURL:(NSURL *)imageURL
{
    self = [super init];
    if (self) {
        _imageURL = [imageURL retain];
        
        _request = [[NSURLRequest alloc] initWithURL:_imageURL];
        _conn    = [[NSURLConnection alloc] initWithRequest:_request delegate:self];
        
        _incrementallyImgSource = CGImageSourceCreateIncremental(NULL);
        
        _recieveData = [[NSMutableData alloc] init];
        _isLoadFinished = false;
    }
    
    return self;
}

- (void)dealloc
{
    [_request release]; _request = nil;
    [_conn release];    _conn = nil;
    [_recieveData release]; _recieveData = nil;
    [_image release]; _image = nil;
    [_thumbImage release]; _thumbImage = nil;
    
    CFRelease(_incrementallyImgSource); _incrementallyImgSource = NULL;
    
    [super dealloc];
}

#pragma mark -
#pragma mark NSURLConnectionDataDelegate

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    _expectedLeght = response.expectedContentLength;
    NSLog(@"expected Length: %lld", _expectedLeght);
    
    NSString *mimeType = response.MIMEType;
    NSLog(@"MIME TYPE %@", mimeType);
    
    NSArray *arr = [mimeType componentsSeparatedByString:@"/"];
    if (arr.count < 1 || ![[arr objectAtIndex:0] isEqual:@"image"]) {
        NSLog(@"not a image url");
        [connection cancel];
        [_conn release]; _conn = nil;
    }
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"Connection %@ error, error info: %@", connection, error);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"Connection Loading Finished!!!");
    
    // if download image data not complete, create final image
    if (!_isLoadFinished) {
        CGImageSourceUpdateData(_incrementallyImgSource, (CFDataRef)_recieveData, _isLoadFinished);
        CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_incrementallyImgSource, 0, NULL);
        self.image = [UIImage imageWithCGImage:imageRef];
        CGImageRelease(imageRef);
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [_recieveData appendData:data];
    
    _isLoadFinished = false;
    if (_expectedLeght == _recieveData.length) {
        _isLoadFinished = true;
    }
    
    CGImageSourceUpdateData(_incrementallyImgSource, (CFDataRef)_recieveData, _isLoadFinished);
    CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_incrementallyImgSource, 0, NULL);
    self.image = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
}


4、显示图像属性:
包括image dimensions(大小)、resolution(分辨率)、orientation(方向)、color profile、aperture、metering mode,focal length、creation date、keywords、caption等等。
虽然函数CGImageSourceCopyPropertiesAtIndex可以检索所有图像相关的属性的字典,你还是需要写代码来检索这个字典并显示信息。
// get gif info with each frame
        NSDictionary *dict = (NSDictionary*)CGImageSourceCopyPropertiesAtIndex(gifSource, i, NULL);
        NSLog(@"kCGImagePropertyGIFDictionary %@", [dict valueForKey:(NSString*)kCGImagePropertyGIFDictionary]);

结果如下:
Printing description of dict:
{
    ColorModel = RGB;
    Depth = 8;
    HasAlpha = 1;
    PixelHeight = 155;
    PixelWidth = 270;
    "{GIF}" =     {
        DelayTime = "0.1";
        UnclampedDelayTime = "0.1";
    };
}
2014-05-30 11:19:52.659 SvGifSample[512:907] kCGImagePropertyGIFDictionary {
    DelayTime = "0.1";
    UnclampedDelayTime = "0.1";
}



三、使用Image Destinations:
在你创建了一个CGImageDestination对象之后,你可以添加image数据和设置image属性,然后调用函数CGImageDestinationFinalize来结束。
1、设置Image Destination的属性:
函数CGImageDestinationSetProperties添加一个属性字典CFDictionaryRef到image destination的图像中。虽然设置属性是可选的,但是很多时候你都需要这么做。例如,如果你的应用允许用户添加keywords到图像或更改saturation(色饱和度)、exposure(曝光值)等等。

2、将图像写入到一个Image Destination:
CGImageDestinationCreateWithURL、CGImageDestinationCreateWithData、CGImageDestinationCreateWithDataConsumer函数。
创建完之后,你可以添加image,通过调用CGImageDestinationAddImage或CGImageDestinationAddImageFromSource函数。
最后调用CGImageDestinationFinalize来结束。一旦结束,你就不能再添加更多的数据到image destination。
例子:
- (void) writeCGImage: (CGImageRef) image toURL: (NSURL*) url withType: (CFStringRef) imageType andOptions: (CFDictionaryRef) options
{
   CGImageDestinationRef myImageDest = CGImageDestinationCreateWithURL((CFURLRef)url, imageType, 1, nil);
   CGImageDestinationAddImage(myImageDest, image, options);
   CGImageDestinationFinalize(myImageDest);
   CFRelease(myImageDest);
}
-》利用CGImageDestination合成gif

#define kUTTypeGIF @"com.compuserve.gif"

//gif的制作
     
    //获取源数据image
    NSMutableArray *imgs = [[NSMutableArray alloc]initWithObjects:[UIImage imageNamed:@bear_1],[UIImage imageNamed:@bear_2], nil];
     
    //图像目标
    CGImageDestinationRef destination;
     
    //创建输出路径
    NSArray *document = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentStr = [document objectAtIndex:0];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *textDirectory = [documentStr stringByAppendingPathComponent:@gif];
    [fileManager createDirectoryAtPath:textDirectory withIntermediateDirectories:YES attributes:nil error:nil];
    NSString *path = [textDirectory stringByAppendingPathComponent:@test101.gif];
     
     
    NSLog(@%@,path);
     
    //创建CFURL对象
    /*
     CFURLCreateWithFileSystemPath(CFAllocatorRef allocator, CFStringRef filePath, CFURLPathStyle pathStyle, Boolean isDirectory)
      
     allocator : 分配器,通常使用kCFAllocatorDefault
     filePath : 路径
     pathStyle : 路径风格,我们就填写kCFURLPOSIXPathStyle 更多请打问号自己进去帮助看
     isDirectory : 一个布尔值,用于指定是否filePath被当作一个目录路径解决时相对路径组件
     */
    CFURLRef url = CFURLCreateWithFileSystemPath (
                                                  kCFAllocatorDefault,
                                                  (CFStringRef)path,
                                                  kCFURLPOSIXPathStyle,
                                                  false);
     
    //通过一个url返回图像目标
    destination = CGImageDestinationCreateWithURL(url, kUTTypeGIF, imgs.count, NULL);
     
    //设置gif的信息,播放间隔时间,基本数据,和delay时间
    NSDictionary *frameProperties = [NSDictionary
                                     dictionaryWithObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithFloat:0.3], (NSString *)kCGImagePropertyGIFDelayTime, nil]
                                     forKey:(NSString *)kCGImagePropertyGIFDictionary];
     
    //设置gif信息
    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:2];
     
    [dict setObject:[NSNumber numberWithBool:YES] forKey:(NSString*)kCGImagePropertyGIFHasGlobalColorMap];
     
    [dict setObject:(NSString *)kCGImagePropertyColorModelRGB forKey:(NSString *)kCGImagePropertyColorModel];
     
    [dict setObject:[NSNumber numberWithInt:8] forKey:(NSString*)kCGImagePropertyDepth];
     
    [dict setObject:[NSNumber numberWithInt:0] forKey:(NSString *)kCGImagePropertyGIFLoopCount];
    NSDictionary *gifProperties = [NSDictionary dictionaryWithObject:dict
                                                              forKey:(NSString *)kCGImagePropertyGIFDictionary];
    //合成gif
    for (UIImage* dImg in imgs)
    {
        CGImageDestinationAddImage(destination, dImg.CGImage, (__bridge CFDictionaryRef)frameProperties);
    }
    CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)gifProperties);
    CGImageDestinationFinalize(destination);
    CFRelease(destination);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值