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 {
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
private HBITMAP bitmap;
@ -42,54 +44,58 @@ public class HBITMAPWrap extends HBITMAP {
HBITMAP createBitmap(BufferedImage image) {
int w = image.getWidth(null);
int h = image.getHeight(null);
HDC screenDC = User32.GetDC(null);
HDC memDC = GDI32.CreateCompatibleDC(screenDC);
HBITMAP hBitmap = null;
try {
BufferedImage buf = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
Graphics2D g = (Graphics2D) buf.getGraphics();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
g.drawImage(image, 0, 0, w, h, null);
// all sorts of issues occur if this is called quickly from different threads!
synchronized(lockObject) {
HDC screenDC = User32.GetDC(null);
HDC memDC = GDI32.CreateCompatibleDC(screenDC);
HBITMAP hBitmap = null;
WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO();
bmi.bmiHeader.biWidth = w;
bmi.bmiHeader.biHeight = h;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
bmi.bmiHeader.biSizeImage = w * h * 4;
try {
BufferedImage buf = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
Graphics2D g = (Graphics2D) buf.getGraphics();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
g.drawImage(image, 0, 0, w, h, null);
Memory memory = new Memory(w*h*32*4);
PointerByReference pointerRef = new PointerByReference(memory);
hBitmap = GDI32.CreateDIBSection(memDC, bmi, WinGDI.DIB_RGB_COLORS, pointerRef, null, 0);
Pointer pointerToBits = pointerRef.getValue();
WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO();
bmi.bmiHeader.biWidth = w;
bmi.bmiHeader.biHeight = h;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
bmi.bmiHeader.biSizeImage = w * h * 4;
if (pointerToBits == null) {
// the bitmap was invalid
LoggerFactory.getLogger(HBITMAPWrap.class).error("The image was invalid", Kernel32Util.getLastErrorMessage());
}
else {
Raster raster = buf.getData();
int[] pixel = new int[4];
int[] bits = new int[w * h];
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
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;
}
Memory memory = new Memory(w*h*32*4);
PointerByReference pointerRef = new PointerByReference(memory);
hBitmap = GDI32.CreateDIBSection(memDC, bmi, WinGDI.DIB_RGB_COLORS, pointerRef, null, 0);
Pointer pointerToBits = pointerRef.getValue();
if (pointerToBits == null) {
// the bitmap was invalid
LoggerFactory.getLogger(HBITMAPWrap.class).error("The image was invalid", Kernel32Util.getLastErrorMessage());
}
else {
Raster raster = buf.getData();
int[] pixel = new int[4];
int[] bits = new int[w * h];
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
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;
} finally {
User32.ReleaseDC(null, screenDC);
GDI32.DeleteDC(memDC);
return hBitmap;
} finally {
User32.ReleaseDC(null, screenDC);
GDI32.DeleteDC(memDC);
}
}
}

View File

@ -27,6 +27,7 @@ import dorkbox.jna.windows.structs.ICONINFO;
* http://www.pinvoke.net/default.aspx/user32.createiconindirect
*/
public class HICONWrap extends HICON {
private static final Object lockObject = new Object();
static HICON createIconIndirect(HBITMAP bm) {
ICONINFO info = new ICONINFO();
@ -36,7 +37,14 @@ public class HICONWrap extends HICON {
HICON hicon = User32.CreateIconIndirect(info);
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;