Неожиданное поведение CGImageDestinationAddImage, которое меняется в зависимости от моего UIImage var в Swift - PullRequest
0 голосов
/ 03 июля 2018

У меня есть функция, которая генерирует GIF с массивом UIImages. Размер массива изображений составляет 31, но я установил емкость на 15, потому что я использую только избранные изображения.

В конечном счете, проблема, с которой я сталкиваюсь, заключается в том, что когда я использую функцию для изменения размера CGImage и использую ее в качестве изображения в CGImageDestinationAddImage, получаемый в результате gif представляет собой фотографии, которые я отправлял ранее, вместо фотографий, которые я на этот раз через функцию. Я понятия не имею, как это может произойти, поскольку полученный gif все еще может генерировать массив изображений, который я использовал ранее, даже если я закрылся из приложения.

Ниже приведены основные функции generateGIF и imageWithImage, а затем я покажу разные вещи, которые я пробовал. Полученные результаты.

func generateGIF(photos: [UIImage], filename: String) -> Bool {

    let documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
    let path = documentsDirectoryPath.appending(filename)

    let fileProperties = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFLoopCount as String: 0]]

    var gifProperties = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFDelayTime as String: 0.1]] // actual speed is 0.2

    gifProperties = [kCGImagePropertyGIFDictionary as String: [kCGImageDestinationLossyCompressionQuality as String: 0.1]]

    let cfURL = URL(fileURLWithPath: path) as CFURL

    let imageCapacity = 15

    if let destination = CGImageDestinationCreateWithURL(cfURL, kUTTypeGIF, imageCapacity, nil) {

        CGImageDestinationSetProperties(destination, fileProperties as CFDictionary?)

        var inc:Int = 0

        for _ in 0..<imageCapacity { // actual photos.count is 31
            // I create 'photo' to determine what new size I should
            // use, for my own convenience, not included in this code
            let photo = photos[inc]

            let width:CGFloat = 200

            let smallerPhoto = imageWithImage(image:photos[inc], newWidth:width)

            CGImageDestinationAddImage(destination, smallerPhoto.cgImage!, gifProperties as CFDictionary?)

            inc += 2
        }

    }
    // do something with gif, i.e. save to photo albums or display
    // in my case I save using path as a URL
}

func imageWithImage(image:UIImage, newWidth:CGFloat) -> UIImage{
    let scale = newWidth / image.size.width
    let newHeight = image.size.height * scale
    let newSize = CGSize(width: newWidth, height: newHeight)

    let renderer = UIGraphicsImageRenderer(size: newSize)

    let image = renderer.image { (context) in
        image.draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
    }
    return image
}

Как я объяснил, полученный gif с использованием приведенного выше кода сделает gif из изображений, которые я сделал ранее.

Если я использую 'photo' в CGImageDestinationAddImage, получаемый в результате gif будет тем, что я ожидал, а не тем, что я создал в прошлый раз, но CGImages не изменяется, потому что я не пропустил их через эту функцию.

CGImageDestinationAddImage(destination, photo.cgImage!, gifProperties as CFDictionary?)

В качестве эксперимента я определил lowerPhoto как 'photo', ожидая, что он скопирует то, что я определил ранее, и использовал это с CGImageDestinationAddImage. Вместо этого полученный gif - это то, что я из массива UIImages, который я отправил в функцию generateGIF с последнего раза.

let smallerPhoto = photo
CGImageDestinationAddImage(destination, smallerPhoto.cgImage!, gifProperties as CFDictionary?)

В качестве альтернативы, я попытался определить smallPhoto непосредственно как текущий индекс массива на фотографиях и использовал его в CGImageDestinationAddImage. Это дало мне правильный набор изображений, которые я передал в generateGIF. Тем не менее, это пропускает изменение размера CGImages, что мне нужно сделать.

let smallerPhoto = photos[inc]
CGImageDestinationAddImage(destination, smallerPhoto.cgImage!, gifProperties as CFDictionary?)

1 Ответ

0 голосов
/ 03 июля 2018

Мне нужно было завершить свое изображение с помощью CGImageDestinationFinalize (destination).

func generateGIF (фотографии: [UIImage], имя файла: строка) -> Bool {

let documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let path = documentsDirectoryPath.appending(filename)

let fileProperties = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFLoopCount as String: 0]]

var gifProperties = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFDelayTime as String: 0.1]] // actual speed is 0.2

gifProperties = [kCGImagePropertyGIFDictionary as String: [kCGImageDestinationLossyCompressionQuality as String: 0.1]]

let cfURL = URL(fileURLWithPath: path) as CFURL

let imageCapacity = 15

if let destination = CGImageDestinationCreateWithURL(cfURL, kUTTypeGIF, imageCapacity, nil) {

    CGImageDestinationSetProperties(destination, fileProperties as CFDictionary?)

    var inc:Int = 0

    for _ in 0..<imageCapacity { // actual photos.count is 31
        // I create 'photo' to determine what new size I should
        // use, for my own convenience, not included in this code
        let photo = photos[inc]

        let width:CGFloat = 200

        let smallerPhoto = imageWithImage(image:photos[inc], newWidth:width)

        CGImageDestinationAddImage(destination, smallerPhoto.cgImage!, gifProperties as CFDictionary?)

        inc += 2
    }

}

let finalized:Bool = CGImageDestinationFinalize(destination)

if finalized {
   // do something with gif, i.e. save to photo albums or display
   // in my case I save using path as a URL
}

// return finalized boolean value
return finalized

}

...