Маскирование изображения в Swift с использованием CALayer и UIImage

Программирую на Swift. Я хочу замаскировать изображение с помощью CALayer и UIImage. Я создаю свое изображение маски программно. Созданное изображение маски является UIImage и отлично работает, когда я просматриваю его отдельно. Но когда я использую его как маску, весь экран становится белым. Я подозреваю, что моя проблема в настройке объекта CALayer. Буду признателен за вашу помощь. Спасибо!

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        var maskImageSize = CGSizeMake(self.imageView.frame.width, self.imageView.frame.height)
        UIGraphicsBeginImageContextWithOptions(maskImageSize, false, 0.0)

        var color = UIColor(white: 1.0, alpha: 1.0)
        color.setFill()
        var rect = CGRectMake(0, 0, self.imageView.frame.width, self.imageView.frame.height)
        UIRectFill(rect)

        color = UIColor(white: 0.0, alpha: 1.0)
        color.setFill()
        rect = CGRectMake((self.imageView.frame.width/2)-100, (self.imageView.frame.height/2)-100, 200, 200)
        UIRectFill(rect)

        var maskImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        var maskLayer = CALayer()
        maskLayer.contents = maskImage
        maskLayer.contentsRect = CGRectMake(0, 0, self.imageView.bounds.width, self.imageView.bounds.height)


        self.imageView.image = UIImage(named: "pictobemasked.png")

        self.imageView.layer.mask = maskLayer;
    }

}

person user2732722    schedule 30.12.2014    source источник


Ответы (1)


К сожалению, вы задали свой вопрос довольно плохо - вы не сказали, что именно вы пытаетесь сделать! Однако похоже, что вы пытаетесь пробить прямоугольное отверстие в представлении изображения с помощью маски. Если это так, то в вашем коде есть как минимум три огромных недостатка.

  • Одна из причин, по которой ваш код не работает, заключается в том, что маска основана на прозрачности, а не на цвете. Вы используете непрозрачный белый и непрозрачный черный, которые оба являются непрозрачными, поэтому нет никакой разницы. Вам нужно, чтобы ваши два цвета были такими:

     var color = UIColor(white: 1.0, alpha: 1.0)
    // ... and then, later ...
    color = UIColor(white: 1.0, alpha: 0.0)
    
  • Вторая проблема в том, что у вашего слоя нет размера. Вам нужно дать ему один:

    var maskLayer = CALayer()
    maskLayer.frame = CGRectMake(
        0, 0, self.imageView.bounds.width, self.imageView.bounds.height)
    
  • Третья и самая большая проблема заключается в том, что изображение вашей маски никогда не попадает в слой маски, потому что вы забыли извлечь его CGImage:

    maskLayer.contents = maskImage.CGImage
    

Последний действительно убийственный, потому что если вы установите contents в UIImage, не извлекая его CGImage, изображение не сможет тихо попасть на слой. Нет ни сообщения об ошибке, ни сбоя, ни изображения.

Внеся эти три исправления в ваш код, я смог заставить маску пробить прямоугольное отверстие в изображении. Так что, если это ваша цель, эти изменения ее достигнут.

person matt    schedule 30.12.2014
comment
Спасибо за ваш ответ. Все три пункта верны. У меня все еще есть проблема, которая должна быть связана с размером и расположением объекта CALayer. Я новичок в этой теме. Я отправлю еще один комментарий, в котором подробно расскажу о проблеме и возможном исправлении или других вопросах. Спасибо! - person user2732722; 31.12.2014
comment
Задайте новый вопрос! Если вы напишете мне здесь комментарий, я постараюсь его посмотреть. - Обратите внимание, что вы бы не сделали ни одной из вышеперечисленных ошибок, если бы прочитали главу моей книги о слоях: apeth.com/iOSBook/ch16.html Все три пункта прямо и решительно упомянуты. - person matt; 31.12.2014
comment
Спасибо за ссылку на главу вашей книги. Я признаю, что сначала мне нужно хорошенько изучить. Я почти в цейтноте и поэтому начал взламывать. Моя проблема в том, что я не знаю, как совместить маску с исходным изображением. Я хочу показать изображение произвольного размера. Я создаю содержимое маски программно, чтобы оно было того же размера, что и изображение. Это отверстие в середине маски - всего лишь проверка. После того, как я запустил это, я хочу иметь более сложную маску, которая должна покрывать все изображение. Буду признателен за любую помощь в правильном выравнивании. Спасибо! - person user2732722; 31.12.2014
comment
Это действительно должен быть новый вопрос! - person matt; 31.12.2014
comment
Я разместил здесь новый вопрос: stackoverflow.com/questions/27714562/. Спасибо за вашу помощь. - person user2732722; 31.12.2014
comment
Я сделал то же самое, и это сработало. Однако я хотел круг. Использовать UIBezierPath для рисования круга было легко, но есть разница между UIRectFill (..) и объектом Безье .fill (). Разница в том, что .fill () с полностью прозрачным цветом ничего не рисует. Невидимые чернила! Поэтому не забудьте использовать CGContextSetBlendMode (UIGraphicsGetCurrentContext (), .Copy), чтобы сказать, что вы хотите заменить то, что находится под пикселем, на пиксель. - person specimen; 28.11.2015
comment
@specimen Я думаю, что вам не хватает команды UIBezierPath fillWithBlendMode. Используйте режим наложения .Clear (и неважно, какая альфа), и теперь вы стерли область круга. Неважно, какой цвет заливки! - person matt; 29.11.2015
comment
@matt Я попробую, но CGContextSetBlendMode у меня работает, но было бы неплохо удалить эту строку. - person specimen; 29.11.2015
comment
@specimen Я хочу сказать, что fillWithBlendMode вызывает CGContextSetBlendMode для вас, поэтому вам никогда не нужно получать текущий графический контекст - вы можете сделать все это с помощью UIBezierPath (и UIColor). - person matt; 29.11.2015
comment
@matt Да, я понял это :) Спасибо, что помог мне, я все еще учусь. - person specimen; 30.11.2015