我想要在 UOS 上支持上古的图片格式,也就是差不多废弃了 20 年的 EMF 和 WMF 增强图形格式,这两个格式十分古老,而在 Windows 下也存在一些不兼容的图片。我在 Windows 下是使用 GDI+ 的方法支持的,可以将 EMF 转 PNG 或 jpg 等格式。而在 UOS 下,因为 GDI+ 是跨平台的,可以使用跨平台的 System.Drawing.Common 库进行转换

在哪里可以找到很多 EMF 或 WMF 格式的图片?去 PPT 里面的剪辑版找,安装 Office 2013 的版本,可以在 Program Files\Microsoft Office\CLIPART\PUB60COR\ 找到一些图片

如将 EMF 或 WMF 转 png 格式图片的代码,在 C# 中可以这样写

        public static void ConvertEnhancedMetaFileImage(FileInfo originFile, FileInfo generatedFile, int requestedPixel)
        {
            using var image = Image.FromFile(originFile.FullName);

            var size = GetImageOptimizationSize(new Size(image.Width, image.Height), MaxWidth * MaxHeight,
                requestedPixel);

            var width = size.Width;
            var height = size.Height;

            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);
                resized.Save(generatedFile.FullName, ImageFormat.Png);
            }
        }

上面代码的 GetImageOptimizationSize 就是 dotnet C# 图片等比限制最大和最小大小缩放算法 所使用的方法

就是通过这么简单的逻辑就能实现,上面代码能在 Linux 和 Windows 使用

在使用之前需要使用 NuGet 安装 System.Drawing.Common 库,如果是 SDK 的 csproj 可以添加下面代码安装

    <ItemGroup>
        <PackageReference Include="System.Drawing.Common" Version="4.7.0" />
    </ItemGroup>

而除了 System.Drawing.Common 库之外,其他的库的支持也是很差,如非常有名的 SixLabors.ImageSharp 等

而在 System.Drawing.Common 库的支持也很弱,大概只有2成左右的命令支持。在 EMF 等格式里面,其实 EMF 可以细分为多个不同的格式,如 EMF 和 EMF+ 等,这个格式核心是通过记录 GDI 和 GDI+ 绘制命令实现图片绘制。因此解析这个图片格式的前提是需要实现超级庞大的 GDI 绘图,这是特别有工作量的

因此在转换的时候,也许你会看到控制台或 VS 输出窗口有这样的输出内容

** (process:1209): WARNING **: 17:03:45.698: SelectObject 2, no created object, slot empty.

上面输出的 no created object, slot empty 就是核心,在 System.Drawing.Common 库的核心是调用 LibGdiPlus 库,这是放在 mono 组织下的一个库,可以大概认为是有微软官方在维护的库

在 LibGdiPlus 库的核心代码里面,可以在 https://github.com/mono/libgdiplus 找到 metafile.c 文件,这是一个用 c 写的库,可以看到有如下代码

  switch (context->created.type) 
  {
  case METAOBJECT_TYPE_EMPTY:
    /* if nothing is "created" (and not yet selected into a slot) then we "reselect" the object */
    switch (context->objects [slot].type) 
    {
    case METAOBJECT_TYPE_EMPTY:
      g_warning ("SelectObject %d, no created object, slot empty.", slot);
      break;
    case METAOBJECT_TYPE_PEN:
      context->selected_pen = slot;
      break;
    case METAOBJECT_TYPE_BRUSH:
      context->selected_brush = slot;
      break;
    }
  }

这就是上面输出的内容了,也就是这份图片存在不能解析的内容

另外还有其他纯 C 或 C++ 的库,现在是 2020 年,我还没有找到一个支持比较好的库

一些 Linux 上完成度很高的软件

一些反向转换项目


本文会经常更新,请阅读原文: https://blog.lindexi.com/post/dotnet-%E5%9C%A8-Linux-%E4%B8%8B%E7%9A%84-GDI-%E5%BA%93%E5%AF%B9-EMF-%E5%9B%BE%E7%89%87%E6%A0%BC%E5%BC%8F%E7%9A%84%E6%94%AF%E6%8C%81.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

如果你想持续阅读我的最新博客,请点击 RSS 订阅,推荐使用RSS Stalker订阅博客,或者前往 CSDN 关注我的主页

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系

以下是广告时间

推荐关注 Edi.Wang 的公众号