How do I autocrop a UIImage?

后端 未结 6 499
南方客
南方客 2020-12-23 15:04

I have a UIImage which contains a shape; the rest is transparent. I\'d like to get another UIImage by cropping out as much of the transparent part as possible, still retain

6条回答
  •  悲&欢浪女
    2020-12-23 15:54

    Improved from @Danny182's answer, i also added white-space (any pixels brighter than 0xe0e0e0) trimming for my own need.

    Usage:

    let newimage = UIImage(named: "XXX")!.trim()
    

    import UIKit
    
    extension UIImage {
    
        func trim() -> UIImage {
            let newRect = self.cropRect
            if let imageRef = self.cgImage!.cropping(to: newRect) {
                return UIImage(cgImage: imageRef)
            }
            return self
        }
    
        var cropRect: CGRect {
            let cgImage = self.cgImage
            let context = createARGBBitmapContextFromImage(inImage: cgImage!)
            if context == nil {
                return CGRect.zero
            }
    
            let height = CGFloat(cgImage!.height)
            let width = CGFloat(cgImage!.width)
    
            let rect = CGRect(x: 0, y: 0, width: width, height: height)
            context?.draw(cgImage!, in: rect)
    
            //let data = UnsafePointer(CGBitmapContextGetData(context))
            guard let data = context?.data?.assumingMemoryBound(to: UInt8.self) else {
                return CGRect.zero
            }
    
            var lowX = width
            var lowY = height
            var highX: CGFloat = 0
            var highY: CGFloat = 0
    
            let heightInt = Int(height)
            let widthInt = Int(width)
            //Filter through data and look for non-transparent pixels.
            for y in (0 ..< heightInt) {
                let y = CGFloat(y)
                for x in (0 ..< widthInt) {
                    let x = CGFloat(x)
                    let pixelIndex = (width * y + x) * 4 /* 4 for A, R, G, B */
    
                    if data[Int(pixelIndex)] == 0  { continue } // crop transparent
    
                    if data[Int(pixelIndex+1)] > 0xE0 && data[Int(pixelIndex+2)] > 0xE0 && data[Int(pixelIndex+3)] > 0xE0 { continue } // crop white
    
                    if (x < lowX) {
                        lowX = x
                    }
                    if (x > highX) {
                        highX = x
                    }
                    if (y < lowY) {
                        lowY = y
                    }
                    if (y > highY) {
                        highY = y
                    }
    
                }
            }
    
            return CGRect(x: lowX, y: lowY, width: highX - lowX, height: highY - lowY)
        }
    
        func createARGBBitmapContextFromImage(inImage: CGImage) -> CGContext? {
    
            let width = inImage.width
            let height = inImage.height
    
            let bitmapBytesPerRow = width * 4
            let bitmapByteCount = bitmapBytesPerRow * height
    
            let colorSpace = CGColorSpaceCreateDeviceRGB()
    
            let bitmapData = malloc(bitmapByteCount)
            if bitmapData == nil {
                return nil
            }
    
            let context = CGContext (data: bitmapData,
                                     width: width,
                                     height: height,
                                     bitsPerComponent: 8,      // bits per component
                bytesPerRow: bitmapBytesPerRow,
                space: colorSpace,
                bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue)
    
            return context
        }
    }
    

提交回复
热议问题