Compartilhar via


Codec de extensão HEIF

Importante

Algumas informações referem-se a um produto de pré-lançamento que pode ser substancialmente modificado antes de ser lançado comercialmente. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Informações sobre o codec de extensão HEIF (Formato de Imagem de Alta Eficiência) disponível por meio do WIC. Para baixar o codec de extensão da Microsoft Store, consulte a Extensão de Imagem HEIF.

As duas GUIDs de formato de pixel permitem que os visualizadores de fotos recuperem representações alternativas de uma imagem HEIF.

  • Somente profundidade
    • GUID_WICPixelFormat8bppDepth
  • Somente ganho
    • GUID_WICPixelFormat8bppGain

Para obter mais informações sobre esses formatos, consulte a visão geral dos formatos de pixel nativos.

A enumeração WICHeifCompressionOption de opções de codificação permite que os aplicativos escolham qual formato de compactação usar ao criar um arquivo de imagem HEIF.

Usando o codec de extensão HEIF

Se você tiver um aplicativo que usa WIC, poderá usar um GUID de formato de pixel para solicitar como a imagem é representada. Seu aplicativo pode verificar se um decodificador WIC dá suporte a um formato de pixel específico usando o método IWICBitmapSourceTransform::GetClosestPixelFormat.

Em seguida, para decodificar uma imagem em um bitmap que usa um formato de pixel específico, seu aplicativo pode chamar IWICBitmapSourceTransform::CopyPixels.

Por exemplo, se uma imagem for convertida em um bitmap que usa o formato de pixel GUID_WICPixelFormat24bppRGB, isso significa que o bitmap contém informações de cor vermelha, verde e azul para cada pixel. (8 bits por componente de cor.) GUID_WICPixelFormat32bppRGBA adiciona informações alfa (transparência) a cada pixel. O formato de pixel GUID_WICPixelFormat8bppAlpha é usado para bitmaps que contêm apenas informações alfa de 8 bits para cada pixel.

Informações de profundidade e ganho para HEIF

Para arquivos HEIF (Formato de Imagem de Alta Eficiência), o formato de pixel GUID_WICPixelFormat8bppDepth é relevante. Ele funciona da mesma forma para GUID_WICPixelFormat8bppAlpha. Exceto que, embora alfa especifique a transparência dos pixels, a profundidade especifica a distância relativa dos pixels do visualizador da imagem.

Em um bitmap que usa GUID_WICPixelFormat8bppDepth, o bitmap contém um valor de 8 bits com informações de profundidade por pixel. Um valor de 0 significa que o pixel co-localizado na representação de bitmap de cor da imagem está localizado mais próximo do visualizador; e um valor de 255 significa que o pixel co-localizado no bitmap de cor está localizado mais distante do visualizador.

Além disso, para HEIF, há um formato de pixel chamado GUID_WICPixelFormat8bppGain. Semelhante aos formatos de pixel para alfa e profundidade, GUID_WICPixelFormat8bppGain fornece um valor de 8 bits por pixel. A finalidade das informações de ganho é especificar um ganho de brilho que pode ser aplicado aos pixels de formato RGB: convertendo efetivamente uma imagem RGB normal em uma imagem HDR (Alto Intervalo Dinâmico). As informações de ganho são expostas como estão. Seu aplicativo pode usar os metadados Exif ou XMP na imagem HEIF para determinar qual modelo de câmera gerou o ganho. Atualmente, obter informações é incluído apenas em arquivos HEIF que foram criados por dispositivos Apple iOS recentes.

Não há informações de profundidade ou ganho padrão para imagens. Chamar IWICBitmapSourceTransform::CopyPixels solicitando uma representação de ganho ou profundidade de uma imagem que não tenha essas informações resultará em um erro WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT.

Opções de compactação

A enumeração WICHeifCompressionOption é usada para especificar uma opção chamada HeifCompressionMethod ao codificar um bitmap no formato HEIF.

HEIF é um contêiner, semelhante ao TIFF, que pode usar métodos de compactação diferentes. O método de compactação padrão é o HEVC (Codec de Vídeo de Alta Eficiência). Os arquivos HEIF compactados com HEVC normalmente usam a extensão de arquivo .heic. Com o valor de enumeração WICHeifCompressionAV1, será possível especificar que o codec AV1 deve ser usado. Arquivos HEIF que usam AV1 para compactação normalmente usam a extensão de arquivo .avif.

O HEIF tentará fazer determinadas edições, como rotação e corte, sem compactar novamente a imagem. Você pode usar o valor de enumeração WICHeifCompressionNone para impor que a imagem não seja recompactada. Se a imagem precisar ser recompactada, a operação Commit retornará WINCODEC_ERR_UNSUPPORTEDOPERATION se WICHeifCompressionNone tiver sido especificado.

Os codecs HEVC e AV1 podem não estar disponíveis em todos os computadores. Você pode baixar esses codecs da Microsoft Store. Para verificar se o HEVC ou o AV1 estão instalados, você pode usar a função MFTEnumEx para consultar a presença de um codificador de vídeo para os formatos MFVideoFormat_HEVC e MFVideoFormat_AV1, respectivamente.

Exemplos de código

Esses exemplos de código usam as Bibliotecas de Implementação do Windows (WIL). Uma maneira conveniente de instalar o WIL é acessar o Visual Studio, clicar em Projeto>Gerenciar Pacotes NuGet...>Procurar, digitar ou colar Microsoft.WIndows.ImplementationLibrary na caixa de pesquisa, selecionar o item nos resultados da pesquisa e clicar em Instalar para instalar o pacote para esse projeto.

Exemplo 1: Profundidade

Este exemplo mostra como verificar se as informações de profundidade estão disponíveis e como recuperá-las.

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

Exemplo 2: Ganho

Este exemplo mostra como verificar se as informações de ganho estão disponíveis e como recuperá-las. Este exemplo reutiliza a função IsPixelFormatSupported mostrada no Exemplo 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;
}

Exemplo 3: Especificando que a compactação AV1 deve ser usada

Este exemplo mostra como usar a compactação AV1 para codificar um arquivo HEIF, criando um arquivo .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;
}

Exemplo 4: especificar que a compactação não é permitida

Este exemplo mostra como salvar uma imagem em um contêiner HEIF e aplicar rotação e corte à imagem; mas impondo que a imagem não está sendo compactada. Se a origem já estiver no formato HEVC ou AV1, isso dará certo. Mas se a origem for um bitmap bruto ou em algum outro formato, a função retornará um erro se a codificação não for permitida.

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