Cocoa Touch — Добавление текстуры с видом наложения

#cocoa-touch #core-graphics #quartz-graphics

#cocoa-touch #ядро-графика #quartz-графика

Вопрос:

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

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

Ответ №1:

Это может кому-то помочь, хотя это было собрано по частям из других разделов SO. Чтобы создать скошенное изображение с произвольным цветом для обычного дисплея и для дисплея retina, я создал скошенное изображение в photoshop и установил насыщенность равной нулю, создав изображение в оттенках серого, называемое tileBevel.png

tileBevel.png

Я также создал текстуру для дисплея retina ( tileBevel@2x.png )

Вот код:

   (UIImage*) createTileWithColor:(UIColor*)tileColor {

    int pixelsHigh = 44;
    int pixelsWide = 46;
    UIImage *bottomImage;

    if([UIScreen respondsToSelector:@selector(scale)] amp;amp; [[UIScreen mainScreen] scale] == 2.0) {
        pixelsHigh *= 2;
        pixelsWide *= 2;
        bottomImage = [UIImage imageNamed:@"tileBevel@2x.png"];        
    }
    else {
        bottomImage = [UIImage imageNamed:@"tileBevel.png"];
    }

    CGImageRef theCGImage = NULL;
    CGContextRef tileBitmapContext = NULL;

    CGRect rectangle = CGRectMake(0,0,pixelsWide,pixelsHigh);

    UIGraphicsBeginImageContext(rectangle.size);

    [bottomImage drawInRect:rectangle];

    tileBitmapContext = UIGraphicsGetCurrentContext();

    CGContextSetBlendMode(tileBitmapContext, kCGBlendModeOverlay);

    CGContextSetFillColorWithColor(tileBitmapContext, tileColor.CGColor);        
    CGContextFillRect(tileBitmapContext, rectangle);

    theCGImage=CGBitmapContextCreateImage(tileBitmapContext);

    UIGraphicsEndImageContext();

    return [UIImage imageWithCGImage:theCGImage];

}
  

При этом проверяется, используется ли дисплей retina, определяется размер прямоугольника для рисования, выбирается подходящее базовое изображение в оттенках серого, устанавливается режим наложения на наложение, затем рисуется прямоугольник поверх нижнего изображения. Все это выполняется внутри графического контекста, заключенного в квадратные скобки вызовами BeginImageContext и EndImageContext. Они задают текущий контекст, необходимый UIImage drawRect: метод. Основным графическим функциям необходим контекст в качестве параметра, который получается вызовом для получения текущего контекста.

И результат выглядит следующим образом:

введите описание изображения здесь

Ответ №2:

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

 // Apply mask
CGContextTranslateCTM(tileBitmapContext, 0, rectangle.size.height);
CGContextScaleCTM(tileBitmapContext, 1.0f, -1.0f);

CGContextClipToMask(tileBitmapContext, rectangle, bottomImage.CGImage);
  

Ответ №3:

Решение Swift 3, в основном основанное на ответе Джима с добавлением Scriptease и некоторыми незначительными изменениями:

 class func image(bottomImage: UIImage, topImage: UIImage, tileColor: UIColor) -> UIImage? {
    let pixelsHigh: CGFloat = bottomImage.size.height
    let pixelsWide: CGFloat = bottomImage.size.width

    let rectangle = CGRect.init(x: 0, y: 0, width: pixelsWide, height: pixelsHigh)
    UIGraphicsBeginImageContext(rectangle.size);

    bottomImage.draw(in: rectangle)

    if let tileBitmapContext = UIGraphicsGetCurrentContext() {
        tileBitmapContext.setBlendMode(.overlay)
        tileBitmapContext.setFillColor(tileColor.cgColor)
        tileBitmapContext.scaleBy(x: 1.0, y: -1.0)
        tileBitmapContext.clip(to: rectangle, mask: bottomImage.cgImage!)
        tileBitmapContext.fill(rectangle)
        let theCGImage = tileBitmapContext.makeImage()
        UIGraphicsEndImageContext();

        if let theImage = theCGImage {
            return UIImage.init(cgImage: theImage)
        }
    }

    return nil
}