webentwicklung-frage-antwort-db.com.de

Erstellen und exportieren Sie ein animiertes GIF über iOS?

Ich habe eine Reihe von benutzerdefinierten Bildern in einer iOS-App, die in einem einfachen Flipbook-Stil Frame für Frame animiert werden.

Meine Frage lautet: Gibt es eine Möglichkeit, Benutzern das Exportieren ihrer Animation als animiertes GIF zu ermöglichen? Idealerweise möchte ich ihnen die Möglichkeit geben, E-Mails zu versenden, soziale Netzwerke zu teilen (T/FB) oder (im schlimmsten Fall) ein animiertes GIF in ihrem Dokumentenordner zu speichern, um es über iTunes abzurufen.

Ich kann ein PNG in der Fotobibliothek speichern und habe eine Möglichkeit gefunden, eine Animation als QT-Datei aufzuzeichnen ( http://www.cimgf.com/2009/02/03/record-your -core-animation-animation / ), aber ich habe keine Möglichkeit gefunden, ein einfaches altes animiertes GIF rauszuwerfen. Vermisse ich etwas in Core Animation oder woanders? Gibt es Ansätze, Frameworks oder Ressourcen, die jeder empfehlen kann? Tut mir leid, wenn die Frage zu allgemein ist - Probleme, einen Ausgangspunkt zu finden.

73
crgt

Sie können ein animiertes GIF mithilfe des Image I/O-Frameworks (das Teil des iOS SDK ist) erstellen. Sie möchten auch das Framework MobileCoreServices einbinden, das die GIF-Typkonstante definiert. Sie müssen diese Frameworks zu Ihrem Ziel hinzufügen und ihre Header in die Datei importieren, in der Sie das animierte GIF erstellen möchten.

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

Am einfachsten lässt sich das anhand eines Beispiels erklären. Ich zeige dir den Code, mit dem ich dieses GIF auf meinem iPhone 5 erstellt habe:

animated GIF created by the code shown

Hier ist zunächst eine Hilfsfunktion, die eine Größe und einen Winkel annimmt und ein UIImage der roten Scheibe in diesem Winkel zurückgibt:

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

Jetzt können wir das GIF erstellen. Zuerst definieren wir eine Konstante für die Anzahl der Frames, da wir sie später zweimal benötigen:

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

Wir benötigen ein Eigenschaftswörterbuch, um festzulegen, wie oft die Animation wiederholt werden soll:

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

Und wir benötigen ein weiteres Eigenschaftswörterbuch, das wir jedem Frame hinzufügen und angeben, wie lange dieser Frame angezeigt werden soll:

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

Wir erstellen auch eine URL für das GIF in unserem Dokumentenverzeichnis:

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

Jetzt können wir ein CGImageDestination erstellen, das ein GIF in die angegebene URL schreibt:

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

Ich entdeckte, dass das Übergeben von fileProperties als letztes Argument von CGImageDestinationCreateWithURL nicht funktioniert. Sie müssen CGImageDestinationSetProperties verwenden.

Jetzt können wir unsere Frames erstellen und schreiben:

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

Beachten Sie, dass wir das Frame-Eigenschaften-Wörterbuch zusammen mit jedem Frame-Bild übergeben.

Nachdem wir genau die angegebene Anzahl von Frames hinzugefügt haben, stellen wir das Ziel fertig und geben es frei:

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

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

Wenn Sie dies im Simulator ausführen, können Sie die URL von der Debug-Konsole kopieren und in Ihren Browser einfügen, um das Bild anzuzeigen. Wenn Sie es auf dem Gerät ausführen, können Sie im Xcode Organizer-Fenster die App-Sandbox vom Gerät herunterladen und das Bild anzeigen. Oder Sie können eine App wie iExplorer verwenden, mit der Sie das Dateisystem Ihres Geräts direkt durchsuchen können. (Dies erfordert kein Jailbreaking.)

Ich habe dies auf meinem iPhone 5 mit iOS 6.1 getestet, aber ich glaube, der Code sollte bis zu iOS 4.0 funktionieren.

Ich habe den gesamten Code zum einfachen Kopieren in this Gist eingegeben.

160
rob mayoff

Für 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)")
            }
        }
    }
}

Ich habe es aus dem über Antwort konvertiert. Ich hoffe, es hilft.

Verfügbar als Gist .

Änderungen sind willkommen.

1
Nikhil Manapure

Wenn Sie nach einer Swift 3 Lösung suchen, schauen Sie sich https://github.com/onmyway133/GifMagic an. Es hat Encoder und Decoder, die GIF-Dateien zusammenstellen und zerlegen.

Grundsätzlich sollten Sie Image IO Framework mit diesen Funktionen CGImageDestinationCreateWithURL, CGImageDestinationSetProperties, CGImageDestinationAddImage, CGImageDestinationFinalize

Auch mit Swift https://developer.Apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html

Von mit Anmerkungen versehenen APIs zurückgegebene Core Foundation-Objekte werden in Swift automatisch speicherverwaltet. Sie müssen die Funktionen CFRetain, CFRelease oder CFAutorelease nicht selbst aufrufen.

0
onmyway133