【问题标题】:Core Graphics CGImage mask not affecting核心图形 CGImage 蒙版不影响
【发布时间】:2017-07-26 01:54:25
【问题描述】:

我实际上想要做的是有一个文本标签“切割”一个穿过视图的文本形状的洞。我试过使用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。我已经在这两天了,所以任何帮助表示赞赏

【问题讨论】:

  • 我曾经遇到过类似的问题,但我的设置略有不同:UIControl 自定义子类,其中包含UILabel 子视图。
  • 在我的情况下,在渲染 mas 修复它之前,在标签子视图上调用 setNeedsDisplay()

标签: ios swift core-graphics cgimage cgimagemaskcreate


【解决方案1】:

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

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

        self.drawText(in: rect)
    }
}

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

【讨论】:

  • 不确定它是什么,但这似乎不适用于UIVisualEffectView。其他混合模式也没有
  • @Downgoat 你到底想达到什么目的,问题是什么?
  • 与问题相同的问题,设置混合模式时按钮似乎没有变化。这应该只是一个 UI 效果
  • @Downgoat 我发布的代码肯定在视觉效果视图之外工作。您能否提供一个示例项目,说明您希望如何使用它以及您想要达到的效果的图像?
  • here is a sample project 这是我上面的最小版本。 VibrantButton.swiftdraw() 确实绘制了文本(黑色,不是半透明的)但是当我添加混合模式时,看起来好像我根本没有添加文本
【解决方案2】:

我不确定您是否会喜欢下面的代码。它是使用 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()

结果:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多