Graphics.DrawImage变暗了?

发布于 2024-10-15 17:36:53 字数 138 浏览 6 评论 0原文

我使用 DrawImage Image 函数将图像的一部分复制到另一个图像。 是否可以使复制的部分“更暗”?比如,特殊的色调?有人能给我举个例子吗?我听说过一个叫做 ImageAttributes 的东西,但我找不到它!

注意:我不想编辑源图像。

I use the DrawImage Image function to copy a portion from an image to another.
Is it possible to make it so the copied portion is "darker"? Like, a special color tone? Can someone give me an example? I heard of something called ImageAttributes but I can't find it!

Note: I don't want to edit the source image.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

写给空气的情书 2024-10-22 17:36:53

(不一定是这个问题的直接答案,而是一个后续问题,即为 DrawImage 方法指定 ImageAttributes 会导致性能下降。该问题已被删除,但我还是在这里发布了我的回复,因为我已经写了它,如果您愿意,请忽略。)

绘制图形很慢,尤其是当您同时应用渲染效果时。花几分钟在 Photoshop 中工作,您就会明白我的意思。使图像变暗是一项计算成本高昂的任务。您几乎无能为力,可以让它运行得更快。

.NET Framework 中的 System.Drawing.Graphics 类中的例程是使用 GDI+ 在内部实现的,而 GDI+ 不是硬件加速的,这一事实使问题变得更加复杂。一种可能的替代方案是切换回基于 GDI 的渲染,它在大多数系统上都是硬件加速的(这取决于您的显卡供应商,但您今天找到的几乎每张显卡都具有用于位块传输等基本功能的硬件加速) 。当然,这要困难得多,因为您需要从 Windows API 中 P/Invoke 函数才能使用基于 GDI 的绘图例程; .NET 为您提供的只是 GDI+。这是比必要的工作多得多的工作,并且在现代硬件上速度的改进可能很小(特别是启用了 Windows Vista/7 的 Aero 主题,即使使用 GDI,它也不使用硬件加速,因为所有内容都绘制到内存中的位图) 。

坚持当前的实现,一些可能的优化仍然浮现在脑海中:

  1. 重画图像时是否调整图像大小?如果是这样,则需要对图像进行插值,相比之下,这非常慢。

  2. 图像采用什么PixelFormatFormat32bppPArgb 比替代方案快得多。确保您正在使用该格式的图像。如果您现在还没有这样做,那么进行此更改应该会看到渲染速度大幅提高。

  3. 为什么需要如此频繁地重新渲染图像?如果是相同的图像,则在应用效果后绘制它并缓存返回的 Bitmap 对象。然后,每次需要重绘图像时,请使用内存中已有的图像,而不是创建新图像。这是一个简单的技巧,但它可以让您不必每次都重复执行昂贵的部分。正如您提到的,单独使用 DrawImage 比设置渲染属性要快得多。

一般来说,用户愿意等待大图像渲染。在这里,相应地设置界面比尝试优化图形例程更合适。对于用户而言,使用进度条和繁忙的光标来指示实际正在发生的事情比在代码中多压缩几毫秒要好得多。除非您在循环中反复应用此效果大约 100 或 1000 次(这看起来很愚蠢),否则不值得花费时间进行优化。

 (Not necessarily a direct answer to this question, but to a follow-up question that specifying ImageAttributes to the DrawImage method resulted in reduced performance. That question was  since deleted, but I posted my response here anyway, since I'd already written it. Ignore if you wish.)

Drawing graphics is slow, especially when you're applying a rendering effect at the same time. Spend a few minutes working in Photoshop, and you'll see what I mean. Darkening the image is a computationally expensive task. There's little you can do to make it go faster.

The problem is further compounded by the fact that the routines in the System.Drawing.Graphics class in the .NET Framework are internally implemented using GDI+, which is not hardware accelerated. A possible alternative is to switch back to GDI-based rendering, which is hardware accelerated on most systems (it depends on your video card's vendor, but almost every card you'll find today has hardware acceleration for basic functions like bit-block transfers). Of course, this is a lot more difficult because you'll need to P/Invoke functions from the Windows API to use GDI-based drawing routines; all that .NET provides for you is GDI+. It's a whole lot more work than necessary, and the speed improvements are probably minimal on modern hardware (especially with Windows Vista/7's Aero theme enabled, which doesn't use hardware acceleration even with GDI because everything is drawn to a bitmap in memory).

Sticking with the current implementation, a couple of possible optimizations do yet spring to mind:

  1. Are you resizing the image when you redraw it? If so, that requires the image to be interpolated, which is extremely slow by comparison.

  2. What PixelFormat is the image in? Format32bppPArgb is much faster than the alternatives. Make sure that you're working with an image in that format. If you're not now, making this change should see your rendering speed increase substantially.

  3. Why do you need to re-render the image so often? If it's the same image, draw it once applying the effects and cache the Bitmap object that is returned. Then each time you need to redraw the image, use the one already in memory rather than creating a new one. It's a simple trick, but it keeps you from having to do the expensive part again each time. As you mention, DrawImage alone is much faster than setting rendered attributes.

Generally, users are willing to wait for large images to render. Setting up your interface accordingly is more appropriate here than trying to optimize the graphics routines. That a progress bar and a busy cursor are used to indicate something is actually happening will go a lot further as far as the user is concerned than squeezing a few more milliseconds out of your code. Unless you're applying this effect over and over in a loop some 100 or 1000 times (which seems pretty silly), it isn't worth the time it would take to optimize.

也只是曾经 2024-10-22 17:36:53

DrawImage 函数甚至有一个特殊的重载,可以准确地设置 ImageAttributes 对象:

private void Example(PaintEventArgs e)
{
    ImageAttributes imageAttr = new ImageAttributes();
    imageAttr.SetGamma(2.2f);

    Rectangle rect = new Rectangle(250, 20, 200, 200);
    e.Graphics.DrawImage(myImage, rect, 0, 0, 200, 200, GraphicsUnit.Pixel, imageAttr);    
}

The DrawImage function even has a special overload that sets an ImageAttributes object exactly for that reason:

private void Example(PaintEventArgs e)
{
    ImageAttributes imageAttr = new ImageAttributes();
    imageAttr.SetGamma(2.2f);

    Rectangle rect = new Rectangle(250, 20, 200, 200);
    e.Graphics.DrawImage(myImage, rect, 0, 0, 200, 200, GraphicsUnit.Pixel, imageAttr);    
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文