Проблема
Я создаю коллаж из фотографий из массива изображений, которые я размещаю на столе. Я хочу сделать обертывание изображений, когда количество изображений достигнет границы ширины ячейки таблицы (это позволит мне отображать строки изображений в коллаже). В настоящее время я получаю один ряд. Пожалуйста, не стесняйтесь сообщать, требуется ли дополнительная информация. Я, скорее всего, не подхожу к этому наиболее эффективным способом, так как есть задержка, так как количество изображений, используемых в массиве, начинает увеличиваться. (любая обратная связь по этому поводу была бы очень оценена).
Nota Bene
Я создаю изображение коллажа. Это на самом деле одно изображение. я хочу упорядочить коллаж, создав эффективную матрицу столбцов и строк в памяти. Затем я заполняю эти прямоугольники изображениями. Наконец, я делаю снимок полученного изображения и использую его, когда это необходимо. Алгоритм не эффективно, как написано, и создает только одну строку изображений. мне нужно легкая альтернатива алгоритму, используемому ниже. я не верьте, что UICollectionView будет полезной альтернативой в этом случае.
Псевдокод
- Учитывая массив изображений и целевой прямоугольник (представляющий целевой вид)
- Получить количество изображений в массиве по сравнению с максимальным числом, разрешенным для каждой строки.
- Определите меньший прямоугольник соответствующего размера, чтобы удерживать изображение (так что каждая строка заполняет целевой прямоугольник, то есть - если одно изображение затем должно заполнить строку; если 9 изображений, то это должно заполнить строку полностью; если 10 изображений с максимальным количеством 9 изображений на строку, а затем 10-й начинается вторая строка)
- Итерации по коллекции
- Поместите каждый прямоугольник в нужное место слева направо пока не будет достигнуто последнее изображение или максимальное число в строке; продолжить в следующей строке, пока все изображения не будут помещены в целевой прямоугольник
- При достижении максимального количества изображений в строке поместите изображение и установите следующий прямоугольник, который появится в следующей строке
Использование: Swift 2.0
class func collageImage (rect:CGRect, images:[UIImage]) -> UIImage {
        let maxSide = max(rect.width / CGFloat(images.count), rect.height / CGFloat(images.count))
        UIGraphicsBeginImageContextWithOptions(rect.size, false, UIScreen.mainScreen().scale)
        var xtransform:CGFloat = 0.0
        for img in images {
            let smallRect:CGRect = CGRectMake(xtransform, 0.0,maxSide, maxSide)
            let rnd = arc4random_uniform(270) + 15
            //draw in rect
            img.drawInRect(smallRect)
            //rotate img using random angle.
            UIImage.rotateImage(img, radian: CGFloat(rnd))
            xtransform += CGFloat(maxSide * 0.8)
        }
        let outputImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return outputImage
    }
    class func rotateImage(src: UIImage, radian:CGFloat) -> UIImage
    {
        //  Calculate the size of the rotated view containing box for our drawing space
        let rotatedViewBox = UIView(frame: CGRectMake(0,0, src.size.width, src.size.height))
        let t: CGAffineTransform  = CGAffineTransformMakeRotation(radian)
        rotatedViewBox.transform = t
        let rotatedSize = rotatedViewBox.frame.size
        //  Create the bitmap context
        UIGraphicsBeginImageContext(rotatedSize)
        let bitmap:CGContextRef = UIGraphicsGetCurrentContext()
        //  Move the origin to the middle of the image so we will rotate and scale around the center.
        CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
        //  Rotate the image context
        CGContextRotateCTM(bitmap, radian);
        //  Now, draw the rotated/scaled image into the context
        CGContextScaleCTM(bitmap, 1.0, -1.0);
        CGContextDrawImage(bitmap, CGRectMake(-src.size.width / 2, -src.size.height / 2, src.size.width, src.size.height), src.CGImage)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
Альтернатива 1
Я немного уточнил свое решение. Тем не менее, он устанавливает стек в столбцах и строках, как указано; я заинтересован в том, чтобы сделать это максимально эффективным. Что представляет собой моя попытка создать простейшую возможную вещь, которая работает.
Caveat
Изображение, созданное с использованием этого, искажается, а не равномерно распределяется по всей ячейке tableview. Эффективное, равномерное распределение по ячейке tableview было бы оптимальным.
class func collageImage (rect:CGRect, images:[UIImage]) -> UIImage {
        let maxSide = max(rect.width / CGFloat(images.count), rect.height / CGFloat(images.count)) //* 0.80
        //let rowHeight = rect.height / CGFloat(images.count) * 0.8
        let maxImagesPerRow = 9
        var index = 0
        var currentRow = 1
        var xtransform:CGFloat = 0.0
        var ytransform:CGFloat = 0.0
        var smallRect:CGRect = CGRectZero
        UIGraphicsBeginImageContextWithOptions(rect.size, false, UIScreen.mainScreen().scale)
        for img in images {
            let x = ++index % maxImagesPerRow //row should change when modulus is 0
            //row changes when modulus of counter returns zero @ maxImagesPerRow
            if x == 0 {
                //last column of current row
                //xtransform += CGFloat(maxSide)
                smallRect = CGRectMake(xtransform, ytransform, maxSide, maxSide)
                //reset for new row
                ++currentRow
                xtransform = 0.0
                ytransform = (maxSide * CGFloat(currentRow - 1))
            } else {
                //not a new row
                if xtransform == 0 {
                    //this is first column
                    //draw rect at 0,ytransform
                    smallRect = CGRectMake(xtransform, ytransform, maxSide, maxSide)
                    xtransform += CGFloat(maxSide)
                } else {
                    //not the first column so translate x, ytransform to be reset for new rows only
                    smallRect = CGRectMake(xtransform, ytransform, maxSide, maxSide)
                    xtransform += CGFloat(maxSide)
                }
            }
            //draw in rect
            img.drawInRect(smallRect)
        }
        let outputImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return outputImage
    }
Альтернатива 2
Представленная ниже альтернатива масштабирует изображения так, чтобы они всегда заполняли прямоугольник (в моем случае ячейка tableview). По мере добавления большего количества изображений они масштабируются в соответствии с шириной прямоугольника. Когда изображения соответствуют максимальному количеству изображений в строке, они обертываются. Это желаемое поведение, которое происходит в памяти, относительно быстро и содержится в простой функции класса, которую я распространяю на класс UIImage. Меня все еще интересует любой алгоритм, который может доставлять одни и те же функции только быстрее.
Nota Bene: Я не верю, что добавление большего пользовательского интерфейса полезно для достижения как отмечалось выше. Поэтому более эффективный алгоритм кодирования что я ищу.
class func collageImage (rect:CGRect, images:[UIImage]) -> UIImage {
        let maxImagesPerRow = 9
        var maxSide : CGFloat = 0.0
        if images.count >= maxImagesPerRow {
            maxSide = max(rect.width / CGFloat(maxImagesPerRow), rect.height / CGFloat(maxImagesPerRow))
        } else {
            maxSide = max(rect.width / CGFloat(images.count), rect.height / CGFloat(images.count))
        }
        var index = 0
        var currentRow = 1
        var xtransform:CGFloat = 0.0
        var ytransform:CGFloat = 0.0
        var smallRect:CGRect = CGRectZero
        UIGraphicsBeginImageContextWithOptions(rect.size, false,  UIScreen.mainScreen().scale)
        for img in images {
            let x = ++index % maxImagesPerRow //row should change when modulus is 0
            //row changes when modulus of counter returns zero @ maxImagesPerRow
            if x == 0 {
                //last column of current row
                smallRect = CGRectMake(xtransform, ytransform, maxSide, maxSide)
                //reset for new row
                ++currentRow
                xtransform = 0.0
                ytransform = (maxSide * CGFloat(currentRow - 1))
            } else {
                //not a new row
                smallRect = CGRectMake(xtransform, ytransform, maxSide, maxSide)
                xtransform += CGFloat(maxSide)  
            }
            //draw in rect
            img.drawInRect(smallRect)
        }
        let outputImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return outputImage
    }
Тестирование эффективности
Reda Lemeden дает некоторое процедурное представление о том, как тестировать эти вызовы CG внутри инструментов в этом сообщении . Он также отмечает некоторые интересные заметки от Энди Матушака (команды UIKit) о некоторых особенностях off-screen rendering. Вероятно, я до сих пор не использую решение CIImage должным образом, потому что первые результаты показывают, что решение становится медленнее при попытке принудительного использования графического процессора.

