Как нарисовать фигуру поверх UIImage, соблюдая альфа-маску изображения - PullRequest
9 голосов
/ 28 августа 2009

Мне нужен UIImageView, который может рисовать себя в цвете или ч / б в соответствии с флагом:

  BOOL isGrey;

Я пытаюсь сделать это, рисуя черный прямоугольник поверх оригинального изображения с режимом смешивания Quartz, установленным на Color. Это работает, за исключением того, что оно не учитывает альфа-маску изображения.

См. Иллюстрацию: альтернативный текст http://img214.imageshack.us/img214/1407/converttogreyscaleillo.png

В поисках Google и SO я нашел и попробовал несколько решений, но ни одно из них не соответствует маске.

Вот код, который создает изображение «Что я получаю» выше:

 - (void)drawRect:(CGRect)rect {

    if (isGrey) {
        CGContextRef context = UIGraphicsGetCurrentContext();

        // flip orientation
        CGContextTranslateCTM(context, 0, self.bounds.size.height);
        CGContextScaleCTM(context, 1.0, -1.0);

        // draw the image
        CGContextDrawImage(context, self.bounds, self.image.CGImage);

        // set the blend mode and draw rectangle on top of image
        CGContextSetBlendMode(context, kCGBlendModeSaturation);
        CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
        CGContextFillRect(context, rect);       
    } else {
        [self.image drawInRect:rect];
    }
}

Есть ли какой-нибудь режим рисования Кварца, который я забыл установить? Я просмотрел Руководство по программированию кварца, но мне так трудно извлечь один бит информации, который вам нужен, из перекрывающихся и гиперссылок.

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

Ответы [ 4 ]

10 голосов
/ 05 сентября 2009

Чтобы нарисовать фигуру, соблюдая альфа-маску изображения, просто добавьте одну линию перед рисованием:

 CGContextClipToMask(context, self.bounds, image.CGImage);

 // example usage
  - (void)drawRect:(CGRect)rect {

    if (isGrey) {
            CGContextRef context = UIGraphicsGetCurrentContext();

            // flip orientation
            CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
            CGContextScaleCTM(context, 1.0, -1.0);

            // draw the image
            CGContextDrawImage(context, self.bounds, self.image.CGImage);

            // set the blend mode and draw rectangle on top of image
            CGContextSetBlendMode(context, kCGBlendModeColor);
            CGContextClipToMask(context, self.bounds, image.CGImage); // respect alpha mask
            CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
            CGContextFillRect(context, rect);               
    } else {
            [self.image drawInRect:rect];
    }

}

1 голос
/ 31 августа 2009

Я бы выбрал легкий путь и нарисовал черный круг того же размера, что и круглое изображение, которое у вас есть. Наверное, не то, что вы просите.

1 голос
/ 28 августа 2009

Хотя это не дает прямого ответа на ваш вопрос, вы можете получить желаемый эффект, используя режим наложения kCGBlendModeLuminosity:

- (void)drawRect:(CGRect)rect {
    CGSize imageSize = [image size];
    CGContextRef c = UIGraphicsGetCurrentContext();
    if (isGrey)
        CGContextSetBlendMode(c, kCGBlendModeLuminosity);
    CGContextScaleCTM(c, 1.0, -1.0);
    CGContextDrawImage(c, CGRectMake(0.0f, 0.0f, imageSize.width, -imageSize.height), [image CGImage]);
}

Кроме того, прямоугольник, переданный drawRect:, является недопустимой областью, а не всей областью. Вы должны использовать bounds вместо

0 голосов
/ 28 августа 2009

Вы можете попытаться добавить маску к слою Core Animation представления.

CALayer *maskLayer = [CALayer layer];
[maskLayer setBounds:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)];

// Center the layer
[maskLayer setPosition:CGPointMake([self view].bounds.size.width/2, 
                          [self view].bounds.size.height/2)];

// Set the cornerRadius to half the width/height to get a circle.
[maskLayer setCornerRadius:50.f];
[maskLayer setMasksToBounds:YES];

// Any solid color will do. Just using black here.
[maskLayer setBackgroundColor:[[UIColor blackColor] CGColor]];

// Set the mask which will only allow that which is in the
// circle show through
[[[self view] layer] setMask:maskLayer];

Еще одна мысль. Почему вы не можете просто создать черно-белую версию изображения и поменять ее местами в зависимости от вашего флага?

...