2012-05-16 8 views
5

Mac OS X 10.7.4Mac OS X: dibujar en un NSGraphicsContext fuera de pantalla usando las funciones CGContextRef C no tiene ningún efecto. ¿Por qué?

Estoy dibujando en un contexto de gráficos fuera de pantalla creado a través de +[NSGraphicsContext graphicsContextWithBitmapImageRep:].

Cuando dibujo en este contexto gráfico usando la clase NSBezierPath, todo funciona como se esperaba.

Sin embargo, cuando dibujo en este contexto gráfico usando las funciones CGContextRef C, no veo resultados de mi dibujo. Nada funciona.

Por razones que no entraré, realmente necesito dibujar usando las funciones CGContextRef (en lugar de la clase Cocoa NSBezierPath).

Mi ejemplo de código se enumera a continuación. Estoy intentando dibujar una simple "X". Un golpe usando NSBezierPath, un golpe usando CGContextRef funciones C. El primer trazo funciona, el segundo no. ¿Qué estoy haciendo mal?

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]; 

Respuesta

22

No especifica cómo está viendo los resultados. Supongo que está mirando el NSImageimg y no el NSBitmapImageRepoffscreenRep.

Cuando llama al [img lockFocus], está cambiando el actual NSGraphicsContext para que sea un contexto para dibujar en img. Entonces, el dibujo NSBezierPath entra en img y eso es lo que ves. El dibujo CG entra en offscreenRep que no está mirando.

En lugar de bloquear el enfoque en un NSImage y dibujar en él, cree un NSImage y agregue el offscreenRep como uno de sus representantes.

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

Gracias Kurt. Sí, estabas en lo correcto en tu suposición, estoy intentando diagramar 'img'. Además: su solución es correcta y soluciona el problema. ¡Gracias por aclarar esto! –

3

Me pregunto por qué todos escriben un código tan complicado para dibujar en una imagen. A menos que le interese la representación exacta del mapa de bits de una imagen (¡y generalmente no lo hace!), No es necesario crear una. Simplemente puede crear una imagen en blanco y dibujar directamente en ella. En ese caso, el sistema creará una representación de mapa de bits apropiada (o tal vez una representación de PDF o lo que el sistema crea que es más adecuado para el dibujo).

La documentación del método init

- (instancetype)initWithSize:(NSSize)aSize 

que existe desde MacOS 10.0 y todavía no está en desuso, claramente dice:

Después de usar este método para inicializar un objeto de imagen, que está espera proporcionar el contenido de la imagen antes de intentar dibujar la imagen . Puede bloquear el enfoque en la imagen y dibujar en la imagen o podría agregar explícitamente una representación de imagen que haya creado.

Así que aquí es como yo hubiera escrito ese código:

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]; 

eso es todo amigos.

graphicsPort es en realidad void *:

@property (readonly) void * graphicsPort 

y documentado como

El bajo nivel, contexto gráfico específico de la plataforma representada por el puerto gráfico.

¿Qué puede ser más o menos todo, pero la nota final dice

En OS X, este es el contexto núcleo de gráficos, un CGContextRef objeto (tipo opaco).

Esta propiedad ha sido desaprobados en 10.10 en favor de la nueva propiedad

@property (readonly) CGContextRef CGContext 

que sólo está disponible en 10.10 y posteriores. Si tiene que admitir sistemas más antiguos, puede seguir usando graphicsPort.

Cuestiones relacionadas