我一直在尝试使用rococoa(java到osx cocoa api库)编写一个简单的截图应用程序,并设法实际获取屏幕截图,然后将其保存到文件中。不幸的是,偶尔,应用程序失败并显示“位置无效的内存访问...”错误。我假设这是由于垃圾收集的原因,因为我没有保持引用活着。导致崩溃的线是: int [] data = pointer.getIntArray(0,bytesPerPlane / 4);
我真的没有使用Objective C编写任何代码,只是启动了rococoa,所以我发现自己只是对此感到困惑。我已经复制了下面的相关代码,非常感谢您的帮助!
public interface QuartzLibrary extends Library {
QuartzLibrary INSTANCE = (QuartzLibrary) Native.loadLibrary("Quartz", QuartzLibrary.class);
class CGPoint extends Structure {
public double x;
public double y;
}
class CGSize extends Structure {
public double width;
public double height;
}
class CGRect extends Structure implements Structure.ByValue {
public static class CGRectByValue extends CGRect { }
public CGPoint origin;
public CGSize size;
}
int kCGWindowListOptionIncludingWindow = (1 << 3);
int kCGWindowImageBoundsIgnoreFraming = (1 << 0);
ID CGWindowListCreateImage(CGRect screenBounds, int windowOption, int windowId, int imageOption);
}
public interface NSBitmapImageRep extends NSObject {
public static final _Class CLASS = Rococoa.createClass("NSBitmapImageRep", _Class.class);
public interface _Class extends NSClass {
NSBitmapImageRep alloc();
}
NSBitmapImageRep initWithCGImage(ID imageRef);
com.sun.jna.Pointer bitmapData();
NSSize size();
}
public class Screenshot {
public static void getScreenshot(int windowId) throws IOException {
QuartzLibrary.CGRect bounds = new QuartzLibrary.CGRect.CGRectByValue();
bounds.origin = new QuartzLibrary.CGPoint();
bounds.origin.x = 0;
bounds.origin.y = 0;
bounds.size = new QuartzLibrary.CGSize();
bounds.size.width = 0;
bounds.size.height = 0;
ID imageRef = QuartzLibrary.INSTANCE.CGWindowListCreateImage(bounds, QuartzLibrary.kCGWindowListOptionIncludingWindow, windowId, QuartzLibrary.kCGWindowImageBoundsIgnoreFraming);
NSBitmapImageRep imageRep = NSBitmapImageRep.CLASS.alloc();
imageRep = imageRep.initWithCGImage(imageRef);
NSSize size = imageRep.size();
com.sun.jna.Pointer pointer = imageRep.bitmapData();
int width = size.width.intValue();
int height = size.height.intValue();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// The crash always happens when calling 'getIntArray' in the next line.
int[] data = pointer.getIntArray(0, bytesPerPlane / 4);
int idx = 0;
for(int y = 0; y < height; y++)
for(int x = 0; x < width; x++)
image.setRGB(x, y, data[idx++]);
ImageIO.write(image, "png", new File("foo.png"));
}
}
答案 0 :(得分:2)
发现问题。
'imageRep'的最后一次使用就行了 “com.sun.jna.Pointer pointer = imageRep.bitmapData();”。 在此之后,imageRep是Java垃圾收集器的公平游戏。如果它进入 在我们完成使用'指针'之前,它指向的后备缓冲区可能/将会得到 自由,导致坏事发生。 要修复它,为imageRep添加一组额外的保留/释放可以完成这项工作,或者替代 将任何引用添加到方法的末尾。
答案 1 :(得分:0)
可能相关,可能不是:NSBitmapImageRep来自NSImageRep,而不是直接来自NSObject。