Programming, to me, is like one big mashup, thanks to Google and all the much smarter programmers than me who are out there sharing their code. I've learned a lot of cool GDI+ tricks from various programmers and "borrowed" their open source code where I needed it for the Crystal Toolkit. But I think I've learned and lifted from one man in particular: Bob Powell and his GDI tips and tricks website. In trying to create the classes for a cool image viewer, I stumbled into the limitations of the PictureBox control, which Bob has railed against for a while. To prove that there was an alternative, he wrote the ZoomPicBox example, which shows you how to live without it.
CrystalPictureBox is a "crystalization" of ZoomPicBox. You can see it here in action in the CrystalImageGridDemo application. CrystalPictureShow (a derivative of CrystalPictureBox) is in the top splitter pane, while CrystalImageGridView is displaying the thumbnails from an image folder on the bottom. If you examine the painting code in CrystalPictureBox, you'll see that I retained Powell's technique of setting up a Matrix with a zoom factor, setting the Matrix in the Graphics object, and using DrawImage. One thing I added to the mix was the ability to center the image within the client rectangle. I did this by adjusting the starting location, based on the zoom factor. To use this mode, all you have to do is make sure the ImageSizeMode is set to RatioStretch in the CrystalPictureBox object.
When the user starts dragging the trackbar on the lower toolbar, the zoom factor changes. Inside the code, I set ImageSizeMode to Scrollable and also set the zoom factor represented by the trackbar (or combo box). The result is a pretty nice and clean scaling of the image as the user drags the mouse. Give a salute to Captain America in all his glory for his unfortunate "death" (what a joke as I think he will be revived) was revealed this week. And let's hope that Silver Surfer looks as nice in the Fantastic Four movie as he does in this close-up.
CrystalPictureBox simply allows you to display images, zoom to a certain percentage of the original size, ratio stretch within the available rectangle, and gives you a cool gradient background. The concept for Scrollable and RatioStretch size modes came from Gil Klod's Viewer user control on CodeProject. I got very used to switching between these two modes and decided to retain them.
CrystalPictureShow, derived from CrystalPictureBox, is more tightly integrated with CrystalImageGridModel to allow you to navigate through lists of CrystalImageItem objects. In the regular display mode, you can view the image in a window just like the above example. If you press the Slideshow button in the demo, you'll see the sample application take over your whole screen (making the form border, menu, toolbars, etc. disappear) and call CrystalPictureShow's StartSlideShow method.
There are four slideshow effects in this first release of CrystalPictureShow: Slide (image moves in from top, bottom, left or right), Fade (image slowly ghosts into the next one), Spin (second image spins and zooms from the current image), and Iris (second image zooms from the current image in an ellipitical form). There was no way that I could have done these without Bob Powell's help. He used to have a subscription based newsletter called Well Formed, and in a number of these he showed people how to do image transitions using GDI+. Unfortunately, Well Formed is not being published at the moment and there's no way to get them on his website. However, this is where being relentless and using Google searches pays off: I found this article on Google Groups where Mr. Powell graciously published a VB example program of the image transition effects. Which I gratefully gobbled up and converted to C#.
Check out CrystalImageGridDemo for an example of all of these things in action (get the latest version of CrystalToolkit on the Downloads page). I feel like I owe Bob Powell several drinks and a fine dinner.



hi richard-
first of all THANK YOU!! i can't even begin to express my almost infinite gratitude for all of the work you've put into this toolkit. and open-source to boot...fantastico! studying your code has advanced my understanding of image manipluation and C# by leaps and bounds. i am trying to integrate many of the features into a custom scanner interface app i am putting together by which the user can select a previously scanned image from a number of thumbnails. they can then rescan the original, and the new image is displayed side-by-side with the old image. however, getting a single tiff from the scanner into the crystal pictureshow control is proving problematic. it's looking for an imageitem type, which doesn't seem to equate seamlessly with the raw tiff image type, and it also wants to use the collector control to select from a group of imageitems, rather than just a single one at a time. what tips can you pass along to help with this task?
thanks so very much again!
-kevon
Hi Richard,
I came across your profile on LinkedIn. I'm doing a search for a stellar company in the Bay Area that you might be interested in.
Please email me a when you get this today. When can we chat?
Aloha,
Jacquie
Kevon,
If I understand your problem correctly, you are having difficulty getting a single image into the CrystalPictureShow control. You can do this by placing the bitmap into the Image property, as the CrystalImageGridDemo does:
private void DisplayImage(CrystalImageItem imageItem)
{
if (_collector.LoadImage(ref imageItem))
{
_currentImage = imageItem;
viewerMain.Image = imageItem.FullImage;
SetScale();
...
The CrystalPictureShow control really doesn't use the Crystal Collector type of object unless it is doing a slideshow.
Also, in the recently released CrystalMemoryCollector, you can use this to add images that you load yourself (without using the file collector). In a recent application, I did the following:
private void AddImage(ref CrystalMemoryCollector memCollector,
Image image, string imageName)
{
if (image == null)
return;
CrystalImageItem imageItem = new CrystalImageItem();
imageItem.FullImage = image;
imageItem.ThumbnailImage = image;
imageItem.ImageName = imageName;
memCollector.GridModel.CrystalImageList.Add(imageItem);
}
CrystalMemoryCollector memCollector = new CrystalMemoryCollector();
memCollector.CollectImages();
Image image = StampRes.stamp_001;
AddImage(ref memCollector, image, "Spider-Man");
image = StampRes.stamp_002;
AddImage(ref memCollector, image, "Hulk");
...
I am going to improve the Memory Collector in the next release, but you get the idea.