How to efficiently create a multi-row photo collage from an array of images in Swift

后端 未结 4 525
梦如初夏
梦如初夏 2020-12-17 17:01

Problem

I am building a collage of photos from an array of images that I am placing onto a tableview. I want to make the images wrap when the number

4条回答
  •  清歌不尽
    2020-12-17 17:17

    Building on alternative 2 provided by Tommie C above I created a function that

    • Always fills the total rectangle, without spaces in the collage
    • determines the number of rows and columns automatically (maximum 1 more nrOfColumns than nrOfRows)
    • To prevent the spaces mentioned above all individual pics are drawn with "Aspect Fill" (so for some pics this means that parts will be cropped)

    Here's the function:

    func collageImage(rect: CGRect, images: [UIImage]) -> UIImage {
        if images.count == 1 {
            return images[0]
        }
    
        UIGraphicsBeginImageContextWithOptions(rect.size, false,  UIScreen.mainScreen().scale)
    
        let nrofColumns: Int = max(2, Int(sqrt(Double(images.count-1)))+1)
        let nrOfRows: Int = (images.count)/nrofColumns
        let remaindingPics: Int = (images.count) % nrofColumns
        print("columns: \(nrofColumns) rows: \(nrOfRows) first \(remaindingPics) columns will have 1 pic extra")
    
        let w: CGFloat = rect.width/CGFloat(nrofColumns)
        var hForColumn = [CGFloat]()
        for var c=1;c<=nrofColumns;++c {
            if remaindingPics >= c {
                hForColumn.append(rect.height/CGFloat(nrOfRows+1))
            }
            else {
                hForColumn.append(rect.height/CGFloat(nrOfRows))
            }
        }
        var colNr = 0
        var rowNr = 0
        for var i=1; i nrofColumns) {
                ++rowNr
                colNr = 0
            }
            else {
                ++colNr
            }
        }
    
        let outputImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return outputImage
    }
    

    This uses the UIImage extension drawInRectAspectFill:

    extension UIImage {
        func drawInRectAspectFill(rect: CGRect, opacity: CGFloat = 1.0) {
            let targetSize = rect.size
            let scaledImage: UIImage
            if targetSize == CGSizeZero {
                scaledImage = self
            } else {
                let scalingFactor = targetSize.width / self.size.width > targetSize.height / self.size.height ? targetSize.width / self.size.width : targetSize.height / self.size.height
                let newSize = CGSize(width: self.size.width * scalingFactor, height: self.size.height * scalingFactor)
                UIGraphicsBeginImageContext(targetSize)
                self.drawInRect(CGRect(origin: CGPoint(x: (targetSize.width - newSize.width) / 2, y: (targetSize.height - newSize.height) / 2), size: newSize), blendMode: CGBlendMode.Normal, alpha: opacity)
                scaledImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
            }
            scaledImage.drawInRect(rect)
        }
    }
    

提交回复
热议问题