从HttpPostedFileBase转换为图像会由于位置而产生错误

时间:2018-11-03 13:05:44

标签: c# asp.net .net asp.net-mvc

我有以下控制器,该控制器从视图接收文件时会生成一个缩略图,并将图像和缩略图分别保存到数据库中

public async Task<ActionResult> FileUpload(HttpPostedFileBase file)
    {
        if (file != null && file.ContentLength > 0)
        {
            var logo = new Logo() { LogoGuid = Guid.NewGuid() };
            var clinica = await GetClinicaAsync();

            if (IsClinicNonexistent(clinica))
            {
                db.Logos.Add(logo);
                clinica.LogoGuid = logo.LogoGuid;
            }

            else
                logo = await db.Logos.FirstOrDefaultAsync(l => l.LogoGuid == clinica.LogoGuid);

            logo.LogoImage = GetImage(file);
            logo.Thumbnail = GetThumbnail(file);

            db.SaveChanges();
        }

        return RedirectToAction("Arquivos");
    }

对于此错误,请调用方法:

private byte[] GetThumbnail(HttpPostedFileBase file)
    {
        var image = Image.FromStream(file.InputStream);
        var thumbnailSize = GetThumbnailSize(image);
        var memoryStream = new MemoryStream();
        var thumbnail = image.GetThumbnailImage(thumbnailSize.Width, thumbnailSize.Height, null, IntPtr.Zero);
        image.Save(memoryStream, ImageFormat.Jpeg);

        return memoryStream.ToArray();
    }

该代码配置在运行该行时会产生错误

var image = Image.FromStream(file.InputStream);

错误是:“ System.ArgumentException:参数无效。”

The error produced

我可以参考的所有文档使我相信,它们在语义和逻辑上都是正确的,但是仍然存在错误...

但是,有趣的是,如果移动会产生错误的转换行,请执行调用方法,特别是从头开始:

public async Task<ActionResult> FileUpload(HttpPostedFileBase file)
    {
        if (file != null && file.ContentLength > 0)
        {
            var logo = new Logo() { LogoGuid = Guid.NewGuid() };
            var clinica = await ClinicaAsync();

            var image = Image.FromStream(file.InputStream);

没有错误。请注意,转换行位于上面代码的最后一行中,因此位于控制器的开头。同样,如果我将该行进一步向下移动,但仍在控制器中,则会再次出现错误...

如何在GetThumbnail方法中保持该行在逻辑上的位置?

作为附加参考,GetImage方法是:

private byte[] GetImage(HttpPostedFileBase file)
    {
        using (var br = new BinaryReader(file.InputStream))
            return br.ReadBytes(file.ContentLength);
    }

1 个答案:

答案 0 :(得分:1)

您应该知道的第一件事是Image.FromStream()需要尚未被读取的流(MemoryStreamInputStream等),或者位置被重置为开始使用Seek()方法。

首先,在使用GetThumbnail()属性或Position调用Seek()方法之前,尝试重置指针:

// alternative 1
logo.LogoImage = GetImage(file);
file.InputStream.Position = 0;
logo.Thumbnail = GetThumbnail(file);

// alternative 2
logo.LogoImage = GetImage(file);
file.InputStream.Seek(0, SeekOrigin.Begin);
logo.Thumbnail = GetThumbnail(file);

如果这不起作用,可能的原因是您在Image.FromStream()已经HttpPostedFileBase.InputStream使用(并处置)了BinaryReader后调用Dispose()using语句会自动调用它),从而引发异常。

您可以使用Stream.CopyTo()MemoryStream创建HttpPostedFileBase.InputStream的副本,如下例:

public async Task<ActionResult> FileUpload(HttpPostedFileBase file)
{
    if (file != null && file.ContentLength > 0)
    {
        var logo = new Logo() { LogoGuid = Guid.NewGuid() };
        var clinica = await GetClinicaAsync();

        var ms = new MemoryStream();
        file.InputStream.CopyTo(ms); // copy HTTP stream to memory stream

        if (IsClinicNonexistent(clinica))
        {
            db.Logos.Add(logo);
            clinica.LogoGuid = logo.LogoGuid;
        }

        logo.LogoImage = GetImage(file);
        ms.Position = 0; // make sure the stream is read from beginning
        logo.Thumbnail = GetThumbnail(ms);

        db.SaveChanges();
    }

    return RedirectToAction("Arquivos");
}

然后应更改GetThumbnail()参数以接受从HTTP流复制的MemoryStream

// get image from memory stream
private byte[] GetThumbnail(MemoryStream file)
{
    var image = Image.FromStream(ms);
    var thumbnailSize = GetThumbnailSize(image);
    var thumbnail = image.GetThumbnailImage(thumbnailSize.Width, thumbnailSize.Height, null, IntPtr.Zero);
    image.Save(file, ImageFormat.Jpeg);

    return file.ToArray();
}

注意:您还可以将流作为图像文件保存在磁盘上,然后使用Server.MapPath()进行读取以生成缩略图。

相关问题:

Image.FromStream(PostedFile.InputStream) Fails. (Parameter is not valid.) (AsyncFileUpload))

How do you convert a HttpPostedFileBase to an Image?