Skip to content

Instantly share code, notes, and snippets.

@gyk
Created December 24, 2021 03:19

Revisions

  1. gyk created this gist Dec 24, 2021.
    87 changes: 87 additions & 0 deletions load_and_resize_image.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,87 @@
    // Improvements over NWG's built-in implementation:
    //
    // - High quality interpolation mode
    // - Crop non-square images
    fn load_and_resize_image(decoder: &nwg::ImageDecoder, data: &[u8]) -> Result<Bitmap> {
    use winapi::shared::windef::{HBITMAP, HDC};
    use winapi::um::wincodec::{
    IWICBitmapScaler, IWICBitmapSource, WICBitmapInterpolationModeHighQualityCubic,
    };
    use winapi::um::wingdi::{
    BitBlt, CreateCompatibleBitmap, CreateCompatibleDC, DeleteDC, SelectObject, SRCCOPY,
    };

    let image_frame = decoder.from_stream(data)?.frame(0)?;

    // Resize
    let (w, h) = image_frame.size();
    let thumb_size = scaled_thumb_size();
    let (w, h) = if w >= h {
    (thumb_size * w / h, thumb_size)
    } else {
    (thumb_size, thumb_size * h / w)
    };

    let bitmap = unsafe {
    let mut scaler: *mut IWICBitmapScaler = ptr::null_mut();
    (&*decoder.factory).CreateBitmapScaler(&mut scaler);
    let image_source = image_frame.frame as *const IWICBitmapSource;
    (&*scaler).Initialize(
    image_source,
    w,
    h,
    WICBitmapInterpolationModeHighQualityCubic,
    );
    nwg::ImageData {
    frame: scaler as *mut IWICBitmapSource,
    }
    .as_bitmap()?
    };

    if w == thumb_size && h == thumb_size {
    return Ok(bitmap);
    }

    // Crop
    unsafe {
    let hdc_null: HDC = mem::zeroed();

    let hdc_src = CreateCompatibleDC(hdc_null);
    let bmp_src = bitmap.handle;
    SelectObject(hdc_src, bmp_src);

    let hdc_dst = CreateCompatibleDC(hdc_null);
    let bmp_dst: HBITMAP =
    CreateCompatibleBitmap(hdc_src, thumb_size as i32, thumb_size as i32);
    SelectObject(hdc_dst, bmp_dst as *mut _);

    BitBlt(
    hdc_dst,
    0,
    0,
    thumb_size as i32,
    thumb_size as i32,
    hdc_src,
    (w - thumb_size) as i32 / 2,
    (h - thumb_size) as i32 / 2,
    SRCCOPY,
    );

    DeleteDC(hdc_src);
    DeleteDC(hdc_dst);

    #[allow(dead_code)]
    struct MyBitmap {
    handle: *mut std::ffi::c_void,
    owned: bool,
    }

    let my_bmp = MyBitmap {
    handle: bmp_dst as *mut _,
    owned: true,
    };

    let bmp: Bitmap = mem::transmute(my_bmp);
    Ok(bmp)
    }
    }