Freigeben über


HEIF-Erweiterungscodec

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.

Informationen zum HEIF-Erweiterungscodec (High Efficiency Image Format), der über WIC verfügbar ist. Informationen zum Herunterladen des Erweiterungscodecs aus dem Microsoft Store finden Sie unter HEIF-Bilderweiterung.

Zwei Pixelformat-GUIDs ermöglichen Bildbetrachtern das Abrufen alternativer Darstellungen eines HEIF-Bilds.

  • Nur Tiefen
    • GUID_WICPixelFormat8bppDepth
  • Nur Bildverstärkung
    • GUID_WICPixelFormat8bppGain

Weitere Informationen zu diesen Formaten finden Sie in der Übersicht über native Pixelformate.

Mit der Aufzählung der Codierungsoptionen WICHeifCompressionOption können Apps auswählen, welches Komprimierungsformat beim Erstellen einer HEIF-Bilddatei verwendet werden soll.

Verwenden des HEIF-Erweiterungscodecs

Wenn Sie über eine App verfügen, die WIC verwendet, können Sie eine Pixelformat-GUID verwenden, um eine Anforderung zu stellen, wie das Bild dargestellt wird. Ihre App kann mithilfe der Methode IWICBitmapSourceTransform::GetClosestPixelFormat überprüfen, ob ein WIC-Decoder ein bestimmtes Pixelformat unterstützt.

Um ein Bild dann in eine Bitmap zu decodieren, die ein bestimmtes Pixelformat verwendet, kann Ihre App IWICBitmapSourceTransform::CopyPixels aufrufen.

Wenn beispielsweise ein Bild in eine Bitmap konvertiert wird, die das Pixelformat GUID_WICPixelFormat24bppRGB verwendet, bedeutet dies, dass die Bitmap rote, grüne und blaue Farbinformationen für jedes Pixel enthält. (8 Bit pro Farbkomponente.) GUID_WICPixelFormat32bppRGBA fügt jedem Pixel Alpha-Informationen (für Transparenz) hinzu. Das Pixelformat GUID_WICPixelFormat8bppAlpha wird für Bitmaps verwendet, die für jedes Pixel nur 8 Bit Alphainformationen enthalten.

Tiefen- und Bildverstärkungsinformationen für HEIF

Für HEIF-Dateien (High Efficiency Image Format) ist das Pixelformat GUID_WICPixelFormat8bppDepth relevant. Es funktioniert ähnlich wie GUID_WICPixelFormat8bppAlpha. Abgesehen davon, dass Alpha die Transparenz von Pixeln angibt, gibt die Tiefe den relativen Abstand von Pixeln vom Betrachter bzw. von der Betrachterin des Bilds an.

In einer Bitmap, die GUID_WICPixelFormat8bppDepth verwendet, enthält die Bitmap pro Pixel einen 8 Bit-Wert mit Tiefeninformationen. Ein Wert von 0 bedeutet, dass sich das zugehörige Pixel in der Farbbitmapdarstellung des Bilds am nähesten am Betrachter bzw. an der Betrachterin befindet. Ein Wert von 255 hingegen bedeutet, dass das entsprechende Pixel in der Farbbitmap am weitesten vom Betrachter bzw. der Betrachterin entfernt ist.

Außerdem gibt es für HEIF ein Pixelformat mit dem Namen GUID_WICPixelFormat8bppGain. Ähnlich wie bei den Pixelformaten für Alpha und Tiefe stellt GUID_WICPixelFormat8bppGain einen 8 Bit-Wert pro Pixel bereit. Der Zweck der Bildverstärkungsinformationen besteht darin, eine Helligkeitszunahme anzugeben, die auf die RGB-Formatpixel angewendet werden kann. So wird effektiv ein normales RGB-Bild in ein HDR-Bild (High Dynamic Range) konvertiert. Bildverstärkungsinformationen werden so verfügbar gemacht, wie sie sind. Ihre App kann die Exif- oder XMP-Metadaten im HEIF-Bild verwenden, um zu bestimmen, welches Kameramodell die Bildverstärkung generiert hat. Derzeit sind Bildverstärkungsinformationen nur in HEIF-Dateien enthalten, die von aktuellen Apple iOS-Geräten erstellt wurden.

Es gibt keine Standardinformation für die Tiefe oder die Bildverstärkung von Bildern. Das Aufrufen von IWICBitmapSourceTransform::CopyPixels, das eine Bildverstärkung oder Tiefendarstellung eines Bilds anfordert, das nicht über diese Informationen verfügt, führt zu einem WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT Fehler.

Optionen für die Komprimierung

Die Aufzählung WICHeifCompressionOption wird verwendet, um beim Codieren einer Bitmap im HEIF-Format eine Option mit dem Namen HeifCompressionMethod anzugeben.

HEIF ist ein Container, ähnlich wie TIFF, der verschiedene Komprimierungsmethoden verwenden kann. Die Standardkomprimierungsmethode ist der High-Efficiency Video Codec (HEVC). HEIF-Dateien, die mit HEVC komprimiert sind, verwenden in der Regel die Dateierweiterung .heic. Mit dem Enumerationswert WICHeifCompressionAV1 kann stattdessen angegeben werden, dass der AV1-Codec verwendet werden soll. HEIF-Dateien, die AV1 für die Komprimierung verwenden, verwenden in der Regel die Dateierweiterung .avif.

HEIF versucht, bestimmte Bearbeitungsfunktionen durchzuführen, z. B. Drehung und Zuschneiden, ohne das Bild erneut zu komprimieren. Sie können den Enumerationswert WICHeifCompressionNone verwenden, um zu erzwingen, dass das Bild nicht erneut komprimiert wird. Wenn das Bild erneut komprimiert werden muss, gibt der Commit-Vorgang WINCODEC_ERR_UNSUPPORTEDOPERATION zurück, wenn WICHeifCompressionNone angegeben wurde.

Die HEVC- und AV1-Codecs sind möglicherweise nicht auf allen PCs verfügbar. Sie können diese Codecs aus dem Microsoft Store herunterladen. Mit der Funktion MFTEnumEx können Sie überprüfen, ob HEVC oder AV1 installiert sind, indem Sie abfragen, ob ein Video-Encoder für die Formate MFVideoFormat_HEVC bzw . MFVideoFormat_AV1 vorhanden ist.

Codebeispiele

In diesem Beispiel werden die Windows-Implementierungsbibliotheken (WIL) verwendet. Eine bequeme Möglichkeit zum Installieren von WIL besteht darin, zu Visual Studio zu wechseln. Klicken Sie auf Projekt>NuGet-Pakete verwalten...>Durchsuchen, oder geben oder fügen Sie Microsoft.Windows.ImplementationLibrary in das Suchfeld ein. Wählen Sie das Element in den Suchergebnissen aus, und klicken Sie dann auf Installieren, um das Paket für dieses Projekt zu installieren.

Beispiel 1: Tiefe

In diesem Beispiel wird gezeigt, wie Sie überprüfen, ob Tiefeninformationen verfügbar sind und wie Sie diese abrufen.

using namespace wil;

bool IsPixelFormatSupported(_In_ IWICBitmapSourceTransform* bitmap, 
    REFWICPixelFormatGUID proposedPixelFormat)
{
    WICPixelFormatGUID closestPixelFormat = proposedPixelFormat;
    if (SUCCEEDED(bitmap->GetClosestPixelFormat(&closestPixelFormat)) &&
        closestPixelFormat == proposedPixelFormat)
    {
        return true;
    }
    return false;
}

bool IsDepthAvailable(_In_ IWICBitmapSourceTransform* bitmap)
{
    return IsPixelFormatSupported(bitmap, GUID_WICPixelFormat8bppDepth);
}

HRESULT GetDepthBitmap(_In_ IWICBitmapFrameDecode* frame, unique_cotaskmem_ptr<BYTE[]>& bitmap)
{
    bitmap.reset();

    com_ptr_nothrow<IWICBitmapSourceTransform> frameTransform;
    RETURN_IF_FAILED(com_query_to_nothrow(frame, &frameTransform));

    // Check whether depth information is available for this image. If there's no depth
    // information, then just return an empty bitmap.
    if (IsDepthAvailable(frameTransform.get()))
    {
        UINT width;
        UINT height;
        RETURN_IF_FAILED(frame->GetSize(&width, &height));

        size_t bitmapSize;
        RETURN_IF_FAILED(SizeTMult(width, height, &bitmapSize));

        bitmap = make_unique_cotaskmem_nothrow<BYTE[]>(bitmapSize);
        RETURN_IF_NULL_ALLOC(bitmap);

        WICPixelFormatGUID pixelFormat = GUID_WICPixelFormat8bppDepth;
        RETURN_IF_FAILED(frameTransform->CopyPixels(nullptr, width, height,
            &pixelFormat, WICBitmapTransformRotate0, width, bitmapSize, bitmap.get()));
    }
    return S_OK;
}

Beispiel 2: Bildverstärkung

In diesem Beispiel wird gezeigt, wie Sie überprüfen, ob Bildverstärkungsinformationen verfügbar sind und wie sie abgerufen werden. In diesem Beispiel wird die in Beispiel 1 gezeigte Funktion IsPixelFormatSupported wiederverwendet.

using namespace wil;

bool IsGainAvailable(_In_ IWICBitmapSourceTransform* bitmap)
{
    return IsPixelFormatSupported(bitmap, GUID_WICPixelFormat8bppGain);
}

HRESULT GetGainBitmap(_In_ IWICBitmapFrameDecode* frame, unique_cotaskmem_ptr<BYTE[]>& bitmap)
{
    bitmap.reset();

    com_ptr_nothrow<IWICBitmapSourceTransform> frameTransform;
    RETURN_IF_FAILED(com_query_to_nothrow(frame, &frameTransform));

    // Check whether gain information is available for this image. If there's no gain
    // information, then just return an empty bitmap.
    if (IsGainAvailable(frameTransform.get()))
    {
        UINT width;
        UINT height;
        RETURN_IF_FAILED(frame->GetSize(&width, &height));

        size_t bitmapSize;
        RETURN_IF_FAILED(SizeTMult(width, height, &bitmapSize));

        bitmap = make_unique_cotaskmem_nothrow<BYTE[]>(bitmapSize);
        RETURN_IF_NULL_ALLOC(bitmap);

        WICPixelFormatGUID pixelFormat = GUID_WICPixelFormat8bppGain;
        RETURN_IF_FAILED(frameTransform->CopyPixels(nullptr, width, height,
            &pixelFormat, WICBitmapTransformRotate0, width, bitmapSize, bitmap.get()));
    }
    return S_OK;
}

Beispiel 3: Festlegen, dass die AV1-Komprimierung verwendet werden muss

In diesem Beispiel wird gezeigt, wie Sie mithilfe der AV1-Komprimierung eine HEIF-Datei codieren und eine .avif-Datei erstellen.

using namespace wil;

HRESULT EncodeSourceAsAvif(IWICBitmapSource* source, IWICStream* outputStream, IWICImagingFactory* factory)
{
    com_ptr_nothrow<IWICBitmapEncoder> encoder;
    RETURN_IF_FAILED(factory->CreateEncoder(GUID_ContainerFormatHeif, nullptr, &encoder));
    RETURN_IF_FAILED(encoder->Initialize(outputStream, WICBitmapEncoderCacheInMemory));

    com_ptr_nothrow<IWICBitmapFrameEncode> outputFrame;
    com_ptr_nothrow<IPropertyBag2> encoderOptions;
    RETURN_IF_FAILED(encoder->CreateNewFrame(&outputFrame, &encoderOptions));

    // Configure the output frame to compress the source image using the AV1 encoder.
    PROPBAG2 option{};
    option.pstrName = L"HeifCompressionMethod";

    VARIANT propertyValue{};
    propertyValue.vt = VT_UI1;
    propertyValue.bVal = static_cast<BYTE>(WICHeifCompressionAV1);

    RETURN_IF_FAILED(encoderOptions->Write(1, &option, &propertyValue));
    RETURN_IF_FAILED(outputFrame->Initialize(encoderOptions.get()));
    RETURN_IF_FAILED(outputFrame->WriteSource(source, nullptr));

    // Do the actual encoding of the source image. If the AV1 encoder is missing,
    // then this call fails.
    RETURN_IF_FAILED(outputFrame->Commit());
    RETURN_IF_FAILED(encoder->Commit());
    return S_OK;
}

Beispiel 4: Festlegen, dass die Komprimierung nicht zulässig ist

In diesem Beispiel wird gezeigt, wie Sie ein Bild in einem HEIF-Container speichern, es drehen und zuschneidend. Dabei verbieten Sie jedoch auch, dass das Bild komprimiert wird. Wenn die Quelle bereits das HEVC- oder AV1-Format aufweist, ist diese Aktion erfolgreich. Wenn die Quelle jedoch eine unformatierte Bitmap oder ein anderes Format hat, gibt die Funktion einen Fehler zurück, wenn die Codierung nicht zulässig ist.

using namespace wil;

// Rotate and optionally crop the source image, and produce a HEIF image file as output.
// If the input parameter allowEncoding is false, and the image needs to be encoded,
// then this function will return WINCODEC_ERR_UNSUPPORTEDOPERATION.
HRESULT RotateAndCropSource(
    IWICBitmapSource* source,
    IWICStream* outputStream,
    IWICImagingFactory* factory,
    bool allowCompression,
    WICBitmapTransformOptions transformOptions,
    WICRect* cropRectangle = nullptr)
{
    com_ptr_nothrow<IWICBitmapEncoder> encoder;
    RETURN_IF_FAILED(factory->CreateEncoder(GUID_ContainerFormatHeif, NULL, &encoder));
    RETURN_IF_FAILED(encoder->Initialize(outputStream, WICBitmapEncoderCacheInMemory));

    com_ptr_nothrow<IWICBitmapFrameEncode> outputFrame;
    com_ptr_nothrow<IPropertyBag2> encoderOptions;
    RETURN_IF_FAILED(encoder->CreateNewFrame(&outputFrame, &encoderOptions));

    VARIANT propertyValue{};

    if (!allowCompression)
    {
        // Specify that compression of the image is not allowed.
        PROPBAG2 option{};
        option.pstrName = L"HeifCompressionMethod";

        propertyValue.vt = VT_UI1;
        propertyValue.bVal = static_cast<BYTE>(WICHeifCompressionNone);
        RETURN_IF_FAILED(encoderOptions->Write(1, &option, &propertyValue));
    }

    if (transformOptions != WICBitmapTransformRotate0)
    {
        PROPBAG2 option{};
        option.pstrName = L"BitmapTransform";

        propertyValue.vt = VT_UI1;
        propertyValue.bVal = static_cast<BYTE>(transformOptions);
        RETURN_IF_FAILED(encoderOptions->Write(1, &option, &propertyValue));
    }

    RETURN_IF_FAILED(outputFrame->Initialize(encoderOptions.get()));
    RETURN_IF_FAILED(outputFrame->WriteSource(source, cropRectangle));

    // Generate the HEIF file. If the image needs to be compressed, this call fails.
    RETURN_IF_FAILED(outputFrame->Commit());
    RETURN_IF_FAILED(encoder->Commit());
    return S_OK;
}