【问题标题】:Reliable image handling on Azure platform / Dotnet coreAzure 平台/Dotnet 核心上的可靠图像处理
【发布时间】:2018-07-21 21:04:18
【问题描述】:

我在 dotnet core 下的 Azure 平台上的图像有点挣扎,我希望有人能提出明智的建议。 前提很简单:用户上传图片,以 base64 格式保存在数据库中(即将移动到 Azure 存储 blob,但这与此无关)。稍后,网站所有者出现并单击一个按钮以将所有这些图像保存在 ZIP 文件中。在过去的 .net 框架中,这很容易。现在我似乎正在打一组“是的,但是”的cmets。

是的,有 system.drawing.image 但您不能使用它,因为它不在 dotnet 核心中(直到最近)。 是的,您可以使用 CoreCompat,但它在 Azure 上不起作用,因为在 Web 应用程序中不支持 GDI+。 是的,即使我可以,我也在 Mac 上开发,所以据我所知,它无法在本地工作。

我尝试了 ImageSharp 的 beta4,但没有取得很大的成功。它是随机的 - 有时它有效,有时它只是抛出 OutOfMemoryException。 我试过 SkiaSharp 但结果相似;有时它会起作用,有时它会输出随机错误消息。

我没有在处理方面做任何花哨的事情,没有调整大小或任何事情。应该是从 Convert.FromBase64String 加载文件到字节数组,创建 Zip 文件入口,最终吐出 zip 文件的情况。 ZIP 部分很好,但我需要一些可以做图像工作的体面的东西。

这里有一段代码:

if(!string.IsNullOrEmpty(del.Headshot))
{
    var output=SKImage.FromBitmap(SKBitmap.Decode(Convert.FromBase64String(del.Headshot)));
    MemoryStream savedFile=new MemoryStream();
    output.Encode(SKEncodedImageFormat.Jpeg, 100).SaveTo(savedFile);
    string name=$"{del.FirstName} {del.LastName} - {del.Company}".Trim(Path.GetInvalidFileNameChars()) + "_Headshot.jpg";
    ZipArchiveEntry entry=zip.CreateEntry(name);
    using(Stream entryStream=entry.Open())
    {
        entryStream.Write(savedFile.ToArray(), 0, Convert.ToInt32(savedFile.Length));
    }
    output.Dispose();
    savedFile.Dispose();
}

在我拔掉剩下的一点头发之前,谁能给我一个可以处理图像、跨平台和在 Azure 上的库的明智建议!

谢谢

编辑:第一个答案在技术上是正确的,我不需要其他任何东西。但是,当我说我没有进行任何图像处理时,我可能有点错误。因为它都是base64,没有文件名存储在任何地方,我不知道它是什么类型的文件。因此,我将每一个都保存为 JPEG,以确保我始终可以输出该文件类型和扩展名。我猜用户可能正在上传 JPG / PNG 甚至 GIF。

【问题讨论】:

  • 从技术上讲,您不需要任何其他成像(除非您要做的不仅仅是压缩内容)。将 base64 转换为字节数组并将其传递给 zip 文件。无需保存到磁盘只是为了再次读取它以进行压缩。
  • 如果您能够控制上传的图片类型,那么您以后就不必担心了。
  • 当数据与所需的元数据(即内容类型)一起保存时,您还应该验证并执行图像处理。这样,在提取它时,您就可以确信它的类型和大小是正确的。
  • @Michael C 仔细检查您没有在 Azure 上的 32 位环境中运行。这些 OOM 异常表明您的连续内存块已用完。如果两个图形库都出现问题,则表明存在环境问题,而不是库的问题。没有什么是“随机的”。

标签: c# azure asp.net-core skiasharp imagesharp


【解决方案1】:

从技术上讲,您不需要任何其他图像(除非您所做的不仅仅是压缩内容)。将 base64 转换为字节数组并将其传递给 zip 文件。无需保存到磁盘只是为了再次读取它以进行压缩。

//...

if(!string.IsNullOrEmpty(del.Headshot)) {
    var imageBytes = Convert.FromBase64String(del.Headshot);
    string name = $"{del.FirstName} {del.LastName} - {del.Company}".Trim(Path.GetInvalidFileNameChars()) + "_Headshot.jpg";
    ZipArchiveEntry entry = zip.CreateEntry(name);
    using(Stream entryStream = entry.Open()) {
        entryStream.Write(imageBytes, 0, imageBytes.Length));
    }
}

//...

当转换为 base64 时,还对已知图像类型使用小技巧

public static class ImagesUtility {
    static IDictionary<string, string> mimeMap = 
        new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
        {
            { "IVBOR", "png" },
            { "/9J/4", "jpg" },
            //...add others
        };

    /// <summary>
    /// Extract image file extension from base64 string.
    /// </summary>
    /// <param name="base64String">base64 string.</param>
    /// <returns>file extension from string.</returns>
    public static string GetFileExtension(string base64String) {
        var data = base64String.Substring(0, 5);        
        var extension = mimeMap[data.ToUpper()];
        return extension;
    }
}

您可以尝试根据前缀确定文件扩展名

if(!string.IsNullOrEmpty(del.Headshot)) {
    var imageBytes = Convert.FromBase64String(del.Headshot);
    var ext = ImagesUtility.GetFileExtension(del.Headshot) ?? "jpg";
    string name = $"{del.FirstName} {del.LastName} - {del.Company}".Trim(Path.GetInvalidFileNameChars()) + $"_Headshot.{ext}";
    ZipArchiveEntry entry = zip.CreateEntry(name);
    using(Stream entryStream = entry.Open()) {
        entryStream.Write(imageBytes, 0, imageBytes.Length));
    }
}

现在理想情况下,如果您能够控制上传的图像类型,那么您还应该在数据与任何所需的元数据(即内容类型)一起保存时验证并执行图像处理>)。这样从存储中提取它时,您可以确信它的类型和大小是正确的。这样您以后就不必担心了。

【讨论】:

  • 这个函数使用子字符串来获取文件类型是一件很漂亮的事情。我不知道您可以从字符串中的第一个字符中分辨出文件类型,尽管我想这确实是有道理的。
【解决方案2】:

Aspose.DrawingAspose.Imaging 可以处理图像和跨平台运行在 .NET Core 上(我是开发人员之一)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-30
    • 1970-01-01
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-12
    • 2020-09-15
    相关资源
    最近更新 更多