Visão Geral de Codificação

Importante

Algumas informações referem-se a um produto de pré-lançamento que pode ser substancialmente modificado antes de ser lançado comercialmente. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Um codificador grava dados de imagem em um fluxo. Os codificadores podem compactar, criptografar e alterar os pixels de imagem de várias maneiras antes de escrevê-los no fluxo. O uso de alguns codificadores resulta em compensações – por exemplo, JPEG, que troca mais informações de cor por uma melhor compactação. Outros codificadores não resultam em tais perdas – por exemplo, bitmap (BMP). Como muitos codecs usam tecnologia proprietária para obter melhor compactação e fidelidade de imagem, os detalhes sobre como uma imagem é codificada ficam a cargo do desenvolvedor do codec.

IWICBitmapEncoder

IWICBitmapEncoder é a interface principal para codificar uma imagem no formato de destino, e é usada para serializar os componentes de uma imagem, como a miniatura (SetThumbnail) e os quadros (CreateNewFrame), para o arquivo de imagem.

Como e quando ocorre a serialização é deixado para que o desenvolvedor do codec resolva. Cada bloco individual de dados dentro do formato de arquivo de destino deve ser capaz de ser definido independentemente da ordem, mas, novamente, essa é decisão cabe ao desenvolvedor do codec. No entanto, depois que o método Commit for chamado, as alterações na imagem não deverão ser permitidas e o fluxo deverá ser fechado.

IWICBitmapFrameEncode

IWICBitmapFrameEncode é a interface para codificar os quadros individuais de uma imagem. Ela fornece métodos para definir componentes individuais de quadro de uma imagem, como miniaturas e quadros, bem como dimensões de imagem, DPI e formatos de pixel.

Quadros individuais podem ser codificados com metadados específicos do quadro, portanto, IWICBitmapFrameEncode fornece acesso a um gravador de metadados por meio do método GetMetadataQueryWriter.

O método Commit do quadro confirma todas as alterações no quadro individual e indica que as alterações nesse quadro não devem mais ser aceitas.

Exemplo de codificação (TIFF)

No exemplo a seguir, uma imagem no formato TIFF é codificada usando IWICBitmapEncoder e um IWICBitmapFrameEncode. A saída TIFF é personalizada usando o WICTiffCompressionOption e o quadro de bitmap é inicializado usando as opções fornecidas. Depois que a imagem tiver sido criada usando WritePixels, o quadro será confirmado por meio de Commit e a imagem será salva usando 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;

Uso das opções do codificador

Codificadores diferentes para formatos diferentes precisam expor diferentes opções de como uma imagem é codificada. O Windows Imaging Component (WIC) fornece um mecanismo consistente para expressar se as opções de codificação são necessárias enquanto ainda permite que os aplicativos trabalhem com vários codificadores sem exigir conhecimento de um formato específico. Isso é feito fornecendo um parâmetro IPropertyBag no método CreateNewFrame e no método Initialize.

A fábrica de componentes fornece um ponto de criação fácil para criar um conjunto de propriedades de opções do codificador. Os codecs poderão usar esse serviço se precisarem fornecer um conjunto simples, intuitivo e não conflitante de opções do codificador. O conjunto de propriedades da imagem deve ser inicializado durante a criação com todas as opções do codificador relevantes para o respectivo codec. Para opções de codificador do conjunto canônico, o intervalo de valores será imposto na gravação. Para necessidades mais avançadas, os codecs devem escrever sua própria implementação de conjunto de propriedades.

Um aplicativo recebe o conjunto de opções do codificador durante a criação do quadro e deve configurar quaisquer valores antes de inicializar o quadro do codificador. Para um aplicativo orientado para a interface do usuário, ele pode oferecer uma interface do usuário fixa para as opções de codificador canônico e uma exibição avançada para opções restantes. As alterações podem ser feitas uma de cada vez por meio do método Write e qualquer erro será relatado por meio do IErrorLog. O aplicativo de interface do usuário deve sempre ler novamente e exibir todas as opções depois de fazer uma alteração caso a alteração tenha causado um efeito em cascata. Um aplicativo deve estar preparado para lidar com uma inicialização de quadro com falha para codecs que fornecem apenas relatórios de erros mínimos por meio de seu conjunto de propriedades.

Opções do codificador

Um aplicativo pode esperar encontrar o seguinte conjunto de opções de codificador. As opções do codificador refletem os recursos de um codificador e o formato de contêiner subjacente e, portanto, não são, por sua natureza, realmente independentes de codec. Quando possível, novas opções devem ser normalizadas para que possam ser aplicadas a novos codecs que surgem.

Nome da propriedade VARTYPE Valor Codecs aplicáveis
BitmapTransform VT_UI1 WICBitmapTransformOptions JPEG, HEIF
CompressionQuality VT_R4 0-1.0 TIFF
HeifCompressionMethod WICHeifCompressionOption vários HEIF
ImageQuality VT_R4 0-1.0 JPEG, HDPhoto, HEIF
Sem perdas VT_BOOL TRUE, FALSE HDPhoto

ImageQualty de 0.0 significa a menor representação de fidelidade possível, e 1.0 significa a maior fidelidade, o que também pode implicar perda, dependendo do codec.

CompressionQuality de 0.0 significa o esquema de compactação menos eficiente disponível, normalmente resultando em uma codificação rápida, mas uma saída maior. Um valor de 1.0 significa o esquema mais eficiente disponível, normalmente levando mais tempo para codificar, mas produzindo uma saída menor. Dependendo dos recursos do codec, esse intervalo pode ser mapeado para um conjunto discreto de métodos de compactação disponíveis.

Sem perdas significa que o codec codifica a imagem como sem perdas, sem perda de dados de imagem. Se a opção de compactação sem perdas estiver habilitada, ImageQuality será ignorado.

Além das opções de codificador genéricas acima, os codecs fornecidos com o WIC dão suporte às seguintes opções. Se um codec precisar dar suporte a uma opção que seja consistente com o uso nesses codecs fornecidos, será recomendável oferecer esse suporte.

Nome da propriedade VARTYPE Valor Codecs aplicáveis
InterlaceOption VT_BOOL Ativar/Desativar PNG
FilterOption VT_UI1 WICPngFilterOption PNG
TiffCompressionMethod VT_UI1 WICTiffCompressionOption TIFF
Luminância VT_UI4/VT_ARRAY 64 Entradas (DCT) JPEG
Chrominance VT_UI4/VT_ARRAY 64 Entradas (DCT) JPEG
JpegYCrCbSubsampling VT_UI1 WICJpegYCrCbSubsamplingOption JPEG
SuppressApp0 VT_BOOL JPEG
EnableV5Header32bppBGRA VT_BOOL Ativar/Desativar BMP

Use VT_EMPTY para indicar *não definido* como o padrão. Se propriedades adicionais forem definidas, mas não tiverem suporte, o codificador deverá ignorá-las; isso permite que os aplicativos codifiquem menos lógica se quiserem uma funcionalidade que possa ou não estar presente.

Exemplos de opções do codificador

No exemplo de codificação TIFF acima, uma opção de codificador específica é definida. O membro pstrName da estrutura PROPBAG2 é definido como o nome de propriedade apropriado e o VARIANT é definido como o VARTYPE correspondente e o valor desejado – neste caso, um membro da enumeração 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);
    }
}

Para usar as opções de codificador padrão, basta inicializar o quadro de bitmap com o conjunto de propriedades retornado quando o quadro foi criado.

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

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

Também é possível eliminar o conjunto de propriedades quando nenhuma opção de codificador está sendo considerada.

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

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