Проблема
Я создаю коллаж из фотографий из массива изображений, которые я размещаю на столе. Я хочу сделать обертывание изображений, когда количество изображений достигнет границы ширины ячейки таблицы (это позволит мне отображать строки изображений в коллаже). В настоящее время я получаю один ряд. Пожалуйста, не стесняйтесь сообщать, требуется ли дополнительная информация. Я, скорее всего, не подхожу к этому наиболее эффективным способом, так как есть задержка, так как количество изображений, используемых в массиве, начинает увеличиваться. (любая обратная связь по этому поводу была бы очень оценена).
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 должным образом, потому что первые результаты показывают, что решение становится медленнее при попытке принудительного использования графического процессора.