10

Mac OS X 10.7.4

経由で作成されたオフスクリーン グラフィックス コンテキストに描画してい+[NSGraphicsContext graphicsContextWithBitmapImageRep:]ます。

NSBezierPathclassを使用してこのグラフィックス コンテキストに描画すると、すべてが期待どおりに機能します。

しかし、CGContextRefC 関数を使用してこのグラフィック コンテキストに描画すると、描画の結果が表示されません。何も機能しません。

詳細は省きますが、実際には(CocoaクラスCGContextRefではなく) 関数を使用して描画する必要があります。NSBezierPath

私のコードサンプルを以下に示します。単純な「X」を描こうとしています。を使用した一筆書き、 C 関数NSBezierPathを使用した一筆書き。CGContextRef最初のストロークは機能しますが、2 番目のストロークは機能しません。私は何を間違っていますか?

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

5 に答える 5

31

結果をどのように見ているかを指定しません。NSImage imgではなくを見ていると思いますNSBitmapImageRep offscreenRep

を呼び出すと[img lockFocus]、 currentNSGraphicsContextを に描画するコンテキストに変更していますimg。それで、NSBezierPath図面が入りimg、それがあなたが見るものです。あなたが見ていないところに CG の絵が入りoffscreenRepます。

NSImage にフォーカスをロックしてそこに描画する代わりに、NSImage を作成し、offscreenRep をそのレップの 1 つとして追加します。

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
于 2012-05-16T22:35:04.250 に答える
6

なぜ誰もが画像に描画するための複雑なコードを書くのか不思議です。画像の正確なビットマップ表現を必要としない限り (通常は必要ありません!)、作成する必要はありません。空の画像を作成して直接描画するだけです。その場合、システムは適切なビットマップ表現 (または PDF 表現、またはシステムが描画に適していると判断したもの) を作成します。

init メソッドのドキュメント

- (instancetype)initWithSize:(NSSize)aSize

これは MacOS 10.0 以降に存在し、まだ廃止されていません。明確に次のように述べています。

このメソッドを使用して画像オブジェクトを初期化した後、画像を描画する前に画像の内容を提供する必要があります。画像にフォーカスをロックして画像に描画するか、作成した画像表現を明示的に追加することができます。

だからここに私がそのコードを書く方法があります:

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

それはすべての人々です。

graphicsPort実際にはvoid *:

@property (readonly) void * graphicsPort 

として文書化されています

グラフィック ポートによって表される低レベルのプラットフォーム固有のグラフィック コンテキスト。

これはほとんどすべてかもしれませんが、最後のメモには次のように書かれています

OS X では、これは Core Graphics コンテキスト、CGContextRefオブジェクト (不透明型) です。

このプロパティは 10.10 で廃止され、新しいプロパティが採用されました。

@property (readonly) CGContextRef CGContext

これは 10.10 以降でのみ使用できます。古いシステムをサポートする必要がある場合は、引き続き を使用しても問題ありませんgraphicsPort

于 2016-05-24T09:36:11.610 に答える
6

@Robin Stewart による解決策は私にとってはうまくいきました。私はそれを NSImage 拡張子に凝縮することができました。

extension NSImage {
    convenience init(size: CGSize, actions: (CGContext) -> Void) {
        self.init(size: size)
        lockFocusFlipped(false)
        actions(NSGraphicsContext.current!.cgContext)
        unlockFocus()
    }
}

使用法:

let image = NSImage(size: CGSize(width: 100, height: 100), actions: { ctx in
    // Drawing commands here for example:
    // ctx.setFillColor(.white)
    // ctx.fill(pageRect)
})
于 2020-01-21T08:45:49.683 に答える