エンコードの概要

重要

一部の情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

エンコーダーは、画像データをストリームに書き込みます。 エンコーダーは、ストリームに画像を書き込む前に、さまざまな方法で画像ピクセルの圧縮、暗号化、変更を行うことができます。 一部のエンコーダーの使用にはトレードオフが伴います。たとえば、JPEG は圧縮率を向上させるためにトレードオフで色情報を犠牲にしています。 たとえば、ビットマップ (BMP) などの他のエンコーダーでは、そのような損失は発生しません。 多くのコーデックは、より良い圧縮率と画像の忠実度を実現するために独自のテクノロジを使用しているため、画像がどのようにエンコードされるかはコーデックの開発者次第となります。

IWICBitmapEncoder

IWICBitmapEncoder は、画像をターゲットの形式にエンコードするための主要なインターフェイスであり、サムネイル (SetThumbnail) やフレーム (CreateNewFrame) などの画像のコンポーネントを画像ファイルにシリアル化するために使用されます。

シリアル化がいつどのように発生するかは、コーデック開発者次第となります。 ターゲットのファイル形式内の個々のデータ ブロックは、順序に依存せず設定できるようになっているべきですが、これもやはりコーデック開発者の決断次第です。 しかし、Commit メソッドが呼び出されたら、画像への変更は禁止され、ストリームは閉じられる必要があります。

IWICBitmapFrameEncode

IWICBitmapFrameEncode は、画像の個々のフレームをエンコードするためのインターフェイスです。 サムネイルやフレームなどの個々のフレーム イメージング コンポーネントだけでなく、画像のサイズ、DPI、ピクセル形式を設定するための方法を提供します。

個々のフレームはフレーム固有のメタデータを使用してエンコードされる場合があるため、IWICBitmapFrameEncodeGetMetadataQueryWriter メソッドを通してメタデータ ライターへのアクセスを提供します。

フレームの Commit メソッドは、個々のフレームに対するすべての変更をコミットし、それ以降はそのフレームへの変更が受け付けられないことを意味します。

エンコードの例 (TIFF)

次の例では、Tagged Image File Format (TIFF) 画像は、IWICBitmapEncoderIWICBitmapFrameEncode を使用してエンコードされます。 TIFF 出力は WICTiffCompressionOption を使用してカスタマイズされ、ビットマップ フレームは指定されたオプションを使用して初期化されます。 WritePixels を使用して画像が作成されると、フレームは Commit を通してコミットされ、画像は Commit を使用して保存されます。

IWICImagingFactory *piFactory = NULL;
IWICBitmapEncoder *piEncoder = NULL;
IWICBitmapFrameEncode *piBitmapFrame = NULL;
IPropertyBag2 *pPropertybag = NULL;

IWICStream *piStream = NULL;
UINT uiWidth = 640;
UINT uiHeight = 480;

HRESULT hr = CoCreateInstance(
                CLSID_WICImagingFactory,
                NULL,
                CLSCTX_INPROC_SERVER,
                IID_IWICImagingFactory,
                (LPVOID*) &piFactory);

if (SUCCEEDED(hr))
{
    hr = piFactory->CreateStream(&piStream);
}

if (SUCCEEDED(hr))
{
    hr = piStream->InitializeFromFilename(L"output.tif", GENERIC_WRITE);
}

if (SUCCEEDED(hr))
{
   hr = piFactory->CreateEncoder(GUID_ContainerFormatTiff, NULL, &piEncoder);
}

if (SUCCEEDED(hr))
{
    hr = piEncoder->Initialize(piStream, WICBitmapEncoderNoCache);
}

if (SUCCEEDED(hr))
{
    hr = piEncoder->CreateNewFrame(&piBitmapFrame, &pPropertybag);
}

if (SUCCEEDED(hr))
{        
    // This is how you customize the TIFF output.
    PROPBAG2 option = { 0 };
    option.pstrName = L"TiffCompressionMethod";
    VARIANT varValue;    
    VariantInit(&varValue);
    varValue.vt = VT_UI1;
    varValue.bVal = WICTiffCompressionZIP;      
    hr = pPropertybag->Write(1, &option, &varValue);        
    if (SUCCEEDED(hr))
    {
        hr = piBitmapFrame->Initialize(pPropertybag);
    }
}

if (SUCCEEDED(hr))
{
    hr = piBitmapFrame->SetSize(uiWidth, uiHeight);
}

WICPixelFormatGUID formatGUID = GUID_WICPixelFormat24bppBGR;
if (SUCCEEDED(hr))
{
    hr = piBitmapFrame->SetPixelFormat(&formatGUID);
}

if (SUCCEEDED(hr))
{
    // We're expecting to write out 24bppRGB. Fail if the encoder cannot do it.
    hr = IsEqualGUID(formatGUID, GUID_WICPixelFormat24bppBGR) ? S_OK : E_FAIL;
}

if (SUCCEEDED(hr))
{
    UINT cbStride = (uiWidth * 24 + 7)/8/***WICGetStride***/;
    UINT cbBufferSize = uiHeight * cbStride;

    BYTE *pbBuffer = new BYTE[cbBufferSize];

    if (pbBuffer != NULL)
    {
        for (UINT i = 0; i < cbBufferSize; i++)
        {
            pbBuffer[i] = static_cast<BYTE>(rand());
        }

        hr = piBitmapFrame->WritePixels(uiHeight, cbStride, cbBufferSize, pbBuffer);

        delete[] pbBuffer;
    }
    else
    {
        hr = E_OUTOFMEMORY;
    }
}

if (SUCCEEDED(hr))
{
    hr = piBitmapFrame->Commit();
}    

if (SUCCEEDED(hr))
{
    hr = piEncoder->Commit();
}

if (piFactory)
    piFactory->Release();

if (piEncoder)
    piEncoder->Release();

if (piBitmapFrame)
    piBitmapFrame->Release();

if (pPropertybag)
    pPropertybag->Release();

if (piStream)
    piStream->Release();

return hr;

エンコーダー オプションの使用方法

異なる形式用の異なるエンコーダーが公開する画像のエンコード方法のオプションは必然的に異なります。 Windows Imaging Component (WIC) は、特定の形式に関する知識なしでもアプリケーションで複数のエンコーダーを操作できるようにすると同時に、エンコード オプションが必要かどうかを表現するための一貫したメカニズムを提供します。 これは、CreateNewFrame メソッドと Initialize メソッドに IPropertyBag パラメーターを指定することで実現できます。

コンポーネント ファクトリは、エンコーダー オプション プロパティ バッグを作成するための簡単な作成ポイントを提供します。 コーデックは、シンプルで直感的で競合しないエンコーダー オプションのセットを提供する必要がある場合に、このサービスを使用できます。 イメージング プロパティ バッグは、作成時に、そのコーデックに関連するすべてのエンコーダー オプションを使用して初期化する必要があります。 正規セットのエンコーダー オプションの場合、値の範囲は強制的に Write になります。 より高度なニーズのためには、コーデックは独自のプロパティ バッグの実装を記述する必要があります。

アプリケーションは、フレームの作成時にエンコーダー オプション バッグを与えられ、エンコーダー フレームの初期化の前に値を構成する必要があります。 UI 駆動型アプリケーションの場合、アプリケーションは正規エンコーダー オプション用の固定 UI と、その他のオプションの詳細ビューを提供できます。 変更は Write メソッドを通じて一度に 1 つずつ行うことができ、エラーは IErrorLog を通じて報告されます。 変更によって連鎖効果が発生した場合、UI アプリケーションは、常に変更を行った後にすべてのオプションを再読み取りして表示する必要があります。 アプリケーションは、プロパティ バッグを通して最小限のエラー報告しか提供しないコーデックのフレーム初期化の失敗を処理する準備ができている必要があります。

エンコーダー オプション

アプリケーションで目にすることが期待されるエンコーダー オプションのセットを以下に示します。 エンコーダー オプションは、エンコーダーの機能、および根底のコンテナー形式を反映しているため、その性質上、コーデックに依存しません。 新しいオプションは、今後現れる新しいコーデックに適用できるよう、可能な限り正規化する必要があります。

プロパティ名 VARTYPE Value 適用可能なコーデック
BitmapTransform VT_UI1 WICBitmapTransformOptions JPEG、HEIF
CompressionQuality VT_R4 0-1.0 TIFF
HeifCompressionMethod WICHeifCompressionOption 様々 HEIF
ImageQuality VT_R4 0-1.0 JPEG、HDPhoto、HEIF
Lossless VT_BOOL TRUEFALSE HDPhoto

ImageQualty の 0.0 は可能な中で最も低い忠実度による表示を意味し、1.0 は最も高い忠実度を意味し、これはコーデックによってはロスレスを意味する場合もあります。

CompressionQuality の 0.0 は、利用可能な中で最も効率が悪い圧縮スキームを意味し、通常、エンコードは高速になりますが出力は大きくなります。 1.0 という値は、利用可能な中で最も効率が良いスキームを意味し、通常、エンコードには時間がかかりますが出力は小さくなります。 コーデックの機能によっては、この範囲が使用可能な圧縮方法の個別のセットにマップされる場合があります。

Lossless は、コーデックが画像をロスレスとして画像データのロスなしでエンコードすることを意味します。 Lossless が有効になっている場合、ImageQuality は無視されます。

上記の一般的なエンコーダー オプションに加えて、WIC で提供されるコーデックでは、以下のオプションがサポートされます。 コーデックで、これらの提供されたコーデックでの使用方法と一貫性のあるオプションをサポートする必要がある場合、それを行うことが推奨されます。

プロパティ名 VARTYPE Value 適用可能なコーデック
InterlaceOption VT_BOOL オン/オフ PNG
FilterOption VT_UI1 WICPngFilterOption PNG
TiffCompressionMethod VT_UI1 WICTiffCompressionOption TIFF
Luminance VT_UI4/VT_ARRAY 64 エントリ (DCT) JPEG
Chrominance VT_UI4/VT_ARRAY 64 エントリ (DCT) JPEG
JpegYCrCbSubsampling VT_UI1 WICJpegYCrCbSubsamplingOption JPEG
SuppressApp0 VT_BOOL JPEG
EnableV5Header32bppBGRA VT_BOOL オン/オフ BMP

既定値として *設定されていない* ことを指定するには VT_EMPTY を使用します。 追加のプロパティが設定されていて、それらがサポートされていない場合、エンコーダーはそれらを無視する必要があります。これにより、アプリケーションで存在するかしないか分からない機能が必要な場合に、コーディングするロジックを減らすことができます。

エンコーダー オプションの例

上記の TIFF エンコードの例では、特定のエンコーダー オプションが設定されています。 PROPBAG2 構造体の pstrName メンバーは適切なプロパティ名に設定され、VARIANT は対応する VARTYPE と目的の値 (この場合は WICTiffCompressionOption 列挙体のメンバー) に設定されています。

if (SUCCEEDED(hr))
{
    hr = piEncoder->CreateNewFrame(&piBitmapFrame, &pPropertybag);
}

if (SUCCEEDED(hr))
{        
    // This is how you customize the TIFF output.
    PROPBAG2 option = { 0 };
    option.pstrName = L"TiffCompressionMethod";
    VARIANT varValue;    
    VariantInit(&varValue);
    varValue.vt = VT_UI1;
    varValue.bVal = WICTiffCompressionZIP;      
    hr = pPropertybag->Write(1, &option, &varValue);        
    if (SUCCEEDED(hr))
    {
        hr = piBitmapFrame->Initialize(pPropertybag);
    }
}

既定のエンコーダー オプションを使用するには、フレームの作成時に返されたプロパティ バッグを使用してビットマップ フレームを初期化するだけです。

if (SUCCEEDED(hr))
{
    hr = piEncoder->CreateNewFrame(&piBitmapFrame, &pPropertybag);
}

if (SUCCEEDED(hr))
{        
    // Accept the default encoder options.
    if (SUCCEEDED(hr))
    {
        hr = piBitmapFrame->Initialize(pPropertybag);
    }
}

エンコーダー オプションが考慮されていない場合は、プロパティ バッグを排除することもできます。

if (SUCCEEDED(hr))
{
    hr = piEncoder->CreateNewFrame(&piBitmapFrame, 0);
}

if (SUCCEEDED(hr))
{        
    // No encoder options.
    if (SUCCEEDED(hr))
    {
        hr = piBitmapFrame->Initialize(0);
    }
}