将 IWICBtmap 写入文件 - 解析不正确

Writing IWICBtmap to file - incorrect resolution

本文关键字:不正确 文件 IWICBtmap      更新时间:2023-10-16

我有以下代码,我在其中读取图像(JPG 进行测试),指定一个剪切矩形区域并将"剪切"区域写入文件。

我的测试图像是 320 x 240 像素 @ 300dpi。当我在所有迹象中阅读它时,它都是那个大小,但是当我写出来时,结果图像是 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;

图像矩形是正确的 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;

位图PixelSize是正确的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();
   }

ID2D1Bitmap::GetSize让你得到DIPs:

返回位图的大小(以与设备无关的像素 (DIP) 为单位)。

DIP 是 1/96 英寸。若要检索以设备像素为单位的大小,请使用 ID2D1Bitmap::GetPixelSize 方法。

在您的情况下,大小为 320 像素 * 96 dpi/px/300 dpi = 102.4 与设备无关的像素。沿 Y 轴相同。

当我从 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();

关键是在创建中使用原始图像的分辨率,稍后尝试设置它们没有任何作用。罗曼给了我"提示"——谢谢