mko
mko

Reputation: 7325

Cannot access a closed Stream? How to prevent it?

I am trying to run this code but I always get an error "cannot access a closed Stream"

private MemoryStream GetBitmap(Stream stream, int width, int height)
        {
            const int size = 150;
            const int quality = 75;

            using (var image = new Bitmap(System.Drawing.Image.FromStream(stream)))
            {
                //int width, height;
                if (image.Width > image.Height)
                {
                    width = size;
                    height = Convert.ToInt32(image.Height * size / (double)image.Width);
                }
                else
                {
                    width = Convert.ToInt32(image.Width * size / (double)image.Height);
                    height = size;
                }

                var resized = new Bitmap(width, height);
                using (var graphics = Graphics.FromImage(resized))
                {
                    graphics.CompositingQuality = CompositingQuality.HighSpeed;
                    graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    graphics.CompositingMode = CompositingMode.SourceCopy;
                    graphics.DrawImage(image, 0, 0, width, height);

                    using (var output = new MemoryStream())
                    {
                        var qualityParamId = Encoder.Quality;
                        var encoderParameters = new EncoderParameters(1);
                        encoderParameters.Param[0] = new EncoderParameter(qualityParamId, quality);
                        var codec = ImageCodecInfo.GetImageDecoders()
                            .FirstOrDefault(codec => codec.FormatID == ImageFormat.Jpeg.Guid);

                        resized.Save(output, codec, encoderParameters);

                        return output;
                    }
                }
            }
        }

Not sure how can I prevent Memorystream output from closing a Stream stream.

EDIT After your suggestions here is the new code

public Stream GetBitmap(Stream stream)
        {
            using (var image = SystemDrawingImage.FromStream(stream))
            {
                var scaled = ScaledSize(image.Width, image.Height, ThumbnailSize);
                var resized = new Bitmap(scaled.width, scaled.height);
                using (var graphics = Graphics.FromImage(resized))
                using (var attributes = new ImageAttributes())
                {
                    attributes.SetWrapMode(WrapMode.TileFlipXY);
                    graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    graphics.CompositingMode = CompositingMode.SourceCopy;
                    graphics.CompositingQuality = CompositingQuality.AssumeLinear;
                    graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    graphics.DrawImage(image, Rectangle.FromLTRB(0, 0, resized.Width, resized.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes);

                    using (var encoderParams = new EncoderParameters(1))
                    using (var qualityParam = new EncoderParameter(Encoder.Quality, (long)Quality))
                    {
                        encoderParams.Param[0] = qualityParam;

                        var streamOutput = new MemoryStream();
                        resized.Save(streamOutput, systemDrawingJpegCodec, encoderParams);

                        return streamOutput;
                    }
                }
            }
        }

Here is the controller action method

   [HttpGet("{photoId}")]
        public async Task<IActionResult> GetPhoto(intphotoId)
        {
            if (String.IsNullOrEmpty(photoid))
                return NotFound();

            var response = await _service.GetPhotoAsync(photoId);

            Response.Headers.Add("Content-Disposition", new ContentDisposition()
            {
                FileName = "test.jpg",
                Inline = true
            }.ToString());

            return File(response, "image/jpeg");

        }

Upvotes: 0

Views: 10948

Answers (1)

Sean
Sean

Reputation: 62532

You're creating the MemoryStream in a using block. When the block goes out of scope the Dispose method is being called. Just remove the using so that it isn't closed:

var output = new MemoryStream())

var qualityParamId = Encoder.Quality;
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(qualityParamId, quality);
var codec = ImageCodecInfo.GetImageDecoders()
    .FirstOrDefault(codec => codec.FormatID == ImageFormat.Jpeg.Guid);

resized.Save(output, codec, encoderParameters);

return output;

Also, if you're planning to have the caller read the stream then you'll probably want to reset the Position property so that anyone reading from it starts from the beginning:

output.Position = 0;
return output;

Upvotes: 4

Related Questions