Как получить доступ к анимированным кадрам GIF

У меня есть анимированный GIF, успешно загруженный в объект NSData или NSBitmapImageRep. Справочник по NSBitmapImageRep

Я понял, как вернуть данные, такие как количество кадров в этом gif, используя:

NSNumber *frames = [bitmapRep valueForProperty:@"NSImageFrameCount"];

Однако я немного смущен тем, как я могу получить доступ к этому фрейму как к его собственному объекту.

Я думаю, что один из этих двух методов поможет, но я на самом деле не уверен, как они получат для меня индивидуальную рамку.

+ representationOfImageRepsInArray:usingType:properties:
– representationUsingType:properties:

Любая помощь приветствуется. Спасибо


person user339946    schedule 18.06.2013    source источник


Ответы (3)


Я понял, как вернуть данные, такие как количество кадров в этом gif, используя:

NSNumber *frames = [bitmapRep valueForProperty:@"NSImageFrameCount"];

Однако я немного смущен тем, как я могу получить доступ к этому фрейму как к его собственному объекту.

Чтобы иметь доступ к специальному фрейму indexOfFrame ( 0 <= indexOfFrame < [frames intValue] ), вам нужно только установить NSImageCurrentFrame и все готово. Нет необходимости использовать CG-функции или делать копии кадров. Вы можете остаться в объектно-ориентированном мире Cocoa. Небольшой пример показывает продолжительность всех кадров GIF:

NSNumber *frames = [bitmapRep valueForProperty:@"NSImageFrameCount"];
if( frames!=nil ){   // bitmapRep is a Gif imageRep
   for( NSUInteger i=0; i<[frames intValue]; i++ ){
      [bitmapRep setProperty:NSImageCurrentFrame
                   withValue:[NSNumber numberWithUnsignedInt:i] ];
       NSLog(@"%2d duration=%@",
                 i, [bitmapRep valueForProperty:NSImageCurrentFrameDuration] );
   }
}

Другой пример: запишите все кадры изображения GIF в виде файлов PNG в файловую систему:

NSNumber *frames = [bitmapRep valueForProperty:@"NSImageFrameCount"];
if( frames!=nil ){   // bitmapRep is a Gif imageRep
   for( NSUInteger i=0; i<[frames intValue]; i++ ){
      [bitmapRep setProperty:NSImageCurrentFrame
                   withValue:[NSNumber numberWithUnsignedInt:i] ];
       NSData *repData = [bitmapRep representationUsingType:NSPNGFileType
                                                 properties:nil];
       [repData writeToFile:
            [NSString stringWithFormat:@"/tmp/gif_%02d.png", i ] atomically:YES];
    }
}
person Heinrich Giesen    schedule 19.06.2013

Я понял, как вернуть данные, такие как количество кадров в этом gif, используя:

NSNumber *frames = [bitmapRep valueForProperty:@"NSImageFrameCount"];

Однако я немного смущен тем, как я могу получить доступ к этому фрейму как к его собственному объекту.

Насколько я знаю, вы не можете — не из NSBitmapImageRep.

Вместо этого создайте CGImageSource из данных GIF и используйте CGImageSourceCreateImageAtIndex для извлечения каждого кадра (желательно по мере необходимости).

В качестве альтернативы вы можете попробовать настройка свойства NSImageCurrentFrame. Если вам нужно повторение для каждого кадра, сделайте столько копий, сколько есть кадров (минус одна, так как у вас есть оригинал), и установите для каждого повторения текущий кадр разным номером. Но я не пробовал, поэтому не уверен, что это действительно сработает.

По сути, поддержка GIF в NSBitmapImageRep является странной, поэтому вам следует просто использовать CGImageSource.

Я думаю, что один из этих двух методов поможет, но я на самом деле не уверен, как они получат для меня индивидуальную рамку.

+ representationOfImageRepsInArray:usingType:properties:
– representationUsingType:properties:

Нет, эти методы предназначены для сериализации изображения (или представления изображения). Они предназначены для записи данных, а не для их чтения. (Обратите внимание, какие константы эти методы ожидают в своих type параметрах.)

person Peter Hosey    schedule 18.06.2013

Если вы хотите взглянуть на некоторый работающий исходный код для декодера GIF для iOS (работает и для MacOSX), вы можете найти его AVGIF89A2MvidResourceLoader.m на github. Подход заключается в использовании инфраструктуры ImageIO и вызове CGImageSourceCreateWithData() вместе с CGImageSourceCreateImageAtIndex() для получения доступа к N-му gif-изображению в файле. Но есть некоторые каверзные детали, связанные с обнаружением прозрачного пикселя в GIF и с тем, как записать результаты в файл, чтобы избежать нехватки памяти, если GIF очень длинный, что может быть неочевидно.

person MoDJ    schedule 18.06.2013