com.sun.jna.platform.win32.GDI32Util Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jna-platform Show documentation
Show all versions of jna-platform Show documentation
Java Native Access Platform
/* Copyright (c) 2015 Michael Freeman, All Rights Reserved
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
* Apache License 2.0. (starting with JNA version 4.0.0).
*
* You can freely decide which license you want to apply to
* the project.
*
* You may obtain a copy of the LGPL License at:
*
* http://www.gnu.org/licenses/licenses.html
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "LGPL2.1".
*
* You may obtain a copy of the Apache License at:
*
* http://www.apache.org/licenses/
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "AL2.0".
*/
package com.sun.jna.platform.win32;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.GDI32;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.WinDef.HBITMAP;
import com.sun.jna.platform.win32.WinDef.HDC;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.RECT;
import com.sun.jna.platform.win32.WinError;
import com.sun.jna.platform.win32.WinGDI;
import com.sun.jna.platform.win32.WinGDI.BITMAPINFO;
import com.sun.jna.platform.win32.WinNT.HANDLE;
/**
* GDI32 utility API.
*
* @author mlfreeman[at]gmail.com
*/
public class GDI32Util {
private static final DirectColorModel SCREENSHOT_COLOR_MODEL = new DirectColorModel(24, 0x00FF0000, 0xFF00, 0xFF);
private static final int[] SCREENSHOT_BAND_MASKS = {
SCREENSHOT_COLOR_MODEL.getRedMask(),
SCREENSHOT_COLOR_MODEL.getGreenMask(),
SCREENSHOT_COLOR_MODEL.getBlueMask()
};
/**
* Takes a screenshot of the given window
*
* @param target
* The window to target
* @return the window captured as a screenshot, or null if the BufferedImage doesn't construct properly
* @throws IllegalStateException
* if the rectangle from GetWindowRect has a width and/or height
* of 0.
* if the device context acquired from the original HWND doesn't
* release properly
*/
public static BufferedImage getScreenshot(HWND target) {
RECT rect = new RECT();
if (!User32.INSTANCE.GetWindowRect(target, rect)) {
throw new Win32Exception(Native.getLastError());
}
Rectangle jRectangle = rect.toRectangle();
int windowWidth = jRectangle.width;
int windowHeight = jRectangle.height;
if (windowWidth == 0 || windowHeight == 0) {
throw new IllegalStateException("Window width and/or height were 0 even though GetWindowRect did not appear to fail.");
}
HDC hdcTarget = User32.INSTANCE.GetDC(target);
if (hdcTarget == null) {
throw new Win32Exception(Native.getLastError());
}
Win32Exception we = null;
// device context used for drawing
HDC hdcTargetMem = null;
// handle to the bitmap to be drawn to
HBITMAP hBitmap = null;
// original display surface associated with the device context
HANDLE hOriginal = null;
// final java image structure we're returning.
BufferedImage image = null;
try {
hdcTargetMem = GDI32.INSTANCE.CreateCompatibleDC(hdcTarget);
if (hdcTargetMem == null) {
throw new Win32Exception(Native.getLastError());
}
hBitmap = GDI32.INSTANCE.CreateCompatibleBitmap(hdcTarget, windowWidth, windowHeight);
if (hBitmap == null) {
throw new Win32Exception(Native.getLastError());
}
hOriginal = GDI32.INSTANCE.SelectObject(hdcTargetMem, hBitmap);
if (hOriginal == null) {
throw new Win32Exception(Native.getLastError());
}
// draw to the bitmap
if (!GDI32.INSTANCE.BitBlt(hdcTargetMem, 0, 0, windowWidth, windowHeight, hdcTarget, 0, 0, GDI32.SRCCOPY)) {
throw new Win32Exception(Native.getLastError());
}
BITMAPINFO bmi = new BITMAPINFO();
bmi.bmiHeader.biWidth = windowWidth;
bmi.bmiHeader.biHeight = -windowHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
Memory buffer = new Memory(windowWidth * windowHeight * 4);
int resultOfDrawing = GDI32.INSTANCE.GetDIBits(hdcTarget, hBitmap, 0, windowHeight, buffer, bmi,
WinGDI.DIB_RGB_COLORS);
if (resultOfDrawing == 0 || resultOfDrawing == WinError.ERROR_INVALID_PARAMETER) {
throw new Win32Exception(Native.getLastError());
}
int bufferSize = windowWidth * windowHeight;
DataBuffer dataBuffer = new DataBufferInt(buffer.getIntArray(0, bufferSize), bufferSize);
WritableRaster raster = Raster.createPackedRaster(dataBuffer, windowWidth, windowHeight, windowWidth,
SCREENSHOT_BAND_MASKS, null);
image = new BufferedImage(SCREENSHOT_COLOR_MODEL, raster, false, null);
} catch (Win32Exception e) {
we = e;
} finally {
if (hOriginal != null) {
// per MSDN, set the display surface back when done drawing
HANDLE result = GDI32.INSTANCE.SelectObject(hdcTargetMem, hOriginal);
// failure modes are null or equal to HGDI_ERROR
if (result == null || WinGDI.HGDI_ERROR.equals(result)) {
Win32Exception ex = new Win32Exception(Native.getLastError());
if (we != null) {
ex.addSuppressedReflected(we);
}
we = ex;
}
}
if (hBitmap != null) {
if (!GDI32.INSTANCE.DeleteObject(hBitmap)) {
Win32Exception ex = new Win32Exception(Native.getLastError());
if (we != null) {
ex.addSuppressedReflected(we);
}
we = ex;
}
}
if (hdcTargetMem != null) {
// get rid of the device context when done
if (!GDI32.INSTANCE.DeleteDC(hdcTargetMem)) {
Win32Exception ex = new Win32Exception(Native.getLastError());
if (we != null) {
ex.addSuppressedReflected(we);
}
we = ex;
}
}
if (hdcTarget != null) {
if (0 == User32.INSTANCE.ReleaseDC(target, hdcTarget)) {
throw new IllegalStateException("Device context did not release properly.");
}
}
}
if (we != null) {
throw we;
}
return image;
}
}