setIconImages 会改变图像大小吗?

Does setIconImages change the image size?

提问人:Cardinal System 提问时间:11/17/2023 更新时间:11/17/2023 访问量:50

问:

对于概念验证,我使用带有单例列表的 Window#setIconImages(List<? extends Image>) 将 16x16 图标添加到 JFrame。在一个单独的程序中,我利用本机函数提取窗口的图标(请参阅将 HICON 转换为 Java 图像)并将其保存到文件中。生成的图像是 32x32 像素而不是 16x16,并且图像失去了一些质量:

窗口图标 输出图像
window icon(16×16) output image(32×32)

我想确定图像放大的位置,看看我是否可以防止质量损失。也就是说,我想确定其底层本机调用是否正在更改图像,或者是否从本机窗口提供图标的函数负责此升级。setIconImages

我正在使用以下代码检索图标句柄:

private static HICON getIconHandle(HWND window) {
    final DWORDByReference hIconNumber = new DWORDByReference();
    LRESULT result = User32.INSTANCE.SendMessageTimeout(window, WinUser.WM_GETICON, new WPARAM(WinUser.ICON_BIG),
            new LPARAM(0), WinUser.SMTO_ABORTIFHUNG, 500, hIconNumber);
    if (result.intValue() == 0)
        result = User32.INSTANCE.SendMessageTimeout(window, WinUser.WM_GETICON, new WPARAM(WinUser.ICON_SMALL),
                new LPARAM(0), WinUser.SMTO_ABORTIFHUNG, 500, hIconNumber);
    if (result.intValue() == 0)
        result = User32.INSTANCE.SendMessageTimeout(window, WinUser.WM_GETICON, new WPARAM(WinUser.ICON_SMALL2),
                new LPARAM(0), WinUser.SMTO_ABORTIFHUNG, 500, hIconNumber);
    if (result.intValue() == 0) {
        result = new LRESULT(User32.INSTANCE.GetClassLongPtr(window, WinUser.GCLP_HICON).intValue());
        hIconNumber.getValue().setValue(result.intValue());
    }
    if (result.intValue() == 0) {
        result = new LRESULT(User32.INSTANCE.GetClassLongPtr(window, WinUser.GCLP_HICONSM).intValue());
        hIconNumber.getValue().setValue(result.intValue());
    }
    if (result.intValue() == 0)
        return null;

    return new HICON(new Pointer(hIconNumber.getValue().longValue()));
}

我正在使用以下代码将图标转换为图像:

public static BufferedImage toImage(WinDef.HICON hicon) {
    WinDef.HBITMAP bitmapHandle = null;
    User32 user32 = User32.INSTANCE;
    GDI32 gdi32 = GDI32.INSTANCE;

    try {
        WinGDI.ICONINFO info = new WinGDI.ICONINFO();
        if (!user32.GetIconInfo(hicon, info))
            return null;

        info.read();
        bitmapHandle = Optional.ofNullable(info.hbmColor).orElse(info.hbmMask);

        WinGDI.BITMAP bitmap = new WinGDI.BITMAP();
        if (gdi32.GetObject(bitmapHandle, bitmap.size(), bitmap.getPointer()) > 0) {
            bitmap.read();

            int width = bitmap.bmWidth.intValue();
            int height = bitmap.bmHeight.intValue();

            final WinDef.HDC deviceContext = user32.GetDC(null);
            WinGDI.BITMAPINFO bitmapInfo = new WinGDI.BITMAPINFO();

            bitmapInfo.bmiHeader.biSize = bitmapInfo.bmiHeader.size();
            if (gdi32.GetDIBits(deviceContext, bitmapHandle, 0, 0, Pointer.NULL, bitmapInfo,
                    WinGDI.DIB_RGB_COLORS) == 0)
                throw new IllegalArgumentException("GetDIBits should not return 0");

            bitmapInfo.read();

            Memory pixels = new Memory(bitmapInfo.bmiHeader.biSizeImage);
            bitmapInfo.bmiHeader.biCompression = WinGDI.BI_RGB;
            bitmapInfo.bmiHeader.biHeight = -height;

            if (gdi32.GetDIBits(deviceContext, bitmapHandle, 0, bitmapInfo.bmiHeader.biHeight, pixels, bitmapInfo,
                    WinGDI.DIB_RGB_COLORS) == 0)
                throw new IllegalArgumentException("GetDIBits should not return 0");

            int[] colorArray = pixels.getIntArray(0, width * height);
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            image.setRGB(0, 0, width, height, colorArray, 0, width);

            return image;
        }
    } finally {
        gdi32.DeleteObject(hicon);
        Optional.ofNullable(bitmapHandle).ifPresent(gdi32::DeleteObject);
    }

    return null;
}

在那之后,它只是一个很好的老式 ImageIO.write(RenderedImage, String, File) 调用。

故障点在哪里?

java windows winapi java-native-interface awt

评论

0赞 IInspectable 11/17/2023
据猜测,这是在后台使用图像列表,因此调用 SetIconSize 确实会更改该列表中所有图像的大小。
0赞 VGR 11/17/2023
简短的回答:是的。本机桌面系统可以调整图像大小,以用作窗口图标、任务栏图标、任务列表图标和光标图像。这就是为什么应用程序传统上会传递多个不同分辨率的图像,包括 16×16、24×24、32×32、48×48、64×64、128×128、256×256 和 512×512。
0赞 Cardinal System 11/21/2023
@IInspectable AWT 在引擎盖下调用?SetIconSize
0赞 Cardinal System 11/21/2023
@VGR我知道操作系统会选择分辨率最合适的图标,但我从来不知道它实际上可以调整该图标的大小。

答: 暂无答案