Tworzenie i eksportowanie animowanych gif-ów przez iOS?

Mam serię zdjęć dostosowanych przez użytkownika w aplikacji na iOS, które są animowane w prostym, klatka po klatce typu flip book.

Moje pytanie jest takie: czy istnieje sposób, aby umożliwić użytkownikom eksportowanie ich animacji jako animowanego gifa? Najlepiej, chciałbym umożliwić im e-mail, udostępnianie społecznościowe (T/FB) lub (w najgorszym przypadku..) Zapisz animowany gif w folderze Dokumenty do pobrania za pośrednictwem iTunes.

Wiem jak uratować a .png do biblioteki zdjęć i znalazłem sposób na nagranie animacja jako plik QT (http://www.cimgf.com/2009/02/03/record-your-core-animation-animation / ), ale nie znalazłem sposobu, aby po prostu wykopać zwykły stary animowany gif. Brakuje mi czegoś w Core Animation czy gdzieś indziej? Czy są jakieś podejścia, frameworki lub zasoby, które ktoś może polecić? Przepraszam, jeśli pytanie jest zbyt ogólne-trudno znaleźć punkt wyjścia. Każda pomoc mile widziana.

Author: Nikhil Manapure, 2013-02-17

3 answers

Możesz utworzyć animowany GIF za pomocą frameworku I/O obrazu (który jest częścią zestawu SDK iOS). Będziesz również chciał dołączyć framework MobileCoreServices, który definiuje stałą typu GIF. Musisz dodać te frameworki do celu i zaimportować ich nagłówki do pliku, w którym chcesz utworzyć animowany GIF, w następujący sposób:]}

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

Najłatwiej wyjaśnić na przykładzie. Pokażę Ci kod, którego użyłem do zrobienia tego GIFA na moim iPhonie 5:

animowany GIF stworzony przez pokazany kod

Po pierwsze, oto funkcja pomocnicza, która przyjmuje rozmiar i kąt i zwraca UIImage czerwonego dysku pod tym kątem:

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

Teraz możemy utworzyć GIF. Najpierw zdefiniujemy stałą dla liczby klatek, ponieważ potrzebujemy jej dwa razy później:

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

Będziemy potrzebować słownika właściwości, aby określić liczbę powtórzeń animacji:

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

I będziemy potrzebować innego słownika właściwości, który będziemy dołączać do każdej klatki, określając, jak długa powinna być Ta ramka Wyświetlono:

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

Utworzymy również adres URL pliku GIF w naszym katalogu dokumentów:

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

Teraz możemy utworzyć CGImageDestination, który zapisuje GIF na podany adres URL:

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

Odkryłem, że podanie fileProperties jako ostatniego argumentu CGImageDestinationCreateWithURL nie działa. Musisz użyć CGImageDestinationSetProperties.

Teraz możemy tworzyć i pisać nasze ramki:

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

Zauważ, że przekazujemy słownik właściwości ramki wraz z każdym obrazem ramki.

Po tym, jak dodajemy dokładnie określoną liczbę klatek, finalizujemy cel i zwalniamy go:

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

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

Jeśli uruchomisz to na symulatorze, możesz skopiować adres URL z konsoli debugowania i wkleić go do przeglądarki, aby zobaczyć obraz. Jeśli uruchomisz go na urządzeniu, możesz użyć okna Xcode Organizer, aby pobrać piaskownicę aplikacji z urządzenia i spojrzeć na obraz. Możesz też użyć aplikacji iExplorer, która pozwala bezpośrednio przeglądać system plików Twojego urządzenia. (Nie wymaga Ucieczka z więzienia.)

Testowałem to na moim iPhonie 5 z systemem iOS 6.1, ale uważam, że kod powinien działać tak daleko jak iOS 4.0.

Umieściłem cały kod w ten gist dla łatwego kopiowania.

 158
Author: rob mayoff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-16 23:36:51

Jeśli szukasz rozwiązania Swift 3, możesz rzucić okiem na https://github.com/onmyway133/GifMagic . posiada Encoder i Decoder, które montują i demontują plik gif.

Zasadniczo powinieneś używać Image IO frameworku z tymi funkcjami CGImageDestinationCreateWithURL, CGImageDestinationSetProperties, CGImageDestinationAddImage, CGImageDestinationFinalize

Również z Swift https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html

Podstawowe obiekty Fundacji zwracane z adnotowanych interfejsów API są automatycznie zarządzane pamięcią w języku Swift-nie musisz samodzielnie wywoływać funkcji CFRetain, CFRelease lub cfautorelease.

 0
Author: onmyway133,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-01 09:02:19

Dla 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)")
            }
        }
    }
}

Przekonwertowałem z powyższej odpowiedzi . Mam nadzieję, że to pomoże.

Dostępny jako gist .

Edycje są mile widziane.

 0
Author: Nikhil Manapure,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-07 12:05:37