swift 核心图形CGImage蒙版不影响

lf5gs5x2  于 2023-08-02  发布在  Swift
关注(0)|答案(3)|浏览(134)

我想做的是让文本标签在视图中“切割”一个文本形状的洞。我试过使用self.mask = uiLabel,但那些拒绝正确定位文本,所以我通过Core Graphics接近这一点。
下面是无法工作的代码(在draw(_ rect: CGRect)中):

let context = (UIGraphicsGetCurrentContext())!

    // Set mask background color
    context.setFillColor(UIColor.black.cgColor)
    context.fill(rect)

    context.saveGState()

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .center

    let attributes = [
        NSParagraphStyleAttributeName: paragraphStyle,
        NSFontAttributeName: UIFont.systemFont(ofSize: 16, weight: UIFontWeightMedium),
        NSForegroundColorAttributeName: UIColor.white
    ]

    let string = NSString(string: "LOGIN")

    // This wouldn't vertically align so we calculate the string size and create a new rect in which it is vertically aligned
    let size = string.size(attributes: attributes)
    let position = CGRect(
        x: rect.origin.x,
        y: rect.origin.y + (rect.size.height - size.height) / 2,
        width: rect.size.width,
        height: size.height
    )

    context.translateBy(x: 0, y: rect.size.height)
    context.scaleBy(x: 1, y: -1)
    string.draw(
        in: position,
        withAttributes: attributes
    )

    let mask = (context.makeImage())!

    context.restoreGState()

    // Redraw with created mask
    context.clear(rect)

    context.saveGState()
    // !!!! Below line is the problem
    context.clip(to: rect, mask: mask)
    context.restoreGState()

字符串
基本上,我已经成功地创建了一个CGImagemask变量)的代码,它是我想要应用到整个图像的遮罩。
当 * 替换为context.draw(mask, in: rect)(以查看遮罩)时,标记的行正确显示。掩码显示(正确)为:



然而,一旦我尝试应用这个掩码(使用context.clip(to: rect, mask: mask))什么也没有发生!.实际结果:


期望结果为:



但是由于某种原因,掩模没有被正确地施加。
这段代码看起来应该可以工作,因为我已经一遍又一遍地阅读文档。我还尝试在单独的CGContext中创建掩码,但没有成功。此外,当我尝试使用.copy(colorSpace:)将CGImage(mask)转换为CGColorSpaceCreateDeviceGray()时,它返回了nil。我已经做了两天了所以任何帮助都很感激

ttygqcqt

ttygqcqt1#

如果希望标签具有完全半透明的文本,可以使用混合模式而不是蒙版。

public class KnockoutLabel: UILabel {
    public override func draw(_ rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()!
        context.setBlendMode(.clear)

        self.drawText(in: rect)
    }
}

字符串
确保将isOpaque设置为false;默认情况下,视图假定它是不透明的,因为您使用的是不透明的背景色。

hsgswve4

hsgswve42#

我不确定你是否会喜欢下面的代码。它是使用PaintCode创建的。文本将始终位于圆角矩形的中心。希望对你有帮助。
代码,把它放在draw(_ rect:CGRect):

//// General Declarations
    let context = UIGraphicsGetCurrentContext()

    //// Color Declarations - just to make a gradient same as your button have
    let gradientColor = UIColor(red: 0.220, green: 0.220, blue: 0.223, alpha: 1.000)
    let gradientColor2 = UIColor(red: 0.718, green: 0.666, blue: 0.681, alpha: 1.000)
    let gradientColor3 = UIColor(red: 0.401, green: 0.365, blue: 0.365, alpha: 1.000)

    //// Gradient Declarations
    let gradient = CGGradient(colorsSpace: nil, colors: [gradientColor.cgColor, gradientColor3.cgColor, gradientColor2.cgColor] as CFArray, locations: [0, 0.55, 1])!

    //// Subframes
    let group: CGRect = CGRect(x: rect.minX, y: rect.minY, width: rect.width, height: rect.height)

    //// Group
    context.saveGState()
    context.beginTransparencyLayer(auxiliaryInfo: nil)

    //// Rectangle Drawing
    let rectanglePath = UIBezierPath(roundedRect: group, cornerRadius: 5)
    context.saveGState()
    rectanglePath.addClip()
    let rectangleRotatedPath = UIBezierPath()
    rectangleRotatedPath.append(rectanglePath)
    var rectangleTransform = CGAffineTransform(rotationAngle: -99 * -CGFloat.pi/180)
    rectangleRotatedPath.apply(rectangleTransform)
    let rectangleBounds = rectangleRotatedPath.cgPath.boundingBoxOfPath
    rectangleTransform = rectangleTransform.inverted()
    context.drawLinearGradient(gradient,
                               start: CGPoint(x: rectangleBounds.minX, y: rectangleBounds.midY).applying(rectangleTransform),
                               end: CGPoint(x: rectangleBounds.maxX, y: rectangleBounds.midY).applying(rectangleTransform),
                               options: [])
    context.restoreGState()

    //// Text Drawing
    context.saveGState()
    context.setBlendMode(.destinationOut)

    let textRect = group
    let textTextContent = "LOGIN"
    let textStyle = NSMutableParagraphStyle()
    textStyle.alignment = .center
    let textFontAttributes = [
        NSFontAttributeName: UIFont.systemFont(ofSize: 16, weight: UIFontWeightBold),
        NSForegroundColorAttributeName: UIColor.black,
        NSParagraphStyleAttributeName: textStyle,
        ]

    let textTextHeight: CGFloat = textTextContent.boundingRect(with: CGSize(width: textRect.width, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: textFontAttributes, context: nil).height
    context.saveGState()
    context.clip(to: textRect)
    textTextContent.draw(in: CGRect(x: textRect.minX, y: textRect.minY + (textRect.height - textTextHeight) / 2, width: textRect.width, height: textTextHeight), withAttributes: textFontAttributes)
    context.restoreGState()

    context.restoreGState()

    context.endTransparencyLayer()
    context.restoreGState()

字符串
结果如下:


的数据



kzipqqlq

kzipqqlq3#

将图像裁剪成矩形

灵感来自@汪的回答
有点不同,但我需要类似的功能。我想把图像的形状剪到背景中。基本上,这也可以用于反转图像。
我尝试了这个与PNG图像,因为他们有一个清晰的背景。
我画了一个彩色的矩形,然后使用混合模式和剪辑我剪切的形状的图像到矩形。为此,我必须将UIImage转换为CGImage,以将colorSpace设置为linearGray

func cutImageIntoRectangle(_ image: UIImage) -> UIImage {
        let rect = CGRect(x: 0, y: 0, width: 100, height: 100)
        let renderer = UIGraphicsImageRenderer(size: rect.size)
        let img = renderer.image { ctx in
            let context = ctx.cgContext
            context.setFillColor(UIColor.red.cgColor)
            context.addRect(rect)
            context.fillPath()
            context.setBlendMode(.destinationOut)
            context.clip(to: rect)
            let cgImage = image.cgImage?.copy(colorSpace: CGColorSpace(name: CGColorSpace.linearGray)!)
            context.drawFlipped(cgImage!, in: rect)
        }
        return img
    }

字符串
由于某种原因,复制到CGImage时,图像被翻转。为此,我使用了扩展方法drawFlipped,我从这里复制了它:https://stackoverflow.com/a/58470440/15006958

extension CGContext {
    /// Draw `image` flipped vertically, positioned and scaled inside `rect`.
    public func drawFlipped(_ image: CGImage, in rect: CGRect) {
        self.saveGState()
        self.translateBy(x: 0, y: rect.origin.y + rect.height)
        self.scaleBy(x: 1.0, y: -1.0)
        self.draw(image, in: CGRect(origin: CGPoint(x: rect.origin.x, y: 0), size: rect.size))
        self.restoreGState()
    }
}


x1c 0d1x的数据

相关问题