2011-08-01 13 views
8

Ngâm đôi chân của tôi vào một số bản vẽ Đồ họa cốt lõi khác, tôi đang cố gắng tạo lại một núm kim loại trông có vẻ độc ác, và tôi đã hạ cánh xuống những gì có thể là vấn đề hiển thị.CGContextDrawAngleGradient?

Dường như không có cách nào để vẽ các hiệu ứng góc gradient trong Đồ họa chính. Tôi thấy có CGContextDrawRadialGradient()CGContextDrawLinearGradient(), nhưng không có gì mà tôi thấy sẽ cho phép tôi vẽ một góc nghiêng. Có ai biết về một workaround, hoặc một chút khuôn khổ ẩn đi một nơi nào đó để thực hiện điều này mà không cần dựng trước núm vào một tập tin hình ảnh?

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

Trả lời

11

Đây là loại ném cùng nhau, nhưng đó là cách tiếp cận tôi có thể sẽ thực hiện. Điều này tạo ra một gradient góc bằng cách vẽ nó trực tiếp vào một bitmap bằng cách sử dụng một số trig đơn giản, sau đó cắt nó thành một vòng tròn. Tôi tạo ra một mạng lưới bộ nhớ bằng cách sử dụng một không gian màu xám, tính toán góc từ một điểm cho đến trung tâm, và sau đó màu sắc dựa trên một hàm tuần hoàn, chạy từ 0 đến 255. Bạn có thể mở rộng điều này để làm màu RGBA. .

Tất nhiên bạn sẽ lưu bộ nhớ cache này và chơi với toán để có được màu bạn muốn. Điều này hiện đang chạy tất cả các cách từ màu đen sang màu trắng, mà không nhìn tốt như bạn muốn.

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

Nhìn vào vòng lặp của bạn, có vẻ với tôi như nó sẽ là khá đơn giản để dịch cho một lõi hình ảnh hạt nhân có thể tạo ra một vô cùng lớn hình ảnh của gradient bạn đã cho thấy. –

+0

Đồng ý, nhưng OP yêu cầu liên lạc cacao không hỗ trợ bộ lọc hạt nhân CI. Trên Mac, Core Image chắc chắn sẽ hữu ích ở đây. –

+0

Giả thuyết, nếu phiên bản iOS tiếp theo xảy ra để hỗ trợ Core Image (và tôi không nói nó sẽ), điều này sẽ bao gồm các bộ lọc hạt nhân cần thiết, hoặc là một cái gì đó mà sẽ duy trì nghiêm ngặt máy tính để bàn chỉ? –

3

Để mở rộng vào những gì trong các ý kiến ​​để câu trả lời được chấp nhận, đây là đoạn code để tạo ra một gradient góc sử dụng Core Image. Điều này sẽ hoạt động trong iOS 8 trở lên.

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

này tạo ra hình ảnh sau:

Angle gradient made using Core Image

+0

Điều này thật tuyệt vời - Cảm ơn! Tôi đã lấy sự tự do chuyển ví dụ của bạn sang Swift - https://gist.github.com/grgcombs/f70b1f053b9cc3467e2d –

+0

Tôi đã không nhận ra rằng bạn vẫn quan tâm đến vấn đề này bốn năm sau ;-P Nhưng câu hỏi đã giúp tôi giải quyết vấn đề này trong dự án của riêng tôi, vì vậy cảm ơn bạn! – deltacrux