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.
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:
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.
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.
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.
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