使用 StretchBlt 生成的缩略图是全黑?

coolcalf 2019-11-20 05:40:50
请教一下,下面的方法,截屏,然后生成缩略图是正确的:

IntPtr handle = ImageHelper.GDI32.GetDesktopWindow();//获得屏幕的HWND
IntPtr sourceDC = User32.GetWindowDC(handle);//获得屏幕DC
而换成图片
//Graphics sourceGraphics = Graphics.FromImage(bmp);//使用源图创建画板
//IntPtr sourceDC = sourceGraphics.GetHdc(); //得到画板的DC

则会得到全黑的缩略图,实在找不到错在哪里,请指教


---------------------------------------------------------
/// <summary>
/// 生成缩略图
/// </summary>
/// <param name="bmp">源图</param>
/// <param name="widthDest">缩略图宽度</param>
/// <param name="heightDest">缩略图高度</param>
/// <returns></returns>
public static Bitmap MakeThubnail(Bitmap bmp, int widthDest, int heightDest)
{
try
{
//Graphics sourceGraphics = Graphics.FromImage(bmp);//使用源图创建画板
//IntPtr sourceDC = sourceGraphics.GetHdc(); //得到画板的DC

IntPtr handle = ImageHelper.GDI32.GetDesktopWindow();//获得屏幕的HWND
IntPtr sourceDC = User32.GetWindowDC(handle);//获得屏幕DC

// create a device context we can copy to
IntPtr destCDC = GDI32.CreateCompatibleDC(sourceDC); //建立与sourceDC兼容的DC,用于输出
// create a bitmap we can copy it to,
// using GetDeviceCaps to get the width/height
IntPtr hBitmap = GDI32.CreateCompatibleBitmap(sourceDC, widthDest, heightDest);//再建立一个与hdcSrc兼容的位图(双缓冲?)
// select the bitmap object
IntPtr hOld = GDI32.SelectObject(destCDC, hBitmap); //将DC与位图关联

GDI32.SetStretchBltMode(destCDC, GDI32.STRETCH_HALFTONE);
GDI32.POINTAPI point;
GDI32.SetBrushOrgEx(destCDC, 0, 0, out point);

// bitblt over
GDI32.StretchBlt(destCDC, 0, 0, widthDest, heightDest, sourceDC, 0, 0, bmp.Width,bmp.Height, GDI32.SRCCOPY); //复制
// restore selection
GDI32.SelectObject(destCDC, hOld); //取消与位图的关联
// clean up
GDI32.DeleteDC(destCDC);
//User32.ReleaseDC(handle, sourceDC);
//sourceGraphics.ReleaseHdc();
// get a .NET image object for it
Bitmap img = Image.FromHbitmap(hBitmap);
// free up the Bitmap object
GDI32.DeleteObject(hBitmap);

return img;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return null;
}
...全文
176 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
coolcalf 2019-11-26
  • 打赏
  • 举报
回复
谢谢两位 其实后来我明白了,对图片处理时 StretchBlt 根本就无法得到结果,因为它只支持对“显示在屏幕上”的东西进行处理。 而 g.DrawImage 的效率还算过得去。 真正在处理批量图片的时候, 本身就会非常耗时。 解决办法是尽可能避免,并采用后台线程去做,而不是硬着头皮一张张去处理。
github_36000833 2019-11-21
  • 打赏
  • 举报
回复
另外,如下代码可能有问题:
Bitmap img = Image.FromHbitmap(hBitmap);
GDI32.DeleteObject(hBitmap);
return img;

原因是Image.FromHbitmap可能不会进行数据拷贝,一旦GDI32.DeleteObject把img的数据销毁了,返回的img就可能不正常工作。
你可以试试在GDI32.DeleteObject(hBitmap);前保存img,看是否数据存在。

Bitmap img = Image.FromHbitmap(hBitmap);
img.Save("调试.bmp"); // 测试这点是否数据存在
img = img.Clone() as Bitmap; // 尝试拷贝到副本,返回副本
GDI32.DeleteObject(hBitmap);
return img;

这里讨论全黑的原因,并不是鼓励你用本地GDI调用。

coolcalf 2019-11-21
  • 打赏
  • 举报
回复
谢谢,原来用的这个,效率太低了。 也试过ImageMagick,同样效率低。 因为一次载入数百张图
github_36000833 2019-11-21
  • 打赏
  • 举报
回复
Windows Vista后,界面效果提高明显,其中就有Descktop Windows Manager(DWM)的作用。
DWM可以帮助动画窗口,避免不必要的窗口重绘等等。但是,DWM也影响了StretchBlt和BitBlt的作用。
由于多了DWM一层,程序对HDC的操作,不总是反映到屏幕上,对HDC的拷贝,也不一定是拷贝到你眼睛看到的部分。

我的建议是避免本地GDI操作,特别是当缩略图在DotNet中很容易做:
public static Bitmap MakeThumbnail(Bitmap bmp, int widthDest, int heightDest)
{
var bmpDest = new Bitmap(widthDest, heightDest);
using (var g = Graphics.FromImage(bmpDest))
{
g.DrawImage(bmp, 0, 0, widthDest, heightDest);
}
return bmpDest;
}

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧