Groups | Blog | Home
all groups > dotnet performance > september 2004 >

dotnet performance : Why is: Scrolling with background image very slow?


Justin Rogers
9/21/2004 3:56:30 AM
Couple of notes... You'd have to post your Win32 API code for doing the same
actions
else I can't really point out how you might be comparing apples to oranges. The
mouse is
always going to produce more erratic results than scrolling using code because
of the
frequency at which mouse messages get generated.

You add a background image? Do you have some code for that, what version of the
CLR
are you using, etc... Could be plenty of reasons for the slow-down.


--
Justin Rogers
DigiTec Web Consultants, LLC.
Blog: http://weblogs.asp.net/justin_rogers

[quoted text, click to view]

assaf
9/21/2004 11:49:10 AM
hi all

i have simple form.
i add a background image of my desktop.
i set the AutoScrollSize to {1024, 768}.
i run the app.

when i scroll, the cpu shoots up to 100%.
and the bitmap does not draw well.

compare this to Win32 api code
(that i have dll imported),
that uses only 1%.


but that's not all...

when i scroll the form from the code,
(instead of using the mouse),
the cpu does not soot up so high.


this leaves me confused...
what's going on?


could someone please help me?


assaf


assaf
9/25/2004 1:08:11 AM
hi justin

here is the DotNet C# code,
followed by the Win32 (DllImport) code

notice that dot net upon scrolling, shoots cpu up to 100%,
while win32 remains at 1%.

please help.

assaf



************************************************************************
DotNet code start:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace BackgroundImage
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.MainMenu mainMenu1;
private System.Windows.Forms.MenuItem menuItem1;
private System.Windows.Forms.MenuItem menuItemOpen;
private System.Windows.Forms.OpenFileDialog openFileDialog1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.mainMenu1 = new System.Windows.Forms.MainMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
this.menuItemOpen = new System.Windows.Forms.MenuItem();
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
//
// mainMenu1
//
this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuItem1});
//
// menuItem1
//
this.menuItem1.Index = 0;
this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuItemOpen});
this.menuItem1.Text = "Fýile";
//
// menuItemOpen
//
this.menuItemOpen.Index = 0;
this.menuItemOpen.Text = "Open...";
this.menuItemOpen.Click += new
System.EventHandler(this.menuItemOpen_Click);
//
// openFileDialog1
//
this.openFileDialog1.FileOk += new
System.ComponentModel.CancelEventHandler(this.openFileDialog1_FileOk);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Menu = this.mainMenu1;
this.Name = "Form1";
this.Text = "Form1";

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void menuItemOpen_Click(object sender, System.EventArgs e)
{
this.openFileDialog1.ShowDialog(this);
}

private void openFileDialog1_FileOk(object sender,
System.ComponentModel.CancelEventArgs e)
{
this.BackgroundImage = Image.FromFile(this.openFileDialog1.FileName);
this.AutoScrollMinSize = this.BackgroundImage.Size;
}
}
}

DotNet code end
************************************************************************

************************************************************************
Win32 code start:

using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WindowsApplication3
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.OpenFileDialog openFileDialog1;
private System.Windows.Forms.MainMenu mainMenu1;
private System.Windows.Forms.MenuItem menuItem1;
private System.Windows.Forms.MenuItem menuItemOpen;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
this.mainMenu1 = new System.Windows.Forms.MainMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
this.menuItemOpen = new System.Windows.Forms.MenuItem();
//
// openFileDialog1
//
this.openFileDialog1.FileOk += new
System.ComponentModel.CancelEventHandler(this.openFileDialog1_FileOk);
//
// mainMenu1
//
this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuItem1});
//
// menuItem1
//
this.menuItem1.Index = 0;
this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuItemOpen});
this.menuItem1.Text = "&File";
//
// menuItemOpen
//
this.menuItemOpen.Index = 0;
this.menuItemOpen.Text = "&Open...";
this.menuItemOpen.Click += new
System.EventHandler(this.menuItemOpen_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.AutoScroll = true;
this.AutoScrollMinSize = new System.Drawing.Size(1124, 868);
this.ClientSize = new System.Drawing.Size(276, 257);
this.Menu = this.mainMenu1;
this.Name = "Form1";
this.Text = "Form1";
this.Paint += new
System.Windows.Forms.PaintEventHandler(this.Form1_Paint);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void DrawDIB(IntPtr hdc, int XDest, int YDest, int DestWidth, int
DestHeight, int XSrc, int YSrc, int SrcWidth, int SrcHeight, uint rop)
{
Bitmap b = (Bitmap)this._Image;
BitmapData bm = null;
try
{
Rectangle r = new Rectangle(XSrc, YSrc, SrcWidth, SrcHeight);
bm = b.LockBits(r, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
kumaren
4/7/2005 6:42:05 AM
The managed code is not displaying the image on the screen. I want the
image selected to be displayed on to the screen.

Please post a working code image is displayed.

I an currently working on the same.
kumaren
4/7/2005 6:45:58 AM
the code present below is not displaying image on the view. What i have to
do to display selected image on to the screen.if any body have full code
please send it.

Thank u
Naveen

using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WindowsApplication3
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.OpenFileDialog openFileDialog1;
private System.Windows.Forms.MainMenu mainMenu1;
private System.Windows.Forms.MenuItem menuItem1;
private System.Windows.Forms.MenuItem menuItemOpen;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
this.mainMenu1 = new System.Windows.Forms.MainMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
this.menuItemOpen = new System.Windows.Forms.MenuItem();
//
// openFileDialog1
//
this.openFileDialog1.FileOk += new
System.ComponentModel.CancelEventHandler(this.openFileDialog1_FileOk);
//
// mainMenu1
//
this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[]
{
this.menuItem1});
//
// menuItem1
//
this.menuItem1.Index = 0;
this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[]
{
this.menuItemOpen});
this.menuItem1.Text = "&File";
//
// menuItemOpen
//
this.menuItemOpen.Index = 0;
this.menuItemOpen.Text = "&Open...";
this.menuItemOpen.Click += new
System.EventHandler(this.menuItemOpen_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.AutoScroll = true;
this.AutoScrollMinSize = new System.Drawing.Size(1124, 868);
this.ClientSize = new System.Drawing.Size(276, 257);
this.Menu = this.mainMenu1;
this.Name = "Form1";
this.Text = "Form1";
this.Paint += new
System.Windows.Forms.PaintEventHandler(this.Form1_Paint);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void DrawDIB(IntPtr hdc, int XDest, int YDest, int DestWidth,
int
DestHeight, int XSrc, int YSrc, int SrcWidth, int SrcHeight, uint rop)
{
Bitmap b = (Bitmap)this._Image;
BitmapData bm = null;
try
{
Rectangle r = new Rectangle(XSrc, YSrc, SrcWidth, SrcHeight);
bm = b.LockBits(r, ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
uint iStretchDIBits = Gdi32.StretchDIBits(hdc, XDest, YDest,
DestWidth,
DestHeight, XSrc, YSrc, SrcWidth, SrcHeight, bm.Scan0, this._BITMAPINFO,
DIB_RGB_COLORS, rop);
if(iStretchDIBits == Gdi32.GDI_ERROR)
{
throw new ApplicationException("StretchDIBits Failed");
}
}
finally
{
if(bm != null)
{
b.UnlockBits(bm);
}
}
}

private void Form1_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
if(this._Image != null)
{
IntPtr hdc = e.Graphics.GetHdc();

Gdi32.SetWindowOrgEx(hdc, 0, 0, IntPtr.Zero);
int horiz = - User32.GetScrollPos(this.Handle,
User32.ScrollPos.SB_HORZ);
int vert = - User32.GetScrollPos(this.Handle,
User32.ScrollPos.SB_VERT);
Gdi32.SetViewportOrgEx(hdc, horiz, vert, IntPtr.Zero);

int iSaveDC = Gdi32.SaveDC(hdc);
int w = this._Image.Width;
int h = this._Image.Height;
this.DrawDIB(hdc, GAP, GAP, w, h, 0, 0, w, h, SRCCOPY);

bool bRestoreDC = Gdi32.RestoreDC(hdc, -1);
if(bRestoreDC == false)
{
throw new ApplicationException("RestoreDC Failed");
}
e.Graphics.ReleaseHdc(hdc);
}
}

private const int DIB_RGB_COLORS = 0; // color table in RGBs
private const int SRCCOPY = 0x00CC0020; // dest = source
private const int GAP = 16;
private Image _Image;
private Gdi32.BITMAPINFO _BITMAPINFO = new Gdi32.BITMAPINFO();

private void openFileDialog1_FileOk(object sender,
System.ComponentModel.CancelEventArgs e)
{
this._BITMAPINFO.bmiColors.rgbBlue = 200;
this._BITMAPINFO.bmiColors.rgbGreen = 208;
this._BITMAPINFO.bmiColors.rgbRed = 212;
this._BITMAPINFO.bmiColors.rgbReserved = 200;

this._BITMAPINFO.bmiHeader.biSize = 40;
this._BITMAPINFO.bmiHeader.biWidth = 1024;
this._BITMAPINFO.bmiHeader.biHeight = 768;
this._BITMAPINFO.bmiHeader.biPlanes = 1;
this._BITMAPINFO.bmiHeader.biBitCount = 24;
this._BITMAPINFO.bmiHeader.biCompression = 0;
this._BITMAPINFO.bmiHeader.biSizeImage = 2359296;
this._BITMAPINFO.bmiHeader.biXPelsPerMeter = 0;
this._BITMAPINFO.bmiHeader.biYPelsPerMeter = 0;
this._BITMAPINFO.bmiHeader.biClrUsed = 0;
this._BITMAPINFO.bmiHeader.biClrImportant = 0;

this._Image = Image.FromFile(this.openFileDialog1.FileName);
}

private void menuItemOpen_Click(object sender, System.EventArgs e)
{
this.openFileDialog1.ShowDialog(this);
}

private class User32
{
internal enum ScrollPos
{
SB_HORZ = 0,
SB_VERT = 1
}

[DllImport("user32.dll")]
internal static extern
int GetScrollPos(
IntPtr hWnd,
ScrollPos nBar
);
}

private class Gdi32
{
[DllImport("gdi32.dll")]
internal static extern
bool SetViewportOrgEx(
IntPtr hdc, // handle to device context
int X, // new x-coordinate of viewport origin
int Y, // new y-coordinate of viewport origin
IntPtr lpPoint // original viewport origin
);

[DllImport("gdi32.dll")]
internal static extern
bool SetWindowOrgEx(
IntPtr hdc, // handle to device context
int X, // new x-coordinate of window origin
int Y, // new y-coordinate of window origin
IntPtr lpPoint // original window origin
);

[StructLayout(LayoutKind.Sequential)]
ertan.tike NO[at]SPAM gmail.com
4/8/2005 3:32:39 PM
there is a litte more easy way..
this method faster than creating new bitmap.

Bitmap m_Bmp = new Bitmap( m_Data.Width, m_Data.Height, m_Data.Stride,
m_Data.PixelFormat, m_Data.Scan0 );

i think runtime doesnt create actually a new bitmap, it's just viewport
of bitmap. but i'm not sure someshow this methods works very fast.

sample;

protected override void OnPaint( PaintEventArgs e )
{
if ( m_ScreenBitmap != null )
{
try
{
Rectangle m_LockRectangle = new Rectangle();
Rectangle m_ClipRectangle = e.ClipRectangle;

m_LockRectangle.X = (int)( ( ( e.ClipRectangle.X -
ClientRectangle.X ) + HorizontalScroll.Value ) / m_ZoomFactor );
m_LockRectangle.Y = (int)( ( ( e.ClipRectangle.Y -
ClientRectangle.Y ) + VerticalScroll.Value ) / m_ZoomFactor );
m_LockRectangle.Width = (int)(
e.ClipRectangle.Width / m_ZoomFactor );
m_LockRectangle.Height = (int)(
e.ClipRectangle.Height / m_ZoomFactor );

if ( m_LockRectangle.Width > m_ScreenBitmap.Width )
{
m_ClipRectangle.Width = (int)(
m_ScreenBitmap.Width * m_ZoomFactor );
m_LockRectangle.Width = m_ScreenBitmap.Width;
}

if ( m_LockRectangle.Height > m_ScreenBitmap.Height
)
{
m_ClipRectangle.Height = (int)(
m_ScreenBitmap.Height * m_ZoomFactor );
m_LockRectangle.Height = m_ScreenBitmap.Height;
}

BitmapData m_Data = m_ScreenBitmap.LockBits(
m_LockRectangle, ImageLockMode.ReadOnly, m_ScreenBitmap.PixelFormat );

Bitmap m_Bmp = new Bitmap( m_Data.Width,
m_Data.Height, m_Data.Stride, m_Data.PixelFormat, m_Data.Scan0 );

e.Graphics.DrawImage( m_Bmp, m_ClipRectangle );

m_Bmp.Dispose();

m_ScreenBitmap.UnlockBits( m_Data );
}
catch
{
}
}
}
AddThis Social Bookmark Button