Solved

Worst... StretchBlt... Ever...

Posted on 2004-09-01
10
607 Views
Last Modified: 2010-05-02
Okay, how is this for a weird problem?

I have a program that uses StretchBlt to paint an image from one Picture Box into another, smaller one. The user can check whether to squeeze the larger image to fit the smaller area, or to crop the image.

Example "Squeeze" code:
StretchBlt Picture1.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, Picture2.hdc, 0, 0, Picture2.ScaleWidth, Picture2.ScaleHeight, SRCCOPY

Example "Cropped" code:
StretchBlt Picture1.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, Picture2.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, SRCCOPY

Well, it's not weird yet, is it? Until I run the program (either compiled or in the IDE). Then the crazy stuff happens...

(Times in milliseconds are averages gathered using the GetTickCount API)

Okay, let's say my program is the only program that I have open. Here are the times it takes to draw the image:

Squeezed: 50ms
Cropped: <1ms

Now, let's open Internet explorer.

Squeezed: 50ms
Cropped: <1ms

Let's navigate to a site that has an embedded Flash movie on the page.

Squeezed: 2ms
Cropped: <1ms

All I can say is: ???

Seriously, what is going on? Am I going crazy, or does this just not make any sense? Using the .PaintPicture method of the Picture Box, the same thing happens.

Is there an alternative to the StretchBlt API that is reliably fast? It's really, really annoying how inconsistant it is...

Thanks

Edit: I should mention that the program is quickly and repeatedly StretchBlt'ing different images to the Picture Box, which is why the speed matters.

-Burbble
0
Comment
Question by:Burbble
  • 6
  • 4
10 Comments
 
LVL 45

Expert Comment

by:aikimark
ID: 11959871
It is understandable to experience the time differences you see.  Think about what 'work' is required to stretch a picture (either enlarging or shrinking) versus simply transferring a partial picture image (directly).

=================
If performance is a real big problem, you might try the following when doing a stretching operation:
* allocate a data structure to contain all 'frames' of the picture series
* transfer the stretched images without displaying any during this transfer process
* display the stretched images directly, using the clipped call

~~~~~~~~
You might also experiment with an image control when doing a stretched display.
0
 
LVL 7

Author Comment

by:Burbble
ID: 11959962
Why are both operations lightning fast when an Internet Explorer window with a webpage containing a Flash movie is open, but the "Squeeze" operation is 25x slower without it? (That was sort of my primary question ;-)

I can't really load all the images into memory; there could be hundreds, or even thousands, and I know it would just be a disaster, I can feel it... lol

>> You might also experiment with an image control when doing a stretched display.

Image control was the original design, but flickering looks very unprofessional.

So, I mean, my computer is obviously capable of resizing an image in less than 3 milliseconds using StretchBlt, it just "chooses" not to ("I choose not to run!") unless a Flash component is loaded? That just seems to totally not make sense.

Thanks for the quick response, however :)

-Burbble
0
 
LVL 45

Accepted Solution

by:
aikimark earned 500 total points
ID: 11960249
Here are three performance-related ideas:
1. allocate and use long integer variables in place of the picturebox (non-image) properties.
Example:
lng1Width = Picture1.ScaleWidth
lng1Height = Picture1.ScaleHeight
lng2Width = Picture2.ScaleWidth
lng2Height = Picture2.ScaleHeight
...
'within your Do or For loop
StretchBlt Picture1.hdc, 0, 0, lng1Width , lng1Height , Picture2.hdc, 0, 0, lng2Width , lng2Height , SRCCOPY

Note: you also might replace the .hdc property references with long integer variables.

2. look at your pictureboxs' autoredraw property

3. consider a memory-only data structure for your images during the stretching process or hide the picturebox that is being used for the stretching operation.

====================
Question:
* Are you also calling SetStretchBltMode?
* Have you explored alternatives, such as PaintPicture?
0
 
LVL 7

Author Comment

by:Burbble
ID: 11960480
>> * Are you also calling SetStretchBltMode?

Not sure what that is? Should I be? (or how should I be?)

>> * Have you explored alternatives, such as PaintPicture?

Yep, PaintPicture does the same thing, but slower (about 20ms difference between PaintPicture and StretchBlt if I remember correctly).

I changed all of the .ScaleWidth, .ScaleHeight, etc etc properties to be set into Longs in memory, there is a slight increase in speed with the StretchBlt calls.

Autoredraw is set to true (it has to be).

The Picture Box that I am StretchBlt'ing the image from is hidden (.Visible = False).

Thanks

-Burbble
0
 
LVL 7

Author Comment

by:Burbble
ID: 11960493
The "Squeezing" StretchBlt is still lightning fast with Internet Explorer open, and excessively sluggish without IE (but the "Cropping" one is faster *without* IE).

Weird :/

-Burbble
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 45

Expert Comment

by:aikimark
ID: 11962266
I've experienced something similar in one of my commercial applications.  If I positioned a control so that it slightly overlayed the picturebox, the redrawing was noticably faster (much faster).  I never figured out why.

==================
The SetStretchBltMode function sets the bitmap stretching mode in the specified device context. (API definition)
http://www.mentalis.org/apilist/SetStretchBltMode.shtml

When you compress a picture, StretchBlt has to merge many rows of pixels into fewer rows. The SetStretchBltMode function sets one of three modes for dealing with the extra lines. You can combine the extra lines with the remaining lines, using either an AND operation or an OR operation, or you can simply delete the extra lines. Using the SetStretchBltMode function on the destination surface has no effect on how PaintPicture compresses images, however. Visual Basic chooses a default mode (apparently the delete mode), and that’s that.
http://www.mvps.org/vb/hardcore/html/stretchbltversuspaintpicture.htm

So you might explore the performance differences between the default stretching logic and the alternatives.  Perhaps the presence of IE or flash has changed this setting behind the scenes.

You might start reading pages at
http://www.mvps.org/vb/hardcore/html/basicwindowspainting.htm
and moving forward with the navigator buttons on these pages.

============
I still think you might benefit from using a memory only picture object to accomplish your stretching.
0
 
LVL 7

Author Comment

by:Burbble
ID: 11963726
>> I still think you might benefit from using a memory only picture object to accomplish your stretching.

How do you mean?

I am experimenting with SetStretchBltMode... I checked the Picture Boxes using GetStretchBltMode, and they all returned "1" (STRETCH_ANDSCANS) right now, without my intervention. I'm going to play around with it and I'll let you know what happens (and I have to close this Internet Explorer window, so...)

-Burbble
0
 
LVL 7

Author Comment

by:Burbble
ID: 11963962
Well, setting them all to mode "3" helped the speed a little. The "Squeezed" time without Internet Explorer is now around 45ms (as opposed to 50 before). It still doesn't compare to the <2ms time when Internet Explorer is loaded.

If I didn't specify a certain BltMode, it always defaulted to "1", regardless of what else was loaded.

I don't know what else could be causing it to do that. I guess I will wind up adding a warning somewhere in the documentation, "The images will render faster when Crop Mode is selected..."

Or, "Open Internet Explorer and navigate to a webpage in order to decrease render times" ;-)

-Burbble
0
 
LVL 45

Expert Comment

by:aikimark
ID: 11966129
or, as a temporary measure, programmatically start a hidden IE window
0
 
LVL 7

Author Comment

by:Burbble
ID: 11967060
Nah, it's too risky to do that. I will just make a note in the documentation.

Thanks for your help, at least I got it a little faster from your suggestions :)

-Burbble
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Introduction While answering a recent question (http://www.experts-exchange.com/Q_27402310.html) in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
Article by: Martin
Here are a few simple, working, games that you can use as-is or as the basis for your own games. Tic-Tac-Toe This is one of the simplest of all games.   The game allows for a choice of who goes first and keeps track of the number of wins for…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

27 Experts available now in Live!

Get 1:1 Help Now