Scaling a Windows screenshot

I've made a simple function that takes a screenshot of the Windows desktop. Now I want to be able to scale the resulting bitmap. But I'm not sure how to do this, the bitmap I now have is a Windows-thingy called HBITMAP, and I'm not sure how to work with it since I don't really know what format it is. It's probably very similar to a normal bmp-file.

I tried a windows-function called StretchBlt, but the result isn't very good. It's a very brute force smoshing together of pixels type of approach and I would like to have a bit higher quality bitmap when I'm done.

Perhaps I can send the HBITMAP to a function in a crate that does the scaling for me, but I guess this assumes it knows how to work with the HBITMAP?

Anyhow, this is what I have so far and I would love to have som suggestions how I can scale my screenshot.

fn take_screenshot() {
    // get screen size
    let x1 = unsafe { GetSystemMetrics(SM_XVIRTUALSCREEN) };
    let y1 = unsafe { GetSystemMetrics(SM_YVIRTUALSCREEN) };
    let x2 = unsafe { GetSystemMetrics(SM_CXVIRTUALSCREEN) };
    let y2 = unsafe { GetSystemMetrics(SM_CYVIRTUALSCREEN) };
    let w = x2 - x1;
    let h = y2 - y1;
    // copy screen to bitmap
    let hscreen = unsafe { GetDC(None) };
    let hdc = unsafe { CreateCompatibleDC(hscreen) };
    let hbitmap = unsafe { CreateCompatibleBitmap(hscreen, w / 3, h / 3) };
    let old_obj = unsafe { SelectObject(hdc, hbitmap) };
    // let _bret = unsafe { BitBlt(hdc, 0, 0, w, h, hscreen, x1, y1, SRCCOPY) };
    let _bret = unsafe { StretchBlt(hdc, 0, 0, w / 3, h / 3, hscreen, x1, y1, w, h, SRCCOPY) };
    // save bitmap to clipboard
    unsafe {
        OpenClipboard(None);
        EmptyClipboard();
        let _ = SetClipboardData(CF_BITMAP.0 as u32, HANDLE(hbitmap.0));
        CloseClipboard();
    }
    // cleanup
    unsafe {
        SelectObject(hdc, old_obj);
        DeleteDC(hdc);
        ReleaseDC(None, hscreen);
        DeleteObject(hbitmap);
    }
}

What I've tended to do in the past is use GDI+.

You can create a GDI+ Bitmap object from a HBITMAP and render that with a scale transform to a Graphics device. Whilst you have some options to prefer performance over quality this isn't a super-high speed solution but for putting stuff on the clipboard it would be fine.

Main issue in Rust is the Windows binding project doesn't have the GDI+ bindings so when it comes to setting up your bindings you will be looking at using bindgen on gdiplus.h and the GDI+ functions you will need are the Gdip... family such as GdipCreateBitmapFromHBITMAP

1 Like

I think I stumbled on to a solution. The function SetStretchBltMode seems to do an alright job at scaling the image.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.