300 likes | 410 Views
Pixel Test. 朱中華 2010/11/25. CreateARGBBitmapContext. CGContextRef CreateARGBBitmapContext (CGImageRef inImage, CGSize size) { CGContextRef context = NULL; CGColorSpaceRef colorSpace; void * bitmapData; int bitmapByteCount; int bitmapBytesPerRow;
E N D
Pixel Test 朱中華 2010/11/25
CreateARGBBitmapContext • CGContextRef CreateARGBBitmapContext (CGImageRef inImage, CGSize size) • { • CGContextRef context = NULL; • CGColorSpaceRef colorSpace; • void * bitmapData; • int bitmapByteCount; • int bitmapBytesPerRow; • size_t pixelsWide = size.width; • size_t pixelsHigh = size.height; • bitmapBytesPerRow = (pixelsWide * 4); • bitmapByteCount = (bitmapBytesPerRow * pixelsHigh); • colorSpace = CGColorSpaceCreateDeviceRGB(); • if (colorSpace == NULL) • { • fprintf(stderr, "Error allocating color space\n"); • return NULL; • }
CreateARGBBitmapContext (Cont.) • // allocate the bitmap & create context • bitmapData = malloc( bitmapByteCount ); • if (bitmapData == NULL) • { • fprintf (stderr, "Memory not allocated!"); • CGColorSpaceRelease( colorSpace ); • return NULL; • } • context = CGBitmapContextCreate (bitmapData, pixelsWide, pixelsHigh, 8, • bitmapBytesPerRow, colorSpace, • kCGImageAlphaPremultipliedFirst); • if (context == NULL) • { • free (bitmapData); • fprintf (stderr, "Context not created!"); • } • CGColorSpaceRelease( colorSpace ); • return context; • }
RequestImagePixelData • // Return a C-based bitmap of the image data inside an image • unsigned char *RequestImagePixelData(UIImage *inImage) • { • CGImageRef img = [inImage CGImage]; • CGSize size = [inImage size]; • CGContextRef cgctx = CreateARGBBitmapContext(img, size); • if (cgctx == NULL) return NULL; • CGRect rect = {{0,0},{size.width, size.height}}; • CGContextDrawImage(cgctx, rect, img); • unsigned char *data = CGBitmapContextGetData (cgctx); • CGContextRelease(cgctx); • return data; • }
rossHairView • @interface CrossHairView : UIView • @end • @implementation CrossHairView • - (void) drawRect: (CGRect) aRect • { • // Create a new path • CGContextRef context = UIGraphicsGetCurrentContext(); • CGMutablePathRef path = CGPathCreateMutable(); • // Set up the stroke characteristics • CGContextSetLineWidth(context, 3.0f); • CGFloat gray[4] = {0.75f, 0.75f, 0.75f, 1.0f}; • CGContextSetStrokeColor(context, gray);
rossHairView (Cont.) • // Add circle to path • CGRect limits = CGRectMake(2.0f, 2.0f, SIDELENGTH - 4.0f, SIDELENGTH - 4.0f); • CGPathAddEllipseInRect(path, NULL, limits); • CGContextAddPath(context, path); • // Add cross to path, leaving an inspection point in the middle • CGContextMoveToPoint(context, 0.0f, SIDELENGTH/2.0f); • CGContextAddLineToPoint(context, (SIDELENGTH/2.0f) - 2.0f, SIDELENGTH/2.0f); • CGContextMoveToPoint(context, (SIDELENGTH /2.0f) + 2.0f, SIDELENGTH/2.0f); • CGContextAddLineToPoint(context, SIDELENGTH, SIDELENGTH/2.0f); • CGContextMoveToPoint(context, SIDELENGTH/2.0f, 0.0f); • CGContextAddLineToPoint(context, SIDELENGTH/2.0f, (SIDELENGTH / 2.0f) - 2.0f); • CGContextMoveToPoint(context, SIDELENGTH/2.0f, SIDELENGTH); • CGContextAddLineToPoint(context, SIDELENGTH/2.0f, (SIDELENGTH / 2.0f) + 2.0f); • CGContextStrokePath(context); • CFRelease(path); • } • @end
BitMapView • // Create an Image View that stores a copy of its image as an addressable bitmap • @interface BitMapView : UIImageView • { • unsigned char *bitmap; • CGSize size; • } • @end
initWithFrame • - (id) initWithFrame: (CGRect) aFrame • { • if (!(self = [super initWithFrame: aFrame])) return NULL; • // initialize by adding the cross-hair • CrossHairView *crossHair = [[CrossHairView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, SIDELENGTH, SIDELENGTH)]; • crossHair.tag = CROSSHAIR_TAG; • crossHair.backgroundColor = [UIColor clearColor]; • crossHair.center = CGPointMake(160.0f, 240.0f); • [self addSubview:crossHair]; • [crossHair release]; • return self; • }
pointInside • (BOOL) pointInside:(CGPoint)point withEvent:(UIEvent *)event • { • long startByte = (int)((point.y * size.width) + point.x) * 4; • int alpha = (unsigned char) bitmap[startByte]; • return (alpha > 0.5); • }
touchesMoved • - (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event • { • CGPoint pt = [[touches anyObject] locationInView:self]; • long startByte = (int)((pt.y * size.width) + pt.x) * 4; • // Note these points are slightly off in the simulator • [self viewWithTag:CROSSHAIR_TAG].center = pt; • // Output RGB values. The alpha value has offset 0 • /* printf("[%3d, %3d] %3dR %3dG %3dB\n", (int)pt.x, (int)pt.y, • (unsigned char) bitmap[startByte+1], • (unsigned char) bitmap[startByte+2], • (unsigned char) bitmap[startByte+3]); */ • [self viewWithTag:COLOR_VIEW_TAG].backgroundColor = [UIColor • colorWithRed: (float) (bitmap[startByte+1]/255.0f) • green: (float) (bitmap[startByte+2]/255.0f) • blue: (float) (bitmap[startByte+3]/255.0f) • alpha: 1.0f]; • }
setImage • -(void) setImage:(UIImage *) anImage • { • [super setImage:anImage]; • bitmap = RequestImagePixelData(anImage); • size = [anImage size]; • UIView *colorView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 400.0f, 320.0f, 80.0f)]; • colorView.userInteractionEnabled = NO; • colorView.backgroundColor = [UIColor blueColor]; • colorView.tag = COLOR_VIEW_TAG; • [self addSubview:colorView]; • [colorView release]; • }
HelloController • @interface HelloController : UIViewController • @end • @implementation HelloController • - (void)loadView • { • BitMapView *contentView = [[BitMapView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; • [contentView setImage:[UIImage imageNamed:@"image2.jpg"]]; • [contentView setUserInteractionEnabled:YES]; • self.view = contentView; • [contentView release]; • } • @end
SampleAppDelegate • @interface SampleAppDelegate : NSObject <UIApplicationDelegate> • @end • @implementation SampleAppDelegate • - (void)applicationDidFinishLaunching:(UIApplication *)application { • UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; • HelloController *hello = [[HelloController alloc] init]; • [window addSubview:hello.view]; • [window makeKeyAndVisible]; • [application setStatusBarHidden:YES]; • } • @end
Main • int main(int argc, char *argv[]) • { • NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; • int retVal = UIApplicationMain(argc, argv, nil, @"SampleAppDelegate"); • [pool release]; • return retVal; • }
Overview • 這個程式會在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來表示:
applicationsDidFinishLaunching • [window addSubview:hello.view]; 跳入hello所在的HelloController class的loadSubView。
loadView • 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。
RequestImagePixelData • 下面這一行是call RequestImagePixelData,把anImage(image2.jpg)放入bitmap這個array內,每個pixel 4個byte。 • bitmap = RequestImagePixelData(anImage); • 下面這一行是call CreateARGBBitmapContext,產生一個CGContextRef,以便準備放下image2.jpg的所有pixel。 • CreateARGBBitmapContext(img, size)
CreateARGBBitmapContext • Color Space就是用來表現顏色的方式,例如RGB、CMYK等。 • CGColorSpaceCreateDeviceRGB • Create一個device dependent RGB device color space,return value為CGColorSpaceRef object。
CGBitmapContextCreate • 在CGBitmapContext reference裡,把bitmap所需的memory、width、height、bytesPerRow...等七個parameter放入type 為CGContextRef 的context,回傳context,這七個parameter是: • void *data:一塊memory,至少bytesPerRow * height。這一塊memory,用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。
RequestImagePixelData • 這個程式將inImage這file load進memory,並return pointer points to the memory。 注意,這一塊memory是由CreateARGBBitmapContext的malloc來的。 • CGContextDrawImage ( cgctx, rect, img );將image畫上螢幕。 • unsign char *data = CGBitmapContextGetData (cgctx); 會將cgctx內的bitmap image data傳回,讓data這個pointer指向這塊bitmap image data,也就是CreateARGBBitmapContext的malloc來的memory,並由[UIImage imageNamed:@"image2.jpg"]load image2.jpg進memory。
loadView • BitMapView *contentView = ....,call initWithFrame,將crossHair subView放上。 • [contentView setImage:[UIImage imageNamed:@"image2.jpg"]];:拿contentView的資訊,由[UIImage imageNamed:@"image2.jpg"]load image2.jpg進memory。
BitMapView • pointInside:click pixel tester crossHair時,會跳入,如果alpha值>0.5,則系統會繼續。若alpha值<= 0.5,則系統不會繼續。 • touchesMoved:當click及drag時,且如果alpha值> 0.5則跳入 • [self viewWithTag:COLOR_VIEW_TAG].backgroundColor • 將該位置顏色顯示於下方bar。若alpha值< = 0.5,即使click及drag仍不會跳入。
drawRect • 畫出一個圓,中間一個十字的pixel tester(crossHair class),在loadView執行完後,系統會call drawRect: • 行先產生context及path兩個CGContext需用的object。 • CGContextSetStrokeColor(context, gray); • 設定筆畫(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。
畫圓 • 設定的方塊內畫一個圓(畫一個圓),2.0f, 20.f表示內縮2.0,因此size少了4.0,所以SIDELENGTH - 4.0f,從(2.0, 2.0)開始,直徑SIDELENGTH - 4.0f。 • CGRect limits = CGRectMake(2.0f, 2.0f, SIDELENGTH - 4.0f, SIDELENGTH - 4.0f); • CGPathAddEllipseInRect(path, NULL, limits); • CGContextAddPath(context, path);
畫十字 • CGContextMoveToPoint(context, 0.0f, SIDELENGTH/2.0f); CGContextAddLineToPoint(context, (SIDELENGTH/2.0f) - 2.0f, SIDELENGTH/2.0f); CGContextMoveToPoint(context, (SIDELENGTH /2.0f) + 2.0f, SIDELENGTH/2.0f); CGContextAddLineToPoint(context, SIDELENGTH, SIDELENGTH/2.0f); CGContextMoveToPoint(context, SIDELENGTH/2.0f, 0.0f); CGContextAddLineToPoint(context, SIDELENGTH/2.0f, (SIDELENGTH / 2.0f) - 2.0f); CGContextMoveToPoint(context, SIDELENGTH/2.0f, SIDELENGTH); CGContextAddLineToPoint(context, SIDELENGTH/2.0f, (SIDELENGTH / 2.0f) + 2.0f); CGContextStrokePath(context); CFRelease(path);
畫中間橫線 • CGContextMoveToPoint:在CGContext內, 指定一點為(0, SIDELENGTH/2.0f) = ( 0, 20 ) • CGContextAddLineToPoint:在CGContext內,從前一點(0, 20)畫一條線到( ( SIDELENGTH/2.0f ) - 2.0f, SIDELENGTH/2.0f ) = (18, 20)。 • CGContextMoveToPoint: 指定一點為( (SIDELENGTH/2.0f) + 2.0f, SIDELENGTH/2.0f )= ( 22 , 20 )。也就是離上面(18, 20)向右四個點,如此中間留了一個4點的空間。 • CGContextAddLineToPoint:在CGContext內,從前一點(22, 20)畫一條線到( ( SIDELENGTH, SIDELENGTH/2.0f ) = (40, 20)。至此,pixel tester crossHair的中間橫線畫好了。
Homework 5 • Show color space in R, G, and B • Hand in: due 2010/12/02, 00:00 • chchu777@gmail.com • 以組別學號姓名為檔名來繳報告