Übersicht über die Codierung

Wichtig

Einige Informationen beziehen sich auf Vorabversionen, die vor der kommerziellen Freigabe grundlegend geändert werden können. Microsoft übernimmt hinsichtlich der hier bereitgestellten Informationen keine Gewährleistungen, seien sie ausdrücklich oder konkludent.

Ein Encoder schreibt Bilddaten in einen Datenstrom. Encoder können die Bildpixel auf verschiedene Arten komprimieren, verschlüsseln und ändern, bevor sie in den Datenstrom geschrieben werden. Die Verwendung einiger Encoder führt zu Kompromissen, z. B. JPEG, das einige Farbinformationen für eine bessere Komprimierung aufgibt. Andere Encoder führen nicht zu solchen Verlusten, z. B. Bitmap (BMP). Da viele Codecs proprietäre Technologie verwenden, um eine bessere Komprimierung und Bildtreue zu erzielen, sind die Details dazu, wie ein Bild codiert wird, von dem Codecentwickler abhängig.

IWICBitmapEncoder

IWICBitmapEncoder ist die Hauptschnittstelle zum Codieren eines Bilds mit dem Zielformat und zum Serialisieren der Komponenten eines Bilds, z. B. Miniaturansicht (SetThumbnail) und Frames (CreateNewFrame), in die Bilddatei ein.

Wie und wann die Serialisierung auftritt, bleibt dem Codecentwickler überlassen. Jeder einzelne Datenblock im Zieldateiformat sollte unabhängig von der Reihenfolge festgelegt werden können, aber auch hier ist es die Entscheidung des Codecentwicklers. Sobald die Commit-Methode jedoch aufgerufen wird, sollten Änderungen am Bild nicht zulässig sein und der Datenstrom geschlossen werden.

IWICBitmapFrameEncode

IWICBitmapFrameEncode ist die Schnittstelle zum Codieren der einzelnen Frames eines Bilds. Es bietet Methoden zum Festlegen einzelner Frame-Imageerstellungskomponenten wie Miniaturansichten und Frames sowie Bildabmessungen, DPI- und Pixelformate.

Einzelne Frames können mit framespezifischen Metadaten codiert werden, sodass IWICBitmapFrameEncode über die GetMetadataQueryWriter-Methode Zugriff auf einen Metadatenschreiber bietet.

Die Commit-Methode des Frames setzt alle Änderungen an dem einzelnen Frame fest und gibt an, dass Änderungen an diesem Frame nicht mehr akzeptiert werden sollen.

Codierungsbeispiel (TIFF)

Im folgenden Beispiel wird ein Tagged Image File Format (TIFF)-Bild mit IWICBitmapEncoder und einem IWICBitmapFrameEncode codiert. Die TIFF-Ausgabe wird mithilfe der WICTiffCompressionOption angepasst, und der Bitmapframe wird mithilfe der angegebenen Optionen initialisiert. Nachdem das Bild mit WritePixels erstellt wurde, wird der Frame mithilfe von Commit übernommen, und das Bild wird mit Commitgespeichert.

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;

Verwendung von Encoderoptionen

Unterschiedliche Encoder für unterschiedliche Formate müssen verschiedene Optionen für die Codierung eines Bilds verfügbar machen. Windows Imaging Component (WIC) bietet einen konsistenten Mechanismus zum Ausdrücken, ob Codierungsoptionen erforderlich sind, während Anwendungen weiterhin mit mehreren Encodern arbeiten können, ohne dass sie Kenntnisse zu einem bestimmten Format benötigen. Dazu wird ein IPropertyBag-Parameter für die CreateNewFrame-Methode und die Initialize-Methode bereitgestellt.

Die Komponentenfactory bietet einen einfachen Erstellungspunkt zum Erstellen eines Encoder-Optionseigenschaftenbehälters. Codecs können diesen Dienst verwenden, wenn sie einen einfachen, intuitiven und nicht widersprüchlichen Satz von Encoderoptionen bereitstellen müssen. Der Imageerstellungseigenschaftenbehälter muss während der Erstellung mit allen für diesen Codec relevanten Encoderoptionen initialisiert werden. Für Encoderoptionen aus dem kanonischen Satz wird der Wertbereich für Write erzwungen. Für erweiterte Anforderungen sollten Codecs ihre eigene Implementierung des Eigenschaftenbehälters schreiben.

Während der Frameerstellung erhält eine Anwendung den Encoder-Optionsbehälter und muss vor der Initialisierung des Encoderframes alle Werte konfigurieren. Für eine benutzeroberflächengesteuerte Anwendung kann sie eine feste Benutzeroberfläche für die kanonischen Encoderoptionen und eine erweiterte Ansicht für verbleibende Optionen bieten. Änderungen können einzeln über die Write-Methode vorgenommen werden, und alle Fehler werden über IErrorLog gemeldet. Die UI-Anwendung sollte alle Optionen immer erneut lesen und anzeigen, nachdem eine Änderung vorgenommen wurde, falls die Änderung einen Kaskadierungseffekt verursacht hat. Eine Anwendung sollte darauf vorbereitet sein, fehlerhafte Frameinitialisierung für Codecs zu behandeln, die nur minimale Fehlerberichte über ihren Eigenschaftenbehälter bereitstellen.

Encoderoptionen

Eine Anwendung kann erwarten, dass die folgenden Encoderoptionen auftreten. Encoderoptionen spiegeln die Funktionen eines Encoders und des zugrunde liegenden Containerformats wider und sind daher von ihrer Natur aus nicht wirklich codecagnostisch. Wenn möglich, sollten neue Optionen normalisiert werden, damit sie auf neue Codecs, die entstehen, angewendet werden können.

Eigenschaftenname VARTYPE Wert Anwendbare Codecs
BitmapTransform VT_UI1 WICBitmapTransformOptions JPEG, HEIF
CompressionQuality VT_R4 0-1,0 TIFF
HeifCompressionMethod WICHeifCompressionOption verschiedene HEIF
ImageQuality VT_R4 0-1,0 JPEG, HDPhoto, HEIF
Verlustfrei VT_BOOL TRUE, FALSE HDPhoto

ImageQualty von 0,0 bedeutet die niedrigste mögliche Wiedergabetreue und 1,0 bedeutet die höchste Genauigkeit, was je nach Codec auch verlustfrei bedeuten kann.

CompressionQuality von 0,0 bedeutet das am wenigsten effiziente verfügbare Komprimierungsschema, was in der Regel zu einer schnellen, aber größeren Ausgabe führt. Ein Wert von 1,0 bedeutet, das effizienteste verfügbare Schema und nimmt in der Regel mehr Zeit in Anspruch, um eine kleinere Ausgabe zu codieren. Je nach den Funktionen des Codecs kann dieser Bereich einem separaten Satz verfügbarer Komprimierungsmethoden zugeordnet werden.

Verlustfrei bedeutet, dass der Codec das Bild ohne Datenverlust als verlustfrei codiert. Wenn Lossless aktiviert ist, wird ImageQuality ignoriert.

Zusätzlich zu den oben genannten generischen Encoderoptionen unterstützen Codecs, die mit WIC bereitgestellt werden, die folgenden Optionen. Wenn ein Codec eine Option unterstützen muss, die mit der Verwendung in diesen bereitgestellten Codecs konsistent ist, wird dies empfohlen.

Eigenschaftenname VARTYPE Wert Anwendbare Codecs
InterlaceOption VT_BOOL Ein/Aus PNG
FilterOption VT_UI1 WICPngFilterOption PNG
TiffCompressionMethod VT_UI1 WICTiffCompressionOption TIFF
Sättigung VT_UI4/VT_ARRAY 64 Einträge (DCT) JPEG
Chrominanz VT_UI4/VT_ARRAY 64 Einträge (DCT) JPEG
JpegYCrCbSubsampling VT_UI1 WICJpegYCrCbSubsamplingOption JPEG
SuppressApp0 VT_BOOL JPEG
EnableV5Header32bppBGRA VT_BOOL Ein/Aus BMP

Verwenden Sie VT_EMPTY, um *nicht als Standard festlegen* anzugeben. Wenn zusätzliche Eigenschaften festgelegt, aber nicht unterstützt werden, sollte der Encoder sie ignorieren. Auf diese Weise können Anwendungen weniger codierte Logik haben, wenn sie eine Funktion benötigen, die möglicherweise schon vorhanden ist.

Beispiele für Encoderoptionen

Im obigen TIFF-Codierungsbeispiel wird eine bestimmte Encoderoption festgelegt. Das pstrName-Element der PROPBAG2-Struktur wird auf den entsprechenden Eigenschaftennamen festgelegt, und der VARIANT-Wert wird auf den entsprechenden VARTYPE und den gewünschten Wert festgelegt, in diesem Fall ein Element der WICTiffCompressionOption-Aufzählung.

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

Um die Standard-Encoderoptionen zu verwenden, initialisieren Sie einfach den Bitmapframe mit dem Eigenschaftenbehälter, der beim Erstellen des Frames zurückgegeben wurde.

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

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

Es ist auch möglich, den Eigenschaftenbehälter zu beseitigen, wenn keine Encoderoptionen berücksichtigt werden.

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

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