sql-server - 从以二进制形式存储的 Mssql 服务器数据库中检索图像
问题描述
我已经在 MSSql 数据库中以二进制格式存储了一个 jpeg 文件,现在我无法检索原始图像文件/jpeg 文件。有人可以帮我吗?我使用 ASP.net 核心 MVC 将数据存储在数据库中。
ASP.net Core 2.2
MSSQL 2008
Visual Studio 2019
[HttpGet]
public IActionResult Index1()
{
var ab = _context.Movie.Select(a => a.File).Single();
return View(ab);
}
// POST: api/Uploads
[HttpPost]
public IActionResult Post(Movie entity, IFormFile File)
{
using (var stream = new MemoryStream())
{
File.CopyTo(stream);
entity.File = stream.ToArray();
}
_context.Movie.Add(entity);
_context.SaveChanges();
return Ok();
}
@model IEnumerable<FileUploads.Models.Movie>
@{
ViewBag.Title = "Index1";
}
<h1>Index1</h1>
<table>
<tr>
@foreach (var item in Model)
{
<td>
@{
var base64 = Convert.ToBase64String(item.File);
var imgsrc = string.Format("data:image/jpeg;base64,{0}", base64);
}
<img src='@imgsrc' style="max-height:100px;max-width:100px"/>
}
</td>
}
</tr>
</table>
_________
这就是我的 post 方法、get 方法和查看页面的外观。
请帮我。如何获取原始 JPEG 格式的图像?如果您也可以向我展示查看页面,那将会很有帮助。
解决方案
目前尚不清楚实际问题是什么。您拥有的代码应该可以工作。
但是,无论如何,这不是正确的方法,因此与其浪费时间尝试调试它,不如简单地做对。
使用数据 URI 的问题有两个:
您基本上是在 HTML 响应中嵌入图像,这意味着它将非常大并且可能需要很长时间才能下载。Web 浏览器在收到完整的 HTML 文档之前无法开始呈现页面,因此文档越大,第一次有意义的绘制之前的时间就越长(即您将盯着一个空白屏幕)。一张图片可能还不错,但是以这种方式添加的越多,问题就会成倍地恶化。您的 HTML 文档最终可能会达到兆字节大小,尤其是对于移动数据而言,这是一个不好的溢价。
Base64 是一种低效的编码。顾名思义,每个字节由 64 个 ASCII 字符的组合表示。由于一个字节可以编码 256 个数字,因此最多需要 4 个字符(每个字符 1-2 个字节)来表示图像中的每个单独的字节。如果不清楚,这意味着您的图像大小将膨胀。正常运行 50-60KB JPEG 的成本可能高达 240KB Base64 编码,这只会激怒首先描述的页面大小问题。
总而言之,正确的方法是通过一个动作来服务图像。例如:
[HttpGet("movie-image/{movieId}")]
public async Task<IActionResult> MovieImage(int movieId)
{
var movieImage = _context.Movie.Where(x => x.Id == movieId).Select(a => a.File).SingleOrDefault();
if (movieImage == null)
return NotFound();
return File(movieImage, "image/jpeg");
}
那么,在你看来:
<img src="@Url.Action("MovieImage", new { movieId = item.Id })" />
您还可以考虑添加一些缓存标头,以便浏览器缓存图像,并从缓存中加载它,而不是在以后每次显示时都访问服务器:
Response.Headers.Add(HeaderNames.CacheControl, $"max-age={TimeSpan.FromDays(365).TotalSeconds}");
return File(movieImage, "image/jpeg");
最后,由于将被缓存的 URL 与电影 id 而不是物理图像相关联,因此您可以考虑使用 Etags,以防万一您需要更新图像。这有点高级,并不是绝对必要的。最坏的情况是,如果用户之前已经下载了旧图像,则可能会从缓存中加载旧图像。
无论如何,要生成 Etag,您需要生成图像字节的哈希:
string checksum;
using (var sha256 = SHA256.Create())
{
checksum = Convert.ToBase64String(sha256.ComputeHash(movieImage));
}
if (Request.Headers.TryGetValue(HeaderNames.IfNoneMatch, out var etag && checksum == etag)
return StatusCode((int)HttpStatusCode.NotModified);
Response.Headers.Add(HeaderNames.CacheControl, $"max-age={TimeSpan.FromDays(365).TotalSeconds}");
Response.Headers.Add(HeaderNames.Etag, checksum);
return File(movieImage, "image/jpeg");
推荐阅读
- julia - 您如何按字典的值对字典进行排序,然后将这些值相加到某个点?
- r - 应用于主题建模时“增强”背后的细节
- oracle - 用于内部连接和 where 子句的 PL/SQL 过程
- r - R - `try`结合捕获所有控制台输出?
- angular - 加载ag-grid树视图时,我们如何默认第一级展开?
- java - URLDecoder:多部分数据的转义 (%) 模式中的非法十六进制字符
- powershell - PowerShell ISE 中的 XAML 代码在 Visual Studio Code 中不起作用
- jupyter-notebook - 使用 Google Colab 通过 HTTPS 连接到远程 Jupyter 运行时
- grid - 使用 grid.arrange 为使用 gridExtra::grid.arrange 制作的多个绘图添加标题
- jenkins - 如何将自定义 HTML+js 代码传递到 Jenkins 输入步骤页面?