Общие сведения о кодировке

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

Этот раздел включает следующие подразделы:

IWICBitmapEncoder

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

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

IWICBitmapFrameEncode

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

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

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

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

В следующем примере изображение TIFF кодируется с помощью IWICBitmapEncoder и IWICBitmapFrameEncode. Выходные данные TIFF настраиваются с помощью WICTiffCompressionOption , а точечный кадр инициализируется с помощью заданных параметров. После создания образа с помощью WritePixels кадр фиксируется путем фиксации , а изображение сохраняется с помощью параметра Фиксация.

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 Значение Применимые кодеки
ImageQuality VT_R4 0-1.0 JPEG, HDPhoto
CompressionQuality VT_R4 0-1.0 TIFF
Lossless VT_BOOL. TRUE, FALSE HDPhoto
BitmapTransform VT_UI1 WICBitmapTransformOptions JPEG

 

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

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

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

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

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

 

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

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

В приведенном выше примере кодировки 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);
    }
}

Основные понятия

Общие сведения о компоненте обработки образов Windows

Общие сведения о декодировании

Другие ресурсы

Создание кодека WIC-Enabled