Hello,
I am trying to create an animated sequence of HEIC images but I cannot save the frame property duration. It seems this is a well know bug: https://github.com/SDWebImage/SDWebImage/issues/3120
The kCGImagePropertyHEICSDictionary is never saved.
Here's a sample project to reproduce the bug: ImageIOHEICSEncodeDecodeBug.zip
Has anybody managed to save this information in a HEIC sequence?
Thanks!
Here's how I am writing an reading the image sequence
- (void)testHEICSBug {
// First, load an animated image (GIF)
// And you can change the type into png, which is an animated PNG format. Same result
NSData *GIFData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"image1" ofType:@"gif"]];
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)GIFData, nil);
NSUInteger frameCount = CGImageSourceGetCount(source);
NSAssert(frameCount > 1, @"GIF frame count > 1");
// Split into frames array, encode to HEICS
NSMutableData *heicsData = [NSMutableData data];
CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)heicsData, (__bridge CFStringRef)AVFileTypeHEIC, frameCount, nil);
for (int i = 0; i < frameCount; i++) {
// First get the GIF input image and duration
CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, i, nil);
NSDictionary *inputProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(source, i, nil);
NSDictionary *inputDictionary = inputProperties[(__bridge NSString *)kCGImagePropertyGIFDictionary];
NSTimeInterval duration = [inputDictionary[(__bridge NSString *)kCGImagePropertyGIFUnclampedDelayTime] doubleValue];
NSAssert(cgImage, @"CGImage not nil");
NSAssert(duration > 0, @"Input duration > 0");
// Then, encode into HEICS animated image
NSMutableDictionary *outputDProperties = [NSMutableDictionary dictionary];
outputDProperties[(__bridge NSString *)kCGImagePropertyHEICSDictionary] = @{(__bridge NSString *)kCGImagePropertyHEICSUnclampedDelayTime : @(duration)};
CGImageDestinationAddImage(destination, cgImage, (__bridge_retained CFDictionaryRef)outputDProperties);
}
// Output HEICS image data
BOOL result = CGImageDestinationFinalize(destination);
NSAssert(result, @"Encode HEICS failed");
// Next, try to use ImageIO to decode HEICS and check duration
CGImageSourceRef newSource = CGImageSourceCreateWithData((__bridge CFDataRef)heicsData, nil);
frameCount = CGImageSourceGetCount(newSource);
NSAssert(frameCount > 1, @"New HEICS should be aniamted image");
NSUInteger frameIndex = 1; // I pick the 2nd frame, actually any frame contains this issue.
NSDictionary *newProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(newSource, frameIndex, nil);
NSDictionary *newDictionary = newProperties[(__bridge NSString *)kCGImagePropertyHEICSDictionary];
NSTimeInterval newDuration = [newDictionary[(__bridge NSString *)kCGImagePropertyHEICSUnclampedDelayTime] doubleValue];
CGImageRef newImage = CGImageSourceCreateImageAtIndex(newSource, frameIndex, nil);
// Now, check the HEICS frame duration, however, it's nil :(
// Only image is kept.
NSAssert(newImage, @"frame image is not nil");
NSAssert(newDuration > 0, @"Decode the HEICS (which encoded from GIF) will loss the frame duration");
}