¿Crear y exportar un gif animado a través de iOS?

Tengo una serie de imágenes personalizadas por el usuario dentro de una aplicación de iOS que están siendo animadas en un estilo de libro de fotogtwigs simple, fotogtwig a fotogtwig.

Mi pregunta es esta: ¿hay alguna manera de permitir a los usuarios exportar sus animaciones como un gif animado? Idealmente, me gustaría permitirles enviar correos electrónicos, compartir redes sociales (T / FB) o (en el peor de los casos …) guardar un archivo .gif animado en su carpeta de documentos para recuperarlo a través de iTunes.

Sé cómo guardar un .png en la biblioteca de fotos, y encontré una forma de grabar una animación como un archivo QT ( http://www.cimgf.com/2009/02/03/record-your-core-animation -animación / ), pero no he encontrado la manera de echar simplemente un viejo gif animado. ¿Me estoy perdiendo algo en Core Animation o en otro lado? ¿Hay enfoques, marcos o recursos que cualquiera pueda recomendar? Disculpe si la pregunta es demasiado general, luchando por encontrar un punto de partida. Cualquier ayuda apreciada.

Puede crear un GIF animado utilizando el marco de E / S de imagen (que es parte del SDK de iOS). También querrá incluir el marco MobileCoreServices , que define la constante de tipo GIF. Necesita agregar estos marcos a su destino e importar sus encabezados en el archivo donde desea crear el GIF animado, como este:

 #import  #import  

Es más fácil de explicar con el ejemplo. Te mostraré el código que usé para hacer este GIF en mi iPhone 5:

GIF animado creado por el código mostrado

Primero, aquí hay una función auxiliar que toma un tamaño y un ángulo y devuelve un UIImage del disco rojo en ese ángulo:

 static UIImage *frameImage(CGSize size, CGFloat radians) { UIGraphicsBeginImageContextWithOptions(size, YES, 1); { [[UIColor whiteColor] setFill]; UIRectFill(CGRectInfinite); CGContextRef gc = UIGraphicsGetCurrentContext(); CGContextTranslateCTM(gc, size.width / 2, size.height / 2); CGContextRotateCTM(gc, radians); CGContextTranslateCTM(gc, size.width / 4, 0); [[UIColor redColor] setFill]; CGFloat w = size.width / 10; CGContextFillEllipseInRect(gc, CGRectMake(-w / 2, -w / 2, w, w)); } UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } 

Ahora podemos crear el GIF. Primero definiremos una constante para la cantidad de fotogtwigs, porque la necesitamos dos veces más adelante:

 static void makeAnimatedGif(void) { static NSUInteger const kFrameCount = 16; 

Necesitaremos un diccionario de propiedades para especificar el número de veces que debe repetir la animación:

  NSDictionary *fileProperties = @{ (__bridge id)kCGImagePropertyGIFDictionary: @{ (__bridge id)kCGImagePropertyGIFLoopCount: @0, // 0 means loop forever } }; 

Y necesitaremos otro diccionario de propiedades, que adjuntaremos a cada cuadro, especificando cuánto tiempo debe mostrarse ese marco:

  NSDictionary *frameProperties = @{ (__bridge id)kCGImagePropertyGIFDictionary: @{ (__bridge id)kCGImagePropertyGIFDelayTime: @0.02f, // a float (not double!) in seconds, rounded to centiseconds in the GIF data } }; 

También crearemos una URL para el GIF en nuestro directorio de documentos:

  NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil]; NSURL *fileURL = [documentsDirectoryURL URLByAppendingPathComponent:@"animated.gif"]; 

Ahora podemos crear un CGImageDestination que escribe un GIF en la URL especificada:

  CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)fileURL, kUTTypeGIF, kFrameCount, NULL); CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)fileProperties); 

Descubrí que pasar fileProperties como el último argumento de CGImageDestinationCreateWithURL no funciona. Tienes que usar CGImageDestinationSetProperties .

Ahora podemos crear y escribir nuestros cuadros:

  for (NSUInteger i = 0; i < kFrameCount; i++) { @autoreleasepool { UIImage *image = frameImage(CGSizeMake(300, 300), M_PI * 2 * i / kFrameCount); CGImageDestinationAddImage(destination, image.CGImage, (__bridge CFDictionaryRef)frameProperties); } } 

Tenga en cuenta que pasamos el diccionario de propiedades de marco junto con cada imagen de marco.

Después de que hemos agregado exactamente la cantidad de marcos especificada, finalizamos el destino y lo lanzamos:

  if (!CGImageDestinationFinalize(destination)) { NSLog(@"failed to finalize image destination"); } CFRelease(destination); NSLog(@"url=%@", fileURL); } 

Si ejecuta esto en el simulador, puede copiar la URL de la consola de depuración y pegarla en su navegador para ver la imagen. Si lo ejecuta en el dispositivo, puede usar la ventana Xcode Organizer para descargar la zona de pruebas de la aplicación desde el dispositivo y mirar la imagen. O puede usar una aplicación como iExplorer que le permite navegar directamente en el sistema de archivos de su dispositivo. (Esto no requiere jailbreak).

Probé esto en mi iPhone 5 con iOS 6.1, pero creo que el código debería funcionar desde iOS 4.0.

He puesto todo el código en esta esencia para una fácil copia.

Si está buscando la solución Swift 3, puede echar un vistazo a https://github.com/onmyway133/GifMagic . Tiene Encoder and Decoder que ensambla y desensambla el archivo .gif.

Básicamente, debe usar el marco de la Image IO con estas funciones CGImageDestinationCreateWithURL , CGImageDestinationSetProperties , CGImageDestinationAddImage , CGImageDestinationFinalize

También con Swift https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html

Los objetos de Core Foundation devueltos de las API anotadas se administran automáticamente en Swift; no es necesario que invoque las funciones CFRetain, CFRelease o CFAutorelease usted mismo.

Para Swift 3

 import Foundation import UIKit import ImageIO import MobileCoreServices extension UIImage { static func animatedGif(from images: [UIImage]) { let fileProperties: CFDictionary = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFLoopCount as String: 0]] as CFDictionary let frameProperties: CFDictionary = [kCGImagePropertyGIFDictionary as String: [(kCGImagePropertyGIFDelayTime as String): 1.0]] as CFDictionary let documentsDirectoryURL: URL? = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) let fileURL: URL? = documentsDirectoryURL?.appendingPathComponent("animated.gif") if let url = fileURL as CFURL? { if let destination = CGImageDestinationCreateWithURL(url, kUTTypeGIF, images.count, nil) { CGImageDestinationSetProperties(destination, fileProperties) for image in images { if let cgImage = image.cgImage { CGImageDestinationAddImage(destination, cgImage, frameProperties) } } if !CGImageDestinationFinalize(destination) { print("Failed to finalize the image destination") } print("Url = \(fileURL)") } } } } 

Lo he convertido de la respuesta anterior . Espero que ayude.

Disponible como una esencia

Las ediciones son bienvenidas