Atalasoft
Welcome to Atalasoft Community Sign in | Join | Help
in

Thumbnail List Control

Last post 11 Jul 2006, 5:06 PM by jigar_aminsoft. 12 replies.
Sort Posts: Previous Next
  •  23 Nov 2003, 9:32 PM 8427

    Thumbnail List Control

    The first article in the new dotImage Customer Articles and Source forum will be submitted by us.  Due to the overwhelming request for an efficient thumbnail viewer control, we have opted to create one that isn’t quite “production” quality, but good enough for general comsumption as long as the source is provided. Here is a screenshot:
     
     undefined
     
    This thumbnail viewer control has the following features:
    • Load an image from a file or AtalaImage directly and automatically resizes the image to a thumbnail and displays it
    • Asynchronous Processing
    • Scaled JPEG loading for ultra fast thumbnails of JPEG images
    • Uses Scale-To-Gray to quickly resize 1-bit images into grayscale thumbs
    • Extends the ListView control
     
    When an image is loaded into the control, it will keep the thumbnail in memory unless it’s removed.  Therefore, it’s probably not the best control to use for a folder of 10,000 images.  That is something that is left to the developer, or for a future production quality control.  However for general use, I think this control is adequate.  A 100x100 thumbnail only takes up 29 Kb, so it would take 1000 thumbnails to use up 290 Mb, (about equivalent to viewing a 5 Mega-Pixel image).
     
    This ThumbView control was created by inheriting from the ListView control, part of the .NET Framework.  Therefore all features of the ListView are part of ThumbView.  By default, it will display the thumbnails in LargeIcon view, with each thumbnail being represented by an image index in an associated ImageList (also part of the .NET Framework).  When a thumbnail is added to the control either via AddFromFile or AddFromImage, it creates an item in the ListView with a blank image.  The next step is tol run a custom ImageCommad called MakeThumbCommand which loads the image and create the thumbnail.  Because this command will be run in another thread, we use the ProcessFinished event of the Workspace object event to let the ThumbView control know that the thumbnail is ready.
     
    By taking advantage of the extensibility of dotImage and the .NET Framework, creating an efficient multi-threaded thumbnail viewer is a fairly simple process with only intermediate programming knowledge required.
     
    There are some improvements we could make to this control.  The major one would be to make this ListView owner-drawn and virtual.  This would take some fairly complex Win32 code, and if created would be implemented as part of the dotImage WinControls in the future.  This would give the control much more flexibility including the ability to only load the images that are being viewed (or about to be viewed).  And allows for a directory of unlimited number of images to be displayed.  This would also give some more flexibility of the thumbnail spacing, and possible effects like drop shadows and watermarks.
     
    If anyone would like to improve the code, please feel free to post your results here.  See the attached zip file for the entire C# source code.  It would be great if someone here would convert the code to VB for other VB users.
     
    The most interesting code from the ImageProcessing / dotImage perspective in the MakeThumbCommad class with scaled JPEG and resampling example.  Here is that portion of the code.  See the attached file for the complete project.
     
    MakeThumbCommand.cs 
    public class MakeThumbCommand : ImageCommand
    {
     private Size size;
     private Color backgroundColor;
     private ImageList imageList;
     private ListView listView;
     private string fileName;
     private bool inPlace = false;
     public MakeThumbCommand(Size size, Color backgroundColor, ListView listView, string fileName, ImageList imageList)
     {
      this.size = size;
      this.backgroundColor = backgroundColor;
      this.imageList = imageList;
      this.listView = listView;
      this.fileName = fileName;
     }
     //TODO: Include public properties here so they can be accessed once the command is created
     public override AtalaImage ApplyToImage(AtalaImage image)
     {
      AtalaImage srcImage;
      double zoom = 0;
      //load the image from a file if a filename is not empty
      if (fileName.Length > 0)
      {
       //----------------------------------------------------
       //Load image from a file
       //----------------------------------------------------
       //take advantage of a JPEG and open it scaled (improves performance)
       ImageInfo info = RegisteredDecoders.GetImageInfo(this.fileName);
       if (info.ImageType == ImageType.Jpeg)
       {
        JpegDecoder jpg = new JpegDecoder();
        //find out the zoom factor required for the thumbnail
        zoom = GetZoomFromSize(this.size, info.Size);
        //set the JPEG Scale factor
        if (zoom <= 0.125)
         jpg.ScaleFactor = JpegScaleFactor.Eighth;
        else if (zoom <= 0.250)
         jpg.ScaleFactor = JpegScaleFactor.Quarter;
        else if (zoom <= 0.500)
         jpg.ScaleFactor = JpegScaleFactor.Half;
        else
         jpg.ScaleFactor = JpegScaleFactor.Full;
        //open stream for filename and open it with the scaled JPEG Decoder
        Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
        srcImage = new AtalaImage(fileStream, 0, jpg, null);
        fileStream.Close();
       }
       else
        //image is not a JPEG, open it normally
        srcImage = new AtalaImage(this.fileName, null);     
      }
      else
       srcImage = image;
      //-----------------------------
      //Make thumbnail from image
      //-----------------------------
      zoom = GetZoomFromSize(this.size, srcImage.Size);
      AtalaImage newImage;
      if (zoom < 1)
      {
       AtalaImage tmpImage = srcImage;
       ImageCommand cmd = null;
       Size newSize = new Size((int)(srcImage.Width * zoom), (int)(srcImage.Height * zoom));
       switch (srcImage.PixelFormat)
       {
        case PixelFormat.Pixel1bppIndexed:
         //scale to gray
         cmd = new Atalasoft.Imaging.ImageProcessing.Document.ResampleDocumentCommand(
          new Rectangle(Point.Empty, srcImage.Size),
          newSize,
          ResampleMethod.Default);
         break;
        case PixelFormat.Pixel8bppIndexed:
         //scale to RGB
         cmd = new ResampleColormappedToRgbCommand(newSize);
         break;
        default:
         //resize normally
         cmd = new ResampleCommand(newSize);
         if (srcImage.PixelFormat != PixelFormat.Pixel24bppBgr)
          //make the image 24-bit so it's compatible with the image list
          tmpImage = srcImage.GetChangedPixelFormat(PixelFormat.Pixel24bppBgr);
         break;
       }
       newImage = cmd.ApplyToImage(tmpImage);
       if (tmpImage != srcImage)
        tmpImage.Dispose();
      }
      else
      {
       //use the current image
       if (srcImage.PixelFormat != PixelFormat.Pixel24bppBgr)
        newImage = srcImage.GetChangedPixelFormat(PixelFormat.Pixel24bppBgr);
       else
        newImage = srcImage;
      }
      //if image doesn't fit size, then we'll resize canvas
      AtalaImage finalImage;
      if (!(srcImage.Width == this.size.Width && srcImage.Height == this.size.Height))
      {
       ResizeCanvasCommand resizeCanvas = new ResizeCanvasCommand(this.size, new Point((int)((this.size.Width - newImage.Width) / 2), (int)(this.size.Height - newImage.Height) / 2), this.backgroundColor);
       finalImage = resizeCanvas.ApplyToImage(newImage);
      }
      else
       finalImage = newImage;
      if (newImage != srcImage)
       newImage.Dispose(); 
      //if the image didn't change
      //set the in place processing property to true so the workspace doesn't dispose it
      if (image == finalImage)
       inPlace = true;
      return finalImage;
     }
     //Workspace uses this to determine if the image should be autodisposed or not
     public override bool InPlaceProcessing
     {
      get { return inPlace; }
     }
     //this function calculates the zoom level of the current image in order to fit to the thumbnail dimensions
     private double GetZoomFromSize(Size thumbSize, Size imageSize)
     {
      if ((double)imageSize.Width / thumbSize.Width > (double)imageSize.Height / thumbSize.Height)
       //size to the width
       return (double)(thumbSize.Width) / imageSize.Width;
      else
       //size to the height
       return (double)(thumbSize.Height) / imageSize.Height;
     }
    }
     

    Bill Bither
    Atalasoft
  •  16 Dec 2003, 10:20 PM 8428 in reply to 8427

    RE: Thumbnail List Control

    I found this to be very useful. However, I get errors when calling:

    public void AddImage(AtalaImage image, string text)
    {
    //resize image to correct dimensions
    myWorkspace.Image = image;
    base.Items.Add(new ListViewItem(text, -1));
    myWorkspace.ApplyCommand(new MakeThumbCommand(thumbSize, base.BackColor, this, "", imageList));
    }

    It seems that the workspace_ProcessComplete event gets fired when setting myWorkspace.Image and when calling myWorkspace.ApplyCommand, thus causing problems with imageList. What I am trying to do is show the thumbnails for all the pages for a .tif image using the following logic:

    // Called by pressing a button after the workspace viewer has an image loaded
    private void button1_Click(object sender, System.EventArgs e)
    {
    for (int i=0; i<Viewer1.Images.Count; i++)
    {
    thumbView1.AddImage(Viewer1.Images, i.ToString());
    }
    }

    Any suggestions?
  •  17 Dec 2003, 11:10 PM 8429 in reply to 8427

    RE: Thumbnail List Control

    Here is a VB Version.  The code was converted using a converter, then cleaned up manually. 


    For future reference, making a Property named ThumbSize and a local variable named thumbSize is not the best thing to do if you want to be able to easily convert C# to VB code.  VB Variables are not case sensitive  so these two conflict.  It also makes it hard to figure out which ones to change since once you change the declaration all of the others will now point at the property.
     
     
     
    Rick

  •  20 Jan 2004, 10:54 AM 8430 in reply to 8427

    RE: Thumbnail List Control

    Hi,


    can i used this in a web form and how.?????
  •  23 Feb 2004, 10:53 PM 8431 in reply to 8427

    RE: Thumbnail List Control

    Ok, this is probably going to sound really lame, but how do I download the source for this? I can't see a link to an attachment anywhere.
  •  24 Feb 2004, 1:05 AM 8432 in reply to 8427

    RE: Thumbnail List Control

    Oops, we had a problem with the size of our forum database and had to delete all attatchments.  The link to the C# project is http://www.atalasoft.com/components/download/DotImageThumbnails.zip
    Hopefully Rick can repost the VB.NET version.

    Bill Bither
    Atalasoft
  •  10 Mar 2004, 3:11 AM 8433 in reply to 8427

    RE: Thumbnail List Control

    Attachment: attach.zip
    I had downloaded Ricks original file.  This was his attachment.
  •  04 Nov 2004, 2:16 AM 8434 in reply to 8427

    RE: Thumbnail List Control

    This has been made obsolete by the new ThumbnailView and FolderThumbnailView included in DotImage 2.0.
    Bill Bither
    Atalasoft
  •  22 Nov 2005, 12:58 PM 8435 in reply to 8427

    RE: Thumbnail List Control

    Hi
    I like to look at DotImageThumbnails.zip but I can't find it.
    Could you give me new link?

    Rob
  •  22 Nov 2005, 2:38 PM 8436 in reply to 8427

    RE: Thumbnail List Control

    This article is obsolete now that DotImage includes a ThumbnailView control. The new link however is http://www.atalasoft.com/download/dotimagethumbnails.zip


    Bill Bither
    Atalasoft
  •  13 Apr 2006, 5:44 PM 9932 in reply to 8436

    Re: RE: Thumbnail List Control

    Hi Bill,

    I am totally ignorant of atlanta products. Please let me know following things, so that I can decide to buy product..

    So, will this image thumbnail control be able to do following things ?


    1. Load an image (jpg or bmp from disk) and display in thumbnail control. ?
    2. change the preview size of the image thumbnail control at runtime. ?
    3. Giving customized right click menu on thumbnail of the control ?
    4. Getting click-double click event of the control.

    Full source code for this control only (dont want library internal coding..) in C# (VS 2005 ?)

    Please let me know as soon as possible.

    Regards,
    Jigar Mehta
    jigar.aminsoft@gmail.com
  •  14 Apr 2006, 9:17 AM 9935 in reply to 9932

    Re: RE: Thumbnail List Control

    As Bill said last November, this control is now included in DotImage (our imaging library) and we do not sell the source code for it.  However, you are free too look at that older code if you like.  All these features are included in our thumbnail control in DotImage.
    Sean McKenna
    Atalasoft Development Team
  •  11 Jul 2006, 5:06 PM 10382 in reply to 9935

    Re: RE: Thumbnail List Control

    Can I get snapshot of the sample somewhere ?

    Regards,
    Jigar Mehta
View as RSS news feed in XML