Upload images to the grid asynchronously

I am developing a small application that will receive RAW image files, convert them to low-quality JPEG, and then upload these JPEGs as thumbnails to the grid.

My problem: I am having problems blocking the user interface during image conversion. I dynamically add controls to place these images in the grid immediately after conversion for each image. In addition, I bind these images to the control Image Sourceusing my ControlPropertiesViewModel in code.

My coding:

Here I create a new instance of my view model ControlProperties, and inside I do the image conversion on ImageSource.

cp = new ControlProperties()
{
    ImageId = controlCount += 1, ImageSource = ThumbnailCreator.CreateThumbnail(imagePath)
};

My question is:

Having seen that the images have been loading for some time, I need to get full control over my user interface when they are converted and added to my grid, but I don’t understand at all. Can someone please help me with some tips or snippets of code to get me going, please?

My ThumbnailCreatorclass

using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;

namespace SomeProjName
{
    public class ThumbnailCreator
    {
        private static string imageLocation;
        private static int currentImage;
        public static BitmapImage CreateThumbnail(string oldImagePath)
        {
            ConvertHighQualityRAWImage(oldImagePath);

            if (imageLocation != string.Empty && imageLocation != null)
                return OpenImage(imageLocation);
            else return null;
        }

        //Creates low quality JPG image from RAW image
        private static void ConvertHighQualityRAWImage(string oldImagePath)
        {

            BitmapImage image = new BitmapImage(new Uri(oldImagePath));
            var encoder = new JpegBitmapEncoder() { QualityLevel = 17 };
            encoder.Frames.Add(BitmapFrame.Create(image));

            using (var filestream = new FileStream(GetImageLocation(), FileMode.Create))
                encoder.Save(filestream);

            image.UriSource = null;
            image.StreamSource = null;
            image = null;

            GC.WaitForPendingFinalizers();
            GC.Collect();
        }

        //Returns low quality JPG thumbnail to calling method
        private static BitmapImage OpenImage(string imagePath)
        {
            BitmapImage image = new BitmapImage();
            image.BeginInit();
            image.DecodePixelWidth = 283;
            image.CacheOption = BitmapCacheOption.OnLoad;
            image.UriSource = new Uri(imagePath, UriKind.Relative);
            image.EndInit();

            DeleteImage();
            return image;
        }

        private static string GetImageLocation()
        { 
            imageLocation = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "thumbnails")).FullName + GetCurrentImage();
            return imageLocation;
        }

        private static string GetCurrentImage()
        {
            return "\\" + (currentImage += 1).ToString() + ".jpg";
        }

        private static void DeleteImage()
        {
            if (File.Exists(imageLocation))
                File.Delete(imageLocation);
        }
    }
}
+4
source share
2 answers

You do not need to save the thumbnails to a file. Use instead MemoryStream:

public class ThumbnailCreator
{
    public static BitmapImage CreateThumbnail(string imagePath)
    {
        BitmapFrame source;

        using (var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
        {
            source = BitmapFrame.Create(
                stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
        }

        var encoder = new JpegBitmapEncoder() { QualityLevel = 17 };
        encoder.Frames.Add(BitmapFrame.Create(source));

        var bitmap = new BitmapImage();

        using (var stream = new MemoryStream())
        {
            encoder.Save(stream);
            stream.Position = 0;

            bitmap.BeginInit();
            bitmap.DecodePixelWidth = 283;
            bitmap.CacheOption = BitmapCacheOption.OnLoad;
            bitmap.StreamSource = stream;
            bitmap.EndInit();
        }

        bitmap.Freeze();
        return bitmap;
    }

An intermediate encoding and decoding code does not even seem necessary, so you can simply write this:

public class ThumbnailCreator
{
    public static BitmapImage CreateThumbnail(string imagePath)
    {
        var bitmap = new BitmapImage();

        using (var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
        {
            bitmap.BeginInit();
            bitmap.DecodePixelWidth = 283;
            bitmap.CacheOption = BitmapCacheOption.OnLoad;
            bitmap.StreamSource = stream;
            bitmap.EndInit();
        }

        bitmap.Freeze();
        return bitmap;
    }
}

If you want to call the CreateThumbnail method asynchronously, use Task.Run():

cp.ImageSource = await Task.Run(() => ThumbnailCreator.CreateThumbnail(fileName));
+2

:

Clemens. , . , .

public static BitmapImage CreateThumbnail(string imagePath)
{
    var bitmap = new BitmapImage();

    using (var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
    {
        bitmap.BeginInit();
        bitmap.DecodePixelWidth = 283;
        bitmap.CacheOption = BitmapCacheOption.OnLoad;
        bitmap.StreamSource = stream;
        bitmap.EndInit();
    }

    bitmap.Freeze();

    GC.WaitForPendingFinalizers();
    GC.Collect();

    return bitmap;
}
0

Source: https://habr.com/ru/post/1680492/


All Articles