How do I determine the size of an uploaded image using Silverlight 2?

I am loading an image to the background and I want the silverlight canvas containing all its dimensions to resize the image (or the maximum or minimum that I define) regardless of the image size. So I did the following:

private int ImageMargin = 4;

    public Page()
    {
        InitializeComponent();

        BitmapImage bi = new BitmapImage(new Uri("1.jpg", UriKind.Relative));
        backgroundImage.Source = bi;
        bi.DownloadProgress += new EventHandler<DownloadProgressEventArgs>(bi_DownloadProgress);

        backgroundImage.SizeChanged += new SizeChangedEventHandler(backgroundImage_SizeChanged);

    }

    void bi_DownloadProgress(object sender, DownloadProgressEventArgs e)
    {
        if (e.Progress == 100)
        {
          LayoutRoot.Height = backgroundImage.Height + ImageMargin * 2;
          LayoutRoot.Width = backgroundImage.Width + ImageMargin * 2;
        }
    }

      

The image loads correctly, but no matter where I seem to put backgroundImage.Height / Width (off.Loaded event, .SizeChanged event [1], using border [2], etc.) it always returns 0.0 or NaN. What am I doing wrong?

[1] http://silverlight.net/forums/t/14855.aspx [2] http://silverlight.net/forums/t/90235.aspx

0


a source to share


2 answers


Ah, the solution! Silverlight Tip of the Day # 13 - How to get the dimensions of images in Silverlight.

private Image image;

    public Page()
    {
        InitializeComponent();
        LoadImage("image.png");
    }

    private void LoadImage(string path)
    {

        Uri uri = new Uri(path, UriKind.Relative);
        BitmapImage bitmapImage = new BitmapImage();
        bitmapImage.UriSource = uri;
        bitmapImage.DownloadProgress += 
            new EventHandler<DownloadProgressEventArgs>(bitmapImage_DownloadProgress);
    }

    void bitmapImage_DownloadProgress(object sender, DownloadProgressEventArgs e)
    {
        if (e.Progress == 100)
        {
            Dispatcher.BeginInvoke(delegate()
            {
               double height = image.ActualHeight;
               double width = image.ActualWidth;
            });
        }
    }

      



The KEY was like this:

Calling Dispatcher.BeginInvoke (delegate () {...}); required before Width / Height, or they can be intermittently at zero.

+2


a source


You should probably wait for one UI loop to make sure Silverlight has the ability to update layouts. You also need to be sure that the image is actually visible. I actually wrote a little routine that gets the image size from a binary image. The downside is that you will need to load the image explicitly through the WebClient, but the good thing is that you will know the dimensions without actually displaying anything:

namespace StatMap.Silverlight.Services.UIHelpers
{
    public static class ImageSizeExtractor
    {
        public static bool TryGetImageSize(byte[] buf, out int width, out int height)
        {
            return TryGetPngSize(buf, out width, out height) || TryGetJpegSize(buf, out width, out height);
        }

        private static bool IsPng(byte[] buf)
        {
            return (buf.Length > 8)&&(buf[0] == 137) && (buf[1] == 80) && (buf[2] == 78) && (buf[3] == 71)
                   && (buf[4]==13)&&(buf[5]== 10)&&(buf[6]== 26)&&(buf[7]== 10);
        }

        private static bool TryGetPngSize(byte[] buf, out int width, out int height)
        {
            width = 0;
            height = 0;
            if (IsPng(buf))
            {
                int index = -1;
                for (int i = 8; i < buf.Length - 12;i++)
                {
                    if ((buf[i]==0x49)&&(buf[i+1]==0x48)&&(buf[i+2]==0x44)&&(buf[i+3]==0x52))
                    {
                        index = i + 4;
                        break;
                    }
                }

                if (index<0)
                {
                    return false;
                }
                width = buf[index + 3] + buf[index + 2]*256;
                height = buf[index + 7] + buf[index + 6]*256;
                return true;
            }
            return false;
        }

        private static bool TryGetJpegSize(byte[] buf, out int width, out int height)
        {
            //static char get_jpeg_size(unsigned char* data, unsigned int data_size, unsigned short *width, unsigned short *height) {
            //Check for valid JPEG image
            int i = 0; // Keeps track of the position within the file
            width = 0;
            height = 0;
            if (buf[i] == 0xFF && buf[i + 1] == 0xD8 && buf[i + 2] == 0xFF && buf[i + 3] == 0xE0)
            {
                i += 4;
                // Check for valid JPEG header (null terminated JFIF)
                if (buf[i + 2] == 'J' && buf[i + 3] == 'F' && buf[i + 4] == 'I' && buf[i + 5] == 'F' &&
                    buf[i + 6] == 0x00)
                {
                    //Retrieve the block length of the first block since the first block will not contain the size of file
                    int blockLength = buf[i]*256 + buf[i + 1];
                    while (i < buf.Length)
                    {
                        i += blockLength; //Increase the file index to get to the next block
                        if (i >= buf.Length) return false; //Check to protect against segmentation faults
                        if (buf[i] != 0xFF) return false; //Check that we are truly at the start of another block
                        if (buf[i + 1] == 0xC0)
                        {
                            //0xFFC0 is the "Start of frame" marker which contains the file size
                            //The structure of the 0xFFC0 block is quite simple [0xFFC0][ushort length][uchar precision][ushort x][ushort y]
                            width = buf[i + 5]*256 + buf[i + 6];
                            height = buf[i + 7]*256 + buf[i + 8];
                            return true;
                        }
                        i += 2; //Skip the block marker
                        blockLength = buf[i]*256 + buf[i + 1]; //Go to the next block
                    }
                    return false; //If this point is reached then no size was found
                }
                return false;
            }
            return false;
        }
    }
}

      



Hope it helps.

+1


a source







All Articles