Поделиться через


Кодек расширения HEIF

Важно!

Некоторые сведения относятся к предварительному продукту, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

Сведения о кодеке расширения high efficiency Image Format (HEIF), доступном через WIC. Чтобы скачать кодек расширения из Microsoft Store, см . раздел "Расширение образа HEIF".

Два графических идентификатора формата пикселей позволяют зрителям фотографий получать альтернативные представления изображения HEIF.

  • Только для глубины
    • GUID_WICPixelFormat8bppDepth
  • Только получение
    • GUID_WICPixelFormat8bppGain

Дополнительные сведения об этих форматах см. в обзоре форматов собственных пикселей.

Перечисление параметров кодирования WICHeifCompressionOption позволяет приложениям выбирать формат сжатия, используемый при создании файла образа HEIF.

Использование кодека расширения HEIF

Если у вас есть приложение, использующее WIC, можно использовать GUID формата пикселей для запроса представления изображения. Приложение может проверка, поддерживает ли декодирования WIC определенный формат пикселей с помощью метода IWICBitmapSourceTransform::GetClosestPixelFormat.

Затем, чтобы декодировать изображение в растровое изображение, использующее определенный формат пикселей, приложение может вызывать IWICBitmapSourceTransform::CopyPixels.

Например, если изображение преобразуется в растровое изображение, использующее формат GUID_WICPixelFormat24bppRGB пикселя, то это означает, что растровое изображение содержит красные, зеленые и синие сведения о цвете для каждого пикселя. (8 бит на компонент цвета.) GUID_WICPixelFormat32bppRGBA добавляет к каждому пикселю информацию альфа (прозрачность). Формат пикселя GUID_WICPixelFormat8bppAlpha используется для растровых изображений, содержащих только 8-разрядную альфа-информацию для каждого пикселя.

Глубина и получение сведений для HEIF

Для файлов формата изображений с высокой эффективностью (HEIF) соответствующий формат пикселя GUID_WICPixelFormat8bppDepth . Он работает аналогично GUID_WICPixelFormat8bppAlpha. За исключением того, что альфа-символ указывает прозрачность пикселей, глубина указывает относительное расстояние пикселей от средства просмотра изображения.

В растровом рисунке, использующего GUID_WICPixelFormat8bppDepth, растровое изображение содержит 8-разрядное значение с информацией о глубине на пиксель. Значение 0 означает, что совместно расположенный пиксель в представлении растрового изображения цвета расположен ближе к средству просмотра; и значение 255 означает, что совместно расположенный пиксель в цветовой растровой карте находится в самом далеком от средства просмотра.

Кроме того, для HEIF есть формат пикселей с именем GUID_WICPixelFormat8bppGain. Аналогично форматам пикселей для альфа-и глубины, GUID_WICPixelFormat8bppGain предоставляет 8-разрядное значение на пиксель. Цель получения сведений заключается в том, чтобы указать увеличение яркости, которое можно применить к пикселям формата RGB: эффективно преобразовыв обычный RGB-образ в изображение высокого динамического диапазона (HDR). Получение сведений предоставляется как есть. Приложение может использовать метаданные Exif или XMP на изображении HEIF, чтобы определить, какая модель камеры вызвала получение. В настоящее время получение информации включается только в ФАЙЛЫ HEIF, созданные последними устройствами Apple iOS.

Для изображений нет глубины по умолчанию или получения сведений. Вызов IWICBitmapSourceTransform::CopyPixels , запрашивающий представление получения или глубины изображения, которое не имеет этой информации, приведет к ошибке WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT .

Параметры сжатия

Перечисление WICHeifCompressionOption используется для указания параметра с именем HeifCompressionMethod при кодировании растрового изображения в формате HEIF.

HEIF — это контейнер, аналогичный TIFF, который может использовать различные методы сжатия. Метод сжатия по умолчанию — это высокопроизводительный видеокодек (HEVC). ФАЙЛЫ HEIF, сжатые с помощью HEVC, обычно используют .heic расширение файла. При значении перечисления WICHeifCompressionAV1 можно указать, что кодек AV1 следует использовать вместо этого. HEIF-файлы, использующие AV1 для сжатия, обычно используют .avif расширение файла.

HEIF попытается выполнить определенные изменения, такие как поворот и обрезка, без повторного сжатия изображения. Значение перечисления WICHeifCompressionNone можно использовать для принудительного применения повторного сжатия образа. Если изображение необходимо повторно сжать, операция Commit вернет WINCODEC_ERR_UNSUPPORTEDOPERATION, если был указан WICHeifCompressionNone.

Кодеки HEVC и AV1 могут быть недоступны на всех компьютерах. Эти кодеки можно скачать из Microsoft Store. Чтобы проверка, установлены ли HEVC или AV1, можно использовать функцию MFTEnumEx для запроса наличия кодировщика видео для форматов MFVideoFormat_HEVC и MFVideoFormat_AV1 соответственно.

Примеры кода

В этих примерах кода используются библиотеки реализации Windows (WIL). Удобный способ установки WIL — перейти в Visual Studio, щелкните "Управление пакетами NuGet"...>>Просмотрите, введите или вставьте Microsoft.Windows.ImplementationLibrary в поле поиска, выберите элемент в результатах поиска и нажмите кнопку "Установить", чтобы установить пакет для этого проекта.

Пример 1. Глубина

В этом примере показано, как проверка, доступна ли информация о глубине и как получить ее.

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

Пример 2. Получение

В этом примере показано, как проверка доступно ли получение информации и как получить ее. В этом примере повторно используется функция IsPixelFormatSupported , показанная в примере 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;
}

Пример 3. Указание того, что необходимо использовать сжатие AV1

В этом примере показано, как использовать сжатие AV1 для кодирования ФАЙЛА HEIF, создания .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;
}

Пример 4. Указание недопустимого сжатия

В этом примере показано, как сохранить изображение в контейнере HEIF и применить поворот и обрезку к изображению; но принудительное применение изображения не сжимается. Если источник уже находится в формате HEVC или AV1, это завершится успешно. Но если источник является необработанным растровым изображением или в другом формате, функция вернет ошибку, если кодировка не разрешена.

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