Introduction
This control was originally developed to mimic some existing software that my company was using to view and process medical claims. The original plan was to develop a PictureBox
that would allow the users to draw a box on the image and then zoom in on that point. It was immediately apparent that this would be no easy task.
Changes
The PictureBoxEx
still uses .NET 1.1 to make it more compatible with current and future projects, but has been completely rewritten.
This control is a completely new control, it is no longer based on a PictureBox
but a ScrollableControl
. Making this switch was necessary to create a control that was both flexible and fast. When drawing the drag window, the old control was slow to build the image and refresh, whereas the new control is very smooth.
This new version also contains the ability to add annotations to the images. These annotations can be colored, resized to match the image's current zoom, and best of all are XmlSerializable
, so they can be saved to file and retrieved later.
Scrolling was also added to this new control. The control now has the ability to be scrolled vertically and horizontally, by both the keys and the mouse. Scrolling the wheel causes the image to be scrolled vertically, but if you hold the control key while scrolling the mouse wheel, the image can now be scrolled horizontally. The arrow keys plus Home, End, PageUp, PageDown can all be used to scroll the image. Because the control is unable to receive and hold direct focus, the focus can shift from control to control on the same form. So to make use of the key scrolling, it is best to make this PictureBoxEx
the only control on the form. (If anyone knows how to improve this limitation, I would love to hear about it.)
Also the current zoom of the control can be changed by scrolling the mouse wheel while holding the shift key down.
Features
- Click and drag window to zoom or copy
- Parentless design (New)
- Annotate (Includes custom cursor) (New)
- Diagnostics mode (New)
- Zoom and scroll with the mouse wheel (New)
- Scroll with keys (Works best if the only control on form) (New)
Custom Properties
Most of the controls custom properties are available through the designer.
AllowDrag
: Indicates whether or not the user should be allowed to drag and copy or zoom
CurrentZoom
: Controls the PictureBox
's current zoom.
DefaultZoom
: Controls the PictureBox
's default zoom.
DiagnosticMode
: Set to true to display diagnostics information.
DoubleClickRestore
: Controls the PictureBox
's ability to restore the image to the default zoom on double-click.
DragOptions
: Controls the PictureBox
's drag options. (Copy, Zoom, or Prompt)
DragWindowColor
: Controls the PictureBox
's drag window color.
DragWindowMinimum
: Controls the PictureBox
's minimum invokable drag window size.
DragWindowPattern
: The dash pattern that is used by the control when drawing the drag window.
DrawMode
: Controls the imaging filter that will be applied to the image if it is resized. (InterpolationMode
)
MaximumZoom
: Controls the maximum allowed zoom.
MinimumZoom
: Controls the minimum allowed zoom.
The Code
The following code is used by GenerateResizedImage
to generate the resized image from the backup which is created when the Image
property of the control is set. The creating of the resized image happens regardless of the current zoom, even if it's 1. The reason it's generated anyway is because the control can't work with images of an indexed pixel format. So it's just easier to convert the images straight away.
int resizedWidth = Convert.ToInt32(backup.Width * _currentZoom);
int resizedHeight = Convert.ToInt32(backup.Height * _currentZoom);
resized = new Bitmap(resizedWidth, resizedHeight);
using (Graphics g = Graphics.FromImage(resized))
{
g.InterpolationMode = (_currentZoom < 1F) ?
_drawMode : InterpolationMode.Default;
Rectangle srceRect =
new Rectangle(0, 0, backup.Width, backup.Height);
Rectangle destRect =
new Rectangle(0, 0, resized.Width, resized.Height);
g.DrawImage(backup, destRect, srceRect, GraphicsUnit.Pixel);
DrawAnnotations(g);
}
Determining where the zoom should occur requires a lot of math. The first step it to compensate for the current zoom and the current scroll position. Then, it needs to be determined which part of the drag window is larger in proportion to the size of the control, and enlarge that section to fill the control while centering the remainder.
float xRatio = (float)Width / (float)dragWindowSave.Width;
float yRatio = (float)Height / (float)dragWindowSave.Height;
float largerRatio;
int xAdjust = 0;
int yAdjust = 0;
largerRatio = (xRatio < yRatio) ? xRatio : yRatio;
if ((largerRatio * _currentZoom) > _maximumZoom)
largerRatio = _maximumZoom / _currentZoom;
if (dragWindowSave.Width * largerRatio > Width)
largerRatio = (float)Width / (float)dragWindowSave.Width;
if (dragWindowSave.Height * largerRatio > Height)
largerRatio = (float)Height / (float)dragWindowSave.Height;
yAdjust = Convert.ToInt32(
((float)Height - (float)dragWindowSave.Height * largerRatio) / 2F);
xAdjust = Convert.ToInt32(
((float)Width - (float)dragWindowSave.Width * largerRatio) / 2F);
int xScrollPos = Math.Max(Convert.ToInt32(((float)-AutoScrollPosition.X +
(float)dragWindowSave.X) * largerRatio) - xAdjust, 0);
int yScrollPos = Math.Max(Convert.ToInt32(((float)-AutoScrollPosition.Y +
(float)dragWindowSave.Y) * largerRatio) - yAdjust, 0);
CurrentZoom *= largerRatio;
Using the Control
The control is very much like a PictureBox
. All that really needs to be done is to add the control to a form and set its Image
property.
- Add a reference to the Build DLL.
- Add the control to your form.
- Set the desired control properties.
- Set the control's
Image
property.
Lessons Learned
This control has an event that fires after the image has been changed. If subscribers of this event take a lot of time or processor power, it will appear to have a negative impact on the performance of this control.
Without a backup
image, the zooming process (in and out) will degrade image quality.
Known Issues
- Some designer mode instability.
- Some issues with the border styles not being drawn correctly.
History
This control was developed for Trusted Plans Service Corp. Tacoma WA.
- Version 1 - released 3/6/2006.
- Version 2 - released 12/12/2006.