Kodek ekstensi HEIF

Penting

Beberapa informasi berkaitan dengan produk prarilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.

Info tentang codec ekstensi High Efficiency Image Format (HEIF) yang tersedia melalui WIC. Untuk mengunduh codec ekstensi dari Microsoft Store, lihat Ekstensi Gambar HEIF.

GUID format dua piksel memungkinkan penampil foto untuk mengambil representasi alternatif dari gambar HEIF.

  • Khusus kedalaman
    • GUID_WICPixelFormat8bppDepth
  • Perolehan saja
    • GUID_WICPixelFormat8bppGain

Untuk informasi selengkapnya tentang format tersebut, lihat Gambaran umum format piksel asli.

Enumerasi WICHeifCompressionOption dari opsi pengodean memungkinkan aplikasi untuk memilih format kompresi mana yang akan digunakan saat membuat file gambar HEIF.

Menggunakan kodek ekstensi HEIF

Jika Anda memiliki aplikasi yang menggunakan WIC, maka Anda dapat menggunakan GUID format piksel untuk meminta bagaimana gambar diwakili. Aplikasi Anda dapat memeriksa apakah dekoder WIC mendukung format piksel tertentu dengan menggunakan metode IWICBitmapSourceTransform::GetClosestPixelFormat .

Kemudian, untuk mendekode gambar ke dalam bitmap yang menggunakan format piksel tertentu, aplikasi Anda dapat memanggil IWICBitmapSourceTransform::CopyPixels.

Misalnya, jika gambar dikonversi menjadi bitmap yang menggunakan format piksel GUID_WICPixelFormat24bppRGB , maka itu berarti bahwa bitmap berisi informasi warna merah, hijau, dan biru untuk setiap piksel. (8 bit per komponen warna.) GUID_WICPixelFormat32bppRGBA menambahkan informasi alfa (transparansi) ke setiap piksel. Format piksel GUID_WICPixelFormat8bppAlpha digunakan untuk bitmap yang hanya berisi informasi alfa 8-bit untuk setiap piksel.

Info kedalaman dan perolehan untuk HEIF

Untuk file Format Gambar Efisiensi Tinggi (HEIF), format piksel GUID_WICPixelFormat8bppDepth relevan. Cara kerjanya mirip dengan GUID_WICPixelFormat8bppAlpha. Kecuali bahwa sementara alfa menentukan transparansi piksel, kedalaman menentukan jarak relatif piksel dari penampil gambar.

Dalam bitmap yang menggunakan GUID_WICPixelFormat8bppDepth, bitmap berisi nilai 8-bit dengan informasi kedalaman per piksel. Nilai 0 berarti bahwa piksel yang terletak bersama dalam representasi bitmap warna gambar terletak terdekat dengan penampil; dan nilai 255 berarti bahwa piksel yang terletak bersama di bitmap warna terletak paling jauh dari penampil.

Selain HEIF, ada format piksel bernama GUID_WICPixelFormat8bppGain. Mirip dengan format piksel untuk alfa dan kedalaman, GUID_WICPixelFormat8bppGain menyediakan nilai 8-bit per piksel. Tujuan dari informasi perolehan adalah untuk menentukan perolehan kecerahan yang dapat diterapkan ke piksel format RGB: secara efektif mengonversi gambar RGB normal menjadi gambar Rentang Dinamis Tinggi (HDR). Informasi perolehan diekspos apa adanya. Aplikasi Anda dapat menggunakan metadata Exif atau XMP dalam gambar HEIF untuk menentukan model kamera mana yang telah menghasilkan keuntungan. Saat ini, informasi perolehan hanya disertakan dalam file HEIF yang dibuat oleh perangkat Apple iOS terbaru.

Tidak ada informasi kedalaman atau perolehan default untuk gambar. Memanggil IWICBitmapSourceTransform::CopyPixels yang meminta representasi keuntungan atau kedalaman gambar yang tidak memiliki informasi tersebut akan mengakibatkan kesalahan WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT .

Opsi pemadatan

Enumerasi WICHeifCompressionOption digunakan untuk menentukan opsi bernama HeifCompressionMethod saat mengodekan bitmap ke dalam format HEIF.

HEIF adalah kontainer, mirip dengan TIFF, yang dapat menggunakan metode kompresi yang berbeda. Metode kompresi default adalah High-Efficiency Video Codec (HEVC). File HEIF yang dikompresi dengan HEVC biasanya menggunakan .heic ekstensi file. Dengan nilai enum WICHeifCompressionAV1, akan menjadi mungkin untuk menentukan bahwa codec AV1 harus digunakan sebagai gantinya. File HEIF yang menggunakan AV1 untuk pemadatan biasanya menggunakan .avif ekstensi file.

HEIF akan mencoba melakukan pengeditan tertentu, seperti rotasi dan pemotongan, tanpa mengkompresi ulang gambar. Anda dapat menggunakan nilai enum WICHeifCompressionNone untuk memberlakukan bahwa gambar tidak dikompresi ulang. Jika gambar perlu dikompresi ulang, maka operasi Penerapan akan mengembalikan WINCODEC_ERR_UNSUPPORTEDOPERATION jika WICHeifCompressionNone telah ditentukan.

Codec HEVC dan AV1 mungkin tidak tersedia di semua PC. Anda dapat mengunduh codec tersebut dari Microsoft Store. Untuk memeriksa apakah HEVC atau AV1 diinstal, Anda dapat menggunakan fungsi MFTEnumEx untuk mengkueri keberadaan encoder video untuk format MFVideoFormat_HEVC dan MFVideoFormat_AV1.

Contoh kode

Contoh kode ini menggunakan Windows Implementation Libraries (WIL). Cara mudah untuk menginstal WIL adalah dengan membuka Visual Studio, klik Proyek>Kelola Paket NuGet...>Telusuri, ketik, atau tempel Microsoft.Windows.ImplementationLibrary di kotak pencarian, pilih item di hasil pencarian, lalu klik Instal untuk menginstal paket untuk proyek tersebut.

Contoh 1: Kedalaman

Contoh ini menunjukkan cara memeriksa apakah informasi kedalaman tersedia, dan cara mengambilnya.

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

Contoh 2: Keuntungan

Contoh ini menunjukkan cara memeriksa apakah informasi perolehan tersedia, dan cara mengambilnya. Contoh ini menggunakan kembali fungsi IsPixelFormatSupported yang diperlihatkan dalam Contoh 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;
}

Contoh 3: Menentukan bahwa kompresi AV1 harus digunakan

Contoh ini menunjukkan cara menggunakan kompresi AV1 untuk mengodekan file HEIF, membuat .avif file.

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

Contoh 4: Menentukan bahwa pemadatan tidak diizinkan

Contoh ini menunjukkan cara menyimpan gambar dalam kontainer HEIF dan menerapkan rotasi dan pemotongan ke gambar; tetapi memberlakukan bahwa gambar tidak dikompresi. Jika sumber sudah dalam format HEVC atau AV1, maka sumber tersebut akan berhasil. Tetapi jika sumbernya adalah bitmap mentah atau dalam beberapa format lain, maka fungsi akan mengembalikan kesalahan jika pengodean tidak diizinkan.

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