You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何裁剪主体外透明像素并填充主体内部为黑色?

问题描述

我有一张PNG蒙版图:
原始蒙版图
希望将主体内部填充为黑色。初步思路是裁剪掉主体外的透明像素,再添加纯色背景,也想知道其他可行方法。

目前已实现主体轮廓绘制,代码如下:

Image(uiImage: UIImage(named: "outline")!.stroked())
                .resizable()
                .aspectRatio(contentMode: .fit)
                .background(.red)

当前能得到精准的主体轮廓:
轮廓效果图
但最终需要的效果是:
最终目标效果

解决方案

方法一:路径填充(推荐)

直接基于蒙版的轮廓路径填充内部,无需额外裁剪操作,步骤如下:

1. 扩展UIImage实现填充+描边

在现有stroked()方法基础上,添加填充逻辑:

extension UIImage {
    func filledAndStroked(fillColor: UIColor = .black, strokeColor: UIColor = .black, strokeWidth: CGFloat = 1) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        defer { UIGraphicsEndImageContext() }
        
        guard let context = UIGraphicsGetCurrentContext(), let cgImage = cgImage else { return nil }
        
        let rect = CGRect(origin: .zero, size: size)
        // 绘制原图以提取路径
        context.draw(cgImage, in: rect)
        
        guard let maskPath = context.path else { return nil }
        
        // 填充内部区域
        fillColor.setFill()
        context.addPath(maskPath)
        context.fillPath()
        
        // 绘制轮廓
        strokeColor.setStroke()
        context.setLineWidth(strokeWidth)
        context.addPath(maskPath)
        context.strokePath()
        
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}

2. SwiftUI中调用

Image(uiImage: UIImage(named: "outline")!.filledAndStroked())
    .resizable()
    .aspectRatio(contentMode: .fit)

方法二:裁剪+背景填充

如果坚持用你最初的思路,可按以下步骤实现:

1. 计算蒙版的有效区域(裁剪透明部分)

extension UIImage {
    func cropTransparentArea() -> UIImage? {
        guard let cgImage = cgImage else { return nil }
        let alphaInfo = cgImage.alphaInfo
        guard alphaInfo == .first || alphaInfo == .last || alphaInfo == .premultipliedFirst || alphaInfo == .premultipliedLast else { return self }
        
        let width = cgImage.width
        let height = cgImage.height
        let bytesPerPixel = 4
        let bytesPerRow = bytesPerPixel * width
        let pixelData = UnsafeMutablePointer<UInt8>.allocate(capacity: bytesPerRow * height)
        
        defer { pixelData.deallocate() }
        
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let context = CGContext(data: pixelData, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
        
        context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
        
        var minX = width, minY = height, maxX = 0, maxY = 0
        for y in 0..<height {
            for x in 0..<width {
                let pixelIndex = (y * bytesPerRow) + (x * bytesPerPixel)
                let alpha = pixelData[pixelIndex + 3]
                if alpha > 0 {
                    if x < minX { minX = x }
                    if x > maxX { maxX = x }
                    if y < minY { minY = y }
                    if y > maxY { maxY = y }
                }
            }
        }
        
        if minX > maxX || minY > maxY { return nil }
        
        let cropRect = CGRect(x: minX, y: minY, width: maxX - minX + 1, height: maxY - minY + 1)
        guard let croppedCGImage = cgImage.cropping(to: cropRect) else { return nil }
        
        return UIImage(cgImage: croppedCGImage, scale: scale, orientation: imageOrientation)
    }
}

2. 添加黑色背景并合成

extension UIImage {
    func addSolidBackground(color: UIColor = .black) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, true, scale)
        color.setFill()
        UIRectFill(CGRect(origin: .zero, size: size))
        draw(at: .zero)
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result
    }
}

3. SwiftUI中组合调用

if let croppedImage = UIImage(named: "outline")?.cropTransparentArea(),
   let filledImage = croppedImage.addSolidBackground() {
    Image(uiImage: filledImage)
        .resizable()
        .aspectRatio(contentMode: .fit)
}

内容的提问来源于stack exchange,提问作者erotsppa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 08:17:41