Поделиться через


Загрузка изображения в эффекты Direct2D с помощью FilePicker

Показывает, как использовать Windows::Storage::P ickers::FileOpenPicker для загрузки изображения в эффекты Direct2D. Если вы хотите разрешить пользователю выбрать файл изображения из хранилища в приложении Магазина Windows, рекомендуется использовать FileOpenPicker.

Это важно знать

Технологии

Необходимые компоненты

Instructions

Шаг 1. Открытие средства выбора файлов

Создайте объект FileOpenPicker и задайте ViewMode, SuggestedStartLocation и FileTypeFilter для выбора изображений. Вызовите метод PickSingleFileAsync.

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

После завершения pickSingleFileAsync вы получите поток файлов из интерфейса IAsyncOperation, который он возвращает.

Шаг 2. Получение потока файлов

Объявите обработчик завершения для запуска после возврата асинхронной операции выбора файлов. Используйте метод GetResults для извлечения файла и получения объекта потока файлов.

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

На следующем шаге вы преобразуете объект IRandomAccessStream в IStream , который можно передать в WIC.

Шаг 3. Преобразование потока файлов

Используйте функцию CreateStreamOverRandomAccessStream для преобразования потока файлов. СРЕДА ВЫПОЛНЕНИЯ WINDOWS API представляют потоки с помощью IRandomAccessStream, в то время как WIC использует IStream.

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

Примечание.

Чтобы использовать функцию CreateStreamOverRandomAccessStream, необходимо включить shcore.h в проект.

 

Шаг 4. Создание декодера WIC и получение кадра

Создайте объект IWICBitmapDecoder с помощью метода IWICImagingFactory::CreateDecoderFromStream.

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

Получите первый кадр изображения из декодера с помощью метода IWICBitmapDecoder::GetFrame .

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

Шаг 5. Создание преобразователя WIC и инициализация

Преобразуйте изображение в формат цвета BGRA с помощью WIC. IWICBitmapFrameDecode возвращает собственный формат пикселя изображения, например JPEG, хранится в GUID_WICPixelFormat24bppBGR. Однако в качестве оптимизации производительности с помощью Direct2D рекомендуется преобразовать в WICPixelFormat32bppPGRA.

  1. Создайте объект IWICFormatConverter с помощью метода IWICImagingFactory::CreateFormatConverter.

        ComPtr<IWICFormatConverter> converter;
        DX::ThrowIfFailed(
            m_wicFactory->CreateFormatConverter(&converter)
            ); 
    
    
  2. Инициализировать преобразователь формата, чтобы использовать WICPixelFormat32bppPBGRA и передать в кадр растрового изображения.

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

Интерфейс IWICFormatConverter является производным от интерфейса IWICBitmapSource, поэтому можно передать преобразователь в эффект источника растрового изображения.

Шаг 6. Создание эффекта и передача в IWICBitmapSource

Используйте метод CreateEffect для создания объекта источника растрового изображения ID2D1Effect с помощью контекста устройства Direct2D.

Используйте метод ID2D1Effect::SetValue, чтобы задать свойство D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE преобразователю формата WIC.

Примечание.

Эффект источника растрового изображения не принимает входные данные из метода SetInput, как и многие эффекты Direct2D. Вместо этого объект IWICBitmapSource указывается как свойство.

 

    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.

Теперь, когда у вас есть эффект источника растрового изображения, его можно использовать в качестве входных данных для любого id2D1Effect и создать граф эффектов.

Полный пример

Ниже приведен полный код для этого примера.

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