Bagikan melalui


Gambaran umum pengodean

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.

Encoder menulis data gambar ke aliran. Encoder dapat mengompresi, mengenkripsi, dan mengubah piksel gambar dengan sejumlah cara sebelum menulisnya ke aliran. Menggunakan beberapa encoder menghasilkan tradeoff—misalnya, JPEG, yang menukar informasi warna untuk pemadatan yang lebih baik. Encoder lain tidak mengakibatkan kerugian tersebut—misalnya, bitmap (BMP). Karena banyak codec menggunakan teknologi eksklusif untuk mencapai kompresi dan keakuratan gambar yang lebih baik, detail tentang bagaimana gambar dikodekan hingga pengembang codec.

IWICBitmapEncoder

IWICBitmapEncoder adalah antarmuka utama untuk mengodekan gambar ke format target dan digunakan untuk membuat serial komponen gambar, seperti gambar mini (SetThumbnail) dan bingkai (CreateNewFrame), ke file gambar.

Bagaimana dan kapan serialisasi terjadi diserahkan kepada pengembang codec. Setiap blok data individual dalam format file target harus dapat menetapkan independen dari urutan, tetapi sekali lagi, ini adalah keputusan pengembang codec. Namun, setelah metode Penerapan dipanggil, perubahan pada gambar tidak boleh diizinkan dan aliran harus ditutup.

IWICBitmapFrameEncode

IWICBitmapFrameEncode adalah antarmuka untuk mengodekan bingkai gambar individual. Ini menyediakan metode untuk mengatur komponen pencitraan bingkai individual, seperti gambar mini dan bingkai, serta dimensi gambar, DPI, dan format piksel.

Bingkai individual dapat dikodekan dengan metadata khusus bingkai sehingga IWICBitmapFrameEncode menyediakan akses ke penulis metadata melalui metode GetMetadataQueryWriter.

Metode Penerapan bingkai menerapkan semua perubahan pada bingkai individual dan menunjukkan bahwa perubahan pada bingkai tersebut tidak boleh lagi diterima.

Contoh pengodean (TIFF)

Dalam contoh berikut, gambar Format File Gambar Bertag (TIFF) dikodekan menggunakan IWICBitmapEncoder dan IWICBitmapFrameEncode. Output TIFF disesuaikan menggunakan WICTiffCompressionOption dan bingkai bitmap diinisialisasi menggunakan opsi yang diberikan. Setelah gambar dibuat menggunakan WritePixels, bingkai diterapkan dengan cara Penerapan dan gambar disimpan menggunakan Commit.

IWICImagingFactory *piFactory = NULL;
IWICBitmapEncoder *piEncoder = NULL;
IWICBitmapFrameEncode *piBitmapFrame = NULL;
IPropertyBag2 *pPropertybag = NULL;

IWICStream *piStream = NULL;
UINT uiWidth = 640;
UINT uiHeight = 480;

HRESULT hr = CoCreateInstance(
                CLSID_WICImagingFactory,
                NULL,
                CLSCTX_INPROC_SERVER,
                IID_IWICImagingFactory,
                (LPVOID*) &piFactory);

if (SUCCEEDED(hr))
{
    hr = piFactory->CreateStream(&piStream);
}

if (SUCCEEDED(hr))
{
    hr = piStream->InitializeFromFilename(L"output.tif", GENERIC_WRITE);
}

if (SUCCEEDED(hr))
{
   hr = piFactory->CreateEncoder(GUID_ContainerFormatTiff, NULL, &piEncoder);
}

if (SUCCEEDED(hr))
{
    hr = piEncoder->Initialize(piStream, WICBitmapEncoderNoCache);
}

if (SUCCEEDED(hr))
{
    hr = piEncoder->CreateNewFrame(&piBitmapFrame, &pPropertybag);
}

if (SUCCEEDED(hr))
{        
    // This is how you customize the TIFF output.
    PROPBAG2 option = { 0 };
    option.pstrName = L"TiffCompressionMethod";
    VARIANT varValue;    
    VariantInit(&varValue);
    varValue.vt = VT_UI1;
    varValue.bVal = WICTiffCompressionZIP;      
    hr = pPropertybag->Write(1, &option, &varValue);        
    if (SUCCEEDED(hr))
    {
        hr = piBitmapFrame->Initialize(pPropertybag);
    }
}

if (SUCCEEDED(hr))
{
    hr = piBitmapFrame->SetSize(uiWidth, uiHeight);
}

WICPixelFormatGUID formatGUID = GUID_WICPixelFormat24bppBGR;
if (SUCCEEDED(hr))
{
    hr = piBitmapFrame->SetPixelFormat(&formatGUID);
}

if (SUCCEEDED(hr))
{
    // We're expecting to write out 24bppRGB. Fail if the encoder cannot do it.
    hr = IsEqualGUID(formatGUID, GUID_WICPixelFormat24bppBGR) ? S_OK : E_FAIL;
}

if (SUCCEEDED(hr))
{
    UINT cbStride = (uiWidth * 24 + 7)/8/***WICGetStride***/;
    UINT cbBufferSize = uiHeight * cbStride;

    BYTE *pbBuffer = new BYTE[cbBufferSize];

    if (pbBuffer != NULL)
    {
        for (UINT i = 0; i < cbBufferSize; i++)
        {
            pbBuffer[i] = static_cast<BYTE>(rand());
        }

        hr = piBitmapFrame->WritePixels(uiHeight, cbStride, cbBufferSize, pbBuffer);

        delete[] pbBuffer;
    }
    else
    {
        hr = E_OUTOFMEMORY;
    }
}

if (SUCCEEDED(hr))
{
    hr = piBitmapFrame->Commit();
}    

if (SUCCEEDED(hr))
{
    hr = piEncoder->Commit();
}

if (piFactory)
    piFactory->Release();

if (piEncoder)
    piEncoder->Release();

if (piBitmapFrame)
    piBitmapFrame->Release();

if (pPropertybag)
    pPropertybag->Release();

if (piStream)
    piStream->Release();

return hr;

Penggunaan opsi encoder

Encoder yang berbeda untuk format yang berbeda perlu mengekspos opsi yang berbeda tentang bagaimana gambar dikodekan. Komponen Pencitraan Windows (WIC) menyediakan mekanisme yang konsisten untuk mengekspresikan apakah opsi pengodean diperlukan sambil tetap memungkinkan aplikasi untuk bekerja dengan beberapa encoder tanpa memerlukan pengetahuan tentang format tertentu. Ini dicapai dengan menyediakan parameter IPropertyBag pada metode CreateNewFrame dan metode Inisialisasi.

Pabrik komponen menyediakan titik pembuatan yang mudah untuk membuat kantong properti opsi encoder. Codec dapat menggunakan layanan ini jika perlu menyediakan serangkaian opsi encoder yang sederhana, intuitif, dan tidak bertentangan. Tas properti pencitraan harus diinisialisasi selama pembuatan dengan semua opsi encoder yang relevan dengan codec tersebut. Untuk opsi encoder dari set kanonis, rentang nilai akan diberlakukan pada Tulis. Untuk kebutuhan yang lebih canggih, codec harus menulis implementasi tas properti mereka sendiri.

Aplikasi diberi kantong opsi encoder selama pembuatan bingkai dan harus mengonfigurasi nilai apa pun sebelum menginisialisasi bingkai encoder. Untuk aplikasi berbasis UI, aplikasi ini dapat menawarkan UI tetap untuk opsi encoder kanonis dan tampilan tingkat lanjut untuk opsi yang tersisa. Perubahan dapat dilakukan satu per satu melalui metode Tulis dan kesalahan apa pun akan dilaporkan melalui IErrorLog. Aplikasi UI harus selalu membaca ulang dan menampilkan semua opsi setelah membuat perubahan jika perubahan menyebabkan efek kaskade. Aplikasi harus disiapkan untuk menangani inisialisasi bingkai yang gagal untuk codec yang hanya memberikan pelaporan kesalahan minimal melalui tas properti mereka.

Opsi encoder

Aplikasi dapat mengharapkan untuk menemukan serangkaian opsi encoder berikut. Opsi encoder mencerminkan kemampuan encoder dan format kontainer yang mendasar, dan oleh karena itu sifatnya tidak benar-benar codec-agnostic. Jika memungkinkan, opsi baru harus dinormalisasi sehingga dapat diterapkan ke codec baru yang muncul.

Nama Properti VARTYPE Value Codec yang berlaku
BitmapTransform VT_UI1 WICBitmapTransformOptions JPEG, HEIF
CompressionQuality VT_R4 0-1.0 TIFF
HeifCompressionMethod WICHeifCompressionOption Berbagai HEIF
ImageQuality VT_R4 0-1.0 JPEG, HDPhoto, HEIF
Lossless VT_BOOL TRUE, FALSE HDPhoto

ImageQualty 0.0 berarti rendisi keakuratan serendah mungkin dan 1,0 berarti keakuratan tertinggi, yang juga dapat menyiratkan lossless tergantung pada codec.

CompressionQuality 0.0 berarti skema kompresi paling tidak efisien yang tersedia, biasanya menghasilkan enkode cepat tetapi output yang lebih besar. Nilai 1,0 berarti skema paling efisien yang tersedia, biasanya membutuhkan lebih banyak waktu untuk mengodekan tetapi menghasilkan output yang lebih kecil. Tergantung pada kemampuan codec, rentang ini dapat dipetakan ke set diskrit metode kompresi yang tersedia.

Lossless berarti bahwa codec mengodekan gambar sebagai lossless tanpa kehilangan data gambar. Jika Lossless diaktifkan, ImageQuality diabaikan.

Selain opsi encoder generik di atas, codec yang disediakan dengan WIC mendukung opsi berikut. Jika codec memiliki kebutuhan untuk mendukung opsi yang konsisten dengan penggunaan dalam codec yang disediakan ini, dianjurkan untuk melakukannya.

Nama Properti VARTYPE Value Codec yang berlaku
InterlaceOption VT_BOOL Aktif/Nonaktif PNG
FilterOption VT_UI1 WICPngFilterOption PNG
TiffCompressionMethod VT_UI1 WICTiffCompressionOption TIFF
Luminance VT_UI4/VT_ARRAY 64 Entri (DCT) JPEG
Krominasi VT_UI4/VT_ARRAY 64 Entri (DCT) JPEG
JpegYCrCbSubsampling VT_UI1 WICJpegYCrCbSubsamplingOption JPEG
SuppressApp0 VT_BOOL JPEG
EnableV5Header32bppBGRA VT_BOOL Aktif/Nonaktif BMP

Gunakan VT_EMPTY untuk menunjukkan *tidak diatur* sebagai default. Jika properti tambahan diatur tetapi tidak didukung, encoder harus mengabaikannya; ini memungkinkan aplikasi untuk mengkodekan lebih sedikit logika jika mereka menginginkan kemampuan yang mungkin atau mungkin tidak ada.

Contoh opsi encoder

Dalam contoh pengodean TIFF di atas, opsi encoder tertentu diatur. Anggota pstrName dari struktur PROPBAG2 diatur ke nama properti yang sesuai, dan VARIANT diatur ke VARTYPE yang sesuai dan nilai yang diinginkan—dalam hal ini, anggota enumerasi WICTiffCompressionOption .

if (SUCCEEDED(hr))
{
    hr = piEncoder->CreateNewFrame(&piBitmapFrame, &pPropertybag);
}

if (SUCCEEDED(hr))
{        
    // This is how you customize the TIFF output.
    PROPBAG2 option = { 0 };
    option.pstrName = L"TiffCompressionMethod";
    VARIANT varValue;    
    VariantInit(&varValue);
    varValue.vt = VT_UI1;
    varValue.bVal = WICTiffCompressionZIP;      
    hr = pPropertybag->Write(1, &option, &varValue);        
    if (SUCCEEDED(hr))
    {
        hr = piBitmapFrame->Initialize(pPropertybag);
    }
}

Untuk menggunakan opsi encoder default, cukup inisialisasi bingkai bitmap dengan tas properti yang dikembalikan saat bingkai dibuat.

if (SUCCEEDED(hr))
{
    hr = piEncoder->CreateNewFrame(&piBitmapFrame, &pPropertybag);
}

if (SUCCEEDED(hr))
{        
    // Accept the default encoder options.
    if (SUCCEEDED(hr))
    {
        hr = piBitmapFrame->Initialize(pPropertybag);
    }
}

Dimungkinkan juga untuk menghilangkan tas properti ketika tidak ada opsi encoder yang dipertimbangkan.

if (SUCCEEDED(hr))
{
    hr = piEncoder->CreateNewFrame(&piBitmapFrame, 0);
}

if (SUCCEEDED(hr))
{        
    // No encoder options.
    if (SUCCEEDED(hr))
    {
        hr = piBitmapFrame->Initialize(0);
    }
}