10
votes

Mac OS X: S'appuyant sur un nsgraphicscontext offScreen à l'aide de fonctions CGContexTref C n'a aucun effet. Pourquoi?

Mac OS X 10.7.4

Je dessine dans un contexte graphique hors écran créé via + [nsgraphicsContext graphiqueContextwithbitmapimagere:] .

Quand je tire dans ce contexte graphique Utilisation du NSBEZIERPATH Classe , tout fonctionne comme prévu.

Cependant, lorsque je dessine dans ce contexte graphique à l'aide du CGCONTEXTREF C Fonces , je ne vois aucun résultat de mon dessin. Rien ne fonctionne.

Pour des raisons pour lesquelles je ne vais pas entrer dans, j'ai vraiment besoin de dessiner à l'aide des fonctions CGCONTEXTREF (plutôt que le cacao nsbezierpath classe) .

Mon échantillon de code est répertorié ci-dessous. Je tente de dessiner un simple "x". Un trait utilisant nsbezierpath , une course à l'aide de CGContexTref C. Le premier tour fonctionne, le second ne le fait pas. Qu'est-ce que je fais mal? xxx


0 commentaires

5 Réponses :


31
votes

Vous ne spécifiez pas comment vous envisagez les résultats. Je suppose que vous regardez le nsimage code> img code> et non le nsbitmapimagere code> elfreenrep code>.

lorsque vous appelez [img Lockfocus] Code>, vous modifiez le courant nsgraphicscontext code> pour être un contexte à dessiner dans img code>. Ainsi, le dessin code> nsbezierpath code> est dans img code> et c'est ce que vous voyez. Le dessin CG passe dans elfreenrep code> que vous ne regardez pas. P>

au lieu de verrouiller la mise au point sur un NSImage et de le dessiner, créez une nsimage et ajoutez l'offcreenrep comme l'un des ses représentants. P>

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


1 commentaires

Merci kurt. Oui, vous avez été correct dans votre hypothèse, je tente d'afficher dans . Aussi: votre correctif est correct et corrige le problème. Merci d'avoir refusé cela!



6
votes

Je me demande pourquoi tout le monde écrit un tel code compliqué pour dessiner à une image. Sauf si vous vous souciez de la représentation de bitmap exacte d'une image (et que vous ne le faites pas!), Il n'est pas nécessaire de le créer un. Vous pouvez simplement créer une image vierge et le dessiner directement. Dans ce cas, le système créera une représentation bitmap appropriée (ou peut-être une représentation PDF ou quel que soit le système croit plus approprié pour le dessin).

La documentation de la méthode init xxx

qui existe depuis que MacOS 10.0 et n'est toujours pas obsolète, dit clairement:

Après avoir utilisé cette méthode pour initialiser un objet image, vous êtes devrait fournir le contenu de l'image avant d'essayer de dessiner la image. Vous pouvez verrouiller la mise au point sur l'image et dessiner à l'image ou vous pourrait explicitement ajouter une représentation d'image que vous avez créée.

Voici comment j'aurais écrit ce code: xxx

c'est tout les gens.

graphiqueport est en fait vide * : xxx

et documenté comme < BlockQuote>

Le contexte graphique spécifique à basse plate-forme représenté par le port graphique.

qui peut être à peu près tout, mais la note finale indique

Dans OS X, il s'agit du contexte graphique principal, Un objet CGContextref (type opaque).

Cette propriété a été obsolète en 10.10 en faveur de la nouvelle propriété xxx

qui n'est disponible que dans 10.10 et ultérieure. Si vous devez soutenir les systèmes plus anciens, il convient de toujours utiliser graphique .


0 commentaires

1
votes

Voici 3 façons de dessiner la même image (Swift 4).

La méthode suggérée par @Mecki produit une image sans floue code> artefacts (comme des courbes floues). Mais cela peut être corrigé en ajustant les paramètres CGContext CODE> (non inclus dans cet exemple). P>

public struct ImageFactory {

   public static func image(size: CGSize, fillColor: NSColor, rounded: Bool = false) -> NSImage? {
      let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
      return drawImage(size: size) { context in
         if rounded {
            let radius = min(size.height, size.width)
            let path = NSBezierPath(roundedRect: rect, xRadius: 0.5 * radius, yRadius: 0.5 * radius).cgPath
            context.addPath(path)
            context.clip()
         }
         context.setFillColor(fillColor.cgColor)
         context.fill(rect)
      }
   }

}

extension ImageFactory {

   private static func drawImage(size: CGSize, drawingCalls: (CGContext) -> Void) -> NSImage? {
      return drawImageInLockedImageContext(size: size, drawingCalls: drawingCalls)
   }

   private static func drawImageInLockedImageContext(size: CGSize, drawingCalls: (CGContext) -> Void) -> NSImage? {
      let image = NSImage(size: size)
      image.lockFocus()
      guard let context = NSGraphicsContext.current else {
         image.unlockFocus()
         return nil
      }
      drawingCalls(context.cgContext)
      image.unlockFocus()
      return image
   }

   // Has scalling or antialiasing issues, like blurred curves.
   private static func drawImageInBitmapImageContext(size: CGSize, drawingCalls: (CGContext) -> Void) -> NSImage? {
      guard let offscreenRep = NSBitmapImageRep(pixelsWide: Int(size.width), pixelsHigh: Int(size.height),
                                                bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true,
                                                isPlanar: false, colorSpaceName: .deviceRGB) else {
                                                   return nil
      }
      guard let context = NSGraphicsContext(bitmapImageRep: offscreenRep) else {
         return nil
      }
      NSGraphicsContext.saveGraphicsState()
      NSGraphicsContext.current = context
      drawingCalls(context.cgContext)
      NSGraphicsContext.restoreGraphicsState()
      let img = NSImage(size: size)
      img.addRepresentation(offscreenRep)
      return img
   }

   // Has scalling or antialiasing issues, like blurred curves.
   private static func drawImageInCGContext(size: CGSize, drawingCalls: (CGContext) -> Void) -> NSImage? {
      let colorSpace = CGColorSpaceCreateDeviceRGB()
      let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
      guard let context = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: 8,
                                    bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) else {
         return nil
      }
      drawingCalls(context)
      guard let image = context.makeImage() else {
         return nil
      }
      return NSImage(cgImage: image, size: size)
   }
}


0 commentaires

1
votes

Swift 4: strong> J'utilise ce code, qui réplique l'API pratique de Uikit (mais exécute sur MacOS):

let renderer = UIGraphicsImageRenderer(size: imageSize)
let image = renderer.image { ctx in
    // Drawing commands here
}


1 commentaires

@ingconti merci, corrigé maintenant. Cela a fonctionné dans mon projet avec UiImage parce que j'ai aussi eu: TypeAmias uiimage = Nsimage



5
votes

La solution de @Robin Stewart a bien fonctionné pour moi. J'ai pu la condenser à une extension Nsimage. XXX PRE>

Usage: P>

let image = NSImage(size: CGSize(width: 100, height: 100), actions: { ctx in
    // Drawing commands here for example:
    // ctx.setFillColor(.white)
    // ctx.fill(pageRect)
})


0 commentaires