CGContextDrawAngleGradient?

发布于 2024-11-27 09:55:10 字数 446 浏览 1 评论 0原文

我将脚浸入更多的 Core Graphics 绘图中,试图重新创建一个看起来很邪恶的金属旋钮,并且我发现了一个可能是一个令人停止的问题。

似乎没有任何方法可以在 Core Graphics 中绘制角度渐变。我看到有 CGContextDrawRadialGradient()CGContextDrawLinearGradient(),但我没有看到任何可以让我绘制角度渐变的东西。有谁知道解决方法,或者隐藏在某处的一些框架来完成此操作,而无需将旋钮预先渲染到图像文件中?

AngleGradientKnob http://dl.dropbox.com/u/3009808/AngleGradient.png

Dipping my feet into some more Core Graphics drawing, I'm attempting to recreate a wicked looking metallic knob, and I've landed on what is probably a show-stopping issue.

There doesn't seem to be any way to draw angle gradients in Core Graphics. I see there's CGContextDrawRadialGradient() and CGContextDrawLinearGradient(), but there's nothing that I see that would allow me to draw an angle gradient. Does anyone know of a workaround, or a bit of framework hidden away somewhere to accomplish this without pre-rendering the knob into an image file?

AngleGradientKnob http://dl.dropbox.com/u/3009808/AngleGradient.png.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甜味超标? 2024-12-04 09:55:10

这是一种拼凑在一起的方式,但这是我可能会采取的方法。这是通过使用一些简单的三角函数将其直接绘制到位图中来创建角度渐变,然后将其剪切为圆形。我使用灰度色彩空间创建内存网格,计算从给定点到中心的角度,然后基于周期函数进行着色,在 0 到 255 之间运行。当然,您也可以扩展它以执行 RGBA 颜色。

当然,您可以缓存它并进行数学运算以获得您想要的颜色。目前它是从黑到白的,看起来并不像你想要的那么好。

- (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);
}

This is kind of thrown together, but it's the approach I'd probably take. This is creating an angle gradient by drawing it directly into a bitmap using some simple trig, then clipping it to a circle. I create a grid of memory using a grayscale colorspace, calculate the angle from a given point to the center, and then color that based on a periodic function, running between 0 to 255. You could of course expand this to do RGBA color as well.

Of course you'd cache this and play with the math to get the colors you want. This currently runs all the way from black to white, which doesn't look as good as you'd like.

- (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);
}
仲春光 2024-12-04 09:55:10

为了扩展已接受答案的注释中的内容,这里是使用 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);

这会生成以下图像:

使用核心图像制作的角度渐变

To expand on what's in the comments to the accepted answer, here's the code for generating an angle gradient using Core Image. This should work in iOS 8 or later.

// 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);

This generates the following image:

Angle gradient made using Core Image

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文