Запись IWICBtmap в файл — неправильное разрешение

У меня есть следующий код, где я читаю изображение (JPG для теста), задаю область отсечения прямоугольника и записываю область «отсечения» в файл.

Мое тестовое изображение — 320 x 240 пикселей при 300 точек на дюйм. Когда я читаю его по всем признакам, говорят, что это тот размер, но когда я его записываю, получается изображение размером 102 x 76, и, глядя на свойства файла, я не вижу разрешения H / V.

Теперь 320/102 = 3,1372 и 300/96 = 3,125, так что-нибудь с разрешением экрана и изображением?

Весь этот предмет написания IWICBitmap был боксерским поединком с самого начала. Почему это так сложно?

Огромное спасибо

IWICImagingFactory *pImageFactory = GfxAgent::WICImagingFactory::GetInstance().GetFactory();

D2D1_SIZE_U sizeFrame = D2D1::SizeU(imageRect.Width(), imageRect.Height());

CComPtr<IWICBitmap> pWICBitmap;
hr = pImageFactory->CreateBitmap(imageRect.Width(), imageRect.Height(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapCacheOnLoad,
&pWICBitmap
);

D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties();
rtProps.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED);
rtProps.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
rtProps.usage = D2D1_RENDER_TARGET_USAGE_NONE;

// define the render target
CComPtr<ID2D1RenderTarget> pRenderTarget = 0;
hr = m_pDirect2dFactory->CreateWicBitmapRenderTarget(pWICBitmap, rtProps, &pRenderTarget);

CComPtr<ID2D1Bitmap> imageS;
hr = GfxAgent::ImageUtilities::LoadImageFromFile(pRenderTarget, m_imgPath, 0, 0, 0, &imageS, &resX, &resY);

if (hr != S_OK)
{
}

// get format of image we just read
D2D1_PIXEL_FORMAT fmt = imageS->GetPixelFormat();

CComPtr<ID2D1Bitmap> imageD;
D2D1_SIZE_U bitmapPixelSize = D2D1::SizeU(imageRect.Width(), imageRect.Height());

// create destination image of "clipped" source image
hr = pRenderTarget->CreateBitmap(bitmapPixelSize, D2D1::BitmapProperties(
D2D1::PixelFormat(fmt.format, fmt.alphaMode),
(float)resX, (float)resY), &imageD);

D2D1_POINT_2U topleft = D2D1::Point2U(0, 0);
D2D1_RECT_U srcRect = D2D1::RectU(imageRect.left, imageRect.top, imageRect.right, imageRect.bottom);
// get the "clipped" source
hr = imageD->CopyFromBitmap(&topleft, imageS, &srcRect);

if (hr != S_OK)
{
}

CComPtr<IWICBitmapEncoder> pEncoder;
CComPtr<IWICBitmapFrameEncode> pFrame;
CComPtr<IWICStream> pStream;

WICPixelFormatGUID format = GUID_WICPixelFormat32bppPBGRA;

// draw the "clipped" image into the render target (WIC image)
if (SUCCEEDED(hr)) {
pRenderTarget->BeginDraw();
pRenderTarget->Clear();
pRenderTarget->DrawBitmap(imageD);
hr = pRenderTarget->EndDraw();
}

// now proceed to write the "clipped" image to a file
if (SUCCEEDED(hr)) {
hr = pImageFactory->CreateStream(&pStream);
}

if (SUCCEEDED(hr)) {
hr = pStream->InitializeFromFilename(MultiByteToUnicode(szNewFileName).c_str(), GENERIC_WRITE);
}

if (SUCCEEDED(hr)) {
hr = pImageFactory->CreateEncoder(GUID_ContainerFormatJpeg, NULL, &pEncoder);
}

if (SUCCEEDED(hr)) {
hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
}

if (SUCCEEDED(hr)) {
hr = pEncoder->CreateNewFrame(&pFrame, NULL);
}

if (SUCCEEDED(hr)) {
hr = pFrame->Initialize(NULL);
}

if (SUCCEEDED(hr)) {
hr = pFrame->SetSize((UINT)imageD->GetSize().width, (UINT)imageD->GetSize().height);
}

if (SUCCEEDED(hr)) {
hr = pFrame->SetPixelFormat(&format);
}

if (SUCCEEDED(hr)) {
hr = pFrame->WriteSource(pWICBitmap, NULL);
}

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

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

Больше информации

      D2D1_POINT_2U topleft = D2D1::Point2U(0, 0);
D2D1_RECT_U srcRect = D2D1::RectU(imageRect.left, imageRect.top, imageRect.right, imageRect.bottom);
// get the "clipped" source
hr = imageD->CopyFromBitmap(&topleft, imageS, &srcRect);

if (hr != S_OK)
{
}

UINT wD, hD;
wD = (UINT)imageD->GetSize().width;
hD = (UINT)imageD->GetSize().height;

ImageRect является правильным LTRB = 0,0,320,240

но после копирования wD = 102 и hD = 76

Зачем?

Вот еще немного информации

CComPtr<ID2D1Bitmap> imageD;
D2D1_SIZE_U bitmapPixelSize = D2D1::SizeU(imageRect.Width(), imageRect.Height());

// create destination image of "clipped" source image
hr = pRenderTarget->CreateBitmap(bitmapPixelSize, D2D1::BitmapProperties(
D2D1::PixelFormat(fmt.format, fmt.alphaMode),
(float)resX, (float)resY), &imageD);

UINT wD, hD;
wD = (UINT)imageD->GetSize().width;
hD = (UINT)imageD->GetSize().height;

Размер bitmapPixelSize правильный 320 x 240, resX и Y — 300

    format= DXGI_FORMAT_B8G8R8A8_UNORM
alphaMode   D2D1_ALPHA_MODE_PREMULTIPLIED

wD = 102 и hD = 76 — Почему?

Последний код

IWICImagingFactory *pImageFactory = GfxAgent::WICImagingFactory::GetInstance().GetFactory();

D2D1_SIZE_U sizeFrame = D2D1::SizeU(imageRect.Width(), imageRect.Height());

CComPtr<IWICBitmap> pWICBitmap;
hr = pImageFactory->CreateBitmap(imageRect.Width(), imageRect.Height(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapCacheOnLoad,
&pWICBitmap
);

// sanity check
UINT wicW, wicH;
pWICBitmap->GetSize(&wicW, &wicH);

D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties();
rtProps.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED);
rtProps.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
rtProps.usage = D2D1_RENDER_TARGET_USAGE_NONE;

// define the render target
CComPtr<ID2D1RenderTarget> pRenderTarget = 0;
hr = m_pDirect2dFactory->CreateWicBitmapRenderTarget(pWICBitmap, rtProps, &pRenderTarget);

CComPtr<ID2D1Bitmap> imageS;
hr = GfxAgent::ImageUtilities::LoadImageFromFile(pRenderTarget, m_imgPath, 0, 0, 0, &imageS, &resX, &resY);

if (hr != S_OK)
{
}

// set new image resolution same as source
pWICBitmap->SetResolution(resX, resY);

// get format of image we just read
D2D1_PIXEL_FORMAT fmt = imageS->GetPixelFormat();

CComPtr<ID2D1Bitmap> imageD;
D2D1_SIZE_U bitmapPixelSize = D2D1::SizeU(imageRect.Width(), imageRect.Height());

// create destination image of "clipped" source image
hr = pRenderTarget->CreateBitmap(bitmapPixelSize, D2D1::BitmapProperties(
D2D1::PixelFormat(fmt.format, fmt.alphaMode),
(float)resX, (float)resY), &imageD);

D2D1_POINT_2U topleft = D2D1::Point2U(0, 0);
D2D1_RECT_U srcRect = D2D1::RectU(imageRect.left, imageRect.top, imageRect.right, imageRect.bottom);
// get the "clipped" source
hr = imageD->CopyFromBitmap(&topleft, imageS, &srcRect);

if (hr != S_OK)
{
}

// just a sanity check (pixels NOT DIPS)
D2D1_SIZE_U sourcePixelSize = imageS->GetPixelSize();
D2D1_SIZE_U destPixelSize = imageD->GetPixelSize();

CComPtr<IWICBitmapEncoder> pEncoder;
CComPtr<IWICBitmapFrameEncode> pFrame;
CComPtr<IWICStream> pStream;

WICPixelFormatGUID format = GUID_WICPixelFormat32bppPBGRA;

// draw the "clipped" image into the render target (WIC image)
if (SUCCEEDED(hr)) {
pRenderTarget->BeginDraw();
pRenderTarget->Clear();
pRenderTarget->DrawBitmap(imageD);
hr = pRenderTarget->EndDraw();
}

// now proceed to write the "clipped" image to a file
if (SUCCEEDED(hr)) {
hr = pImageFactory->CreateStream(&pStream);
}

if (SUCCEEDED(hr)) {
hr = pStream->InitializeFromFilename(MultiByteToUnicode(szNewFileName).c_str(), GENERIC_WRITE);
}

if (SUCCEEDED(hr)) {
hr = pImageFactory->CreateEncoder(GUID_ContainerFormatJpeg, NULL, &pEncoder);
}

if (SUCCEEDED(hr)) {
hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
}

if (SUCCEEDED(hr)) {
hr = pEncoder->CreateNewFrame(&pFrame, NULL);
}

if (SUCCEEDED(hr)) {
hr = pFrame->Initialize(NULL);
}

if (SUCCEEDED(hr)) {
hr = pFrame->SetSize(destPixelSize.width, destPixelSize.height);
}

if (SUCCEEDED(hr)) {
hr = pFrame->SetPixelFormat(&format);
}

if (SUCCEEDED(hr)) {
hr = pFrame->WriteSource(pWICBitmap, NULL);
}

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

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

1

Решение

ID2D1Bitmap::GetSize дает вам DIPs:

Возвращает размер в пикселях, не зависящих от устройства (DIP), растрового изображения.

DIP составляет 1/96 дюйма. Чтобы получить размер в пикселях устройства, используйте метод ID2D1Bitmap :: GetPixelSize.

В вашем случае размер составляет 320 px * 96 dpi / px / 300 dpi = 102,4 независимых от устройства пикселя. То же самое по оси Y.

1

Другие решения

Зная, каково разрешение исходного изображения, когда я создаю цель рендеринга из WICBitmap, я использовал следующие свойства

   D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties();
rtProps.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED);
rtProps.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
rtProps.usage = D2D1_RENDER_TARGET_USAGE_NONE;
rtProps.dpiX = (float)m_img.GetResolutionX();
rtProps.dpiY = (float)m_img.GetResolutionY();

ключ использовал разрешение исходного изображения при создании, попытка установить их позже ничего не делала. Роман дал мне «подсказку» — спасибо

0

По вопросам рекламы [email protected]