Click here to Skip to main content
15,886,110 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
I’m having a problem using StretchBlt to copy an image from a PictureBox to a Bitmap for use in creating an AVI file.
The AVI file is an unimportant aspect I believe - I can just display the Bitmap on another PictureBox and see the problem.

The problem is that occasionally (not often) a single image is flipped (mirrored across the X axis).
I’m not sure if this is a known problem with StretchBlt I haven’t yet found mention of or if I am doing something wrong.
It is NOT due to the intended functionality with StretchBlt of "If the signs of source and destination height or width are different then it creates a mirror image".

UPDATE: I changed things to force the source/destination to be the same size, and am using BitBlt with the same behavior.

I’ve included some code (c#), hopefully all of the important parts.

Stepping through the code I can see this happen for a single image that has exactly the same information being passed to StretchBlt (other than the hdc to copy to) as the previous image and the next image (and next, next) all of which are fine.
It doesn't happen often, and I dont see any reason when it does. Or a way to detect it happened (so I can flip it back).
I have a work around that doesn't use StretchBlt, but it is much slower and really degrades performance.

Another possibly useful bit: this flipped image is rare in normal usage (less than 1 in 100 frames). But when run in the IDE, stepping through image by image, it happens very regularly (maybe 1 in 10).

Any ideas what could be causing this or what I could be doing wrong? Or other FAST methods to copy the Bitmap including re-sizing.
NOTE: The bitmaps do vary in size (can't use BitBlt), but not by a lot.

Thank you!
Kate

// --- Import statement
[DllImport("GDI32.DLL", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
    public static extern bool StretchBlt( 
IntPtr hdcDest, int nXDest, int nYDest, int nDestWidth, int nDestHeight,
IntPtr hdcSrc, int nXSrc, int nYSrc, int nSrcWidth, int nSrcHeight, Int32 dwRop );

// --- A small class for creating/storing Bitmap and Graphics objects, which get reused
public class CAviImageInfo
  {
    private Bitmap    mAviBitmap = null;
    private Graphics  mAviGraphics = null;

    public CAviImageInfo(int width, int height )
    {
      mAviBitmap = new Bitmap(width, height);
      mAviGraphics = Graphics.FromImage(mAviBitmap);
    }
    ~CAviImageInfo()
    {
      mAviGraphics.Dispose();
      mAviGraphics = null;
    }
    public Bitmap AviBitmap
    { get { return mAviBitmap; } }
    public Graphics AviGraphics
    { get { return mAviGraphics;  } }
}

// --- Two PictureBoxs placed on form at design time (one is just to watch for these mirrored images):
PictureBox mMainPictureBox; // --- Displays the images to be copied
PictureBox DebugPictureBox;

//  --- The following done one time:
Graphics  mMainPictureBoxGraphics = mMainPictureBox.CreateGraphics();
IntPtr    mMainPictureBoxHdc      = mMainPictureBoxGraphics.GetHdc();

// --- Method that does the copying.  Called each time image on panel is updated.
Public void UpdateAviRecording()
{
  // --- Gets unused Bitmap and Graphics objects (these are reused)
  CAviImageInfo aviImageInfo = GetUnusedAviImageInfo();

  IntPtr destinationHdc = aviImageInfo.AviGraphics.GetHdc();

  StretchBlt(
    destinationHdc, 
    0, 0, aviImageInfo.AviBitmap.Width, aviImageInfo.AviBitmap.Height,
    mMainPictureBoxHdc, 
    0, 0, mMainPictureBox.Width, mMainPictureBox.Height, SRCCOPY);
		
  // --- Show the copied Bitmap on the debug PictureBox 
  // --- (normally would pass it to be written to avi file)
  DebugPictureBox.Image = aviImageInfo.AviBitmap;
  DebugPictureBox.Refresh();

  aviImageInfo.AviGraphics.ReleaseHdc(destinationHdc);		
}
Posted
Updated 4-Jun-12 13:03pm
v8

See the comments for the StretchBlt()[^] function. If the signs of source and destination height or width are different then it creates a mirror image. This may be something to do with the type of your source images.
 
Share this answer
 
Comments
KateToo 3-Jun-12 13:22pm    
I had read that, yes, but it is not the cause.
Those values are never negative, and the exact same values for those, from one image to the next, can result in one of the images having been flipped.
Please try this:

During the copying image (my mean is when using "StretchBlt"), please compare the size of the DESTINATION rectangle and the source RECTANGLE (source image size). It is safe to do this procedure for all frames.

If the sizes (rectangles) are different from each other, do resampling the source image and let the dest and source image frames be the same in terms of sizes.

The abve process prevents occuring differences in the "nHeightSrc and nHeightDest parameters in StretchBlt " randomly.


Regards.
 
Share this answer
 
v2
Comments
KateToo 4-Jun-12 15:08pm    
I do check the sizes and if they are the same use BitBlt.
What would you suggest for the resampling? Isn't that basically what I'm using StretchBlt for? My work around is actually to use Graphics.DrawImage so I dont need StretchBlt ... but this is too slow.

Please let me know if there is some other way to do the resample that is quick that I'm missing.
Thanks!
MuhtarQong 4-Jun-12 15:41pm    
First, please always check the DEST and SOURCE rectangles. If they are equal, skip resampling. If accasionally or randomly, they are not equal, do resampling only for that frame. Thus, we can skip many exta-resampling jobs and only do small amount of resampling if any exists.

If the Graphics.DrawImage is slow. You may use pixel-wise operations for resampling. In general, pixel-wise operations is quite fast. Please try it.

You may try also this. It has resampling command in Generic imaging dll. It is fast.
http://www.artuxsoft.com/
KateToo 4-Jun-12 16:10pm    
I do check the DEST and SOURCE and do not resample if the same.

Can you point me to what functions you mean for the pixel-wise resampling operations?

I'll take a look at artuxsoft, thanks.
MuhtarQong 4-Jun-12 16:33pm    
My mean is do not use Graphics.DrawImage(....), but use pixel-wise operations for the resampling procedure (e.g., Use LockBits and BitmapData directly access pixel values and do resumple). I think this is fast and safe. Because in some case you can not get graphics from some image formats.
KateToo 4-Jun-12 18:04pm    
Still not following you. I can access the pixels directly, yes - but how do I map from one size to another?
Are there re-sampling functions I'm missing?
All I'm aware are of the StretchBlt and Graphics.DrawImage. Generally StretchBlt works great except for this occasional mirrored image.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900