Comment charger une image dans des effets Direct2D à l’aide de FilePicker

Montre comment utiliser le Windows::Stockage::P ickers::FileOpenPicker pour charger une image dans des effets Direct2D. Si vous souhaitez permettre à l’utilisateur de sélectionner un fichier image à partir du stockage dans une application Windows Store, nous vous recommandons d’utiliser FileOpenPicker.

Bon à savoir

Technologies

Prérequis

Instructions

Étape 1 : Ouvrir le sélecteur de fichiers

Créez un objet FileOpenPicker et définissez ViewMode, SuggestedStartLocation et FileTypeFilter pour sélectionner des images. Appelez la méthode PickSingleFileAsync .

    FileOpenPicker^ openPicker = ref new FileOpenPicker();
    openPicker->ViewMode = PickerViewMode::Thumbnail;
    openPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary;
    openPicker->FileTypeFilter->Append(".jpg");
    auto pickOperation = openPicker->PickSingleFileAsync();

Une fois pickSingleFileAsync terminé, vous obtenez un flux de fichiers à partir de l’interface IAsyncOperation qu’il retourne.

Étape 2 : Obtenir un flux de fichiers

Déclarez un gestionnaire d’achèvement à exécuter une fois l’opération asynchrone du sélecteur de fichiers retournée. Utilisez la méthode GetResults pour récupérer le fichier et obtenir l’objet de flux de fichiers.

    pickOperation->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>(
          [=](IAsyncOperation<StorageFile^> ^operation, AsyncStatus status)
    {
        auto file = operation->GetResults();
        if (file) // If file == nullptr, the user did not select a file.
        {
                             auto openOperation = file->OpenAsync(FileAccessMode::Read);
                             openOperation->Completed = ref new
                                      AsyncOperationCompletedHandler<IRandomAccessStream^>(
                                      [=](IAsyncOperation<IRandomAccessStream^> ^operation, AsyncStatus status)
                             {
                                      auto fileStream = operation->GetResults();

                                      // Pass IRandomAccessStream^ into DirectXApp for decoding/processing.
                                      OpenFile(fileStream);
                             });
        }
    });

À l’étape suivante, vous convertissez l’objet IRandomAccessStream en IStream que vous pouvez passer à WIC.

Étape 3 : Convertir le flux de fichiers

Utilisez la fonction CreateStreamOverRandomAccessStream pour convertir le flux de fichiers. Windows Runtime API représentent des flux avec IRandomAccessStream, tandis que WIC consomme IStream.

    ComPtr<IStream> istream;
    DX::ThrowIfFailed(
        CreateStreamOverRandomAccessStream(
        reinterpret_cast<IUnknown*>(fileStream),
        IID_PPV_ARGS(&istream)
        )
    );

Notes

Pour utiliser la fonction CreateStreamOverRandomAccessStream , vous devez inclure shcore.h dans votre projet.

 

Étape 4 : Créer un décodeur WIC et obtenir le frame

Créez un objet IWICBitmapDecoder à l’aide de la méthode IWICImagingFactory::CreateDecoderFromStream .

    ComPtr<IWICBitmapDecoder> decoder;
    DX::ThrowIfFailed(
          m_wicFactory->CreateDecoderFromStream(
                    istream.Get(),
                    nullptr,
                    WICDecodeMetadataCacheOnDemand,
                    &decoder
                    )
          );

Obtenez la première image de l’image à partir du décodeur à l’aide de la méthode IWICBitmapDecoder::GetFrame .

    ComPtr<IWICBitmapFrameDecode> frame;
    DX::ThrowIfFailed(
        decoder->GetFrame(0, &frame)
        );

Étape 5 : Créer un convertisseur WIC et initialiser

Convertissez l’image au format de couleur BGRA à l’aide de WIC. IWICBitmapFrameDecode retourne le format de pixel natif de l’image, comme les JPEG, stockés dans GUID_WICPixelFormat24bppBGR. Toutefois, en tant qu’optimisation des performances avec Direct2D, nous vous recommandons de convertir en WICPixelFormat32bppPBGRA.

  1. Créez un objet IWICFormatConverter à l’aide de la méthode IWICImagingFactory::CreateFormatConverter .

        ComPtr<IWICFormatConverter> converter;
        DX::ThrowIfFailed(
            m_wicFactory->CreateFormatConverter(&converter)
            ); 
    
    
  2. Initialisez le convertisseur de format pour utiliser WICPixelFormat32bppPBGRA et passer le frame bitmap.

       DX::ThrowIfFailed(
            converter->Initialize(
                frame.Get(),
                GUID_WICPixelFormat32bppPBGRA,
                WICBitmapDitherTypeNone,
                nullptr,
                0.0f,
                WICBitmapPaletteTypeCustom  // premultiplied BGRA has no paletting, so this is ignored
                )
            );
    

L’interface IWICFormatConverter est dérivée de l’interface IWICBitmapSource , ce qui vous permet de transmettre le convertisseur à l’effet source bitmap .

Étape 6 : Créer un effet et passer un IWICBitmapSource

Utilisez la méthode CreateEffect pour créer un objet bitmapsourceID2D1Effect à l’aide du contexte Direct2Ddevice.

Utilisez la méthode ID2D1Effect::SetValue pour définir la propriété D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE sur le convertisseurWICformat.

Remarque

L’effet source bitmap ne prend pas d’entrée à partir de la méthode SetInput , comme de nombreux effets Direct2D. Au lieu de cela, l’objet IWICBitmapSource est spécifié en tant que propriété.

 

    ComPtr<ID2D1Effect> bitmapSourceEffect;

    DX::ThrowIfFailed(
        m_d2dContext->CreateEffect(CLSID_D2D1BitmapSource, &bitmapSourceEffect)
        );

    DX::ThrowIfFailed(
        bitmapSourceEffect->SetValue(D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE, converter.Get())
        );

    // Insert code using the bitmap source in an effect graph.

Maintenant que vous avez l’effet source bitmap , vous pouvez l’utiliser comme entrée dans n’importe quel ID2D1Effect et créer un graphique d’effet.

Exemple complet

Voici le code complet de cet exemple.

ComPtr<ID2D1Effect> bitmapSourceEffect;

void OpenFilePicker()
{
    FileOpenPicker^ openPicker = ref new FileOpenPicker();
    openPicker->ViewMode = PickerViewMode::Thumbnail;
    openPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary;
    openPicker->FileTypeFilter->Append(".jpg");
    auto pickOperation = openPicker->PickSingleFileAsync();
    
    pickOperation->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>(
          [=](IAsyncOperation<StorageFile^> ^operation, AsyncStatus status)
    {
        auto file = operation->GetResults();
        if (file)
        {
                             auto openOperation = file->OpenAsync(FileAccessMode::Read);
                             openOperation->Completed = ref new
                                      AsyncOperationCompletedHandler<IRandomAccessStream^>(
                                      [=](IAsyncOperation<IRandomAccessStream^> ^operation, AsyncStatus status)
                             {
                                      auto fileStream = operation->GetResults();

                                      // Pass IRandomAccessStream^ into DirectXApp for decoding/processing.
                                      OpenFile(fileStream);
                             });
        }
    });
}

void OpenFile(Windows::Storage::Streams::IRandomAccessStream^ fileStream)
{
    ComPtr<IStream> istream;
    DX::ThrowIfFailed(
        CreateStreamOverRandomAccessStream(
            reinterpret_cast<IUnknown*>(fileStream),
            IID_PPV_ARGS(&istream)
            )
        );

    ComPtr<IWICBitmapDecoder> decoder;
    DX::ThrowIfFailed(
          m_wicFactory->CreateDecoderFromStream(
                    istream.Get(),
                    nullptr,
                    WICDecodeMetadataCacheOnDemand,
                    &decoder
                    )
          );

    ComPtr<IWICBitmapFrameDecode> frame;
    DX::ThrowIfFailed(
        decoder->GetFrame(0, &frame)
        );

    ComPtr<IWICFormatConverter> converter;
    DX::ThrowIfFailed(
        m_wicFactory->CreateFormatConverter(&converter)
        );

    DX::ThrowIfFailed(
        converter->Initialize(
            frame.Get(),
            GUID_WICPixelFormat32bppPBGRA,
            WICBitmapDitherTypeNone,
            nullptr,
            0.0f,
            WICBitmapPaletteTypeCustom  // premultiplied BGRA has no paletting, so this is ignored
            )
        );

       ComPtr<ID2D1Effect> bitmapSourceEffect;

    DX::ThrowIfFailed(
        m_d2dContext->CreateEffect(CLSID_D2D1BitmapSource, &bitmapSourceEffect)
        );

    DX::ThrowIfFailed(
        bitmapSourceEffect->SetValue(D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE, converter.Get())
        );

    // Insert code using the bitmap source in an effect graph.
}