More cautious image creation

This commit is contained in:
Robinson 2021-02-07 00:14:43 +01:00
parent e09faaf491
commit 1b3f66703f
2 changed files with 57 additions and 43 deletions

View File

@ -34,6 +34,8 @@ import com.sun.jna.ptr.PointerByReference;
public class HBITMAPWrap extends HBITMAP { public class HBITMAPWrap extends HBITMAP {
private static final Object lockObject = new Object();
// NOTE: This is a field (instead of private) so that GC does not try to collect this object // NOTE: This is a field (instead of private) so that GC does not try to collect this object
private HBITMAP bitmap; private HBITMAP bitmap;
@ -42,54 +44,58 @@ public class HBITMAPWrap extends HBITMAP {
HBITMAP createBitmap(BufferedImage image) { HBITMAP createBitmap(BufferedImage image) {
int w = image.getWidth(null); int w = image.getWidth(null);
int h = image.getHeight(null); int h = image.getHeight(null);
HDC screenDC = User32.GetDC(null);
HDC memDC = GDI32.CreateCompatibleDC(screenDC);
HBITMAP hBitmap = null;
try { // all sorts of issues occur if this is called quickly from different threads!
BufferedImage buf = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); synchronized(lockObject) {
Graphics2D g = (Graphics2D) buf.getGraphics(); HDC screenDC = User32.GetDC(null);
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); HDC memDC = GDI32.CreateCompatibleDC(screenDC);
g.drawImage(image, 0, 0, w, h, null); HBITMAP hBitmap = null;
WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO(); try {
bmi.bmiHeader.biWidth = w; BufferedImage buf = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
bmi.bmiHeader.biHeight = h; Graphics2D g = (Graphics2D) buf.getGraphics();
bmi.bmiHeader.biPlanes = 1; g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
bmi.bmiHeader.biBitCount = 32; g.drawImage(image, 0, 0, w, h, null);
bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
bmi.bmiHeader.biSizeImage = w * h * 4;
Memory memory = new Memory(w*h*32*4); WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO();
PointerByReference pointerRef = new PointerByReference(memory); bmi.bmiHeader.biWidth = w;
hBitmap = GDI32.CreateDIBSection(memDC, bmi, WinGDI.DIB_RGB_COLORS, pointerRef, null, 0); bmi.bmiHeader.biHeight = h;
Pointer pointerToBits = pointerRef.getValue(); bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
bmi.bmiHeader.biSizeImage = w * h * 4;
if (pointerToBits == null) { Memory memory = new Memory(w*h*32*4);
// the bitmap was invalid PointerByReference pointerRef = new PointerByReference(memory);
LoggerFactory.getLogger(HBITMAPWrap.class).error("The image was invalid", Kernel32Util.getLastErrorMessage()); hBitmap = GDI32.CreateDIBSection(memDC, bmi, WinGDI.DIB_RGB_COLORS, pointerRef, null, 0);
} Pointer pointerToBits = pointerRef.getValue();
else {
Raster raster = buf.getData(); if (pointerToBits == null) {
int[] pixel = new int[4]; // the bitmap was invalid
int[] bits = new int[w * h]; LoggerFactory.getLogger(HBITMAPWrap.class).error("The image was invalid", Kernel32Util.getLastErrorMessage());
for (int y = 0; y < h; y++) { }
for (int x = 0; x < w; x++) { else {
raster.getPixel(x, h - y - 1, pixel); Raster raster = buf.getData();
int red = (pixel[2] & 0xFF) << 0; int[] pixel = new int[4];
int green = (pixel[1] & 0xFF) << 8; int[] bits = new int[w * h];
int blue = (pixel[0] & 0xFF) << 16; for (int y = 0; y < h; y++) {
int alpha = (pixel[3] & 0xFF) << 24; for (int x = 0; x < w; x++) {
bits[x + y * w] = alpha | red | green | blue; raster.getPixel(x, h - y - 1, pixel);
} int red = (pixel[2] & 0xFF) << 0;
int green = (pixel[1] & 0xFF) << 8;
int blue = (pixel[0] & 0xFF) << 16;
int alpha = (pixel[3] & 0xFF) << 24;
bits[x + y * w] = alpha | red | green | blue;
}
}
pointerToBits.write(0, bits, 0, bits.length);
} }
pointerToBits.write(0, bits, 0, bits.length);
}
return hBitmap; return hBitmap;
} finally { } finally {
User32.ReleaseDC(null, screenDC); User32.ReleaseDC(null, screenDC);
GDI32.DeleteDC(memDC); GDI32.DeleteDC(memDC);
}
} }
} }

View File

@ -27,6 +27,7 @@ import dorkbox.jna.windows.structs.ICONINFO;
* http://www.pinvoke.net/default.aspx/user32.createiconindirect * http://www.pinvoke.net/default.aspx/user32.createiconindirect
*/ */
public class HICONWrap extends HICON { public class HICONWrap extends HICON {
private static final Object lockObject = new Object();
static HICON createIconIndirect(HBITMAP bm) { static HICON createIconIndirect(HBITMAP bm) {
ICONINFO info = new ICONINFO(); ICONINFO info = new ICONINFO();
@ -36,7 +37,14 @@ public class HICONWrap extends HICON {
HICON hicon = User32.CreateIconIndirect(info); HICON hicon = User32.CreateIconIndirect(info);
if (hicon == null) { if (hicon == null) {
throw new GetLastErrorException(); // something weird is going on! Try again but more carefully!
synchronized(lockObject) {
hicon = User32.CreateIconIndirect(info);
}
if (hicon == null) {
throw new GetLastErrorException();
}
} }
return hicon; return hicon;