Cómo cargar una imagen en efectos de Direct2D mediante FilePicker

Muestra cómo usar Windows::Storage::P ickers::FileOpenPicker para cargar una imagen en efectos de Direct2D. Si quieres permitir que el usuario seleccione un archivo de imagen del almacenamiento en una aplicación de la Tienda Windows, te recomendamos que uses FileOpenPicker.

Lo que necesita saber

Tecnologías

Requisitos previos

Instrucciones

Paso 1: Abrir el selector de archivos

Cree un objeto FileOpenPicker y establezca ViewMode, SuggestedStartLocation y FileTypeFilter para seleccionar imágenes. Llame al método PickSingleFileAsync .

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

Una vez que se complete PickSingleFileAsync , obtendrá una secuencia de archivos de la interfaz IAsyncOperation que devuelve.

Paso 2: Obtener una secuencia de archivos

Declare un controlador de finalización para que se ejecute después de que se devuelva la operación asincrónica del selector de archivos. Use el método GetResults para recuperar el archivo y para obtener el objeto de secuencia de archivos.

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

En el paso siguiente se convierte el objeto IRandomAccessStream en un IStream que se puede pasar a WIC.

Paso 3: Convertir la secuencia de archivos

Use la función CreateStreamOverRandomAccessStream para convertir la secuencia de archivos. Windows Runtime API representan secuencias con IRandomAccessStream, mientras que WIC consume IStream.

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

Nota:

Para usar la función CreateStreamOverRandomAccessStream , debe incluir shcore.h en el proyecto.

 

Paso 4: Crear un descodificador WIC y obtener el marco

Cree un objeto IWICBitmapDecoder mediante el método IWICImagingFactory::CreateDecoderFromStream .

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

Obtenga el primer fotograma de la imagen del descodificador mediante el método IWICBitmapDecoder::GetFrame .

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

Paso 5: Crear un convertidor WIC e inicializar

Convierta la imagen al formato de color BGRA mediante WIC. IWICBitmapFrameDecode devolverá el formato de píxel nativo de la imagen, como los JPEG se almacenan en GUID_WICPixelFormat24bppBGR. Sin embargo, como optimización del rendimiento con Direct2D, se recomienda convertir a WICPixelFormat32bppPBGRA.

  1. Cree un objeto IWICFormatConverter mediante el método IWICImagingFactory::CreateFormatConverter .

        ComPtr<IWICFormatConverter> converter;
        DX::ThrowIfFailed(
            m_wicFactory->CreateFormatConverter(&converter)
            ); 
    
    
  2. Inicialice el convertidor de formato para usar WICPixelFormat32bppPBGRA y pase el marco de mapa de bits.

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

La interfaz IWICFormatConverter se deriva de la interfaz IWICBitmapSource , por lo que puede pasar el convertidor al efecto de origen del mapa de bits .

Paso 6: Crear efecto y pasar un IWICBitmapSource

Use el método CreateEffect para crear un objeto ID2D1Effect de origen de mapa de bits mediante el contexto del dispositivoDirect2D.

Use el método ID2D1Effect::SetValue para establecer la propiedad D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE en el convertidor de formatoWIC.

Nota:

El efecto de origen del mapa de bits no toma una entrada del método SetInput como muchos efectos direct2D. En su lugar, el objeto IWICBitmapSource se especifica como una propiedad .

 

    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.

Ahora que tiene el efecto de origen del mapa de bits , puede usarlo como entrada para cualquier ID2D1Effect y crear un gráfico de efectos.

Ejemplo completo

Este es el código completo de este ejemplo.

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