2012-05-16 15 views
5

Mac OS X 10.7.4Mac OS X: Das Zeichnen in einem Offscreen-NSGraphicsContext mit CGContextRef C-Funktionen hat keine Auswirkungen. Warum?

Ich zeichne in einen Offscreen-Grafikkontext, der über +[NSGraphicsContext graphicsContextWithBitmapImageRep:] erstellt wurde.

Wenn ich in diesem Grafikkontext unter Verwendung der NSBezierPath Klasse zeichnen, funktioniert alles wie erwartet.

Wenn ich jedoch in diesen Grafikkontext unter Verwendung der CGContextRef C-Funktionen zeichnen, sehe ich keine Ergebnisse meiner Zeichnung. Nichts funktioniert.

Aus Gründen, auf die ich nicht eingehen werde, muss ich wirklich mit den CGContextRef Funktionen zeichnen (anstatt der Cocoa NSBezierPath Klasse).

Mein Codebeispiel ist unten aufgeführt. Ich versuche ein einfaches "X" zu zeichnen. Ein Hub mit NSBezierPath, ein Hub mit CGContextRef C-Funktionen. Der erste Strich funktioniert, der zweite nicht. Was mache ich falsch?

NSRect imgRect = NSMakeRect(0.0, 0.0, 100.0, 100.0); 
NSSize imgSize = imgRect.size; 

NSBitmapImageRep *offscreenRep = [[[NSBitmapImageRep alloc] 
    initWithBitmapDataPlanes:NULL 
    pixelsWide:imgSize.width 
    pixelsHigh:imgSize.height 
    bitsPerSample:8 
    samplesPerPixel:4 
    hasAlpha:YES 
    isPlanar:NO 
    colorSpaceName:NSDeviceRGBColorSpace 
    bitmapFormat:NSAlphaFirstBitmapFormat 
    bytesPerRow:0 
    bitsPerPixel:0] autorelease]; 

// set offscreen context 
NSGraphicsContext *g = [NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]; 
[NSGraphicsContext setCurrentContext:g]; 

NSImage *img = [[[NSImage alloc] initWithSize:imgSize] autorelease]; 

CGContextRef ctx = [g graphicsPort]; 

// lock and draw 
[img lockFocus]; 

// draw first stroke with Cocoa. this works! 
NSPoint p1 = NSMakePoint(NSMaxX(imgRect), NSMinY(imgRect)); 
NSPoint p2 = NSMakePoint(NSMinX(imgRect), NSMaxY(imgRect)); 
[NSBezierPath strokeLineFromPoint:p1 toPoint:p2]; 

// draw second stroke with Core Graphics. This doesn't work! 
CGContextBeginPath(ctx); 
CGContextMoveToPoint(ctx, 0.0, 0.0); 
CGContextAddLineToPoint(ctx, imgSize.width, imgSize.height); 
CGContextClosePath(ctx); 
CGContextStrokePath(ctx); 

[img unlockFocus]; 

Antwort

22

Sie geben nicht an, wie Sie die Ergebnisse betrachten. Ich nehme an, Sie betrachten die NSImageimg und nicht die NSBitmapImageRepoffscreenRep.

Wenn Sie [img lockFocus] anrufen, ändern Sie den aktuellen NSGraphicsContext als Kontext, um in img zu zeichnen. Also, die NSBezierPath Zeichnung geht in img und das ist, was Sie sehen. Die CG-Zeichnung geht in offscreenRep, die Sie nicht betrachten.

Anstatt den Fokus auf ein NSMage zu fixieren und hineinzuzeichnen, erstellen Sie ein NSMage und fügen Sie offscreenRep als einen seiner Wiederholungen hinzu.

NSRect imgRect = NSMakeRect(0.0, 0.0, 100.0, 100.0); 
NSSize imgSize = imgRect.size; 

NSBitmapImageRep *offscreenRep = [[[NSBitmapImageRep alloc] 
    initWithBitmapDataPlanes:NULL 
    pixelsWide:imgSize.width 
    pixelsHigh:imgSize.height 
    bitsPerSample:8 
    samplesPerPixel:4 
    hasAlpha:YES 
    isPlanar:NO 
    colorSpaceName:NSDeviceRGBColorSpace 
    bitmapFormat:NSAlphaFirstBitmapFormat 
    bytesPerRow:0 
    bitsPerPixel:0] autorelease]; 

// set offscreen context 
NSGraphicsContext *g = [NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]; 
[NSGraphicsContext saveGraphicsState]; 
[NSGraphicsContext setCurrentContext:g]; 

// draw first stroke with Cocoa 
NSPoint p1 = NSMakePoint(NSMaxX(imgRect), NSMinY(imgRect)); 
NSPoint p2 = NSMakePoint(NSMinX(imgRect), NSMaxY(imgRect)); 
[NSBezierPath strokeLineFromPoint:p1 toPoint:p2]; 

// draw second stroke with Core Graphics 
CGContextRef ctx = [g graphicsPort];  
CGContextBeginPath(ctx); 
CGContextMoveToPoint(ctx, 0.0, 0.0); 
CGContextAddLineToPoint(ctx, imgSize.width, imgSize.height); 
CGContextClosePath(ctx); 
CGContextStrokePath(ctx); 

// done drawing, so set the current context back to what it was 
[NSGraphicsContext restoreGraphicsState]; 

// create an NSImage and add the rep to it  
NSImage *img = [[[NSImage alloc] initWithSize:imgSize] autorelease]; 
[img addRepresentation:offscreenRep]; 

// then go on to save or view the NSImage 
+0

Danke Kurt. Ja, du warst in deiner Annahme richtig, ich versuche, "img" zu diappeln. Außerdem: Ihre Fehlerbehebung ist korrekt und behebt das Problem. Danke für das Aufräumen! –

3

Ich frage mich, warum jeder so komplizierten Code zum Zeichnen auf ein Bild schreibt. Es sei denn, Sie interessieren sich für die genaue Bitmap-Darstellung eines Bildes (und in der Regel nicht!), Es ist nicht notwendig, eine zu erstellen. Sie können einfach ein leeres Bild erstellen und direkt darauf zeichnen. In diesem Fall erstellt das System eine geeignete Bitmap-Darstellung (oder möglicherweise eine PDF-Darstellung oder was auch immer das System für besser geeignet zum Zeichnen hält).

Die Dokumentation der init-Methode

- (instancetype)initWithSize:(NSSize)aSize 

die seit MacOS vorhanden 10.0 und noch nicht veraltet ist, sagt klar:

Nach dieser Methode ein Bildobjekt zu initialisieren, Sie sind wird erwartet, dass der Bildinhalt bereitgestellt wird, bevor versucht wird, das Bild zu zeichnen. Sie können den Fokus auf das Bild fixieren und auf das Bild zeichnen, oder Sie können eine von Ihnen erstellte Bilddarstellung explizit hinzufügen ( ).

Also hier ist, wie ich diesen Code geschrieben hätte:

NSRect imgRect = NSMakeRect(0.0, 0.0, 100.0, 100.0); 
NSImage * image = [[NSImage alloc] initWithSize:imgRect.size]; 

[image lockFocus]; 
// draw first stroke with Cocoa 
NSPoint p1 = NSMakePoint(NSMaxX(imgRect), NSMinY(imgRect)); 
NSPoint p2 = NSMakePoint(NSMinX(imgRect), NSMaxY(imgRect)); 
[NSBezierPath strokeLineFromPoint:p1 toPoint:p2]; 

// draw second stroke with Core Graphics 
CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort]; 
CGContextBeginPath(ctx); 
CGContextMoveToPoint(ctx, 0.0, 0.0); 
CGContextAddLineToPoint(ctx, imgRect.size.width, imgRect.size.height); 
CGContextClosePath(ctx); 
CGContextStrokePath(ctx); 
[image unlockFocus]; 

, dass alle Leute ist.

graphicsPort ist eigentlich void *:

@property (readonly) void * graphicsPort 

und dokumentiert als

Der Low-Level, plattformspezifische Grafikkontext durch die Grafik-Port vertreten.

der so ziemlich alles sein kann, aber die letzte Note sagt

In OS X, das ist die Core Graphics Zusammenhang ein CGContextRef Objekt (opak-Typ).

Diese Eigenschaft wurde

@property (readonly) CGContextRef CGContext 

, die nur in 10.10 verfügbar ist und später in 10.10 zugunsten der neuen Eigenschaft ist veraltet. Wenn Sie ältere Systeme unterstützen müssen, ist es in Ordnung, immer noch graphicsPort zu verwenden.