How to take screenshots fast in Java?

匆匆过客 提交于 2019-12-17 04:30:24

问题


I am implementing a simple eye tracker, which requires fast screenshoting of what is happening on the screen simultaneously with capturing the video from webcam.

The thing is that the way of doing it with Robot, mentioned here: https://stackoverflow.com/questions/2475303/java-library-for-capturing-active-window-screenshot is extremely slow.

By the way, retrieving the video from a webcam works much faster and returns the byte array, which is very fast to be processed.

Does anybody know a faster solution? C++ libraries, which can be linked to Java for doing this may help as well.

Thank you!

UPDATE: Decided to switch to OpenCV, now looking for the way to make screenshot with it :)


回答1:


u should definitely give a shot to OpenCV




回答2:


Here's a Windows-specific version using JNA that I am using in one of my projects.

I have found it to be an order-of-magnitude faster than Robot, even with the native call overhead.

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.platform.win32.W32API;
import com.sun.jna.win32.W32APIOptions;

public class JNAScreenShot {

    public static BufferedImage getScreenshot(Rectangle bounds) {
        W32API.HDC windowDC = GDI.GetDC(USER.GetDesktopWindow());
        W32API.HBITMAP outputBitmap =
            GDI.CreateCompatibleBitmap(windowDC,
                                       bounds.width, bounds.height);
        try {
            W32API.HDC blitDC = GDI.CreateCompatibleDC(windowDC);
            try {
                W32API.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);
                }
                GDI32.BITMAPINFO bi = new GDI32.BITMAPINFO(40);
                bi.bmiHeader.biSize = 40;
                boolean ok =
                    GDI.GetDIBits(blitDC, outputBitmap, 0, bounds.height,
                                  (byte[]) null, bi, GDI32.DIB_RGB_COLORS);
                if (ok) {
                    GDI32.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(GDI32.HDC        blitDC,
                            GDI32.HBITMAP    outputBitmap,
                            GDI32.BITMAPINFO bi) {
        GDI32.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 {
    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);
    HWND GetDesktopWindow();
}



回答3:


The robot.createScreenCapture(captureSize); call takes about 20ms for me.




回答4:


May be you can make use of JMF.. Checkout the Screen Grabber code @ Oracle's site. I think it will help you solve your problem.




回答5:


To capture full screen.

Robot robot = new Robot();
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage screenFullImage = robot.createScreenCapture(screenRect);
ImageIO.write(screenFullImage, format, new File(destination));

To capture partial screen.

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Rectangle rect = new Rectangle(0, 0, screenSize.width / 2, screenSize.height / 2);
Robot robot = new Robot();
BufferedImage screenFullImage = robot.createScreenCapture(rect);
ImageIO.write(screenFullImage, format, new File(destination));

Reference : link



来源:https://stackoverflow.com/questions/2912007/how-to-take-screenshots-fast-in-java

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!