我希望我能找到答案。我搜索并搜索过,但答案不对。这是我的情况:
在Mac OS Cocoa应用程序中,我想在我的应用程序窗口的专用区域上绘制一个像素(实际上是几个像素)。我想,放置NSImageView
放在那里会更好(我使用IB并将插座连接到我的应用代表)并使用它而不是我的NSWindow
。
我怎么能这样做? Mac OS似乎提供NSBezierPath
作为最基本的绘图工具 - 是真的吗?这对我来说是完全令人震惊的。我来自Windows编程的悠久历史,并且通常在画布上绘制像素是最简单的事情。
我不想使用OpenGL,我不确定Quartz参与的程度如何。
我想要的就是如何在真正的Objective-C / Cocoa中实现这个伪代码的一些帮助:
imageObj.drawPixel(10,10,blackColor);
我很想听听你的回答,我相信这会有很多人从Cocoa开始。
谢谢!
答案 0 :(得分:12)
您要求的是以下两种方法之一:
NSBitmapRep setColor:atX:y:更改指定坐标处像素的颜色。
NSBitmapRep setPixel:atX:y:将指定坐标处的接收器像素设置为指定的原始像素值。
请注意,这些在iOS上不可用。在iOS上,看起来这样做的方法是为给定的颜色空间(可能是RGB)创建像素数据的原始缓冲区,用颜色数据填充它(写一点setPixel方法来执行此操作),然后调用CGImageCreate()像这样:
//Create a raw buffer to hold pixel data which we will fill algorithmically
NSInteger width = theWidthYouWant;
NSInteger height = theHeightYouWant;
NSInteger dataLength = width * height * 4;
UInt8 *data = (UInt8*)malloc(dataLength * sizeof(UInt8));
//Fill pixel buffer with color data
for (int j=0; j<height; j++) {
for (int i=0; i<width; i++) {
//Here I'm just filling every pixel with red
float red = 1.0f;
float green = 0.0f;
float blue = 0.0f;
float alpha = 1.0f;
int index = 4*(i+j*width);
data[index] =255*red;
data[++index]=255*green;
data[++index]=255*blue;
data[++index]=255*alpha;
}
}
// Create a CGImage with the pixel data
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGImageRef image = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
provider, NULL, true, kCGRenderingIntentDefault);
//Clean up
CGColorSpaceRelease(colorspace);
CGDataProviderRelease(provider);
// Don't forget to free(data) when you are done with the CGImage
最后,您可能想要操作已加载到CGImage中的图像中的像素。在Apple Technical Q&amp; A中有一个标题为QA1509 Getting the pixel data from a CGImage object的示例代码。
答案 1 :(得分:9)
Cocoa的低级绘图API是Core Graphics(Quartz)。您将获得绘图上下文并发出命令以绘制到该上下文。 API被设计为与设备无关(您在打印时使用相同的命令绘制到屏幕上,就像在纸上绘图一样)。因此,没有用于填充单个像素的命令,因为在纸上没有诸如像素之类的东西。即使在屏幕上,您的视图也可能以某种方式进行了转换,因此单个点不会映射到单个设备像素。
如果要绘制单个像素,则需要指定一个像素大小的矩形,然后将其填入。对于(x,y)处的像素,您需要一个原点为矩形的矩形(x-0.5,y-0.5)和(1,1)的大小。
您可以使用NSBezierPath执行此操作,或者您可以从[[NSGraphicsContext currentContext] graphicsPort]
获取Core Graphics上下文(CGContextRef)并使用CGContextFillRect()
等函数。
如果要绘制大量像素,这显然不会很快;这不是API的目的。如果这是您需要做的,请考虑使用malloc
创建一个缓冲区并将像素数据写入其中,然后使用Core Graphics将其转换为CGImageRef,可以将其绘制到屏幕上。
答案 2 :(得分:3)
如您所描述的那样绘制像素,则无需创建Quartz 2D或OpenGL API的路径或手段。
请参阅NSRectFill()
以及NSRectFillList()
和NSRectFillUsingOperation()
等相关功能。
如果您绘制了大量单个像素,NSRectFillList()
的速度与您可以执行的速度差不多,而无需使用自己的图像缓冲区。
答案 3 :(得分:1)
也许我误解了这个问题,但是Quartz有能力填充矩形:
void CGContextFillRect (CGContextRef c, CGRect rect);
答案 4 :(得分:1)
这是在OS X上绘制像素的快捷方法:
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
initWithFocusedViewRect:dirtyRect];
for (int x = 0; x < [rep pixelsWide]; x++) {
for (int y = 0; y < [rep pixelsHigh]; y++) {
NSUInteger pixel[4] = { 0, 255, 0, 255 };
[rep setPixel:pixel atX:x y:y];
}
}
[rep drawInRect:dirtyRect];
}
答案 5 :(得分:0)
我发现你的问题有点迟了,因为我有同样的问题。也许Apples开发人员文档可以帮助您。我自己没有测试过,但请看一下这个文件:
大致位于文档的中心,您将找到“创建位图”部分。它告诉您创建像素数据的不同方法。
答案 6 :(得分:0)
class CMKViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let testIV = TestImageView(image: NSImage(named: "test.png")!)
// testIV.frame = CGRect(x:0,y:0,width:100,height:100)
self.view.addSubview(testIV)
testIV.myPixels = [CGPoint(x:10,y:10)]
}
}
class TestImageView:NSImageView{
var myPixels:[CGPoint] = []
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
guard let context: CGContext = NSGraphicsContext.current()?.cgContext else {
consolePrint("Cannot get graphics context")
return
}
// Fill background to white
context.setFillColor(.white)
context.fill(bounds)
context.setFillColor(NSColor.red.cgColor)
// Draw pixels
context.fillPixels(myPixels)
}
}
extension CGContext {
func fillPixels(_ pixels: [CGPoint]) {
var size:CGSize?
if Screen.retinaScale > 1{
size = CGSize(width: 1.5, height: 1.5)
}else{
size = CGSize(width: 1.0, height: 1.0)
}
for pixel in pixels{
fill(CGRect(origin: pixel, size: size!))
}
}
func fill(_ pixel: CGPoint) {
fill(CGRect(origin: pixel, size: CGSize(width: 1.0, height: 1.0)))
}
}
答案 7 :(得分:-11)
NSBezierPath是Cocoa中唯一可用于绘制大多数原始形状和许多复杂形状的工具。 您可以在此处找到详细说明: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaDrawingGuide/Paths/Paths.html%23//apple_ref/doc/uid/TP40003290-CH206-BBCHFJJG http://en.wikibooks.org/wiki/Programming_Mac_OS_X_with_Cocoa_for_Beginners/Graphics_-_Drawing_with_Quartz