2011年6月30日

編寫隨機色彩時遇到的一些問題及心得

話說我正學習 iOS programming,在想試用 Quartz2D 跟 touch event 寫一個 try-out program。程式裡面有一個隨機色彩繪線,心想只要把 RGB 值轉為 HSL,再隨機產生 Hue 值便成。但竟然問題出在 HSL/HSB 裡。

從 API 裡,我可以把 UIColor 中取出 CGColorRef,再用 CGColorGetComponents 便取到 RGB 值。
但怎樣才可以把 RGB 值轉為 HSL 呢? Google 一下後找到一個 Utility Lib,很簡單很好用的:
https://github.com/alessani/ColorConverter

不過裡面可能有點問題,若果嘗試 RGB2HSL -> HSL2RGB,轉換後 RGB 值會改變。按理是不變的。沒問題,只要把 ColorSpaceUtilities.h 中的這些行 comment out 便可以了:

r = r/255.0f;
g = g/255.0f;
b = b/255.0f;


好了,有了 HSL,又有了隨機 Hue 值,只差轉回 UIColor 便可以了。找一下 API,發現 UIColor 裡有一個 factory method: [UIColor colorWithHue:saturation:brightness:alpha:],這不是很合用嗎?

可借用了後發現亮度不對。按理應該不可能這樣啊~~
花了一段時間後,才知道我的基本概念錯了! 從 WIKI 看到,我一直以為色彩學裡嘅 HSV 跟 HSL 是一樣,原來是我錯了!
http://en.wikipedia.org/wiki/HSL_and_HSV

最終,我只用回原本的方法,即:
UIColor -> RGB -> RGB2HSL -> Random(H) -> HSL2RGB -> UIColor

以下是我的 UIView (.m):

#import "draw2D.h"
#import "ColorSpaceUtilities.h"

@implementation draw2D

@synthesize fromPoint;
@synthesize toPoint;
@synthesize currentColor;

-(id) initWithCoder:(NSCoder*)sourceCoder
{
if( ( self = [super initWithCoder:sourceCoder]))
{
//place any other initialization here
NSLog(@"Init Draw2D with coder");
currentColor = [UIColor blueColor];
}
return self;
}

-(void)updateColorRand{
float hColor,sColor,lColor;
float rColor,gColor,bColor,aColor;

const CGFloat* colors = CGColorGetComponents(currentColor.CGColor);
rColor = colors[0];
gColor = colors[1];
bColor = colors[2];
aColor = colors[3];

RGB2HSL(rColor,gColor,bColor,&hColor,&sColor,&lColor);
hColor = (float)(arc4random() % 255) / 255;
HSL2RGB(hColor, sColor, lColor,&rColor,&gColor,&bColor);
self.currentColor = [UIColor
colorWithRed:rColor
green:gColor
blue:bColor
alpha:aColor];
colors = nil;
}

- (void)actGraphic1:(CGContextRef) context {
CGContextSetLineWidth(context,4);
CGContextSetStrokeColorWithColor(context, currentColor.CGColor);
CGContextMoveToPoint(context,fromPoint.x , fromPoint.y);
CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
CGContextStrokePath(context);

}

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code.
CGContextRef context = UIGraphicsGetCurrentContext();

[self actGraphic1:context];
context=nil;
}

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch* touchPoint = [touches anyObject];
fromPoint = [touchPoint locationInView:self];
toPoint = [touchPoint locationInView:self];
NSLog(@"Touch Began");
[self updateColorRand];
[self setNeedsDisplay];
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
toPoint=[touch locationInView:self];
NSLog(@"Touch End");
[self setNeedsDisplay];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
toPoint = [touch locationInView:self];
[self setNeedsDisplay];
}

- (void)dealloc {
[currentColor release];
[super dealloc];
}

@end


(.h) (註,請把 | 改為 "<" 同 ">":

#import |uikit.h|
@interface draw2D : UIView {
CGPoint fromPoint;
CGPoint toPoint;
UIColor *currentColor;
}

@property CGPoint fromPoint;
@property CGPoint toPoint;
@property (nonatomic, retain) UIColor *currentColor;

@end


還有一個問題,就是在這程式中, 變數(instance variable) currentColor 的 TYPE 不能使用 CGColorRef,必須用 UIColor! 因為我在其中一個method中,會把 currentColor 替換,若使用 CGColorRef,就算用 CGColorRelease 或 CGColorRetain,無論我怎樣嘗試,Apps 始終會 crash!

Google 了很久,還是沒有方法,一部份人提議以 UIColor 代替。雖然這方法可行,但為什麼呢?真的搞不懂 Objective-C。

沒有留言:

發佈留言