Direct2D コンテンツを画像ファイルに保存する方法
このトピックでは、 IWICImageEncoder を使用して 、ID2D1Image 形式のコンテンツを JPEG などのエンコードされたイメージ ファイルに保存する方法について説明します。 Windows ストア アプリを作成している場合は、 Windows::Storage::P ickers::FileSavePicker を使用して、ユーザーにコピー先ファイルを選択させることができます。
知っておくべきこと
テクノロジ
前提条件
- ID2D1DeviceContext オブジェクトと、ID2D1Image (ID2D1Effect や ID2D1Bitmap1 など) を実装する Direct2D コンテンツを含むオブジェクトが必要です。
Instructions
手順 1: 宛先ファイルとストリームを取得する
ユーザーが宛先ファイルを選択できるようにする場合は、 FileSavePicker を使用し、返されたファイルを開き、WIC で使用する IStream を取得できます。
Windows::Storage::P ickers::FileSavePicker を作成し、イメージ ファイルのパラメーターを設定します。 PickSaveFileAsync メソッドを呼び出します。
Pickers::FileSavePicker^ savePicker = ref new Pickers::FileSavePicker();
auto jpgExtensions = ref new Platform::Collections::Vector<Platform::String^>();
pngExtensions->Append(".png");
savePicker->FileTypeChoices->Insert("PNG file", pngExtensions);
auto jpgExtensions = ref new Platform::Collections::Vector<Platform::String^>();
jpgExtensions->Append(".jpg");
savePicker->FileTypeChoices->Insert("JPEG file", jpgExtensions);
savePicker->DefaultFileExtension = ".jpg";
savePicker->SuggestedFileName = "SaveScreen";
savePicker->SuggestedStartLocation = Pickers::PickerLocationId::PicturesLibrary;
task<StorageFile^> fileTask(savePicker->PickSaveFileAsync());
ファイル ピッカーの非同期操作が返された後に実行する完了ハンドラーを宣言します。 GetResults メソッドを使用してファイルを取得し、ファイル ストリーム オブジェクトを取得します。
task<StorageFile^> fileTask(savePicker->PickSaveFileAsync());
fileTask.then([=](StorageFile^ file) {
if (file != nullptr)
{
// User selects a file.
GUID wicFormat = GUID_ContainerFormatPng;
if (file->FileType == ".jpg")
{
wicFormat = GUID_ContainerFormatJpeg;
}
ファイルで OpenAsync を呼び出し、非同期操作の結果を取得することで、IRandomAccessStream を取得します。
task<Streams::IRandomAccessStream^> createStreamTask(file->OpenAsync(FileAccessMode::ReadWrite));
createStreamTask.then([=](Streams::IRandomAccessStream^ randomAccessStream) {
最後に、 CreateStreamOverRandomAccessStream メソッドを使用してファイル ストリームを変換します。 WINDOWS ランタイム API は IRandomAccessStream を使用するストリームを表し、WIC は IStream を使用します。
ComPtr<IStream> stream;
DX::ThrowIfFailed(
CreateStreamOverRandomAccessStream(randomAccessStream, IID_PPV_ARGS(&stream))
);
注意
CreateStreamOverRandomAccessStream 関数を使用するには、プロジェクトに shcore.h を含める必要があります。
手順 2: WIC ビットマップとフレーム エンコーダーを取得する
IWICBitmapEncoder と IWICBitmapFrameEncode は、イメージング データをエンコードされたファイル形式に保存する機能を提供します。
エンコーダー オブジェクトを作成して初期化します。
ComPtr<IWICBitmapEncoder> wicBitmapEncoder;
DX::ThrowIfFailed(
wicFactory2->CreateEncoder(
wicFormat,
nullptr, // No preferred codec vendor.
&wicBitmapEncoder
)
);
DX::ThrowIfFailed(
wicBitmapEncoder->Initialize(
stream,
WICBitmapEncoderNoCache
)
);
ComPtr<IWICBitmapFrameEncode> wicFrameEncode;
DX::ThrowIfFailed(
wicBitmapEncoder->CreateNewFrame(
&wicFrameEncode,
nullptr // No encoder options.
)
);
DX::ThrowIfFailed(
wicFrameEncode->Initialize(nullptr)
);
手順 3: IWICImageEncoder を取得する
IWICImageEncoder は、Windows 8の新しいインターフェイスです。 これは、IWICImagingFactory を拡張する IWICImagingFactory2 から作成でき、Windows 8の新機能でもあります。
ComPtr<IWICImagingFactory2> m_wicFactory;
DX::ThrowIfFailed(
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&m_wicFactory)
)
);
IWICImagingFactory2::CreateImageEncoder を呼び出します。 最初のパラメーターは ID2D1Device で、エンコードするイメージが作成されたデバイスである必要があります。1 つの IWICImageEncoder 内で異なるリソース ドメインのイメージを混在させることはできません。
ComPtr<IWICImageEncoder> imageEncoder;
DX::ThrowIfFailed(
wicFactory2->CreateImageEncoder(
d2dDevice.Get(),
&imageEncoder
)
);
手順 4: IWICImageEncoder を使用して Direct2D コンテンツを書き込む
IWICImageEncoder は、 Direct2D イメージをイメージ フレーム、フレーム サムネイル、またはコンテナー サムネイルに書き込むことができます。 その後、 IWICBitmapEncoder と IWICBitmapFrameEncode を使用して、イメージング データを通常どおりファイルにエンコードできます。
Direct2D イメージをフレームに書き込みます。 このスニペットでは、ラスタライズされた Direct2D コンテンツを含む ID2D1Bitmap を記述します。 ただし、 ID2D1Image を実装する任意のインターフェイスを指定できます。
DX::ThrowIfFailed(
imageEncoder->WriteFrame(
d2dBitmap.Get(),
wicFrameEncode.Get(),
nullptr // Use default WICImageParameter options.
)
);
注意
ID2D1Image パラメーターは、IWICImagingFactory2::CreateImageEncoder に渡された ID2D1Device に作成されている必要があります。
WIC とストリーム リソースをコミットして操作を終了します。
DX::ThrowIfFailed(
wicFrameEncode->Commit()
);
DX::ThrowIfFailed(
wicBitmapEncoder->Commit()
);
// Flush all memory buffers to the next-level storage object.
DX::ThrowIfFailed(
stream->Commit(STGC_DEFAULT)
);
これで、Direct2D イメージを含むファイルが作成されました。
コード例全体
この例の完全なコードを次に示します。
ComPtr<IWICImagingFactory2> m_wicFactory;
DX::ThrowIfFailed(
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&m_wicFactory)
)
);
void SaveAsImageFile::SaveBitmapToFile()
{
// Prepare a file picker for customers to input image file name.
Pickers::FileSavePicker^ savePicker = ref new Pickers::FileSavePicker();
auto pngExtensions = ref new Platform::Collections::Vector<Platform::String^>();
pngExtensions->Append(".png");
savePicker->FileTypeChoices->Insert("PNG file", pngExtensions);
auto jpgExtensions = ref new Platform::Collections::Vector<Platform::String^>();
jpgExtensions->Append(".jpg");
savePicker->FileTypeChoices->Insert("JPEG file", jpgExtensions);
auto bmpExtensions = ref new Platform::Collections::Vector<Platform::String^>();
bmpExtensions->Append(".bmp");
savePicker->FileTypeChoices->Insert("BMP file", bmpExtensions);
savePicker->DefaultFileExtension = ".png";
savePicker->SuggestedFileName = "SaveScreen";
savePicker->SuggestedStartLocation = Pickers::PickerLocationId::PicturesLibrary;
task<StorageFile^> fileTask(savePicker->PickSaveFileAsync());
fileTask.then([=](StorageFile^ file) {
if (file != nullptr)
{
// User selects a file.
m_imageFileName = file->Name;
GUID wicFormat = GUID_ContainerFormatPng;
if (file->FileType == ".bmp")
{
wicFormat = GUID_ContainerFormatBmp;
}
else if (file->FileType == ".jpg")
{
wicFormat = GUID_ContainerFormatJpeg;
}
// Retrieve a stream from the file.
task<Streams::IRandomAccessStream^> createStreamTask(file->OpenAsync(FileAccessMode::ReadWrite));
createStreamTask.then([=](Streams::IRandomAccessStream^ randomAccessStream) {
// Convert the RandomAccessStream to an IStream.
ComPtr<IStream> stream;
DX::ThrowIfFailed(
CreateStreamOverRandomAccessStream(randomAccessStream, IID_PPV_ARGS(&stream))
);
SaveBitmapToStream(m_d2dTargetBitmap, m_wicFactory, m_d2dContext, wicFormat, stream.Get());
});
}
});
}
// Save render target bitmap to a stream using WIC.
void SaveAsImageFile::SaveBitmapToStream(
_In_ ComPtr<ID2D1Bitmap1> d2dBitmap,
_In_ ComPtr<IWICImagingFactory2> wicFactory2,
_In_ ComPtr<ID2D1DeviceContext> d2dContext,
_In_ REFGUID wicFormat,
_In_ IStream* stream
)
{
// Create and initialize WIC Bitmap Encoder.
ComPtr<IWICBitmapEncoder> wicBitmapEncoder;
DX::ThrowIfFailed(
wicFactory2->CreateEncoder(
wicFormat,
nullptr, // No preferred codec vendor.
&wicBitmapEncoder
)
);
DX::ThrowIfFailed(
wicBitmapEncoder->Initialize(
stream,
WICBitmapEncoderNoCache
)
);
// Create and initialize WIC Frame Encoder.
ComPtr<IWICBitmapFrameEncode> wicFrameEncode;
DX::ThrowIfFailed(
wicBitmapEncoder->CreateNewFrame(
&wicFrameEncode,
nullptr // No encoder options.
)
);
DX::ThrowIfFailed(
wicFrameEncode->Initialize(nullptr)
);
// Retrieve D2D Device.
ComPtr<ID2D1Device> d2dDevice;
d2dContext->GetDevice(&d2dDevice);
// Create IWICImageEncoder.
ComPtr<IWICImageEncoder> imageEncoder;
DX::ThrowIfFailed(
wicFactory2->CreateImageEncoder(
d2dDevice.Get(),
&imageEncoder
)
);
DX::ThrowIfFailed(
imageEncoder->WriteFrame(
d2dBitmap.Get(),
wicFrameEncode.Get(),
nullptr // Use default WICImageParameter options.
)
);
DX::ThrowIfFailed(
wicFrameEncode->Commit()
);
DX::ThrowIfFailed(
wicBitmapEncoder->Commit()
);
// Flush all memory buffers to the next-level storage object.
DX::ThrowIfFailed(
stream->Commit(STGC_DEFAULT)
);
}