CGContextDrawAngleGradient? - PullRequest
       40

CGContextDrawAngleGradient?

8 голосов
/ 02 августа 2011

Окунувшись в еще один рисунок Core Graphics, я пытаюсь воссоздать злобную металлическую ручку и обнаружил, что, вероятно, проблема с остановкой шоу.Похоже, что любой способ рисовать угол градиенты в Core Graphics.Я вижу, что есть CGContextDrawRadialGradient() и CGContextDrawLinearGradient(), но я не вижу ничего, что позволило бы мне нарисовать угловой градиент.Кто-нибудь знает об обходном пути или небольшом количестве фреймворков, спрятанных где-нибудь, чтобы выполнить это без предварительной рендеринга ручки в файл изображения?

Ответы [ 2 ]

11 голосов
/ 02 августа 2011

Это своего рода объединение, но я бы, наверное, выбрал такой подход. Это создает угловой градиент, рисуя его непосредственно в растровое изображение с помощью некоторого простого триггера, а затем обрезая его до круга. Я создаю сетку памяти, используя цветовое пространство в градациях серого, вычисляю угол от заданной точки к центру, а затем окрашиваю, основываясь на периодической функции, в диапазоне от 0 до 255. Конечно, вы можете расширить это, чтобы сделать цвет RGBA .

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

image

- (void)drawRect:(CGRect)rect {
  CGImageAlphaInfo alphaInfo = kCGImageAlphaNone;
  CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
  size_t components = CGColorSpaceGetNumberOfComponents( colorSpace );
  size_t width = 100;
  size_t height = 100;
  size_t bitsPerComponent = 8;
  size_t bytesPerComponent = bitsPerComponent / 8;
  size_t bytesPerRow = width * bytesPerComponent * components;
  size_t dataLength = bytesPerRow * height;

  uint8_t data[dataLength];

  CGContextRef imageCtx = CGBitmapContextCreate( &data, width, height, bitsPerComponent,
                                      bytesPerRow, colorSpace, alphaInfo );

  NSUInteger offset = 0;
  for (NSUInteger y = 0; y < height; ++y) {
    for (NSUInteger x = 0; x < bytesPerRow; x += components) {
      CGFloat opposite = y - height/2.;
      CGFloat adjacent = x - width/2.;
      if (adjacent == 0) adjacent = 0.001;
      CGFloat angle = atan(opposite/adjacent);
      data[offset] = abs((cos(angle * 2) * 255));
      offset += components * bytesPerComponent;
    }
  }

  CGImageRef image = CGBitmapContextCreateImage(imageCtx);

  CGContextRelease(imageCtx);
  CGColorSpaceRelease(colorSpace);

  CGContextRef ctx = UIGraphicsGetCurrentContext();

  CGRect buttonRect = CGRectMake(100, 100, width, width);
  CGContextAddEllipseInRect(ctx, buttonRect);
  CGContextClip(ctx);

  CGContextDrawImage(ctx, buttonRect, image);
  CGImageRelease(image);
}
3 голосов
/ 30 ноября 2015

Чтобы подробнее узнать, что в комментариях к принятому ответу, приведен код генерации углового градиента с использованием Core Image.Это должно работать в iOS 8 или более поздней версии.

// generate a dummy image of the required size
UIGraphicsBeginImageContextWithOptions(CGSizeMake(256.0, 256.0), NO, [[UIScreen mainScreen] scale]);
CIImage *dummyImage = [CIImage imageWithCGImage:UIGraphicsGetImageFromCurrentImageContext().CGImage];

// define the kernel algorithm
NSString *kernelString = @"kernel vec4 circularGradientKernel(__color startColor, __color endColor, vec2 center, float radius) { \n"
"    vec2 point = destCoord() - center;"
"    float rsq = point.x * point.x + point.y * point.y;"
"    float theta = mod(atan(point.y, point.x), radians(360.0));"
"    return (rsq < radius*radius) ? mix(startColor, endColor, 0.5+0.5*cos(4.0*theta)) : vec4(0.0, 0.0, 0.0, 1.0);"
"}";

// initialize a Core Image context and the filter kernel
CIContext *context = [CIContext contextWithOptions:nil];
CIColorKernel *kernel = [CIColorKernel kernelWithString:kernelString];

// argument array, corresponding to the first line of the kernel string
NSArray *args = @[ [CIColor colorWithRed:0.5 green:0.5 blue:0.5],
                   [CIColor colorWithRed:1.0 green:1.0 blue:1.0],
                   [CIVector vectorWithCGPoint:CGPointMake(CGRectGetMidX(dummyImage.extent),CGRectGetMidY(dummyImage.extent))],
                   [NSNumber numberWithFloat:200.0]];

// apply the kernel to our dummy image, and convert the result to a UIImage
CIImage *ciOutputImage = [kernel applyWithExtent:dummyImage.extent arguments:args];
CGImageRef cgOutput = [context createCGImage:ciOutputImage fromRect:ciOutputImage.extent];
UIImage *gradientImage = [UIImage imageWithCGImage:cgOutput];
CGImageRelease(cgOutput);

Это создает следующее изображение:

Angle gradient made using Core Image

...