locked
Generating thumbnail images RRS feed

  • Question

  • I already described my problem that I have huge images inside of my LS database. All stored nicely in image attributes. However, I do not want to transfer these images all the time when a grid with the images is shown.

     

    My idea is to write a image_Change() event that generates a thumbnail image in another property that is shown inside the grid instead of the full-size image.

    Problem: I need System.Drawing -- which is not available in Common -- in order to create the thumbnail image. Is there an alternative?

     


    -- Holger Flick
    Friday, February 3, 2012 9:57 AM

Answers

  • Image helper class (client project):

    using System;
    using System.IO;
    using System.Reflection;
    using System.Windows.Media.Imaging;
    using System.Windows.Controls;
    using System.Windows.Media;
    using FluxJpeg.Core;
    using FluxJpeg.Core.Encoder;
    
    namespace LightSwitchApplication
    {
        public class ImageHelper
        {
            public static byte[] GetStreamAsByteArray(Stream stream)
            {
                if (stream != null)
                {
                    var streamLength = Convert.ToInt32(stream.Length);
                    var imageData = new byte[streamLength];
                    stream.Read(imageData, 0, streamLength);
                    stream.Close();
                    return imageData;
                }
                return null;
            }
    
            public static WriteableBitmap GetImageSource(Stream stream, double maxWidth, double maxHeight)
            {
                BitmapImage bmp = new BitmapImage();
                bmp.SetSource(stream);
    
                System.Windows.Controls.Image img = new System.Windows.Controls.Image();
                //img.Effect = new DropShadowEffect() { ShadowDepth = 0, BlurRadius = 0 };
                img.Source = bmp;
    
                double scaleX = 1;
                double scaleY = 1;
    
                if (bmp.PixelHeight > maxHeight)
                    scaleY = maxHeight / bmp.PixelHeight;
                if (bmp.PixelWidth > maxWidth)
                    scaleX = maxWidth / bmp.PixelWidth;
    
                // maintain aspect ratio by picking the most severe scale
                double scale = Math.Min(scaleY, scaleX);
    
                int newWidth = Convert.ToInt32(bmp.PixelWidth * scale);
                int newHeight = Convert.ToInt32(bmp.PixelHeight * scale);
                WriteableBitmap result = new WriteableBitmap(newWidth, newHeight);
                result.Render(img, new ScaleTransform() { ScaleX = scale, ScaleY = scale });
                result.Invalidate();
                return result;
            }
    
            public static Stream JpgEncoder(WriteableBitmap bitmap, int quality)
            {
                //Convert the Image to pass into FJCore
                int width = bitmap.PixelWidth;
                int height = bitmap.PixelHeight;
                int bands = 3;
    
                byte[][,] raster = new byte[bands][,];
    
                for (int i = 0; i < bands; i++)
                {
                    raster[i] = new byte[width, height];
                }
    
                for (int row = 0; row < height; row++)
                {
                    for (int column = 0; column < width; column++)
                    {
                        int pixel = bitmap.Pixels[width * row + column];
                        raster[0][column, row] = (byte)(pixel >> 16);
                        raster[1][column, row] = (byte)(pixel >> 8);
                        raster[2][column, row] = (byte)pixel;
                    }
                }
    
                ColorModel model = new ColorModel { colorspace = ColorSpace.RGB };
    
                FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster);
    
                //Encode the Image as a JPEG
                MemoryStream stream = new MemoryStream();
                JpegEncoder encoder = new JpegEncoder(img, quality, stream);
    
                encoder.Encode();
    
                //Move back to the start of the stream
                stream.Flush();
                stream.Seek(0, SeekOrigin.Begin);
                return stream;
            }
        }
    }

    Client screen consumer:

    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.IO;
    using System.Linq;
    using Microsoft.LightSwitch;
    using Microsoft.LightSwitch.Presentation.Extensions;
    using Microsoft.LightSwitch.Threading;
    
    namespace LightSwitchApplication
    {
        public partial class ProductsListDetail
        {
            partial void ProductsListDetail_Saving(ref bool handled)
            {
                var products = Products.Where(i => i.Details.EntityState == EntityState.Added || i.Details.EntityState == EntityState.Modified).AsEnumerable();
                foreach (var product in products)
                {
                    if (product.Picture != null && product.Details.Properties.Picture.IsChanged)
                    {
                        System.Diagnostics.Debug.WriteLine(string.Format("Shrinking picture for product: {0}", product.Name));
                        byte[] bytes = null;
                        Dispatchers.Main.BeginInvoke(() =>
                        {
                            //http://programmerpayback.com/2010/01/21/use-silverlight-to-resize-images-and-increase-compression-before-uploading/
                            var wb = ImageHelper.GetImageSource(new MemoryStream(product.Picture), 128, 128); //RESIZE...
                            bytes = ImageHelper.GetStreamAsByteArray(ImageHelper.JpgEncoder(wb, 75));		  //JPEG COMPRESSION...
                        });
    
                        var startTime = DateTime.Now;
                        while (true) //need to wait some time to resize+compression task complete
                        {
                            //System.Diagnostics.Debug.WriteLine(DateTime.Now.Subtract(startTime).TotalMilliseconds);
                            if (bytes != null)
                            {
                                product.Picture = bytes;
                                break;
                            }
                            if (DateTime.Now.Subtract(startTime).TotalMilliseconds > 8000)
                            {
                                break;
                            }
                        }
                        //File.WriteAllBytes(string.Format(@"c:\{0}.jpg", product.Name), product.Picture); //only for desktop application
                    }
                }
            }
        }
    }

    This article helps me to accomplish this:

    http://programmerpayback.com/2010/01/21/use-silverlight-to-resize-images-and-increase-compression-before-uploading/

    You will need add FJCore.dll reference to client project.

    You can find it in this project: link

    Hope this will help you...





    Saturday, March 3, 2012 7:16 AM

All replies

  • Hi

    This is how to create the thumbnail image in asp.net.

    We can do the same thing in lightswitch.

    http://www.mindfiresolutions.com/How-to-generate-thumbnail-image-at-runtime-in-ASPNET-619.php

    Hope it helpful.

    Thursday, February 9, 2012 10:32 AM
    Moderator

  • http://www.mindfiresolutions.com/How-to-generate-thumbnail-image-at-runtime-in-ASPNET-619.php

    Hope it helpful.

    Sadly, no, as the code depends on System.Drawing and that is not available on the client-side.


    -- Holger Flick

    Thursday, February 9, 2012 2:57 PM
  • We really need a thumbnail solution for image storage.

    Why can't we generate the thumbnails on the server side?


    Garth Henderson - Vanguard Business Technology

    Thursday, February 9, 2012 6:31 PM
  • Well you can generate thumbnails on Server side (I do it to store Products picture and display them on a website) if you need help to store thumbnails on server side (Inserting/Updating methods) I'll try to help you.

    Like Yann Said : "If you found this post helpful, please "Vote as Helpful". If it actually answered your question, remember to "Mark as Answer". This will help people find the answers that they're looking for more quickly."

    Friday, March 2, 2012 4:43 PM
  • Image helper class (client project):

    using System;
    using System.IO;
    using System.Reflection;
    using System.Windows.Media.Imaging;
    using System.Windows.Controls;
    using System.Windows.Media;
    using FluxJpeg.Core;
    using FluxJpeg.Core.Encoder;
    
    namespace LightSwitchApplication
    {
        public class ImageHelper
        {
            public static byte[] GetStreamAsByteArray(Stream stream)
            {
                if (stream != null)
                {
                    var streamLength = Convert.ToInt32(stream.Length);
                    var imageData = new byte[streamLength];
                    stream.Read(imageData, 0, streamLength);
                    stream.Close();
                    return imageData;
                }
                return null;
            }
    
            public static WriteableBitmap GetImageSource(Stream stream, double maxWidth, double maxHeight)
            {
                BitmapImage bmp = new BitmapImage();
                bmp.SetSource(stream);
    
                System.Windows.Controls.Image img = new System.Windows.Controls.Image();
                //img.Effect = new DropShadowEffect() { ShadowDepth = 0, BlurRadius = 0 };
                img.Source = bmp;
    
                double scaleX = 1;
                double scaleY = 1;
    
                if (bmp.PixelHeight > maxHeight)
                    scaleY = maxHeight / bmp.PixelHeight;
                if (bmp.PixelWidth > maxWidth)
                    scaleX = maxWidth / bmp.PixelWidth;
    
                // maintain aspect ratio by picking the most severe scale
                double scale = Math.Min(scaleY, scaleX);
    
                int newWidth = Convert.ToInt32(bmp.PixelWidth * scale);
                int newHeight = Convert.ToInt32(bmp.PixelHeight * scale);
                WriteableBitmap result = new WriteableBitmap(newWidth, newHeight);
                result.Render(img, new ScaleTransform() { ScaleX = scale, ScaleY = scale });
                result.Invalidate();
                return result;
            }
    
            public static Stream JpgEncoder(WriteableBitmap bitmap, int quality)
            {
                //Convert the Image to pass into FJCore
                int width = bitmap.PixelWidth;
                int height = bitmap.PixelHeight;
                int bands = 3;
    
                byte[][,] raster = new byte[bands][,];
    
                for (int i = 0; i < bands; i++)
                {
                    raster[i] = new byte[width, height];
                }
    
                for (int row = 0; row < height; row++)
                {
                    for (int column = 0; column < width; column++)
                    {
                        int pixel = bitmap.Pixels[width * row + column];
                        raster[0][column, row] = (byte)(pixel >> 16);
                        raster[1][column, row] = (byte)(pixel >> 8);
                        raster[2][column, row] = (byte)pixel;
                    }
                }
    
                ColorModel model = new ColorModel { colorspace = ColorSpace.RGB };
    
                FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster);
    
                //Encode the Image as a JPEG
                MemoryStream stream = new MemoryStream();
                JpegEncoder encoder = new JpegEncoder(img, quality, stream);
    
                encoder.Encode();
    
                //Move back to the start of the stream
                stream.Flush();
                stream.Seek(0, SeekOrigin.Begin);
                return stream;
            }
        }
    }

    Client screen consumer:

    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.IO;
    using System.Linq;
    using Microsoft.LightSwitch;
    using Microsoft.LightSwitch.Presentation.Extensions;
    using Microsoft.LightSwitch.Threading;
    
    namespace LightSwitchApplication
    {
        public partial class ProductsListDetail
        {
            partial void ProductsListDetail_Saving(ref bool handled)
            {
                var products = Products.Where(i => i.Details.EntityState == EntityState.Added || i.Details.EntityState == EntityState.Modified).AsEnumerable();
                foreach (var product in products)
                {
                    if (product.Picture != null && product.Details.Properties.Picture.IsChanged)
                    {
                        System.Diagnostics.Debug.WriteLine(string.Format("Shrinking picture for product: {0}", product.Name));
                        byte[] bytes = null;
                        Dispatchers.Main.BeginInvoke(() =>
                        {
                            //http://programmerpayback.com/2010/01/21/use-silverlight-to-resize-images-and-increase-compression-before-uploading/
                            var wb = ImageHelper.GetImageSource(new MemoryStream(product.Picture), 128, 128); //RESIZE...
                            bytes = ImageHelper.GetStreamAsByteArray(ImageHelper.JpgEncoder(wb, 75));		  //JPEG COMPRESSION...
                        });
    
                        var startTime = DateTime.Now;
                        while (true) //need to wait some time to resize+compression task complete
                        {
                            //System.Diagnostics.Debug.WriteLine(DateTime.Now.Subtract(startTime).TotalMilliseconds);
                            if (bytes != null)
                            {
                                product.Picture = bytes;
                                break;
                            }
                            if (DateTime.Now.Subtract(startTime).TotalMilliseconds > 8000)
                            {
                                break;
                            }
                        }
                        //File.WriteAllBytes(string.Format(@"c:\{0}.jpg", product.Name), product.Picture); //only for desktop application
                    }
                }
            }
        }
    }

    This article helps me to accomplish this:

    http://programmerpayback.com/2010/01/21/use-silverlight-to-resize-images-and-increase-compression-before-uploading/

    You will need add FJCore.dll reference to client project.

    You can find it in this project: link

    Hope this will help you...





    Saturday, March 3, 2012 7:16 AM