2

I am attempting to draw "pixelated" or "vectorized" lines that look like this style: enter image description here enter image description here

Ideally I am trying to draw a path via something like CAShapeLayer and have the path be pixelated to this style. It doesn't need to look super great like an actual asset but it needs to follow that general style. I have tried several approaches and got pretty close with a result is on the right track here: enter image description here

The only issue I have now is removing the blur applied to the way I attempted to do this. I need my result to be pixelated but still very crisp, this is my most recent approach used to get the effect above:

let path = UIBezierPath(roundedRect: bounds, cornerRadius: 20)
let lay = CAShapeLayer()
lay.path = path.cgPath
lay.strokeColor = UIColor.green_bright.cgColor
lay.lineWidth = 5
lay.fillColor = nil
lay.shouldRasterize = true
lay.rasterizationScale = 0.1
layer.addSublayer(lay)

I have also attempted using CIFilters like CIPixellate but cannot figure out how you can apply a filter like this to a CAShapeLayer or path in any way.

Is there any way to clean this method up or any other way to achieve this type of effect? All feedback or ideas are appreciated.

UPDATE: I am attempting to use filters by turning my layer into an image and applying a CIFilter, here is how I am unsuccessfully trying:

extension CAShapeLayer {
    func apply(_ filter: String) -> UIImage? {
        let context = CIContext(options: nil)
        let renderer = UIGraphicsImageRenderer(size: frame.size)
        if let currentFilter = CIFilter(name: filter) {
            let image = renderer.image { context in
                render(in: context.cgContext)
            }
            let beginImage = CIImage(image: image)
            currentFilter.setValue(beginImage, forKey: kCIInputImageKey)

            if let output = currentFilter.outputImage {
                if let cgimg = context.createCGImage(output, from: output.extent) {
                    return UIImage(cgImage: cgimg)
                }
            }
        }
        return nil
    }
}
harrisondev
  • 127
  • 7

1 Answers1

1

If this is the sort of thing you mean...

enter image description here

... then I think your idea of using the CIPixellate CIFilter is right, because that's how I got that image. The steps are:

  1. Construct your shape using a shape layer, basically as you're already doing.

  2. Make a graphics image context and render the shape layer into it. Now you've made a UIImage out of the shape layer.

  3. Make the UIImage into a CIImage and pass it thru the CIPixellate filter.

  4. Again make a graphics image context; wrap a UIImage around the CIImage output from the filter and draw that into the image context. Now you've rendered the filter output as a new pixellated UIImage.

  5. Display the resulting UIImage.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I cannot figure out how to successfully do this, I had it working last night but my current method is not working. I have my function in the update to my question. It is now returning nil no matter, I've tried debugging it but cannot figure out where I went wrong. Do you mind sharing how you did this? – harrisondev Feb 24 '20 at 19:11
  • You say you've debugged it, so which of the three `if let` statements is failing? – matt Feb 24 '20 at 23:13
  • My mistake, the second statement is failing: "if let output = currentFilter.outputImage" – harrisondev Feb 25 '20 at 01:44
  • You have not provided enough information, but my guess is that your CAShapeLayer has a zero frame. – matt Feb 25 '20 at 02:22
  • Yes that was it, the reason It was working before is because I was doing it inside of a UIView and was using the views frame, not the layers. Thank you. – harrisondev Feb 25 '20 at 14:47