Lire en anglais

Partager via


Codec d’extension HEIF

Important

Certaines informations portent sur la préversion du produit qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Informations sur l’extension codec HEIF (Format d’image à haute efficacité) disponible via WIC. Pour télécharger le codec d’extension à partir du Microsoft Store, consultez l’extension d’image HEIF.

Deux GUID de formats de pixel permettent aux visionneuses photo d’extraire d’autres représentations d’une image HEIF.

  • Profondeur uniquement
    • GUID_WICPixelFormat8bppDepth
  • Gain uniquement
    • GUID_WICPixelFormat8bppGain

Pour plus d’informations sur ces formats, consultez la vue d’ensemble des formats de pixel natif.

L’énumération WICHeifCompressionOption des options d’encodage permet aux applications de choisir le format de compression à utiliser lors de la création d’un fichier image HEIF.

Utilisation du codec d’extension HEIF

Si vous avez une application qui utilise WIC, vous pouvez utiliser un GUID de format pixel pour demander comment l'image est représentée. Votre application peut vérifier si un décodeur WIC prend en charge un format de pixel spécifique à l’aide de la méthode IWICBitmapSourceTransform::GetClosestPixelFormat.

Ensuite, pour décoder une image dans une bitmap qui utilise un format de pixel spécifique, votre application peut appeler IWICBitmapSourceTransform::CopyPixels.

Par exemple, si une image est convertie en image bitmap qui utilise le format GUID_WICPixelFormat24bppRGB pixels, cela signifie que la bitmap contient des informations de couleur rouge, verte et bleue pour chaque pixel. (8 bits par composante de couleur.) GUID_WICPixelFormat32bppRGBA ajoute des informations alpha (transparence) à chaque pixel. Le format de pixel GUID_WICPixelFormat8bppAlpha est utilisé pour les bitmaps qui contiennent uniquement des informations alpha 8 bits pour chaque pixel.

Informations sur la profondeur et le gain pour HEIF

Pour les fichiers HEIF (High Efficiency Image Format), le format de pixel GUID_WICPixelFormat8bppDepth est pertinent. Il fonctionne de la même façon que GUID_WICPixelFormat8bppAlpha. Sauf que si alpha spécifie la transparence des pixels, la profondeur spécifie la distance relative des pixels de la visionneuse de l’image.

Dans une bitmap qui utilise GUID_WICPixelFormat8bppDepth, la bitmap contient une valeur de 8 bits avec des informations de profondeur par pixel. Une valeur de 0 signifie que le pixel co-localisé dans la représentation bitmap couleur de l'image est situé le plus près de l'observateur ; et une valeur de 255 signifie que le pixel co-localisé dans la représentation bitmap couleur est situé le plus loin de l'observateur.

En outre, pour HEIF, il existe un format de pixel nommé GUID_WICPixelFormat8bppGain. Comme pour les formats de pixels alpha et de profondeur, GUID_WICPixelFormat8bppGain fournit une valeur de 8 bits par pixel. L’objectif des informations de gain est de spécifier un gain de luminosité qui peut être appliqué aux pixels au format RVB : conversion efficace d’une image RVB normale en image HDR (High Dynamic Range). Les informations sur les gains sont exposées telles quelles. Votre application peut utiliser les métadonnées Exif ou XMP de l'image HEIF pour déterminer le modèle de caméra qui a généré le gain. Actuellement, les informations sur les gains ne sont incluses que dans les fichiers HEIF créés par les appareils iOS récents d'Apple.

Il n’y a pas de profondeur par défaut ni d’informations sur les images. Appel de IWICBitmapSourceTransform::CopyPixels demandant une représentation de gain ou de profondeur d’une image qui n’a pas ces informations entraîne une erreur WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT.

Options de compression

L’énumération WICHeifCompressionOption est utilisée pour spécifier une option nommée HeifCompressionMethod lors de l’encodage d’une bitmap au format HEIF.

HEIF est un conteneur, similaire à TIFF, qui peut utiliser différentes méthodes de compression. La méthode de compression par défaut est le codec vidéo haute efficacité (HEVC). Les fichiers HEIF compressés avec HEVC utilisent généralement l’extension de fichier .heic. Avec la valeur d’énumération WICHeifCompressionAV1, il sera possible de spécifier que le codec AV1 doit être utilisé à la place. Les fichiers HEIF qui utilisent AV1 pour la compression utilisent généralement l’extension de fichier .avif.

HEIF tente d’effectuer certaines modifications, telles que la rotation et le recadrage, sans recompresser l’image. Vous pouvez utiliser la valeur d’énumération WICHeifCompressionNone pour appliquer que l’image n’est pas compressée. Si l’image doit être re compressée, l’opération Commit retourne WINCODEC_ERR_UNSUPPORTEDOPERATION si WICHeifCompressionNone a été spécifié.

Les codecs HEVC et AV1 peuvent ne pas être disponibles sur tous les PC. Vous pouvez télécharger ces codecs à partir du Microsoft Store. Pour vérifier si HEVC ou AV1 sont installés, vous pouvez utiliser la fonction MFTEnumEx pour rechercher la présence d’un encodeur vidéo pour les formats MFVideoFormat_HEVC et MFVideoFormat_AV1, respectivement.

Exemples de code

Ces exemples de code utilisent les bibliothèques d’implémentation Windows (WIL). Le plus simple pour installer les bibliothèques WIL est de procéder comme suit : accédez à Visual Studio, cliquez sur Projet>Gérer les packages NuGet>Parcourir, tapez ou collez Microsoft.Windows.ImplementationLibrary dans la zone de recherche, sélectionnez l’élément dans les résultats de la recherche, puis cliquez sur Installer pour installer le package correspondant à ce projet.

Exemple 1 : profondeur

Cet exemple montre comment vérifier si les informations sur la profondeur sont disponibles et comment les récupérer.

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

Exemple 2 : gain

Cet exemple montre comment vérifier si les informations sur le gain sont disponibles et comment les récupérer. Cet exemple réutilise la fonction IsPixelFormatSupported illustrée dans l’exemple 1.

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

Exemple 3 : spécifier que la compression AV1 doit être utilisée

Cet exemple montre comment utiliser la compression AV1 pour encoder un fichier HEIF, en créant un fichier .avif.

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

Exemple 4 : spécifier que la compression n’est pas autorisée

Cet exemple montre comment enregistrer une image dans un conteneur HEIF et lui appliquer une rotation et un recadrage, tout en veillant à ce que l'image ne soit pas compressée. Si la source est déjà au format HEVC ou AV1, cela réussira. Mais si la source est une image bitmap brute ou un autre format, la fonction renverra une erreur si l'encodage n'est pas autorisé.

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