This is a migrated thread and some comments may be shown as answers.

Resize image when uploading

16 Answers 278 Views
Upload
This is a migrated thread and some comments may be shown as answers.
hwu
Top achievements
Rank 1
hwu asked on 13 Sep 2010, 09:39 PM
Hi,
I have problem when using the upload control. Please help.

1) I try to resize the image in the before uploading to the server, but it does not work. It loads the original image.

    private void radUpload1_FileUploadStarting(object sender, FileUploadStartingEventArgs e)
        {
            RadUploadSelectedFile file = e.SelectedFile as RadUploadSelectedFile;
            WriteableBitmap wb;
           
            using (Stream stream = file.File.OpenRead())
            {
                wb = ResizeImage(stream, 300); //resize the image to 300 pix
            }

           using (Stream Source = GetSource(wb))
            {
                 // The GetSource function will return the small Stream from the new resize image.  This is working

                // upload the resized image instead the original image. 
                // This does not work. It loads the original image but not the new image.
                e.NewFileStream = Source;
            }
        }

2) When I try to upload more than 1 image. When start to load the second, it will throw out "Invalid cross-thread access."

private WriteableBitmap ResizeImage(Stream stream, double targetSize)
        {
            // This is the line that throw the error when the second image start to load.
            BitmapImage bmp = new BitmapImage(); 


            bmp.SetSource(stream);

            Image img = new Image();
            img.Source = bmp;
            double scaleX = 1;
            double scaleY = 1;

            if (bmp.PixelHeight > targetSize)
                scaleY = targetSize / bmp.PixelHeight;
            if (bmp.PixelWidth > targetSize)
                scaleX = targetSize / bmp.PixelWidth;

            
            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;
        }

Thank you.

16 Answers, 1 is accepted

Sort by
0
Tina Stancheva
Telerik team
answered on 16 Sep 2010, 06:33 PM
Hi hwu,

Can you please take a look at the project I attached to the support thread you sent. Thank you in advance.

Greetings,
Tina Stancheva
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Louis Bouchard
Top achievements
Rank 1
answered on 20 Oct 2010, 12:19 AM
Hello Tina,

Can you post your project please?  I got the very same issue.

Thank you
0
Tina Stancheva
Telerik team
answered on 21 Oct 2010, 01:54 PM
Hello Louis Bouchard,

In order to resize the uploaded images on the clent-side you can use the approach described here.

I also attached the sample project. Hope it helps.

Best wishes,
Tina Stancheva
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Louis Bouchard
Top achievements
Rank 1
answered on 22 Oct 2010, 12:09 PM
Hello Tina Stancheva

Very interesting article.

But HOW I can use it in the RadUpload events?

Thank you for your precious time.
0
Tina Stancheva
Telerik team
answered on 22 Oct 2010, 03:48 PM
Hello Louis Bouchard,

In the previously attached sample (348506-uploadsample.zip) the FileUploadStarting event is handled to get the stream of each SelectedFile in order to resize it.

The ResizeImage method actually resizes the SelectedFile using its source and returning the result as a WriteableBitmap. Once you have the resized WriteableBitmap object, you can pass it to the server using the e.NewFileStream property. Here you can either go with the approach illustrated in the attached project - creating a buffer, or you can simply implement the following:
private void myUpload_FileUploadStarting(object sender, FileUploadStartingEventArgs e)
{
    RadUploadSelectedFile file = e.SelectedFile as RadUploadSelectedFile;
    WriteableBitmap wb;
  
    using (Stream stream = file.File.OpenRead())
    {
        wb = ResizeImage(stream, 300); //resize the image to 300 pix
    }
  
    e.NewFileStream = JpgEncoder.Encode(wb, 50);
}
The final result should be for example, if you upload an image with size: 1280x800, on the server this image should be resized to 300x188. Have a look at the project and let me know if you need more info.

All the best,
Tina Stancheva
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Louis Bouchard
Top achievements
Rank 1
answered on 22 Oct 2010, 07:39 PM
Dear Tina Stancheva,

Thank you a lot for the project.  But I dont see anything about multiple files.

Can you explain more about the situation when I upload more that 1 file?  I suppose it's use some kind of foreach...

Wait for your answer.

Bye bye
0
Tina Stancheva
Telerik team
answered on 28 Oct 2010, 09:21 AM
Hi Louis Bouchard,

Please accept my apology for the delayed response.

The FileUploadStarting event occurs before a file starts uploading therefore it occurs for each selected file. And since the resizing logic is entirely implemented in FileUploadStarting event handler, you shouldn't have any issues implementing it for multiple files.

For example if 3 image files are selected for upload in the above example - Image1.png, Image2.png, Image3.png, the FileUploadStarting event will be raised 3 times for each image in the order the images are displayed in the RadUpload control (alphabetically) and the FileUploadStartingEventArgs e object will hold the image file that is about to be uploaded and will modify its size accordingly.

Here you can find more info about the RadUpload events. I hope this info helps but please let me know if you need more or if I am missing something.

Greetings,
Tina Stancheva
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Louis Bouchard
Top achievements
Rank 1
answered on 30 Oct 2010, 01:53 AM
Hello Tina,

No problem about the delay. You help me a lot.

But, when I try to upload 3 or 4 files (see iimage), I got this error "Invalid cross-thread access" at BitmapImage bmp = new BitmapImage();

This seem related to thread.  So, what's I can do to manage it?  I read something about this "problem" (http://stackoverflow.com/questions/1924408/invalid-cross-thread-access-issue) :

Also, BitmapImages have to be instantiated on the UI thread. This is because it uses DependencyProperties, which can only be used on the UI thread. I have tried instantiating BitmapImages on separate threads and it just doesn't work. You could try to use some other means to store images in memory. For example, when you download the image, store it in a MemoryStream. Then a BitmapImage on the UI thread can set its source to the MemoryStream.

 

private void RadUploadPhotosEspaceClos_FileUploadStarting(object sender, Telerik.Windows.Controls.FileUploadStartingEventArgs e)
{
    RadUploadSelectedFile file = e.SelectedFile as RadUploadSelectedFile;
    WriteableBitmap wb;
    using (Stream stream = file.File.OpenRead())
    {
        wb = ResizeImage(stream, 500); //resize the image to 300 pix
    }
    byte[] buffer;
    using (Stream Source = JpgEncoder.Encode(wb, 80))
    {
        int bufferSize = Convert.ToInt32(Source.Length);
        buffer = new byte[bufferSize];
        Source.Read(buffer, 0, bufferSize);
    }
    //NOTE: use the buffer to show the image...
    e.NewFileStream = new MemoryStream(buffer);
}
private WriteableBitmap ResizeImage(Stream stream, double targetSize)
{
    BitmapImage bmp = new BitmapImage();
    bmp.SetSource(stream);
    System.Windows.Controls.Image img = new System.Windows.Controls.Image();
    img.Source = bmp;
    double scaleX = 1;
    double scaleY = 1;
    if (bmp.PixelHeight > targetSize)
        scaleY = targetSize / bmp.PixelHeight;
    if (bmp.PixelWidth > targetSize)
        scaleX = targetSize / bmp.PixelWidth;
    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;
}
0
Alex Fidanov
Telerik team
answered on 03 Nov 2010, 09:06 AM
Hello Louis Bouchard,

Please try using the Dispatcher.BeginInvoke() method inside the FileUploadStarting event. This will ensure that you are always on the main (UI) thread and you should not be getting this exception. The source of this issue is that the server side of the RadUpload is raising this event and it is on another thread. We are currenctly working on resolving this trying to prevent any concurrency or timing issues that may appear.

Sincerely yours,
Alex Fidanov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Louis Bouchard
Top achievements
Rank 1
answered on 03 Nov 2010, 03:55 PM
Hello Alex,

A big thank you for your answer.  But I have already try this code (see below) and file are transfered but the size are not changed (see jpg attached file).  Do you see something  wrong in my code?

private void RadUploadPhotos_FileUploadStarting(object sender, Telerik.Windows.Controls.FileUploadStartingEventArgs e)
{
    RadUploadSelectedFile file = e.SelectedFile as RadUploadSelectedFile;
    WriteableBitmap wb;
         
    Deployment.Current.Dispatcher.BeginInvoke ( () =>{
    using (Stream stream = file.File.OpenRead())
    {
        wb = ResizeImage(stream, 500); //resize the image to 300 pix
    }
  
    byte[] buffer;
    using (Stream Source = JpgEncoder.Encode(wb, 80))
    {
        int bufferSize = Convert.ToInt32(Source.Length);
        buffer = new byte[bufferSize];
        Source.Read(buffer, 0, bufferSize);
    }
    e.NewFileStream = new MemoryStream(buffer);
    });
}
  
private WriteableBitmap ResizeImage(Stream stream, double targetSize)
{
    BitmapImage bmp = new BitmapImage();
  
    bmp.SetSource(stream);
    System.Windows.Controls.Image img = new System.Windows.Controls.Image();
    img.Source = bmp;
    double scaleX = 1;
    double scaleY = 1;
  
    if (bmp.PixelHeight > targetSize)
        scaleY = targetSize / bmp.PixelHeight;
    if (bmp.PixelWidth > targetSize)
        scaleX = targetSize / bmp.PixelWidth;
  
  
    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;
}


0
Alex Fidanov
Telerik team
answered on 08 Nov 2010, 10:39 AM
Hi Louis Bouchard,

This looks like a timing issue when dispatching the code inside the event handler. I have logged this ("RadUpload: Concurrency issue when using a Dispatcher inside the FileUploadStarting event") as an issue in our PITS system and you can check its progress from here. Your Telerik points were also updated.

Sincerely yours,
Alex Fidanov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Don
Top achievements
Rank 1
answered on 30 Mar 2011, 06:54 PM
Hi,

I have the same issue. I get a cross-thread exception when uploading multiple flies. 

For each file, when the file uploading event occurs, i try and set some file parameters from my ViewModel. I found that when i get to the File uploading event the 2nd time, i get a cross thread exception when trying to call a method on my ViewModel. In fact, i can't even cast my ViewModel (it's an interface reference in the view, using prism) to my actual concrete ViewModel class, i get the cross-thread exception.

So i tried the Dispatcher.BeginInvoke(). The problem with that is it runs async and my method returns before the Dispatcher has time to set the event args for the file parameters. So i basically need to "wait" for the dispatcher call to finish. 

Here is how i worked around the issue:

private int originalThreadId;
private AutoResetEvent _waitHandler = new AutoResetEvent(false);
private void RadUpload1_FileUploadStarting(object sender, FileUploadStartingEventArgs e)
{
 if (originalThreadId == 0)
 {
   originalThreadId = Thread.CurrentThread.ManagedThreadId;
 }
 
 var isOriginalThread = (originalThreadId == Thread.CurrentThread.ManagedThreadId);
 
 if (!isOriginalThread)
 {
  Dispatcher.BeginInvoke(() =>;
  {
   Debug.WriteLine("Starting RadUpload1_FileUploadingStarting.BeginInvoke.GetDocumentModelForUpload");
   _waitHandler.Reset(); //Call this method to make sure the _waitHandler is indeed in a wait state.
   ViewModel.GetDocumentModelForUpload(e.FileParameters, e.SelectedFile.Name);
   _waitHandler.Set(); //Signal _waitHandler to continue on
  });
 }
 else
 {
   Debug.WriteLine("Starting RadUpload1_FileUploadingStarting.GetDocumentModelForUpload");
   ViewModel.GetDocumentModelForUpload(e.FileParameters, e.SelectedFile.Name);
 }
 
 if (!isOriginalThread)
 {
   //Only call this if we are not on the original thread.
   _waitHandler.WaitOne();
 }
}

0
Andrew
Top achievements
Rank 1
answered on 11 Jul 2012, 07:21 PM
Having the same issue with cross-thread collision on the BitmapImage object when trying to upload multiple files. Any solution to this yet?
0
Tina Stancheva
Telerik team
answered on 16 Jul 2012, 01:44 PM
Hello Andrew,

Please accept our apology for this inconvenience, unfortunately this issue hasn't been addressed yet. I am not sure what is your scenario and why you use the FileUploadStarting event, but if you can modify your implementation not to use the handler of this event, that should get over the exception.

Kind regards,
Tina Stancheva
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Dave Navarro
Top achievements
Rank 2
answered on 11 Oct 2012, 03:01 PM
Hello,

I'm also looking to resize images (for thumbnails) before uploading.

Are the methods described in this post still the suggested methods now that we're using Silverlight 5?

I've got one of the samples wired up but I'm getting corrupted files in the end... so, my hope is that there's a new method in place. Ideally, it would be a function built into SL5.

Anyway, please let me know and thanks!

~ Dave
0
Tina Stancheva
Telerik team
answered on 16 Oct 2012, 01:54 PM
Hi Dave,

We are not aware of any other approaches in Silverlight 5 for resizing images. And the approach described in the thread works as expected on our side so I'm not sure what might be corrupting the files on your side. If you'd like, you can send over a sample solution demonstrating the issue so that we can take a closer look at it.

Regards,
Tina Stancheva
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

Tags
Upload
Asked by
hwu
Top achievements
Rank 1
Answers by
Tina Stancheva
Telerik team
Louis Bouchard
Top achievements
Rank 1
Alex Fidanov
Telerik team
Don
Top achievements
Rank 1
Andrew
Top achievements
Rank 1
Dave Navarro
Top achievements
Rank 2
Share this question
or