【C++/WinRT】ファイルからの画像読み込み

XamlC++/WinRTを使用してGUIを作る勉強中です。

画像のクラスが複数あるので、それぞれの読み込みと変換方法をメモしておきます。

パターンは以下の3つです。

  • 画像をBitmapImageとして読み込む
  • 画像をSoftwareBitmapとして読み込む
  • 画像を読み込み、ピクセル情報にアクセスする

画像をBitmapImageとして読み込む

メンバ変数のbitmapImageに書き込みます

Windows::Foundation::IAsyncAction MainPage::OpenFileAsBitmapImage_Click(IInspectable const&, RoutedEventArgs const&)
{
    auto lifetime = get_strong();
        
    FileOpenPicker openPicker;
    openPicker.ViewMode(PickerViewMode::Thumbnail);
    openPicker.SuggestedStartLocation(PickerLocationId::PicturesLibrary);
    openPicker.FileTypeFilter().ReplaceAll({ L".jpg", L".jpeg", L".png" });

    StorageFile loadedImageFile{ co_await openPicker.PickSingleFileAsync() };

    IRandomAccessStream fileStream{ co_await loadedImageFile.OpenAsync(FileAccessMode::Read) };
        
    m_bitmapImage.SetSource(fileStream);
}

画像をSoftwareBitmapとして読み込む

メンバ変数のm_softwareBitmapに書き込みます

Windows::Foundation::IAsyncAction MainPage::OpenFileAsSoftwareBitmap_Click(IInspectable const&, RoutedEventArgs const&)
{
    auto lifetime = get_strong();

    FileOpenPicker openPicker;
    openPicker.ViewMode(PickerViewMode::Thumbnail);
    openPicker.SuggestedStartLocation(PickerLocationId::PicturesLibrary);
    openPicker.FileTypeFilter().ReplaceAll({ L".jpg", L".jpeg", L".png" });

    StorageFile loadedImageFile{ co_await openPicker.PickSingleFileAsync() };

    IRandomAccessStream fileStream = co_await loadedImageFile.OpenAsync(FileAccessMode::Read);

    BitmapDecoder decoder { co_await BitmapDecoder::CreateAsync(fileStream)};

    m_softwareBitmap = co_await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat::Bgra8, BitmapAlphaMode::Premultiplied);
}

画像を読み込み、ピクセル情報にアクセスする

StorageFileを開いたのちにピクセル情報にアクセスします。 最終的にメンバ変数のm_writeableBitmapに書き込みます。

Windows::Foundation::IAsyncAction MainPage::OpenFileAsPixel_Click(IInspectable const&, RoutedEventArgs const&)
{
    auto lifetime = get_strong();

    uint32_t scaledSize = 300;
    m_writeableBitmap = Imaging::WriteableBitmap(scaledSize, scaledSize);

    FileOpenPicker openPicker;
    openPicker.ViewMode(PickerViewMode::Thumbnail);
    openPicker.SuggestedStartLocation(PickerLocationId::PicturesLibrary);
    openPicker.FileTypeFilter().ReplaceAll({ L".jpg", L".jpeg", L".png" });

    StorageFile loadedImageFile = co_await openPicker.PickSingleFileAsync();

    IRandomAccessStream fileStream{ co_await loadedImageFile.OpenAsync(Windows::Storage::FileAccessMode::Read) };

    BitmapDecoder decoder{ co_await BitmapDecoder::CreateAsync(fileStream) };

    // Scale the image to the appropriate size.
    Windows::Graphics::Imaging::BitmapTransform transform;
    transform.ScaledWidth(scaledSize);
    transform.ScaledHeight(scaledSize);

    Windows::Graphics::Imaging::PixelDataProvider pixelData{ co_await decoder.GetPixelDataAsync(
        Windows::Graphics::Imaging::BitmapPixelFormat::Bgra8, // WriteableBitmap uses BGRA format 
        Windows::Graphics::Imaging::BitmapAlphaMode::Straight,
        transform,
        Windows::Graphics::Imaging::ExifOrientationMode::IgnoreExifOrientation, // This sample ignores Exif orientation 
        Windows::Graphics::Imaging::ColorManagementMode::DoNotColorManage
    ) };

    winrt::com_array<uint8_t> sourcePixels{ pixelData.DetachPixelData() };

    auto bufferByteAccess{ m_writeableBitmap.PixelBuffer().as<::IBufferByteAccess>() };
    uint8_t* pTargetBytes{ nullptr };
    bufferByteAccess->Buffer(&pTargetBytes);

    for (auto& element : sourcePixels)
    {
        *(pTargetBytes++) = element;
    }

    ImageElement().Source(m_writeableBitmap);
}