iphone - poner - Cómo dibujar una rueda de color en Object-C
rueda de color photoshop (5)
A continuación, se dibuja una rueda de color HSL en una subclase UIView. Lo hace generando un mapa de bits computando, para cada píxel, el valor de color correcto. Esto no es exactamente lo que estás tratando de hacer (parece que el matiz varía en el círculo con una luminancia / saturación constante), pero deberías poder adaptarlo a tus necesidades.
Tenga en cuenta que esto puede no tener un rendimiento óptimo, pero debe comenzar. Además, puede usar getColorWheelValue()
para manejar la entrada del usuario (clics / toques en una determinada coordenada).
- (void)drawRect:(CGRect)rect
{
int dim = self.bounds.size.width; // should always be square.
bitmapData = CFDataCreateMutable(NULL, 0);
CFDataSetLength(bitmapData, dim * dim * 4);
generateColorWheelBitmap(CFDataGetMutableBytePtr(bitmapData), dim, luminance);
UIImage *image = createUIImageWithRGBAData(bitmapData, self.bounds.size.width, self.bounds.size.height);
CFRelease(bitmapData);
[image drawAtPoint:CGPointZero];
[image release];
}
void generateColorWheelBitmap(UInt8 *bitmap, int widthHeight, float l)
{
// I think maybe you can do 1/3 of the pie, then do something smart to generate the other two parts, but for now we''ll brute force it.
for (int y = 0; y < widthHeight; y++)
{
for (int x = 0; x < widthHeight; x++)
{
float h, s, r, g, b, a;
getColorWheelValue(widthHeight, x, y, &h, &s);
if (s < 1.0)
{
// Antialias the edge of the circle.
if (s > 0.99) a = (1.0 - s) * 100;
else a = 1.0;
HSL2RGB(h, s, l, &r, &g, &b);
}
else
{
r = g = b = a = 0.0f;
}
int i = 4 * (x + y * widthHeight);
bitmap[i] = r * 0xff;
bitmap[i+1] = g * 0xff;
bitmap[i+2] = b * 0xff;
bitmap[i+3] = a * 0xff;
}
}
}
void getColorWheelValue(int widthHeight, int x, int y, float *outH, float *outS)
{
int c = widthHeight / 2;
float dx = (float)(x - c) / c;
float dy = (float)(y - c) / c;
float d = sqrtf((float)(dx*dx + dy*dy));
*outS = d;
*outH = acosf((float)dx / d) / M_PI / 2.0f;
if (dy < 0) *outH = 1.0 - *outH;
}
UIImage *createUIImageWithRGBAData(CFDataRef data, int width, int height)
{
CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef imageRef = CGImageCreate(width, height, 8, 32, width * 4, colorSpace, kCGImageAlphaLast, dataProvider, NULL, 0, kCGRenderingIntentDefault);
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];
CGDataProviderRelease(dataProvider);
CGColorSpaceRelease(colorSpace);
CGImageRelease(imageRef);
return image;
}
// Adapted from Apple sample code. See http://en.wikipedia.org/wiki/HSV_color_space#Comparison_of_HSL_and_HSV
void HSL2RGB(float h, float s, float l, float* outR, float* outG, float* outB)
{
float temp1, temp2;
float temp[3];
int i;
// Check for saturation. If there isn''t any just return the luminance value for each, which results in gray.
if(s == 0.0)
{
*outR = l;
*outG = l;
*outB = l;
return;
}
// Test for luminance and compute temporary values based on luminance and saturation
if(l < 0.5)
temp2 = l * (1.0 + s);
else
temp2 = l + s - l * s;
temp1 = 2.0 * l - temp2;
// Compute intermediate values based on hue
temp[0] = h + 1.0 / 3.0;
temp[1] = h;
temp[2] = h - 1.0 / 3.0;
for(i = 0; i < 3; ++i)
{
// Adjust the range
if(temp[i] < 0.0)
temp[i] += 1.0;
if(temp[i] > 1.0)
temp[i] -= 1.0;
if(6.0 * temp[i] < 1.0)
temp[i] = temp1 + (temp2 - temp1) * 6.0 * temp[i];
else {
if(2.0 * temp[i] < 1.0)
temp[i] = temp2;
else {
if(3.0 * temp[i] < 2.0)
temp[i] = temp1 + (temp2 - temp1) * ((2.0 / 3.0) - temp[i]) * 6.0;
else
temp[i] = temp1;
}
}
}
// Assign temporary values to R, G, B
*outR = temp[0];
*outG = temp[1];
*outB = temp[2];
}
Estoy tratando de dibujar una rueda de colores para un iPhone, pero no puedo hacer que la pendiente gire alrededor de un punto. Estoy tratando de usar degradados pero objetivo-c proporciona un gradiente lineal, que dibuja un degradado en una línea recta como esta:
y un gradiente radial, que dibuja el gradiente comenzando en el punto e irradiando en todas las direcciones de esta manera:
Quiero dibujar un degradado lineal que gira alrededor de un punto como este:
Hice algo como esto creando un gran mapa de bits RGBA, coloreando cada píxel según su ubicación convertida en coordenadas polares, luego convirtiendo el mapa de bits en una imagen y dibujando la imagen reducida. La reducción fue para ayudar a antialias pixelación cerca del centro.
No estoy al tanto de nada que pueda hacer esto por ti. Puedes aproximarlo dibujando triángulos que van desde (amarillo-> rojo, rojo-> purp, purp-> azul, etc.) y luego colocando una máscara circular sobre él. Mira CGGradient .
Lo siento, no puedo ser de más ayuda.
Tendrás que hacer un mapa de bits como lo sugiere hotpaw2. La forma más eficiente de calcular esto es usar el espacio de color HSL . Eso le permitirá crear una función que toma como entrada una ubicación de píxel y escupe un valor RGB, usando solo unas pocas operaciones aritméticas básicas y un poco de trigonometría para calcularlo.
Si desea colores arbitrarios a lo largo de los "radios" de la rueda, bueno, eso requiere más trabajo. Necesitas calcular los valores de fusión para cada píxel, e implica una vista más trigonométrica, y no es tan rápido. Cuando hice esto, tuve que vectorizar y paralelizarlo para eliminar el ligero (aunque perceptible) retraso en la actualización al volver a calcular el mapa de bits, en una MacBook Pro. En el iPhone no tienes esas opciones, así que tendrás que vivir con el retraso.
Avíseme si necesita explicaciones más detalladas de estas técnicas; Estaré feliz de ayudar.
Usando solo métodos UIKit:
// ViewController.m; assuming ViewController is the app''s root view controller
#include "ViewController.h"
@interface ViewController ()
{
UIImage *img;
UIImageView *iv;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
CGSize size = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height);
UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width, size.height), YES, 0.0);
[[UIColor whiteColor] setFill];
UIRectFill(CGRectMake(0, 0, size.width, size.height));
int sectors = 180;
float radius = MIN(size.width, size.height)/2;
float angle = 2 * M_PI/sectors;
UIBezierPath *bezierPath;
for ( int i = 0; i < sectors; i++)
{
CGPoint center = CGPointMake(size.width/2, size.height/2);
bezierPath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:i * angle endAngle:(i + 1) * angle clockwise:YES];
[bezierPath addLineToPoint:center];
[bezierPath closePath];
UIColor *color = [UIColor colorWithHue:((float)i)/sectors saturation:1. brightness:1. alpha:1];
[color setFill];
[color setStroke];
[bezierPath fill];
[bezierPath stroke];
}
img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
iv = [[UIImageView alloc] initWithImage:img];
[self.view addSubview:iv];
}
@end
Básicamente todo lo que hace el código anterior es dar la vuelta al círculo dibujando sectores estrechos llenándolos con colores de tono cada vez mayor.
Por supuesto, puede hacer todo el dibujo directamente en el contexto de gráficos de una vista con drawRect()
y no tiene que crear un contexto de imagen explícito.