Comment charger une image dans les effets Direct2D en utilisant le FilePicker

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

Bon à savoir

Technologies

Prérequis

Instructions

Étape 1 : Ouvrir le sélecteur de fichiers

Créez un objet FileOpenPicker et définissez les paramètres ViewMode, SuggestedStartLocation et FileTypeFilter pour la sélection 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 la méthode PickSingleFileAsync terminée, vous obtenez un flux de fichiers à partir de l'interface IAsyncOperation qu'elle renvoie.

Étape 2 : Obtenir un flux de fichiers

Déclarez un gestionnaire d'achèvement à exécuter après le retour de l'opération asynchrone de sélection de fichiers. Utilisez la méthode GetResults pour récupérer le fichier et l'objet file stream.

    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);
                             });
        }
    });

Dans l'étape suivante, vous convertissez l'objet IRandomAccessStream en un IStream que vous pouvez transmettre à WIC.

Étape 3 : Conversion du flux de fichiers

Utilisez la fonction CreateStreamOverRandomAccessStream pour convertir le flux de fichiers. Les API d'exécution Windows représentent les flux avec IRandomAccessStream, tandis que le WIC utilise IStream.

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

Remarque

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

 

Étape 4 : Créer un décodeur WIC et récupérer la trame

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 trame de l'image à partir du décodeur en utilisant la méthode IWICBitmapDecoder::GetFrame.

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

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

Convertissez l'image au format de couleur BGRA à l'aide de WIC. IWICBitmapFrameDecode retournera le format de pixel natif de l'image, comme les JPEG sont stockés dans GUID_WICPixelFormat24bppBGR. Cependant, pour optimiser les 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 qu'il utilise le WICPixelFormat32bppPBGRA et transmettez la trame 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, vous pouvez donc passer le convertisseur à l'effet bitmap source.

Étape 6 : création d'un effet et transmission d'une IWICBitmapSource

Utilisez la méthode CreateEffect pour créer un objet ID2D1Effect source bitmap en utilisant le contexte de l'appareil Direct2D.

Utilisez la méthode ID2D1Effect::SetValue pour définir la propriété D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE au convertisseur de format WIC.

Remarque

L'effet bitmap source ne prend pas d'entrée à partir de la méthode SetInput comme beaucoup d'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 disposez de l'effet bitmap source, vous pouvez l'utiliser comme entrée de n'importe quel effet 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.
}