简体   繁体   中英

Create thumbnail in c# from stream

After 3 hours of debugging and searching I have this.

        public Stream ResizeImageToThumbnail(Stream imageStream, int width)
        {
            var image = Image.FromStream(imageStream);

            var height = (width * image.Height) / image.Width;
            var thumbnail = image.GetThumbnailImage(width, height, null, IntPtr.Zero);

            using var thumbnailStream = new MemoryStream();
            thumbnail.Save(thumbnailStream, ImageFormat.Jpeg);
            return thumbnailStream;
        }

Problem is, it returns exception

ArgumentException: Parameter is not valid.

at

var image = Image.FromStream(imageStream);

Parameter is file.OpenFileStream(); where file is IFormFile .

I'm out of ideas.

Edit

Requested code:


foreach (var item in model.UploadedImages) //item = IFormFile, image only allowed from HTML's end
{
   using var ms = item.OpenReadStream();
   _service.AttachImage(newId, ms, item.FileName);
   ms.Position = 0;
   _service.AttachThumb(newId, ms, item.FileName); //cannot access a closed stream exception
}

Edit 2

AttachThumb is using closed stream, returns exception (check comment). It appears that ResizeImageToThumbnail returns closed stream.

public void AttachThumb(Guid id, Stream imageStream, string imageName)
        {
            Post post = GetPost(id);

            ObjectId imageId = _gridFS.UploadFromStream(imageName, ResizeImageToThumbnail(imageStream, 640)); //cannot use closed stream

            post.ImagesThumbs.Add(imageId.ToString());

            var filter = Builders<Post>.Filter.Eq(x => x.Id, id);
            var update = Builders<Post>.Update.Set("ImagesThumbs", post.ImagesThumbs);
            _posts.UpdateOne(filter, update);
        }

        public Stream ResizeImageToThumbnail(Stream imageStream, int width)
        {
            var image = Image.FromStream(imageStream);

            var height = (width * image.Height) / image.Width;
            var thumbnail = image.GetThumbnailImage(width, height, null, IntPtr.Zero);

            using var thumbnailStream = new MemoryStream();
            thumbnail.Save(thumbnailStream, ImageFormat.Jpeg);
            return thumbnailStream;
        }

First copy the content of the file into a stream, then use that stream. Rewind the stream in between. Note that the two Attach* methods must not access the stream asynchronously. Otherwise you would have to create a second in-memory copy first.

foreach (var item in model.UploadedImages)
{
    // Copy content in to stream
    using (MemoryStream stream = new MemoryStream())
    {
        item.CopyTo(stream);

        // Rewind and use
        stream.Position = 0;
        _service.AttachImage(newId, stream, item.FileName);
        
        // Rewind and use
        stream.Position = 0;
        _service.AttachThumb(newId, stream, item.FileName);
    }
}

As noted by user Jimi, you have to remove the using clause from the ResizeImageToThumbnail method. Otherwise the method returns an already disposed MemoryStream :

public Stream ResizeImageToThumbnail(Stream imageStream, int width)
{
    var image = Image.FromStream(imageStream);

    var height = (width * image.Height) / image.Width;
    var thumbnail = image.GetThumbnailImage(width, height, null, IntPtr.Zero);

    // Bad: using var thumbnailStream = new MemoryStream();
    // Remove using
    var thumbnailStream = new MemoryStream(); 
    thumbnail.Save(thumbnailStream, ImageFormat.Jpeg);
    return thumbnailStream;
}

Then dispose the stream outside:

public void AttachThumb(Guid id, Stream imageStream, string imageName)
{
    Post post = GetPost(id);

    using var thumbnailStream = ResizeImageToThumbnail(imageStream, 640);
    // rewind stream
    thumbnailStream.position = 0;
    ObjectId imageId = _gridFS.UploadFromStream(imageName, thumbnailStream); 

    ...

You could improve the design of this by not having the ResizeImageToThumbnail method create the stream but instead create the stream outside and pass it to ResizeImageToThumbnail as a parameter. So the caller of ResizeImageToThumbnail is then responsible for creating and disposing the stream.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM