04b-PixelTest

iPhone SDK開發範例大全第二章之五PixelTest(5/14):2009年08月26日星期三

iPhone SDK開發範例大全即iPhone Developer's CookBook的中文譯本,程式可由erica網站下載。第二章講View(視圖),程式共有十四個:

本文講第五個程式04b-PixelTest:

(A)這個程式會在iPhone螢幕上顯示一個image(image在image2.jpg內),並放一個圓形的pixel tester在image之上,一開始,image下方顯示一條藍色bar,一旦移動該pixel tester,中心pixel的顏色會立即顯示在下方bar上,見下圖,任何時候,隨著pixel tester移動,其中心所在位置的顏色會顯示在下方bar。最左邊的圖是剛開始,image下方顯示一條藍色bar,pixel tester在螢幕中間,中間是的圖是pixel tester移至上方,右邊的圖是pixel tester移到魚上,在不同的位置,下方bar顯示出image內某pixel的顏色。pixel tester在程式中是以crossHair class來表示:

(B)本程式的重點在於設立pixel tester及image裡的alpha值,見下圖,程式共有CreateARGBBitmapContext function、RequestImagePixelData function、crossHair class、BitMapView class、helloController class、sampleAppDelegate class、main七大部份,程式的主要流程如下:

由SampleAppDelegate Class的applicationsDidFinishLaunching內,

[window addSubview:hello.view];這一行因hello.view一定為nil,所以跳入hello所在的HelloController class的loadSubView。

HelloController class的loadSubView內,

BitMapView *contentView = [[BitMapView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 這一行呼叫initWithFrame開啟一個BitMapView object -- contentView,在initWithFrame內,

CrossHairView *crossHair = [[CrossHairView alloc] initWithFrame:CGReckMake(0.0f, 0.0f, SIDELENGTH, SIDELENGTH)]; // 將 ( SIDELENGTH, SIDELENGTH ) 這 ( 40 x 40 )的 pixel tester 加入BitMapView object內

[contentView setImage:[UIImage imageNamed:@"image2.jpg"]];這一行呼叫contentView所屬的BitMapView class中的setImage。

BitMapView class中的setImage內,下面這一行是call RequestImagePixelData,把anImage(image2.jpg)放入bitmap這個array內,每個pixel 4個byte。

bitmap = RequestImagePixelData(anImage);進入C程式 RequestImagePixelData,

RequestImagePixelData內,下面這一行是call CreateARGBBitmapContext,產生一個CGContextRef,以便準備放下image2.jpg的所有pixel。

CreateARGBBitmapContext(img, size)。

(C) 見下圖,CGContextRef CreateARGBBitmapContext (CGImageRef inImage, CGSize size) function,是產生一個ARGB的CGContext refernce:

第7行,CGColorSpaceRef opaque type:The CGColorSpaceRef opaque type encapsulates color space information that is used to specify how Quartz interprets color information. Color Space就是用來表現顏色的方式,例如RGB、CMYK等。

CGColor ( Quartz drawing operations use color objects for setting fill and stroke colors, managing alpha, and setting color with a pattern ),

第16行,CGColorSpaceCreateDeviceRGB();:Create一個 device dependent RGB device color space,return value為CGColorSpaceRef object。 Mac 10.4之後用kCGColorSpaceGenericRGB。

第33行,CGBitmapContextCreate():在CGBitmapContext reference裡,把bitmap所需的memory、width、height、bytesPerRow...等七個parameter放入type 為CGContextRef 的context,回傳context,這七個parameter是:

void *data:一塊memory,至少bytesPerRow * height。這一塊memory在25行時用c的malloc得到,由這個程式放入context內。

size_t width:bitmap 的width in pixel。

size_t height: bitmap 的height in pixel。

size_t bitsPerComponent:32-bit pixel format的RGB, 8 bits per component。

size_t bytesPerRow:一個row多少bytes。

CGColorSpaceRef colorspace:

CGBitmapInfo bitmapInfo: 用kCGImageAlphaPremultipliedFirst,見CGImage內Alpha Information for Images ,Alpha information存在pixel的most significant bit。用此info可以blend source ( pixel tester? )及destination image ( image2.jpg ) 。

用CGImageGetAlphaInfo可以得到CGImageAlphaInfo constant的值,CGImageAlphaInfo constant在CGImage內。

(D) 見下圖,unsigned char *RequestImagePixelData(UIImage inImage) :這個程式將inImage這file load進memory,並return pointer points to the memory。 注意,這一塊memory是由 CreateARGBBitmapContext的25行malloc來的。

第55行,CGContextDrawImage ( cgctx, rect, img );將image畫上螢幕。

第56行, unsign char *data = CGBitmapContextGetData (cgctx); 會將cgctx內的bitmap image data傳回,讓data這個pointer指向這塊bitmap image data,也就是 CreateARGBBitmapContext的25行malloc來的memory,並在176行,由[UIImage imageNamed:@"image2.jpg"]load image2.jpg進memory。

(E)initWithFrame:將crossHair加入loadView第175行的contentView為subView。

 

(F)loadView:

175行,BitMapView *contentView = ...., call initWithFrame,將crossHair subView放上。

176行,[contentView setImage:[UIImage imageNamed:@"image2.jpg"]];:拿contentView的資訊,由[UIImage imageNamed:@"image2.jpg"]load image2.jpg進memory。

(G)pointInside, touchesMoved:

pointInside: click pixel tester crossHair時,會跳入,128行回傳,如果alpha值>0.5,則系統會繼續。若alpha值 <= 0.5,則系統不會繼續。

touchesMoved:當click及drag時,且如果alpha值 > 0.5則跳入,136行會將crossHair移至最後的位置,144行將該位置顏色顯示於下方bar。若alpha值 < = 0.5,即使click及drag仍不會跳入。

(H) drawRect method,畫出一個圓,中間一個十字的pixel tester(crossHair class),在loadView執行完後,系統會call drawRect:

72,73行先產生context及path兩個CGContext需用的object。

76~78行設定筆畫(stroke)相關資訊,76行設定筆畫的寬度為3pixel(可試試改為1個pixel或5個pixel),77~78行設定筆畫的顏色及透明度,77行gray[4]有四個值,依次為RGBA,

RGB為1是表示全部0表示沒有,例如:

R=1 G=0 B=0表示全紅。

A值1表示不透明,0表示全透明。所以若A=0,就完全看不到這個pixel tester。

81~83行在設定的方塊內畫一個圓(畫一個圓),81行2.0f, 20.f表示內縮2.0,因此size少了4.0,所以SIDELENGTH - 4.0f,從(2.0, 2.0)開始,直徑SIDELENGTH - 4.0f。

86~93行畫出這pixel tester形狀。

86行的CGContextMoveToPoint:在CGContext內, 指定一點為(0, SIDELENGTH/2.0f) = ( 0, 20 ),也就是以左下為原點(0,0)的座標系統(見下圖、本圖取自“Quartz 2D Coordinates”)的一點,

87行CGContextAddLineToPoint:在CGContext內,從前一點(0, 20)畫一條線到( ( SIDELENGTH/2.0f ) - 2.0f, SIDELENGTH/2.0f ) = (18, 20)。

88行CGContextMoveToPoint: 指定一點為( (SIDELENGTH/2.0f) + 2.0f, SIDELENGTH/2.0f )= ( 22 , 20 )。也就是離上面 (18, 20)向右四個點,如此中間留了一個4點的空間。

89行CGContextAddLineToPoint:在CGContext內,從前一點(22, 20)畫一條線到( ( SIDELENGTH, SIDELENGTH/2.0f ) = (40, 20)。至此,pixel tester crossHair的中間橫線畫好了

90~93行畫pixel tester crossHair的中間直線。