Как инвертировать цвета определенной области UIView?

Легко размыть часть представления, имея в виду, что при изменении содержимого заметок размытие также меняется в реальном времени.

Мои вопросы

  • Как сделать инвертированный эффект, и вы можете поместить его над представлением, а содержимое позади будет иметь инвертированные цвета.

  • Как добавить эффект, который будет знать средний цвет пикселей позади?

В общем, Как получить доступ к пикселям и манипулировать ими? Мой вопрос не о UIImageView, спрашивая о UIView вообще.

есть библиотеки, которые делают что-то подобное, но они настолько медленны и не работают так гладко, как размытие!

Спасибо.

Ответы

Ответ 1

Если вы знаете, как закодировать CIColorKernel, вы получите то, что вам нужно.

  • В Core Image есть несколько фильтров размытия, которые используют графический процессор, который даст вам необходимую производительность.

  • CIAreaAverage даст вам средний цвет для указанной прямоугольной области.

Основные фильтры изображений

Вот про простейшее CIColorKernel, которое вы можете написать. Он меняет красное и зеленое значение для каждого пикселя в изображении (обратите внимание на "grba" вместо "rgba" ):

kernel vec4 swapRedAndGreenAmount(__sample s) {
    return s.grba;
}

Чтобы поместить это в CIColorKernel, просто используйте эту строку кода:

let swapKernel = CIKernel(string:
    "kernel vec4 swapRedAndGreenAmount(__sample s) {" +
    "return s.grba;" +
    "}"

@tww003 имеет хороший код для преобразования слоя представления в UIImage. Предполагая, что вы вызываете свой образ myUiImage, чтобы выполнить это swapKernel, вы можете:

let myInputCi = CIImage(image: myUiImage)
let myOutputCi = swapKernel.apply(withExtent: myInputCi, arguments: myInputCi)
Let myNewImage = UIImage(ciImage: myOutputCi)

Что об этом. Вы можете сделать больше (включая использование CoreGraphics и т.д.), Но это хорошее начало.

В последней заметке вы можете связать отдельные фильтры (включая рукописный цвет, warp и общие ядра). Если вы хотите, вы можете связать свой средний цвет по основному виду с размытием и сделать любую инверсию, которую вы хотите, в качестве одного фильтра/эффекта.

Ответ 2

Я не думаю, что могу полностью ответить на ваш вопрос, но, возможно, я могу указать вам в правильном направлении.

У Apple есть документация по доступу к данным пикселей из CGImages, но, конечно, для этого требуется, чтобы у вас было изображение, с которым можно работать в первое место. К счастью, вы можете создать образ из UIView следующим образом:

    UIGraphicsBeginImageContext(view.frame.size)
    view.layer.render(in: UIGraphicsGetCurrentContext()!)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

Из этого изображения, которое вы создали, вы сможете управлять данными пикселей, как вы хотите. Возможно, это не самый чистый способ решить вашу проблему, но, возможно, это что-то стоит изучить.

К сожалению, ссылка, которую я предоставил, написана в Objective-C и ей несколько лет, но, возможно, вы можете понять, как ее использовать.

Ответ 3

В первую очередь я рекомендую вам расширить UIImageView для этой цели. ref

Хорошо ref от Joe

Вы должны переопределить метод drawRect

import UIKit

@IBDesignable class PortholeView: UIView {
  @IBInspectable var innerCornerRadius: CGFloat = 10.0
  @IBInspectable var inset: CGFloat = 20.0
  @IBInspectable var fillColor: UIColor = UIColor.grayColor()
  @IBInspectable var strokeWidth: CGFloat = 5.0
  @IBInspectable var strokeColor: UIColor = UIColor.blackColor()

  override func drawRect(rect: CGRect) {
    super.drawRect(rect:rect)
    // Prep constants
    let roundRectWidth = rect.width - (2 * inset)
    let roundRectHeight = rect.height - (2 * inset)

    // Use EvenOdd rule to subtract portalRect from outerFill
    // (See https://stackoverflow.com/info/14141081/uiview-drawrect-draw-the-inverted-pixels-make-a-hole-a-window-negative-space)
    let outterFill = UIBezierPath(rect: rect)
    let portalRect = CGRectMake(
      rect.origin.x + inset,
      rect.origin.y + inset,
      roundRectWidth,
      roundRectHeight)
    fillColor.setFill()
    let portal = UIBezierPath(roundedRect: portalRect, cornerRadius: innerCornerRadius)
    outterFill.appendPath(portal)
    outterFill.usesEvenOddFillRule = true
    outterFill.fill()
    strokeColor.setStroke()
    portal.lineWidth = strokeWidth
    portal.stroke()
  }
}

Ваш ответ здесь