SkiaSharp Tiff 支持

2023-12-14

目前,SkiaSharp 不支持 tiff 图像。 (它支持 jpg、gif、bmp、png 和其他一些格式。)

如何将 tiff 图像转换为 SKBitmap 对象?

一个想法:也许有一种有效的方法来转换 tiff 流 > png 流 > SKBitmap 对象?我不知道System.Drawing可以有效地处理 tiff>png 流。另一种可能的选择是LibTiff.Net,但需要一个如何将 tiff 流转换为 png 流的示例。

另一个想法:访问 tiff 像素并将其直接绘制到 SKCanvas 上?

还有其他想法吗?


@DougS

您的实现大部分是正确的,但由于多个内存分配和副本,它的性能不是很好。

我注意到您正在创建 3 个内存块,每个内存块的总大小为 (w*h*4 字节):

// the int[]
raster = new int[width * height];

// the SKColor[]
pixels = new SKColor[width * height];

// the bitmap
bitmap = new SKBitmap(width, height)

您还多次在内存之间复制像素:

// decode the TIFF (first copy)
tifImg.ReadRGBAImageOriented(width, height, raster, Orientation.TOPLEFT)

// convert to SKColor (second copy)
pixels[arrayOffset] = new SKColor(...);

// set bitmap pixels (third copy)
bitmap.Pixels = pixels;

我想我设法创建了一个类似的方法来解码流,只需要一个副本和内存分配:

public static SKBitmap OpenTiff(Stream tiffStream)
{
    // open a TIFF stored in the stream
    using (var tifImg = Tiff.ClientOpen("in-memory", "r", tiffStream, new TiffStream()))
    {
        // read the dimensions
        var width = tifImg.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
        var height = tifImg.GetField(TiffTag.IMAGELENGTH)[0].ToInt();

        // create the bitmap
        var bitmap = new SKBitmap();
        var info = new SKImageInfo(width, height);

        // create the buffer that will hold the pixels
        var raster = new int[width * height];

        // get a pointer to the buffer, and give it to the bitmap
        var ptr = GCHandle.Alloc(raster, GCHandleType.Pinned);
        bitmap.InstallPixels(info, ptr.AddrOfPinnedObject(), info.RowBytes, null, (addr, ctx) => ptr.Free(), null);

        // read the image into the memory buffer
        if (!tifImg.ReadRGBAImageOriented(width, height, raster, Orientation.TOPLEFT))
        {
            // not a valid TIF image.
            return null;
        }

        // swap the red and blue because SkiaSharp may differ from the tiff
        if (SKImageInfo.PlatformColorType == SKColorType.Bgra8888)
        {
            SKSwizzle.SwapRedBlue(ptr.AddrOfPinnedObject(), raster.Length);
        }

        return bitmap;
    }
}

这里有一个要点:https://gist.github.com/mattleibow/0a09babdf0dc9d2bc3deedf85f9b57d6

让我解释一下代码...我基本上正在创建int[]就像你一样,但然后将其传递给SKBitmap并让它接管。我将其固定为SKBitmap存在于非托管内存中,GC 可能会移动它,但我确信在释放位图时会取消固定它。

以下是更详细的步骤:

// this does not actually allocate anything
//  - the size is 0x0 / 0 bytes of pixels
var bitmap = new SKBitmap();

// I create the only buffer for pixel data
var raster = new int[width * height];

// pin the managed array so it can be passed to unmanaged memory
var ptr = GCHandle.Alloc(raster, GCHandleType.Pinned);

// pass the pointer of the array to the bitmap
// making sure to free the pinned memory in the dispose delegate
//  - this is also not an allocation, as the memory already exists
bitmap.InstallPixels(info, ptr.AddrOfPinnedObject(), info.RowBytes, null, (addr, ctx) => ptr.Free(), null);

// the first and only copy from the TIFF stream into memory
tifImg.ReadRGBAImageOriented(width, height, raster, Orientation.TOPLEFT)

// an unfortunate extra memory operation for some platforms
//  - this is usually just for Windows as it uses a BGR color format
//  - Linux, macOS, iOS, Android all are RGB, so no swizzle is needed
SKSwizzle.SwapRedBlue(ptr.AddrOfPinnedObject(), raster.Length);

仅就调试会话中的一些原始统计数据而言,您的代码对于我的一张图像大约需要 500 毫秒,但我的代码只需要 20 毫秒。

我希望我对你的代码听起来不会太严厉/消极,我并不是这个意思。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SkiaSharp Tiff 支持 的相关文章

随机推荐

  • ES6模块导入是否被吊起?

    我知道在新的 ES6 模块语法中 JavaScript 引擎将不必evaluate了解所有导入 导出的代码 它只会parse它并 知道 要加载什么 这听起来像是吊装 ES6模块是否吊装 如果是这样 它们会在运行代码之前全部加载吗 这段代码可
  • Asp.Net core 长时间运行/后台任务

    以下是在 Asp Net Core 中实现长时间运行的后台工作的正确模式吗 或者我应该使用某种形式的Task Run TaskFactory StartNew with TaskCreationOptions LongRunning opt
  • 模运算符如何工作?

    假设我需要格式化数组的输出以显示每行固定数量的元素 我该如何使用模数运算来做到这一点 使用 C 下面的代码可以每行显示 6 个元素 但我不知道它是如何工作的以及为什么工作 for count 0 count lt size count co
  • 如何在多用户环境(500+)中处理 Eclipse?

    您将如何在拥有 500 名或更多开发人员的多用户和多站点环境中处理 Eclipse 让每个人下载自己的安装将导致一场支持和维护的噩梦 强迫每个人都使用集中安装感觉也不理想 并且会限制用户下载插件的选择 Edit 问题不是强迫用户选择Ecli
  • 如何使用 ZipKit 在 iOS 中压缩目录?

    我需要在 iOS 应用程序中压缩文档文件夹的子目录 在咨询了 Google 和其他 SO 帖子后 我发现 ZipKit 和 ZipArchive 作为两个提供此功能的开源项目 此时 我选择实现 ZipKit 因为它目前似乎比 ZipArch
  • 用 Java 找出您网站访问者的 IP 地址

    有没有简单可靠的方法来使用 Java 检测您的网站访问者 IP 地址 我正在尝试利用 Akismet 来检测我的博客文章 评论中的垃圾邮件 API 要求我指定评论者的 IP 地址 谢谢 致电ServletRequest getRemoteA
  • 如何在我的 Android 应用程序的可视化 C# Web 服务中调用 LINQ 中的用户定义函数?

    我目前正在开发一个应用程序 该应用程序将根据距离检索其他用户的位置 我有一个数据库 以纬度和经度存储所有用户位置信息 由于这两对经纬度之间距离的计算相当复杂 所以我需要一个函数来处理它 from a in db Location Where
  • 单击 #-links 时避免窗口跳转到顶部

    我有一个包含一些问题和答案的页面 默认情况下答案是折叠的 当他们单击问题时 我展开隐藏的答案 div 问题是 当我点击这些问题时 窗口跳到屏幕顶部 这不是一个大问题 但我觉得很烦人 因为我必须再次向下滚动到问题 链接看起来就像这样 a hr
  • 如何获取iPhone应用隐藏状态栏区域的触摸事件?

    我有一个隐藏状态栏的 iPhone 应用程序 但是 当我点击状态栏区域时 我的主视图没有收到任何触摸事件 我可以做些什么来解决这个问题吗 以下是我的应用程序设置的一些详细信息 如果重要的话 它是一个基于 OpenGL 的应用程序 该应用程序
  • 如何从 PHP 连接 Jms?

    我正在尝试在我的网站上实现像 Facebook 使用的小聊天功能 我使用了 Html PHP JQuery 和 Apache 我之前用 JMS 做了一些例子 但我不知道如何用 PHP 向 JMS 服务器发送消息 对于 JMS 我使用 Web
  • 将 BigInteger 二进制转换为 BigInteger 数字

    目前我正在使用Long整数类型 我使用以下命令来转换二进制 数字 Convert ToInt64 BinaryString 2 Convert binary string of base 2 to number Convert ToStri
  • java.util.Date 和 java.time.Instant 之间转换古代日期时出现差异

    我有使用 java util Date 创建古代日期 0002 年 11 月 30 日 的遗留代码 我正在尝试更新我可以更新的代码 但这需要在 Date 和 LocalDate 等之间进行转换 我无法完全摆脱使用 Date 或古老的日期选择
  • Spring Integration / JSch:身份验证失败

    我正在尝试使用 Spring Integration 的 SFTP 入站通道适配器 但我被困在这里 20 29 30 458 INFO com jcraft jsch task scheduler 6 Connecting to deplo
  • 在基于 Flask 的应用程序中获取客户端 IP

    我在服务器中部署了 Flask 应用程序 我们正在使用 Nginx nginx 设置如下 proxy set header X Forward For proxy add x forwarded for proxy set header H
  • 在 Windows x86-64 下,发生异常时,有多少内容被推送到 32 位堆栈上?

    In this 这个问题 我给出了一些我已经实现的并行语言的背景知识 编译器生成本机 x86 32 代码 一个关键的实现决策是为每个函数 调用 从堆中分配堆栈空间 这允许递归直到你用完虚拟机 并为词法范围启用仙人掌堆栈 甚至对于嵌套的并行子
  • 使用 Jenkins 管道脚本从 Windows 到 Linux 的 SCP

    我想要做SCP从 Windows Jenkins 节点到 Linux 服务器 在此设置中 Windows 计算机是 Jenkins 从机 我要复制的目标服务器是 Linux 下面是我的 Jenkins 管道脚本 在运行下面的脚本之前 我将克
  • 无法将 dbt cloud 或 dbt core 连接到 databricks

    我在将 dbt cloud 和 dbt core 连接到 databricks 时遇到问题 我已阅读这 4 个链接 但仍然无法连接 https docs databricks com integrations prep dbt html h
  • GridView无法显示图像

    我获取所有应用程序的图标 并在 GridView 中显示图标 GridView 很好地显示了它们 但是当我非常快地向下滑动 GridView 时 有时 GridView 缺少两个图标 这种情况不常出现 您能给我一些建议吗 EDIT 这个问题
  • Google c# Api,从 v2.3 更改为 v3

    我有以下代码使用 C v2 3 api 查询谷歌分析 string username email protected string pass PASS string gkey key XXXXXXXXXXXXXXXXXXXXXXXXXXX
  • SkiaSharp Tiff 支持

    目前 SkiaSharp 不支持 tiff 图像 它支持 jpg gif bmp png 和其他一些格式 如何将 tiff 图像转换为 SKBitmap 对象 一个想法 也许有一种有效的方法来转换 tiff 流 gt png 流 gt SK