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的中間直線。