当前位置: 首页 > 面试题库 >

JNA库的屏幕截图比机器人类的截图慢吗?

乔俊才
2023-03-14
问题内容

由于Robot.createScreenCaputure()方法很慢,因此我决定使用本机库。我搜索并找到了该论坛,并找到了使用 JNA Library
的特定代码段。这是一个旧版本,所以我重写了代码: __

import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferUShort;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;

import com.sun.jna.Native;
import com.sun.jna.win32.W32APIOptions;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.platform.win32.WinGDI;

public class JNAScreenShot {

    public static BufferedImage getScreenshot(Rectangle bounds) {
        WinDef.HDC windowDC = GDI.GetDC(USER.GetDesktopWindow());
        WinDef.HBITMAP outputBitmap =
                GDI.CreateCompatibleBitmap(windowDC,
                bounds.width, bounds.height);
        try {
            WinDef.HDC blitDC = GDI.CreateCompatibleDC(windowDC);
            try {
                WinNT.HANDLE oldBitmap =
                        GDI.SelectObject(blitDC, outputBitmap);
                try {
                    GDI.BitBlt(blitDC,
                            0, 0, bounds.width, bounds.height,
                            windowDC,
                            bounds.x, bounds.y,
                            GDI32.SRCCOPY);
                } finally {
                    GDI.SelectObject(blitDC, oldBitmap);
                }
                WinGDI.BITMAPINFO bi = new WinGDI.BITMAPINFO(40);
                bi.bmiHeader.biSize = 40;
                boolean ok =
                        GDI.GetDIBits(blitDC, outputBitmap, 0, bounds.height,
                        (byte[]) null, bi, WinGDI.DIB_RGB_COLORS);
                if (ok) {
                    WinGDI.BITMAPINFOHEADER bih = bi.bmiHeader;
                    bih.biHeight = -Math.abs(bih.biHeight);
                    bi.bmiHeader.biCompression = 0;
                    return bufferedImageFromBitmap(blitDC, outputBitmap, bi);
                } else {
                    return null;
                }
            } finally {
                GDI.DeleteObject(blitDC);
            }
        } finally {
            GDI.DeleteObject(outputBitmap);
        }
    }

    private static BufferedImage bufferedImageFromBitmap(WinDef.HDC blitDC,
            WinDef.HBITMAP outputBitmap,
            WinGDI.BITMAPINFO bi) {
        WinGDI.BITMAPINFOHEADER bih = bi.bmiHeader;
        int height = Math.abs(bih.biHeight);
        final ColorModel cm;
        final DataBuffer buffer;
        final WritableRaster raster;
        int strideBits =
                (bih.biWidth * bih.biBitCount);
        int strideBytesAligned =
                (((strideBits - 1) | 0x1F) + 1) >> 3;
        final int strideElementsAligned;
        switch (bih.biBitCount) {
            case 16:
                strideElementsAligned = strideBytesAligned / 2;
                cm = new DirectColorModel(16, 0x7C00, 0x3E0, 0x1F);
                buffer =
                        new DataBufferUShort(strideElementsAligned * height);
                raster =
                        Raster.createPackedRaster(buffer,
                        bih.biWidth, height,
                        strideElementsAligned,
                        ((DirectColorModel) cm).getMasks(),
                        null);
                break;
            case 32:
                strideElementsAligned = strideBytesAligned / 4;
                cm = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF);
                buffer =
                        new DataBufferInt(strideElementsAligned * height);
                raster =
                        Raster.createPackedRaster(buffer,
                        bih.biWidth, height,
                        strideElementsAligned,
                        ((DirectColorModel) cm).getMasks(),
                        null);
                break;
            default:
                throw new IllegalArgumentException("Unsupported bit count: " + bih.biBitCount);
        }
        final boolean ok;
        switch (buffer.getDataType()) {
            case DataBuffer.TYPE_INT: {
                int[] pixels = ((DataBufferInt) buffer).getData();
                ok = GDI.GetDIBits(blitDC, outputBitmap, 0, raster.getHeight(), pixels, bi, 0);
            }
            break;
            case DataBuffer.TYPE_USHORT: {
                short[] pixels = ((DataBufferUShort) buffer).getData();
                ok = GDI.GetDIBits(blitDC, outputBitmap, 0, raster.getHeight(), pixels, bi, 0);
            }
            break;
            default:
                throw new AssertionError("Unexpected buffer element type: " + buffer.getDataType());
        }
        if (ok) {
            return new BufferedImage(cm, raster, false, null);
        } else {
            return null;
        }
    }
    private static final User32 USER = User32.INSTANCE;
    private static final GDI32 GDI = GDI32.INSTANCE;
}

interface GDI32 extends com.sun.jna.platform.win32.GDI32,
        com.sun.jna.platform.win32.WinGDI,
        com.sun.jna.platform.win32.WinDef {

    GDI32 INSTANCE =
            (GDI32) Native.loadLibrary(GDI32.class);

    boolean BitBlt(HDC hdcDest, int nXDest, int nYDest,
            int nWidth, int nHeight, HDC hdcSrc,
            int nXSrc, int nYSrc, int dwRop);

    HDC GetDC(HWND hWnd);

    boolean GetDIBits(HDC dc, HBITMAP bmp, int startScan, int scanLines,
            byte[] pixels, BITMAPINFO bi, int usage);

    boolean GetDIBits(HDC dc, HBITMAP bmp, int startScan, int scanLines,
            short[] pixels, BITMAPINFO bi, int usage);

    boolean GetDIBits(HDC dc, HBITMAP bmp, int startScan, int scanLines,
            int[] pixels, BITMAPINFO bi, int usage);
    int SRCCOPY = 0xCC0020;
}

interface User32 extends com.sun.jna.platform.win32.User32 {

    User32 INSTANCE = (User32) Native.loadLibrary(User32.class, W32APIOptions.UNICODE_OPTIONS);

    com.sun.jna.platform.win32.WinDef.HWND GetDesktopWindow();
}

还有一个测试代码,以 了解它 比机器人课程 更快的速度

import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;

public class testClass {

    public static void main(String[] args) {

        BufferedImage bi = null, bj = null;
        Rectangle rect = new Rectangle(0, 0, 810, 384);
        long startTime, finishTime;

        startTime = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) {
            bi = JNAScreenShot.getScreenshot(rect);
        }
        finishTime = System.currentTimeMillis();

        System.out.println("With JNA Library: " + (finishTime - startTime)/10);

        Robot robo = null;

        startTime = System.currentTimeMillis();
        try {
            robo = new Robot();
        } catch (AWTException a) {
        }
        for (int i = 0; i < 10; i++) {
            bj = robo.createScreenCapture(rect);
        }
        finishTime = System.currentTimeMillis();
        System.out.println("With Robot Class " + (finishTime - startTime)/10);
    }
}

结果是

使用JNA库:77
使用机器人课程37

伙计们,请有人解释 为什么 会这样,我该 如何 固定呢?


问题答案:

JNA调用花费很多时间,相反,JNI直接使用c ++。



 类似资料:
  • 在Linux下有很多屏幕载图的工具,下面简单介绍一下: 在GNOME桌面中自带了一个屏幕截图工具,位于“动作”栏内。该工具功能很少,只能截取当前屏幕。 在GMIP中也可截图,在“文件”--“获取”菜单下有一个“屏幕抓图”选项可进行屏幕截图。它可截取任意图窗口的内容,并自动输入到GMIP中,我们可方便地进行处理和保存。 安装ImageMagick软件,它有一个工具叫import可用于屏幕截图。该工具

  • 点击按钮进行截屏,可以将截屏图像保存到相册中。 作者说:听说会和苹果的策略有冲突,应用如果上架可能会被拒绝。这个估计是看人品了吧。经过测试发现,如果先弹出对话框,然后再截屏,似乎并不能把对话框也给保存下来。 [Code4App.com]

  • 问题内容: 我正在使用Selenium自动执行网页功能测试。推出新代码时,对像素进行像素比较非常重要,因此我们使用Selenium进行屏幕截图,并比较base64编码的字符串以查看是否有任何更改。 我们发现,实际上很难获得完全的像素一致性,尤其是图像。我希望将轻微的模糊/渲染伪影算作“通过”而不是“失败”,所以我想知道是否存在一种进行模糊比较的方法,以使我们的测试不那么脆弱。 我当时正在考虑也许以

  • 我正在使用AlarmManager和Pending Intent调用BroadcastReceiver类。这是每天安排的。 以下是“活动”中调用的BroadCast Receiver类的代码(它是一个单独的类)。 问题陈述是,在此接收器中,我正在打开另一个应用程序,我想捕获屏幕截图并将其上传到服务器。但是窗口功能在广播接收器类中不可用,我无法实现,因为我超出了活动控制。 关键挑战: -在以下类中实

  • 问题内容: 我希望用户在Swift中以编程方式按下按钮后继续运行我的应用并为应用截图。我知道需要截图,但是我不需要整个屏幕的图片。我希望弹出一个矩形(有点像裁剪工具),并且用户可以拖动矩形并调整其大小以仅截取屏幕的特定部分的屏幕截图。我希望矩形经过a 并裁剪Web视图的图片。 问题答案: 标准的快照技术是,将其绘制到图像上下文。在iOS 10及更高版本中,您可以使用: 而且您会这样使用: 在iOS

  • 问题内容: 是否可以使用JavaScript截取网页的屏幕截图,然后将其提交回服务器? 我不太担心浏览器的安全性问题。等,因为实施将针对HTA。但是有可能吗? 问题答案: 我已经通过使用ActiveX控件为HTA完成了此操作。在VB6中构建控件以截取屏幕截图非常容易。我必须使用keybd_event API调用,因为SendKeys无法执行PrintScreen。这是该代码: 这只会使您到达将窗口