Общие сведения о Службе кодирования

Важно!

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

Кодировщик записывает данные изображения в поток. Кодировщики могут сжимать, шифровать и изменять пиксели изображения несколькими способами до их записи в поток. Использование некоторых кодировщиков приводит к компромиссам, например JPEG, что позволяет лучше сжать сведения о цвете. Другие кодировщики не приводят к таким потерям, например растровое изображение (BMP). Так как многие кодеки используют собственную технологию для повышения точности сжатия и изображения, сведения о том, как изображение закодировано, зависит от разработчика кодека.

IWICBitmapEncoder

IWICBitmapEncoder — это основной интерфейс для кодирования изображения в целевом формате и используется для сериализации компонентов изображения, таких как эскиз (SetThumbnail) и кадры (CreateNewFrame) в файл изображения.

Как и когда сериализация возникает до разработчика кодека. Каждый отдельный блок данных в целевом формате файла должен иметь возможность задать независимо от порядка, но, опять же, это решение разработчика кодека. После вызова метода Commit изменения изображения не должны быть разрешены, и поток должен быть закрыт.

IWICBitmapFrameEncode

IWICBitmapFrameEncode — это интерфейс для кодирования отдельных кадров изображения. Он предоставляет методы настройки отдельных компонентов изображения кадров, таких как эскизы и кадры, а также измерения изображений, DPI и форматы пикселей.

Отдельные кадры могут быть закодированы с помощью метаданных, зависящих от кадра, поэтому IWICBitmapFrameEncode предоставляет доступ к записи метаданных с помощью метода GetMetadataQueryWriter.

Метод commit кадра фиксирует все изменения в отдельном кадре и указывает, что изменения в этом кадре больше не должны приниматься.

Пример кодирования (TIFF)

В следующем примере изображение формата файла тегов (TIFF) закодировано с помощью IWICBitmapEncoder и IWICBitmapFrameEncode. Выходные данные TIFF настраиваются с помощью WICTiffCompressionOption , а кадр растрового изображения инициализируется с помощью заданных параметров. После создания образа с помощью WritePixels кадр фиксируется путем фиксации, а изображение сохраняется с помощью 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;

Использование параметров кодировщика

Различные кодировщики для разных форматов должны предоставлять различные параметры кодирования изображения. Компонент образов Windows (WIC) предоставляет согласованный механизм для определения необходимости параметров кодирования, позволяя приложениям работать с несколькими кодировщиками без необходимости знать определенный формат. Это достигается путем предоставления параметра IPropertyBag в методе CreateNewFrame и методе Initialize.

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

Приложение получает пакет параметров кодировщика во время создания кадра и должен настроить все значения перед инициализацией кадра кодировщика. Для приложения, управляемого пользовательским интерфейсом, он может предложить фиксированный пользовательский интерфейс для параметров канонического кодировщика и расширенное представление для оставшихся параметров. Изменения можно вносить по одному за раз с помощью метода Write, и любая ошибка будет сообщаться через IErrorLog. Приложение пользовательского интерфейса всегда должно повторно считывать и отображать все параметры после внесения изменений в случае изменения, вызвавшего каскадный эффект. Приложение должно быть готово к обработке неудачной инициализации кадров для кодеков, которые предоставляют только минимальные отчеты об ошибках через контейнер свойств.

Параметры кодировщика

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

Имя свойства VARTYPE Значение Применимые кодеки
BitmapTransform VT_UI1 WICBitmapTransformOptions JPEG, HEIF
СжатиеQuality VT_R4 0-1.0 TIFF
HeifCompressionMethod WICHeifCompressionOption различные HEIF
ImageQuality VT_R4 0-1.0 JPEG, HDPhoto, HEIF
Без потерь VT_BOOL. TRUE, FALSE HDPhoto

ImageQualty 0.0 означает наименьшее возможное представление точности и 1.0 означает самую высокую точность, которая также может означать потерю в зависимости от кодека.

CompressionQuality 0.0 означает наименьшую эффективную схему сжатия, что обычно приводит к быстрому кодированию, но больше выходных данных. Значение 1.0 означает, что наиболее эффективная схема доступна, как правило, занимает больше времени для кодирования, но создает меньшие выходные данные. В зависимости от возможностей кодека этот диапазон может быть сопоставлен с дискретным набором доступных методов сжатия.

Без потери означает, что кодек кодека закодирована как потеря данных изображения без потери данных изображения. Если включена потеря, ImageQuality игнорируется.

Помимо приведенных выше параметров универсального кодировщика кодеки, предоставляемые WIC, поддерживают следующие параметры. Если кодек должен поддерживать вариант, соответствующий использованию в этих указанных кодеках, рекомендуется сделать это.

Имя свойства VARTYPE Значение Применимые кодеки
InterlaceOption VT_BOOL. Вкл./Выкл. PNG
FilterOption VT_UI1 WICPngFilterOption PNG
TiffCompressionMethod VT_UI1 WICTiffCompressionOption TIFF
Освещенность VT_UI4/VT_ARRAY 64 записи (DCT) JPEG
Цветности VT_UI4/VT_ARRAY 64 записи (DCT) JPEG
JpegYCrCbSubsampling VT_UI1 WICJpegYCrCbSubsamplingOption JPEG
ПодавлениеApp0 VT_BOOL. JPEG
EnableV5Header32bppBGRA VT_BOOL. Вкл./Выкл. BMP

Используйте VT_EMPTY , чтобы указать *not set* в качестве значения по умолчанию. Если заданы дополнительные свойства, но не поддерживаются, кодировщик должен игнорировать их; это позволяет приложениям кодировать меньше логики, если они хотят возможности, которые могут или не могут присутствовать.

Примеры параметров кодировщика

В приведенном выше примере кодирования TIFF устанавливается определенный параметр кодировщика. Для элемента pstrName структуры PROPBAG2 задано соответствующее имя свойства, а параметр VARIANT имеет соответствующее значение VARTYPE и требуемое значение, в данном случае член перечисления 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);
    }
}

Чтобы использовать параметры кодировщика по умолчанию, просто инициализировать кадр растрового изображения с помощью контейнера свойств, возвращаемого при создании кадра.

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

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

Кроме того, можно исключить контейнер свойств при отсутствии параметров кодировщика.

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

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