Saturn
Saturn

Reputation: 18149

Graphics.DrawImage darkened?

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.

Upvotes: 0

Views: 2206

Answers (2)

Cody Gray
Cody Gray

Reputation: 244782

 (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.

Upvotes: 2

Foxfire
Foxfire

Reputation: 5755

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);    
}

Upvotes: 1

Related Questions