74 votes

Créer et exporter un fichier gif animé via iOS?

J'ai une série d'utilisateur personnalisé des images dans une application iOS qui sont en cours d'animation dans une simple image-par-image flip book de style.

Ma question est la suivante: est-il un moyen pour permettre aux utilisateurs d'exporter leur animation comme un gif animé? Idéalement, j'aimerais leur permettre de messagerie, de partage sociaux (T/FB) ou (pire des cas..) enregistrer un gif animé à leur dossier de documents pour la récupération via iTunes.

Je sais comment faire pour enregistrer un .png pour les photo de la bibliothèque, et j'ai trouvé un moyen pour enregistrer une animation en tant que QT fichier (http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/), mais je n'ai pas trouvé un moyen de lancer un bon vieux gif animé. Ai-je raté quelque chose dans le Cœur de l'Animation ou quelque part d'autre? Existe-il des approches, des cadres, ou des ressources que n'importe qui peut recommander? Désolé si la question est trop générale - de la difficulté à trouver un point de départ. Toute aide appréciée.

161voto

rob mayoff Points 124153

Vous pouvez créer un GIF animé à l'aide de l'Image I/O-cadre (qui fait partie du SDK iOS). Vous voulez également inclure l' MobileCoreServices - cadre, qui définit le GIF de type constant. Vous devez ajouter ces cadres de votre cible, et l'importation de leurs en-têtes dans le dossier où vous souhaitez créer le GIF animé, comme ceci:

#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>

Il est plus facile d'expliquer par l'exemple. Je vais vous montrer le code que j'ai utilisé pour faire ce GIF sur mon iPhone 5:

animated GIF created by the code shown

Tout d'abord, voici une fonction d'assistance qui prend une taille et un angle et renvoie un UIImage du disque rouge à l'angle:

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

Maintenant, nous pouvons créer le GIF. Nous allons d'abord définir une constante pour le nombre d'images, parce que nous avons besoin de deux fois plus tard:

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

Nous aurons besoin d'une propriété dictionnaire pour spécifier le nombre de fois que l'animation doit se répéter:

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

Et nous allons avoir besoin d'une autre propriété, dictionnaire, qui nous attacher à chaque image, de spécifier combien de temps que l'image devrait s'afficher:

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

Nous allons également créer une URL pour le GIF dans notre répertoire documents:

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

Maintenant, nous pouvons créer un CGImageDestination qui écrit un GIF à l'URL spécifiée:

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

J'ai découvert que la réussite d' fileProperties comme le dernier argument de l' CGImageDestinationCreateWithURL n'a pas de travail. Vous devez utiliser CGImageDestinationSetProperties.

Maintenant, nous pouvons créer et d'écrire nos cadres:

    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);
        }
    }

Notez que nous passons le cadre de dictionnaire des propriétés le long de chaque trame d'image.

Après, nous avons ajouté exactement le nombre d'images spécifié, nous finalisons la destination et de la libération:

    if (!CGImageDestinationFinalize(destination)) {
        NSLog(@"failed to finalize image destination");
    }
    CFRelease(destination);

    NSLog(@"url=%@", fileURL);
}

Si vous exécutez ce code sur le simulateur, vous pouvez copier l'URL à partir de la console de débogage et de le coller dans votre navigateur pour voir l'image. Si vous l'exécutez sur l'appareil, vous pouvez utiliser Xcode Organisateur de la fenêtre de téléchargement de l'application sandbox de l'appareil et de regarder l'image. Ou vous pouvez utiliser une application comme iExplorer qui vous permet de naviguer sur votre appareil du système de fichiers directement. (Cela ne nécessite pas de jailbreak.)

J'ai testé sur mon iPhone 5 sous iOS 6.1, mais je crois que le code devrait fonctionner aussi loin que l'iOS 4.0.

J'ai mis tout le code dans ce gist pour la copie facile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X