【问题标题】:BitBlt drawing bitmap upside downBitBlt 颠倒绘制位图
【发布时间】:2012-02-19 19:43:26
【问题描述】:

我有一个 MFC 控件,我向其传递位图 (HBITMAP) 的句柄。在控件 OnPaint 方法中,我使用 BitBlt 来呈现位图。但是位图被颠倒了。

作为测试,我从这个句柄创建了一个 CBitmap 对象并将其写入一个文件,它创建了一个正面朝上的位图。那么我对 BitBlt 的调用是否有问题?

我在下面的 OnPaint 中发布了我的代码。我确实尝试将我的设备上下文的映射模式更改为 MM_LOENGLISH 并且能够使位图正面朝上呈现,但它非常粗糙。当我离开 MM_TEXT 的映射模式时,图像的质量是完美的,但正如我所说,它是颠倒的。我对位图、blitting 等工作不多……所以我可能会遗漏一些简单的东西。任何其他建议将不胜感激。对于某些背景,我从摄像机驱动程序中获取 BYTE* 并创建 HBITMAP 来渲染视频。 我怎样才能让它正确渲染?非常感谢

void BitmapControl::OnPaint()
{
EnterCriticalSection (&CriticalSection);

if (_handleBMP)
{

    CPaintDC dc(this);
    //dc.SetMapMode(MM_LOENGLISH);
    CDC dcMem;
    dcMem.CreateCompatibleDC(&dc);

    CRect rect;
    GetClientRect(&rect);
    dc.DPtoLP(&rect);


    CBitmap* pBmpOld = dcMem.SelectObject(CBitmap::FromHandle(_handleBMP));
    BitBlt(dc,rect.left,rect.top,rect.Width(),rect.Height(),dcMem,rect.left,rect.top,SRCCOPY); //works with MM_TEXT but upsidedown
    //BitBlt(dc,0,rect.bottom,rect.Width(),-rect.Height(),dcMem,0,0,SRCCOPY); //works with MM_LOENGLISH
    dcMem.SelectObject(pBmpOld);
    DeleteDC(dc);
    DeleteDC(dcMem);
    DeleteObject(_handleBMP);
    DeleteObject(pBmpOld);
    _handleBMP = NULL;

}
LeaveCriticalSection (&CriticalSection);
}

编辑* 我假设因为我可以将位图以正确的方向保存到磁盘,所以问题出在 bitblt 上。这是我用来生成 HBITMAP 的代码。

 HBITMAP BitmapWriter::CreateBitmapFromFrame(BYTE* frame)
{
BITMAPFILEHEADER* bmfh;
bmfh = (BITMAPFILEHEADER*)frame;

BITMAPINFOHEADER* bmih = &_bmi;

BITMAPINFO* bmpInfo = (BITMAPINFO*)bmih;

HBITMAP hbmp = CreateDIBSection(_hdc,bmpInfo,DIB_RGB_COLORS,NULL,NULL,0);
SetBitmapBits(hbmp,_bmi.biSizeImage,frame);


return hbmp;
}

哦,我使用了临界区,因为我将 hbitmap 传递给属性中的控件,然后在 OnPaint 中访问它。如果这是一个潜在的问题,我将不得不重新考虑。谢谢

【问题讨论】:

  • 这可能与您创建_handleBMP 的方式有关,而不是与您绘制它的方式有关。
  • 这几乎肯定在创建位图的代码中开始出错。请注意,扫描线是倒置存储的。顺便说一句,EnterCriticalSection 是绘画代码中的一个危险信号,GDI 从根本上不是线程安全的。

标签: c++ mfc gdi


【解决方案1】:

Windows 位图首先以底线存储。世界上其他大多数人都在第一线工作,所以我想这就是你从相机中得到的结果。

您可以在 BITMAPINFOHEADER 结构中使用负高度来反转正常顺序。

【讨论】:

  • 我将 BITMAPINFOHEADER 对象中的 biHeight 属性从 480 更改为 -480 但这没有效果,它仍然呈现颠倒状态
  • @mash,我希望您理解我的意思是在从原始数据创建位图的地方进行此更改。对不起,如果我不清楚。
  • 是的,我想我设置的太晚了,我从 DirectShow 图表中获取原始数据。我的图表由源过滤器和样本采集器组成,我的样本采集器将原始数据发布给订阅者,其中一个是我的渲染器。我想我需要以某种方式为我的源过滤器设置一个属性?我还不确定该怎么做
【解决方案2】:

MM_TEXT 中,y 轴指向下方,而在其他映射模式中则指向上方。试试MM_ISOTROPIC映射模式。为了更精确的控制,您可能需要在CDC 上设置视口和窗口偏移和范围。

位图可以倒置存储,即在BITMAPINFOHEADER 结构中由负高度表示,但这应该不是问题。

【讨论】:

  • 你总是可以直接否定结构中的高度,强制它以其他方式绘制而不修改映射模式。
【解决方案3】:

好的,我似乎有这个工作。我最终将映射模式更改为 MM_LOENGLISH。正如我之前所说,这给了我一个颗粒状的图像,但通过添加以下内容进行了纠正

dc.SetStretchBltMode(COLORONCOLOR);

我需要做一些阅读才能真正弄清楚为什么......但是现在这是我的渲染代码。

void BitmapControl::OnPaint()
{
EnterCriticalSection (&CriticalSection);

if (_handleBMP)
{

    CPaintDC dc(this);
    //dc.SetMapMode(MM_ISOTROPIC);
    dc.SetMapMode(MM_LOENGLISH);
    CDC dcMem;
    dcMem.CreateCompatibleDC(&dc);

    CRect rect;
    GetClientRect(&rect);
    dc.DPtoLP(&rect);

    CBitmap* pBmpOld = dcMem.SelectObject(CBitmap::FromHandle(_handleBMP));

    //tst
    dc.SetStretchBltMode(COLORONCOLOR);

    //BitBlt(dc,rect.left,-0,rect.Width(),rect.Height(),dcMem,rect.left,rect.top,SRCCOPY); //works with MM_TEXT but upsidedown
    BitBlt(dc,0,rect.bottom,rect.Width(),-rect.Height(),dcMem,0,0,SRCCOPY); //works with MM_LOENGLISH
    dcMem.SelectObject(pBmpOld);
    DeleteDC(dc);
    DeleteDC(dcMem);
    DeleteObject(_handleBMP);
    DeleteObject(pBmpOld);
    _handleBMP = NULL;

}
LeaveCriticalSection (&CriticalSection);
}

【讨论】:

    【解决方案4】:

    只需在 BITMAPINFOHEADER 结构的 biHeight 字段中使用负值即可。

    bi.biHeight = -height;  //this is the line that makes it draw upside down or not
    

    【讨论】:

      猜你喜欢
      • 2018-06-21
      • 2016-05-29
      • 1970-01-01
      • 2012-12-20
      • 2013-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-26
      相关资源
      最近更新 更多