C# Programming – GDI+

C# Programming – GDI+
 
In a windows program, the output to an I/O device such as the display or printer requires going through an intermediate object known as the device context (DC). The purpose of DC is to make the windows program device independent so that the program will work with any type of display or printer without requiring a recompilation. The device context has two portions to it as shown below:
 
Windows Program

 
 
 
 
 
 
 
 
 
Output Device (e.g., display or printer)
 
The context portion of the DC maintains information about the drawing context such as line width, style, color, fill color, font style, font size etc.. The device drive portion of DC contains the actual device driver for a particular output device.
 
In MFC, there is a detailed set of classes that deal with the DC. The general framework that deals with the DC is referred to as the GDI (Graphical Device Interface). In .Net, the GDI interface has been greatly refined and is referred to as GDI+. The .Net GDI+ classes encapsulate some of the important Windows API to create graphical outputs. The set of GDI+ classes is quite comprehensive such that entire books can be written on it. We will try to cover some of the important concepts and the popular GDI+ classes needed in creating windows applications.
 
The System.Drawing namespace contains most of the classes, structs, enums, and delegates that provide the basic drawing functionality. The System.Darwing contains other namespaces for specialized applications such as System.Drawing.Imaging for image processing, System.Drawing.Design for design time controls such as dialog boxes, property sheets etc.., System.Design.Text for conrolling fonts, System.Drawing.Printing for controlling printing and print preview.
 
When dealing with drawings, there are three important .Net structs that are commonly used. These are Point, Size and Rectangle. The Point has two properties X and Y that are of type integer. The Point also has another similar struct called PointF where the X and Y properties are in float data type. Similarly Size and Rectangle have equivalent structs called SizeF and RectangleF. The Size struct has Width and Height as the two properties. The Rectangle can be specified in terms of Top, Left, Bottom, Right or Top, Left, Width and Height, or Location (Point) and Size. There is also a Region class that can be used to define arbitrarily complex shapes.
The Color class has some standard colors defined in it as static members e.g., Color.Red. When a precise control over a color is needed, there is a FromArgb function that can be used to specify the combination of red, green and blue pixels, e.g.,
Color.FromArgb(255,255,0) ; will generate a yellow color.
 
In GDI+, the DC is wrapped in the class System.Drawing.Graphics. All drawing of shapes such as rectangles, lines, text requires you to create the DC first. The typical code that creates a Dc for you is:
Graphics dc = this.CreateGraphics();   // code written inside a form class
 
Windows generates a PAINT message whenever a window needs to be repainted. .Net framework invokes an Paint( ) handler whenever a window needs to be repainted.
 
Example: Create a windows application. Name the project “gditest”. Right click on Form1.cs in the project explorer and choose “view code”. Type the following code in the constructor for form1 class.
public Form1()
{
//
InitializeComponent();
this.BackColor = Color.Aqua;
}
 
Add a Paint event handler by clicking on the lightning symbol above the properties window and double clicking on the Paint event. Type the following code in it. Note that the Paint event handler gets a DC through the PaintEventArgs parameter, so you can simply use, Graphics dc = e.Graphics; to obtain the DC.
 
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
//—first create a device context
// Graphics dc = this.CreateGraphics(); normally but Paint
// is given a DC through the PaintEventArgs parameter
Graphics dc = e.Graphics;
 
Pen bluePen = new Pen(Color.Blue, 3);  // 3 pixels wide
dc.DrawEllipse(bluePen, 30,30,40,50);  //30,30 is top,left, 40=width, 50=height
Pen redPen = new Pen(Color.Red, 2);
dc.DrawLine(redPen, 30,30,100,100);
 
Pen greenPen = new Pen(Color.Green);
dc.DrawRectangle(greenPen,60,60,50,50);
}
 
If you run the program by choosing “debug->start without debugging”, you will see the following results.
 
 
Clipping Region: The PaintEventArgs parameter in the Paint handler also contains information about the clipping rectangle. The clipping rectangle is the rectangular area that needs to be repainted (this is similar to the invalidated region in MFC). The clipping rectangle becomes important when there are a large number of objects to be redrawn in the Paint handler. Using the clipping region information, we can choose to redraw only a few of these objects which are being affected.
 
Example:  Modify the Paint handler code to look as,
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
//—first create a device context
// Graphics dc = this.CreateGraphics(); normally but Paint
// is given a DC through the PaintEventArgs parameter
Graphics dc = e.Graphics;
 
Pen bluePen = new Pen(Color.Blue, 3);  // 3 pixels wide
dc.DrawEllipse(bluePen, 30,30,40,50);  //30,30 is top,left, 40=width, 50=height
 
Pen redPen = new Pen(Color.Red, 2);
dc.DrawLine(redPen, 30,30,100,100);
 
      if ((e.ClipRectangle.Top < 60) && (e.ClipRectangle.Left < 60)
&& (e.ClipRectangle.Bottom > 110) && (e.ClipRectangle.Right > 110))
      {
        Pen greenPen = new Pen(Color.Green);
        dc.DrawRectangle(greenPen,60,60,50,50);
      }
    }
 
Now the green rectangle will appear when you run the program, but if you overlap the above form window such that the top and left of the window covering the above form has greater than 60,60 coordinates, then if you minimize the other window that was covering the above form, the green rectangle will not be redrawn because of the clipping region code.
The clipping region is particularly useful when there are different shapes, and one of the shapes is selected to be moved or deleted. Then as a result of movement or deletion, you should redraw only the moved shape. The clipping region to be redrawn is controlled by the Invalidate call.
 
Brushes are used to fill a particular region with a color or a pattern. For example, the DC has a FillRectangle method and a FillEllipse method which you can pass the brush and the bounding rectangle to fill the shape with the brush.
 
Example: Modify the Paint handler to fill the rectangle and the ellipse with brushes as shown below.
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
//—first create a device context
// Graphics dc = this.CreateGraphics(); normally but Paint
// is given a DC through the PaintEventArgs parameter
Graphics dc = e.Graphics;
      Rectangle r1 = new Rectangle(30,30,40,40);
Pen bluePen = new Pen(Color.Blue, 3);  // 3 pixels wide
      dc.DrawEllipse(bluePen, r1);  //30,30 is top,left, 50=height
      Brush yellowBrush = new SolidBrush(Color.Yellow);
      dc.FillEllipse(yellowBrush,r1);
// alternatively you can use Brushes type
// which has many Brushes defined as static objects
// e.g., dc.FillEllipse(Brushes.Yellow,r1)
 
Pen redPen = new Pen(Color.Red, 2);
dc.DrawLine(redPen, 30,30,100,100);
if ((e.ClipRectangle.Top < 60) && (e.ClipRectangle.Left < 60)
&& (e.ClipRectangle.Bottom > 110) && (e.ClipRectangle.Right > 110))
{
        Rectangle r2 = new Rectangle(60,60,50,50);
Pen greenPen = new Pen(Color.Green);
        dc.DrawRectangle(greenPen,r2);
        Brush coralBrush = new SolidBrush(Color.Coral);
        dc.FillRectangle(coralBrush,r2);
}
}
 
 
There are three popular coordinate systems in .Net windows programming. These are World coordinates, Page coordinates and Device coordinates. The World coordinates measure the position relative to the (top, left) of the document in pixels (it can be thought of as the logical coordinates under the old GDI concepts). The Page coordinates measure the position relative to the (top,left) of the client area in pixels. The device units are used to specify measurements in inches and millimeters.
 
Scrolling:
Scrolling in Windows forms is made easy by the AutoScrollPosition property of the form. If no clipping region is involved, then you can simply adjust the DC properly by the following code:
dc.TranslateTransform(this.AutoScrollPosition.X, this.AutoScrollPosition.Y);
 
When the clipping region is involved, then you have to adjust the offsets of rectangles by the size of the scroll position obtained from the AutoScrollPosition property.
Example:
Modify the constructor and the Paint code to properly support scrolling as shown below.
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
this.BackColor = Color.Aqua;
this.AutoScrollMinSize = new Size(250,350);
}
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
//—first create a device context
// Graphics dc = this.CreateGraphics(); normally but Paint
// is given a DC through the PaintEventArgs parameter
Graphics dc = e.Graphics;
 
      dc.TranslateTransform(this.AutoScrollPosition.X,
        this.AutoScrollPosition.Y);  // without this yellow
      // circle will not scroll properly
Rectangle r1 = new Rectangle(30,30,140,140);
Pen bluePen = new Pen(Color.Blue, 3);  // 3 pixels wide
dc.DrawEllipse(bluePen, r1);  //30,30 is top,left,
Brush yellowBrush = new SolidBrush(Color.Yellow);
dc.FillEllipse(yellowBrush,r1);
 
Pen redPen = new Pen(Color.Red, 2);
dc.DrawLine(redPen, 30,30,100,100);
 
      Size scrollOffset = new Size(this.AutoScrollPosition);
      if ((e.ClipRectangle.Top +scrollOffset.Width < 160) ||
        (e.ClipRectangle.Left + scrollOffset.Height < 160))
//  && (e.ClipRectangle.Bottom + scrollOffset.Width > 310)
//  && (e.ClipRectangle.Right + scrollOffset.Height > 310))
{
        Rectangle r2 = new Rectangle(160+scrollOffset.Width,
          160+scrollOffset.Height,150,150); 
Pen greenPen = new Pen(Color.Green);
dc.DrawRectangle(greenPen,r2);
Brush coralBrush = new SolidBrush(Color.Coral);
dc.FillRectangle(coralBrush,r2);
}
}
Zooming, Scrolling and Hit Testing:
Zooming is easily supported in .Net Windows applications by the scale factor supported as a property in DC. The typical zooming code looks as:
m_Scalef = 2.0; // set in a menu handler for zooming
 
dc.PageUnit = GraphicsUnit.Pixel; // drawing code
dc.PageScale = m_Scalef;  // default value of m_Scalef = 1.0
dc.DrawEllipse(…
 
The zooming does create some complications with respect to scrolling and hit testing to see if the mouse was clicked inside a region. The TranslateTransform and the scroll offsets will be needed just as described in the previous example.
dc.TranslateTransform(this.AutoScrollPosition.X/m_Scalef,
this.AutoScrollPosition.Y/m_Scalef);
 
For hit testing, the mouse position can be obtained from the MouseEventArgs parameter in the MouseDown event handler. This mouse position will need to be adjusted for the scrolling position as,
 
// e is the parameter containing the mouse position
Size scrollOffset = new Size(this.AutoScrollPosition);
mousep[0] = new Point(e.X-scrollOffset.Width, e.Y-scrollOffset.Height);
dc.TransformPoints(CoordinateSpace.Page, CoordinateSpace.Device,mousep);
 
Pen pen = new Pen(Color.Green,1);
dc.DrawRectangle(pen,m_r1);
if (m_r1.Contains(new Rectangle(mousep[0].X, mousep[0].Y,1,1)))
MessageBox.Show(“mouse clicked inside rectangle”);
 
Example: Create a new windows application project called testgrfx. Add a menu control to the form. Add a menu item called “zoom” with “zoom in” and “zoom out” as the menu options underneath zoom.
The code for the important parts of the project is shown below.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Drawing.Drawing2D;
 
namespace testgrfx
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
    float m_Scalef;
    Rectangle m_r1;
….
public Form1()
{
//
// Required for Windows Form Designer support
//
 
InitializeComponent();
m_Scalef = 1.0f;  // for zooming purposes
m_r1 = new Rectangle(50,50,100,100);
this.AutoScrollMinSize = new Size(600,700);
}
 
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
 
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
Graphics dc = e.Graphics;
dc.PageUnit = GraphicsUnit.Pixel;
dc.PageScale = m_Scalef;
dc.TranslateTransform(this.AutoScrollPosition.X/m_Scalef,
this.AutoScrollPosition.Y/m_Scalef);
 
Pen pn = new Pen(Color.Blue,2);
dc.DrawEllipse(pn,m_r1);
}
 
private void mnuZoomin_Click(object sender, System.EventArgs e)
{
m_Scalef = m_Scalef * 2.0f;
Invalidate();  // to trigger Paint of entire client area
}
 
private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
Graphics dc = CreateGraphics();
dc.TranslateTransform(this.AutoScrollPosition.X/m_Scalef,
this.AutoScrollPosition.Y/m_Scalef);
dc.PageUnit = GraphicsUnit.Pixel;
dc.PageScale = m_Scalef;
 
Point [] mousep = new Point[1];
// make sure to adjust mouse pos.for scroll position
Size scrollOffset = new Size(this.AutoScrollPosition);
mousep[0] = new Point(e.X-scrollOffset.Width, e.Y-scrollOffset.Height);
 
dc.TransformPoints(CoordinateSpace.Page, CoordinateSpace.Device,mousep);
Pen pen = new Pen(Color.Green,1);
dc.DrawRectangle(pen,m_r1);
if (m_r1.Contains(new Rectangle(mousep[0].X, mousep[0].Y,1,1)))
MessageBox.Show(“click inside rectangle”);
}
 
private void Form1_Load(object sender, System.EventArgs e)
{
 
}
 
private void mnuZoomout_Click(object sender, System.EventArgs e)
{
m_Scalef = m_Scalef / 2.0f;
Invalidate();
}
}
}
 
Displaying Text, Fonts:
The DC provides a DrawString method to display a text in the client area. Brushes are used with fonts to display the text in a particular color.
 
Example: Create a new windows application. Name the project fontex. Type the following code in the Form1 class.
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
 
private Brush blackBr = Brushes.Black;
private Brush redBr = Brushes.Red;
private Brush royalBlueBr = Brushes.RoyalBlue;
 
private Font boldTRFont = new Font(“Times New Roman”,14,FontStyle.Bold);
private Font italicCOFont = new Font(“Courier”,12,FontStyle.Italic);
private Font ARFont = new Font(“Arial”,10,FontStyle.Regular);
 
 
Add a Paint handler to the form with the following code in it.
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
Graphics dc = e.Graphics;
String s1 = “This is a test of Fonts” ;
String s2 = “This line is in italics”;
String s3 = “This line is in Arial, regular style”;
 
dc.DrawString(s1,boldTRFont,blackBr,new Point(0,20));
dc.DrawString(s1,italicCOFont,redBr,new Point(0,40));
dc.DrawString(s1,ARFont,royalBlueBr,new Point(0,60));
}
 
Collecting Font information from the Common Font Dialog:
Add a menu control to the form in the fontex example. Add a menu item called “choose” with a menu option “choose font” and “choose color” underneath it. Name the “choose” menu item as mnuChoose, “choose Font” as mnuChooseFont and “choose Color” as mnuChooseColor.
Add the following declarations to the Form1 class as,
private string sFont = “Setting Fonts through Font Dialog” ;
private Color fontColor;
private System.Windows.Forms.MenuItem mnuChooseColor;
private Font font;
 
Modify the constructor to look as,
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
      fontColor = Color.Black;
      font = new Font(“Arial”,8,FontStyle.Regular);
}
 
 
Add the following line to the existing Paint handler.
dc.DrawString(sFont,font, new SolidBrush(fontColor),new Point(0,0));
 
Type the following code for the two menu event handlers.
 
private void menuChooseFont_Click(object sender, System.EventArgs e)
{
FontDialog fontDlg = new FontDialog();
//fontDlg.Color = Color.Red ;  // default color
if (fontDlg.ShowDialog() == DialogResult.OK)
{
font = fontDlg.Font;
Invalidate();
}
}
 
private void mnuChooseColor_Click(object sender, System.EventArgs e)
{
ColorDialog colorDlg = new ColorDialog();
if (colorDlg.ShowDialog() == DialogResult.OK)
{
fontColor = colorDlg.Color;
Invalidate();
}
}
 
Run the application and experiment with the color and font dialogs.
 
 
Client Area Determination:
Sometimes our windows application needs to know the size of the client area. In simple situations, the code in a form class can obtain the client area as,
int cx = this.ClientRectangle.Width;
int cy = this.ClientRectangle.Height;
 
C# – Image Processing
 
C# provides the System.Drawing.Imaging namespace that contains the types related to image processing. One of the useful classes in this namespace is called Bitmap which can easily read images from JPEG or GIF files and convert them to bitmaps. The constructor for the Bitmap class takes on an image file and generates the corresponding bitmap for it.
Bitmap b1 = new Bitmap(“t1.jpg”);
 
Once the image has been converted to a bitmap, you can easily apply different image processing techniques to the individual pixels. For example, if you add a small integer to each RGB byte, you will end up increasing the brightness of the picture. We will develop a small windows application that will allow us to display images and perform different operations on them.
 
When operating on bitmaps, we need to modify the pixel memory directly. This is where old C/C++ style pointers can be very handy. Fortunately C# allows us to deal with memory directly through the unsafe keyword. If a C# code uses an unsafe block, the entire project has to be built by specifying the “Configuration Properties” of the project to “allow unsafe blocks”. We will explain these issues through an example.
 
 
Example: Create a new Windows application. Name the project ImageProc.
Put two picture boxes on the form. Name the left picture box as “picOrig”. Name the right picture box as “picRight”. Set the border style property of the picture boxes to Fixed Single. Set the SizeMode property of the picture boxes to “StretchImage”. Try to size the picture boxes so that their width is larger than their height (similar to the aspect ratio of a 3×5 picture). Put a label “Original Image” underneath the left picture box, and a label “After Image Processing” under the right picture box.
 
Add a main menu to the form. Create a top level menu called “File” with a menu item “Load Image” underneath it. Name the menus as “mnuFile” and “mnuFileLoadImage” respectively.
 
Type the following code for the “Load Image” menu handler.
 
private void mnuFileLoadImage_Click(object sender, System.EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = “jpeg files (*.jpg)|*.jpg”;
if (DialogResult.OK == dialog.ShowDialog())
this.picOrig.Image = new Bitmap(dialog.FileName);
}
Run the program and click on the menu to load an image. Choose a jpg type file and see if the image gets loaded properly in the left picture box.
 
Add a C# class to the project (by right clicking on the project name through the project explorer). Name the class MyImageProc. Add the following method to the MyImageProc class to convert to a Gray scale image from a color image.
 
public static bool CovertToGray(Bitmap b)
{
// GDI+ return format is BGR, NOT RGB.
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData.Stride; // bytes in a row 3*b.Width
System.IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte * p = (byte *)(void *)Scan0;
byte red, green, blue;
int nOffset = stride – b.Width*3;
for(int y=0;y < b.Height;++y)
{
for(int x=0; x < b.Width; ++x )
{
blue = p[0];
green = p[1];
red = p[2];
p[0] = p[1] = p[2] = (byte)(.299 * red
+ .587 * green + .114 * blue);
p += 3;
}
p += nOffset;
}
}
b.UnlockBits(bmData);
return true;
}
 
Because the above code is using types that are defined in the System.Drawing and System.Drawing.Imaging namespaces, you will need to add the following lines, at the top of the MyImageProc class.
using System.Drawing;
using System.Drawing.Imaging;
 
Add a top level menu called “Image Proc”. Underneath the “Image Proc” menu, add a menu item called “Convert to Gray”. Name the “Image proc” menu as mnuImage, and the “Convert to Gray” menu as mnuImageGray. Set the enabled property of this menu to false. Write the following event handler for the “Convert to Gray” menu item.
 
private void mnuImageGray_Click(object sender, System.EventArgs e)
{
Bitmap copy = new Bitmap((Bitmap) this.picOrig.Image);
MyImageProc.CovertToGray(copy);
picRight.Image = null;
picRight.Image = copy;
}
 
 
Modify the File->Load Image handler to enable the “Convert to Gary” menu once an image file has been loaded in the left image box.
 
private void mnuFileLoadImage_Click(object sender, System.EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = “jpeg files (*.jpg)|*.jpg”;
if (DialogResult.OK == dialog.ShowDialog())
{
this.picOrig.Image = new Bitmap(dialog.FileName);
          mnuImageGray.Enabled = true;
 
}
}
 
 
Now if you try to build the program, you will get an error message as “Unsafe code may only appear if compiling with /unsafe”. To take care of this error, right click on the project name, and choose properties. Then click on the “Configuration Properties” and change the “Allow unsafe code block” settings to “True”, as shown below.
 
 
Now build the project. Run the application and load an image in the left hand picture box. Then click on the “Image Proc” menu item and choose “Convert to Gray”. You should see the left hand picture being converted to a “Gray Scale” picture and displayed in the right hand picture box.
 
 
Add a method called “Brighten” to the MyImageProc class. This method will increase the brightness of each pixel by adding a number to each of the RGB bytes. The code for the Brighten method is shown below.
 
public static bool Brighten(Bitmap b, int nBrightness)
{
// GDI+ return format is BGR, NOT RGB.
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
unsafe
{
int nVal;
byte * p = (byte *)(void *)Scan0;
int nOffset = stride – b.Width*3;
int nWidth = b.Width * 3;
for(int y=0;y<b.Height;++y)
{
for (int x = 0;  x < nWidth; ++x)
{
nVal = (int) (p[0] + nBrightness);
if (nVal < 0) nVal = 0;
if (nVal > 255) nVal = 255;
p[0] = (byte)nVal;
++p;
}
p += nOffset;
}
}
b.UnlockBits(bmData);
return true;
}
 
Add another menu item called “Brighten Image” underneath the “Image Proc” menu. Name the “Brighten Image” menu as mnuImageBrighten. Set the enabled property of this menu item to false. Type the following code in the “Brighten Image” handler.
private void mnuImageBrighten_Click(object sender, System.EventArgs e)
{
Bitmap copy = new Bitmap((Bitmap) this.picOrig.Image);
MyImageProc.Brighten(copy,40); // add 40 to each byte in pixel
picRight.Image = null;
picRight.Image = copy;
}
 
Modify the File->Load Image handler to enable the mnuImageBrighten by adding the following line to it:
mnuImageBrighten.Enabled = true;
 
Run the program, and choose an image, then choose the “Brighten Image” menu to brighten the image as shown below.
 
Rather than fixing the amount of brightness, it will be nice to let the user choose the brightness level through another dialog. We can provide a default value of 30 in this dialog. To achieve this, add a “windows form” to the project (by right clicking on the project name and choosing Add). Name the form “BrightnessDlg.cs”. Set the FormBorder property to “Fixed Single”. Also set the “Maximize Box” property to False.
Add a text box to the form. Name the text box, txtBrightness. Add two buttons called Apply and Cancel, with names of cmdApply and cmdCancel respectively. This dialog will look as,
 
The important code in the BrightnessDlg.cs file will look as,
public class BrightnessDlg : System.Windows.Forms.Form
{

 
    public int nBrightness
    {
      get
      {
        return (Convert.ToInt32(txtBrightness.Text, 10));
      }
      set{txtBrightness.Text = value.ToString();}
    }
 
  private void cmdApply_Click(object sender, System.EventArgs e)
    {
      this.DialogResult = System.Windows.Forms.DialogResult.OK;
      this.Close();
    }
 
  private void cmdCancel_Click(object sender, System.EventArgs e)
    {
      this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
      this.Close();
    }
}
}
 
Modify the “Brighten Image” event handler as,
 
private void mnuImageBrighten_Click(object sender, System.EventArgs e)
{
BrightnessDlg dlg = new BrightnessDlg();
dlg.nBrightness = 30;  // default brightness of 30
 
if (DialogResult.OK == dlg.ShowDialog())
{
Bitmap copy = new Bitmap((Bitmap) this.picOrig.Image);
MyImageProc.Brighten(copy,dlg.nBrightness);
picRight.Image = null;
picRight.Image = copy;
mnuFileSave.Enabled = true;
}
}
 
Add a menu called “Save Right Image” under the File menu. Give it a name of mnuFileSave. Type the following code in the event handler.
private void mnuFileSave_Click(object sender, System.EventArgs e)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = “jpeg files (*.jpg)|*.jpg”;
if (DialogResult.OK == dlg.ShowDialog())
this.picRight.Image.Save(dlg.FileName, ImageFormat.Jpeg);
}
 
 
You will need to add the following namespace to the Form1.cs file,
using System.Drawing.Imaging;
 
Modify the Image->Convert to Gray handler to enable the File->Save menu by adding the following line shown in bold.
 
private void mnuImageGray_Click(object sender, System.EventArgs e)
{
Bitmap copy = new Bitmap((Bitmap) this.picOrig.Image);
MyImageProc.CovertToGray(copy);
picRight.Image = null;
picRight.Image = copy;
      mnuFileSave.Enabled = true;
}
 
 
Add a menu called “Exit” under the File menu. Give it a name of mnuFileExit. Type the following code in the event handler.
 
private void mnuFileExit_Click(object sender, System.EventArgs e)
{
this.Close();
}
 
Build and test the program.
 
 

“C# Programming – GDI+”의 394개의 댓글

  1. My coder is trying to convince me to move to .net from PHP.
    I have always disliked the idea because of the expenses.

    But he’s tryiong none the less. I’ve been using Movable-type
    on a number of websites for about a year and am anxious
    about switching to another platform. I have heard good things about blogengine.net.
    Is there a way I can import all my wordpress content into it?
    Any kind of help would be really appreciated!

  2. Hello there, just became aware of your blog through Google,
    and found that it is really informative. I’m gonna watch out for brussels.
    I will appreciate if you continue this in future. Many people will be
    benefited from your writing. Cheers!

  3. Do you have a spam problem on this website; I also am a blogger, and I was wanting to know your situation; we have created some nice practices
    and we are looking to exchange strategies with others, why not shoot me an e-mail if interested.

  4. Thanks for one’s marvelous posting! I seriously enjoyed reading it, you happen to be a great author.

    I will remember to bookmark your blog and will eventually
    come back someday. I want to encourage you continue your great writing,
    have a nice weekend!

  5. Thank you so much for providing individuals with a very remarkable opportunity to check tips from this blog. It is always very fantastic and also stuffed with a great time for me and my office fellow workers to search your site at the least three times per week to study the new issues you will have. And definitely, we’re usually pleased with all the dazzling secrets you serve. Some 4 ideas in this posting are indeed the most beneficial we’ve had.

  6. You are so awesome! I do not suppose I’ve truly read through something like that before. So good to discover another person with some original thoughts on this issue. Seriously.. many thanks for starting this up. This web site is something that is required on the web, someone with a bit of originality!

  7. Hi there! This post could not be written any better! Looking at this article reminds me of my previous roommate! He continually kept preaching about this. I will forward this article to him. Fairly certain he’ll have a good read. I appreciate you for sharing!

  8. Having read this I thought it was rather informative. I appreciate you taking the time and energy to put this short article together. I once again find myself personally spending a lot of time both reading and posting comments. But so what, it was still worthwhile!

  9. An impressive share! I’ve just forwarded this onto a colleague who was doing a little research on this. And he in fact ordered me lunch simply because I stumbled upon it for him… lol. So let me reword this…. Thanks for the meal!! But yeah, thanks for spending time to discuss this matter here on your blog.

  10. The next time I read a blog, Hopefully it does not fail me just as much as this one. After all, I know it was my choice to read, nonetheless I actually believed you would have something useful to say. All I hear is a bunch of whining about something that you can fix if you weren’t too busy looking for attention.

  11. May I just say what a comfort to uncover somebody who truly understands what they are talking about on the internet. You actually know how to bring a problem to light and make it important. A lot more people ought to check this out and understand this side of the story. I can’t believe you aren’t more popular because you certainly have the gift.

  12. A fascinating discussion is worth comment. There’s no doubt that that you ought to write more about this subject matter, it might not be a taboo matter but typically people do not talk about these subjects. To the next! Best wishes!!

  13. What i don’t understood is in reality how you are now not actually a lot more well-favored than you may be right now. You’re so intelligent. You recognize therefore considerably when it comes to this matter, produced me individually imagine it from so many various angles. Its like men and women don’t seem to be involved except it’s one thing to do with Woman gaga! Your own stuffs nice. All the time take care of it up!

  14. Great – I should certainly pronounce, impressed with your site. I had no trouble navigating through all the tabs as well as related information ended up being truly easy to do to access. I recently found what I hoped for before you know it at all. Quite unusual. Is likely to appreciate it for those who add forums or anything, website theme . a tones way for your client to communicate. Excellent task.

  15. Thank you for all your valuable work on this web site. My niece loves working on investigations and it is easy to see why. We all hear all about the powerful medium you create both interesting and useful tricks by means of the web site and as well as strongly encourage participation from other individuals on this theme while our favorite daughter is always learning so much. Enjoy the rest of the year. You are always carrying out a fantastic job.

  16. Nice read, I just passed this onto a colleague who was doing a little research on that. And he just bought me lunch as I found it for him smile So let me rephrase that: Thanks for lunch! “Feeling passionate about something is like getting a peak at your soul smiling back at you.” by Amanda Medinger.

  17. Hello very cool site!! Man .. Excellent .. Amazing .. I will bookmark your website and take the feeds additionally…I am happy to search out so many helpful information here in the post, we want work out more strategies on this regard, thank you for sharing.

  18. We are a group of volunteers and opening a new scheme in our community. Your web site provided us with valuable information to work on. You have done an impressive job and our whole community will be thankful to you.

  19. I must show thanks to the writer just for rescuing me from this particular challenge. Because of searching throughout the search engines and obtaining techniques which were not powerful, I was thinking my life was well over. Existing devoid of the solutions to the issues you’ve fixed through your posting is a critical case, as well as the ones that might have in a wrong way affected my entire career if I hadn’t encountered the blog. Your actual natural talent and kindness in playing with all the things was very helpful. I don’t know what I would have done if I had not encountered such a solution like this. It’s possible to at this time look ahead to my future. Thanks for your time so much for the specialized and amazing guide. I won’t think twice to endorse your web site to any individual who desires guidance about this issue.

  20. Nice read, I just passed this onto a colleague who was doing a little research on that. And he actually bought me lunch since I found it for him smile So let me rephrase that: Thank you for lunch! “Any man would be forsworn to gain a kingdom.” by Roger Zelazny.

  21. Hi, I do think this is a great web site. I stumbledupon it 😉 I will come back yet again since I bookmarked it. Money and freedom is the greatest way to change, may you be rich and continue to guide others.

  22. I was extremely pleased to discover this site. I need to to thank you for ones time for this fantastic read!! I definitely loved every little bit of it and I have you book-marked to look at new things on your website.

  23. Can I simply say what a comfort to uncover somebody that really knows what they’re talking about online. You definitely realize how to bring a problem to light and make it important. A lot more people ought to look at this and understand this side of your story. It’s surprising you are not more popular given that you most certainly have the gift.

  24. I’m impressed, I have to admit. Rarely do I encounter a blog that’s equally educative and engaging, and without a doubt, you have hit the nail on the head. The problem is something not enough men and women are speaking intelligently about. I’m very happy that I stumbled across this during my hunt for something regarding this.

  25. Can I simply just say what a comfort to uncover someone who really understands what they’re discussing on the web. You certainly realize how to bring an issue to light and make it important. A lot more people must read this and understand this side of the story. It’s surprising you’re not more popular because you definitely have the gift.

  26. After looking over a handful of the blog posts on your web page, I seriously appreciate your technique of blogging. I book-marked it to my bookmark webpage list and will be checking back in the near future. Take a look at my web site as well and let me know your opinion.

  27. I really love your site.. Pleasant colors & theme. Did you build this site yourself? Please reply back as I’m attempting to create my own website and would like to know where you got this from or exactly what the theme is named. Kudos!

  28. Right here is the perfect web site for anyone who hopes to understand this topic. You realize so much its almost tough to argue with you (not that I personally will need to…HaHa). You definitely put a fresh spin on a subject that’s been written about for a long time. Wonderful stuff, just great!

  29. Oh my goodness! Incredible article dude! Many thanks, However I am going through troubles with your RSS. I don’t understand why I cannot join it. Is there anybody else having similar RSS problems? Anybody who knows the solution can you kindly respond? Thanks!!

  30. A fascinating discussion is definitely worth comment. I think that you need to write more on this subject matter, it may not be a taboo matter but generally people don’t discuss such subjects. To the next! Many thanks!!

  31. You are so interesting! I don’t think I’ve read something like this before. So nice to find somebody with some genuine thoughts on this subject. Really.. many thanks for starting this up. This web site is one thing that is required on the internet, someone with a bit of originality!

  32. After checking out a few of the articles on your web site, I really appreciate your way of writing a blog. I bookmarked it to my bookmark site list and will be checking back in the near future. Please visit my website too and let me know how you feel.

  33. Can I just say what a relief to discover somebody that really understands what they’re discussing on the web. You certainly realize how to bring an issue to light and make it important. More and more people need to look at this and understand this side of the story. I was surprised that you are not more popular given that you definitely possess the gift.

  34. Next time I read a blog, I hope that it does not disappoint me just as much as this one. After all, I know it was my choice to read, but I really thought you’d have something helpful to talk about. All I hear is a bunch of whining about something you could possibly fix if you weren’t too busy looking for attention.

  35. Hi there! This post could not be written much better! Going through this post reminds me of my previous roommate! He constantly kept talking about this. I most certainly will send this post to him. Fairly certain he’ll have a great read. Many thanks for sharing!

  36. Oh my goodness! Impressive article dude! Thank you so much, However I am experiencing troubles with your RSS. I don’t know why I am unable to subscribe to it. Is there anybody else getting identical RSS issues? Anyone who knows the answer can you kindly respond? Thanks!!

  37. Next time I read a blog, I hope that it does not fail me just as much as this one. I mean, Yes, it was my choice to read, but I truly believed you would have something useful to talk about. All I hear is a bunch of complaining about something that you can fix if you were not too busy seeking attention.

  38. you’re truly a just right webmaster. The site loading velocity is amazing. It kind of feels that you’re doing any distinctive trick. Also, The contents are masterwork. you’ve done a great task in this topic!

  39. What i do not realize is if truth be told how you’re now not really a lot more smartly-appreciated than you may be right now. You are very intelligent. You realize thus considerably with regards to this subject, made me personally consider it from a lot of various angles. Its like men and women aren’t fascinated unless it is something to accomplish with Lady gaga! Your own stuffs great. At all times maintain it up!

  40. A person essentially assist to make severely posts I might state. This is the first time I frequented your website page and to this point? I surprised with the research you made to make this particular publish amazing. Wonderful job!

  41. I think this is among the most important info for me. And i am glad reading your article. But wanna remark on some general things, The web site style is wonderful, the articles is really great : D. Good job, cheers

  42. Thank you for sharing excellent informations. Your site is very cool. I am impressed by the details that you have on this site. It reveals how nicely you understand this subject. Bookmarked this website page, will come back for extra articles. You, my pal, ROCK! I found simply the information I already searched all over the place and simply couldn’t come across. What an ideal website.

  43. After looking into a few of the blog posts on your site, I honestly like your technique of blogging. I added it to my bookmark website list and will be checking back in the near future. Please check out my web site as well and let me know how you feel.

  44. After I initially left a comment I seem to have clicked the -Notify me when new comments are added- checkbox and now every time a comment is added I receive 4 emails with the same comment. There has to be a means you can remove me from that service? Appreciate it!

  45. I would like to thank you for the efforts you’ve put in penning this blog. I really hope to see the same high-grade blog posts from you in the future as well. In truth, your creative writing abilities has motivated me to get my own blog now 😉

  46. After checking out a handful of the blog articles on your blog, I really appreciate your technique of blogging. I book marked it to my bookmark site list and will be checking back soon. Please visit my web site too and let me know how you feel.

  47. You’re so interesting! I do not suppose I’ve truly read through anything like this before. So good to discover somebody with some genuine thoughts on this subject. Really.. thank you for starting this up. This website is something that is needed on the internet, someone with some originality!

  48. I’m impressed, I must say. Rarely do I come across a blog that’s equally educative and engaging, and without a doubt, you have hit the nail on the head. The issue is something which not enough men and women are speaking intelligently about. I am very happy that I came across this during my hunt for something relating to this.

  49. Having read this I thought it was extremely enlightening. I appreciate you spending some time and energy to put this information together. I once again find myself spending way too much time both reading and leaving comments. But so what, it was still worth it!

  50. Thanks, I’ve recently been searching for info approximately this topic for ages and yours is the greatest I have came upon so far. But, what concerning the conclusion? Are you certain concerning the source?

  51. When I originally commented I seem to have clicked the -Notify me when new comments are added- checkbox and now every time a comment is added I receive 4 emails with the exact same comment. Is there a way you are able to remove me from that service? Cheers!

  52. After checking out a handful of the blog posts on your site, I seriously like your way of blogging. I book-marked it to my bookmark website list and will be checking back soon. Take a look at my website too and tell me how you feel.

  53. An interesting discussion is definitely worth comment. I think that you should write more about this subject matter, it might not be a taboo subject but typically folks don’t speak about such subjects. To the next! Kind regards!!

  54. I seriously love your site.. Pleasant colors & theme. Did you develop this site yourself? Please reply back as I’m planning to create my very own site and would love to know where you got this from or what the theme is called. Appreciate it!

  55. May I just say what a relief to uncover an individual who truly knows what they’re talking about online. You definitely know how to bring an issue to light and make it important. A lot more people need to check this out and understand this side of the story. I was surprised you are not more popular since you definitely have the gift.

  56. Hi there! This post couldn’t be written much better! Looking at this post reminds me of my previous roommate! He always kept preaching about this. I most certainly will forward this article to him. Fairly certain he’ll have a great read. Thanks for sharing!

  57. The next time I read a blog, I hope that it doesn’t disappoint me just as much as this one. I mean, I know it was my choice to read through, however I really thought you’d have something interesting to say. All I hear is a bunch of whining about something that you could fix if you were not too busy looking for attention.

  58. May I just say what a relief to uncover someone who actually understands what they’re discussing over the internet. You actually realize how to bring a problem to light and make it important. More people must read this and understand this side of the story. I was surprised that you are not more popular since you definitely have the gift.

답글 남기기