Общие сведения о кодировке
Кодировщик записывает данные изображения в поток. Кодировщики могут сжимать, шифровать и изменять пиксели изображений несколькими способами, прежде чем записывать их в поток. Использование некоторых кодировщиков приводит к компромиссам, например JPEG, который позволяет лучше сжать информацию о цвете. Другие кодировщики не приводят к таким потерям, например растровое изображение (BMP). Так как многие кодеки используют собственную технологию для достижения лучшего сжатия и точности изображений, подробные сведения о том, как кодируется изображение, зависят от разработчика кодека.
Этот раздел включает следующие подразделы:
- IWICBitmapEncoder
- IWICBitmapFrameEncode
- Пример кодирования TIFF
- Использование параметров кодировщика
- Параметры кодировщика
- Примеры параметров кодировщика
- Связанные темы
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);
}
}
Связанные темы
-
Основные понятия
-
Другие ресурсы
Обратная связь
Отправить и просмотреть отзыв по