8 votes

CGContextDrawAngleGradient ?

En me plongeant dans le dessin Core Graphics, j'essaie de recréer un bouton métallique à l'allure diabolique, et j'ai trouvé ce qui est probablement un problème époustouflant.

Il ne semble pas y avoir de moyen de dessiner angle gradients dans Core Graphics. Je vois qu'il y a CGContextDrawRadialGradient() y CGContextDrawLinearGradient() mais je ne vois rien qui me permette de dessiner un dégradé d'angle. Quelqu'un connaît-il une solution de contournement ou un cadre caché quelque part qui permettrait d'accomplir cela sans pré-rendre le bouton dans un fichier image ?

Bouton d'angle de gradient http://dl.dropbox.com/u/3009808/AngleGradient.png .

11voto

Rob Napier Points 92148

C'est un peu improvisé, mais c'est l'approche que j'adopterais probablement. Il s'agit de créer un dégradé d'angle en le dessinant directement dans un bitmap à l'aide d'une simple trigonométrie, puis en l'intégrant à un cercle. Je crée une grille de mémoire en utilisant un espace colorimétrique en niveaux de gris, je calcule l'angle entre un point donné et le centre, puis je le colore sur la base d'une fonction périodique, allant de 0 à 255. Vous pouvez bien sûr étendre cette méthode pour obtenir des couleurs RGBA.

Bien sûr, vous pouvez cacher cela et jouer avec les mathématiques pour obtenir les couleurs que vous voulez. Actuellement, l'image va du noir au blanc, ce qui n'est pas aussi bien que vous le souhaiteriez.

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

3voto

deltacrux Points 515

Pour développer ce qui se trouve dans les commentaires de la réponse acceptée, voici le code permettant de générer un gradient d'angle à l'aide de Core Image. Cela devrait fonctionner avec iOS 8 ou une version ultérieure.

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

L'image suivante est générée :

Angle gradient made using Core Image

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X