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

Montre comment utiliser Windows::Storage::P ickers::FileOpenPicker pour charger une image dans des effets Direct2D. Si vous souhaitez permettre à l’utilisateur de sélectionner un fichier image à partir d’un stockage dans une application du 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 le ViewMode, SuggestedStartLocation et le 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 après le retour de l’opération asynchrone du sélecteur de fichiers. 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 un 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 cadre

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 fichiers JPEG sont 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 le WICPixelFormat32bppPBGRA et passez le cadre 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 source bitmap.

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

Utilisez la méthode CreateEffect pour créer un objet ID2D1Effectsource bitmap à l’aide du contexte d’appareilDirect2D.

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

Notes

L’effet source bitmap ne prend pas d’entrée 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 graphe d’effets.

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.
}