保存为 GIF 后图像质量下降

2023-12-03

我正在开发一款 iOS 应用程序,它允许用户拍摄一系列照片 - 然后将照片放入动画中并导出为 MP4 和 GIF。

虽然 MP4 呈现源质量,但 GIF 颜色等级是可见的。

这是视觉比较:

GIF: GIF

MP4 MP4

我用于导出为 GIF 的代码:

var dictFile = new NSMutableDictionary();
        var gifDictionaryFile = new NSMutableDictionary();
        gifDictionaryFile.Add(ImageIO.CGImageProperties.GIFLoopCount, NSNumber.FromFloat(0));

        dictFile.Add(ImageIO.CGImageProperties.GIFDictionary, gifDictionaryFile);

        var dictFrame = new NSMutableDictionary();
        var gifDictionaryFrame = new NSMutableDictionary();
        gifDictionaryFrame.Add(ImageIO.CGImageProperties.GIFDelayTime, NSNumber.FromFloat(0f));

        dictFrame.Add(ImageIO.CGImageProperties.GIFDictionary, gifDictionaryFrame);


        InvokeOnMainThread(() =>
    {
        var imageDestination = CGImageDestination.Create(fileURL, MobileCoreServices.UTType.GIF, _images.Length);

        imageDestination.SetProperties(dictFile);

        for (int i = 0; i < this._images.Length; i++)
        {
            imageDestination.AddImage(this._images[i].CGImage, dictFrame);

        }
        imageDestination.Close();
    });

我用于导出为 MP4 的代码:

var videoSettings = new NSMutableDictionary();
            videoSettings.Add(AVVideo.CodecKey, AVVideo.CodecH264);
            videoSettings.Add(AVVideo.WidthKey, NSNumber.FromNFloat(images[0].Size.Width));
            videoSettings.Add(AVVideo.HeightKey, NSNumber.FromNFloat(images[0].Size.Height));

            var videoWriter = new AVAssetWriter(fileURL, AVFileType.Mpeg4, out nsError);
            var writerInput = new AVAssetWriterInput(AVMediaType.Video, new AVVideoSettingsCompressed(videoSettings));

            var sourcePixelBufferAttributes = new NSMutableDictionary();

            sourcePixelBufferAttributes.Add(CVPixelBuffer.PixelFormatTypeKey, NSNumber.FromInt32((int)CVPixelFormatType.CV32ARGB));

            var pixelBufferAdaptor = new AVAssetWriterInputPixelBufferAdaptor(writerInput, sourcePixelBufferAttributes);

            videoWriter.AddInput(writerInput);

            if (videoWriter.StartWriting())
            {
                videoWriter.StartSessionAtSourceTime(CMTime.Zero);

                for (int i = 0; i < images.Length; i++)
                {
                    while (true)
                    {
                        if (writerInput.ReadyForMoreMediaData)
                        {
                            var frameTime = new CMTime(1, 10);
                            var lastTime = new CMTime(1 * i, 10);

                            var presentTime = CMTime.Add(lastTime, frameTime);
                            var pixelBufferImage = PixelBufferFromCGImage(images[i].CGImage, pixelBufferAdaptor);

                            Console.WriteLine(pixelBufferAdaptor.AppendPixelBufferWithPresentationTime(pixelBufferImage, presentTime));
                            break;
                        }
                    }
                }

                writerInput.MarkAsFinished();
                await videoWriter.FinishWritingAsync();

我将不胜感激您的帮助!

亲切的问候,

Andre


这只是我的评论的总结...

我不在你们的平台上编码,所以我只提供通用答案(以及我自己的见解)GIF编码器/解码器编码经验)。

GIF图像格式支持每像素高达 8 位,通过简单编码可实现每像素最多 256 种颜色。廉价的编码器只是将输入图像截断为 256 种或更少的颜色,通常会导致丑陋的像素化结果。提高着色质量GIF我知道有 3 种方法:

  1. 多个框架覆盖屏幕并带有自己的调色板

    只需将图像划分为多个叠加层,每个叠加层都有自己的调色板。这是很慢的(就解码而言,因为您需要为每个图像处理更多帧,这可能会导致某些查看器出现同步错误,并且您需要为每个图像多次处理所有与帧相关的块)。编码本身很快,因为您只需根据颜色或区域/位置将帧分离为多个帧。这里(基于区域/位置)示例:

    multiple palettes

    示例图像取自此处:Wiki

    The GIF支持透明度,因此子框架可以重叠...这种方法可以从物理上增加每个像素的颜色N*256 (or N*255对于透明框架)其中N是每个图像使用的帧或调色板的数量。

  2. 抖动

    抖动是一种在仅使用指定颜色(来自调色板)的情况下近似区域颜色以尽可能接近地匹配颜色的技术。这是快速且易于实现的,但结果有点嘈杂。有关更多信息,请参阅我的一些相关答案:

    • 将 BMP 图像转换为绘图仪的指令集?
    • c# 接受一定量抖动的图像抖动例程?
  3. 更好的色彩量化方法

    廉价的编码器只是将颜色截断为预定义的调色板。通过基于直方图对使用的颜色进行聚类可以获得更好的结果。例如参见:

    • 有效的 gif/图像颜色量化?

    结果通常比抖动好得多,但与抖动相比,编码时间很长......

The #1 and #3可以一起使用以进一步提高质量...

如果您无权访问编码代码或管道,您仍然可以在编码之前转换图像本身,进行量化和调色板计算,并将结果直接加载到GIF编码器应该是可能的(如果GIF您使用的编码器至少有点复杂......)

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

保存为 GIF 后图像质量下降 的相关文章

  • 什么是 Swift 枚举字节表示?

    我有以下枚举 enum Enum UInt8 case A 0x00 case B 0x01 case C 0x10 我使用以下代码将其转换为NSData var value Enum C let data NSData bytes val
  • YouTube 在 iOS 上直播?

    这里的文档有点难以解析 我想知道是否有什么办法 将 YouTube 直播传输到 iOS 应用程序中 无需显着 任何 YouTube 品牌 Stream from作为 YouTube 直播的广播流的 iOS 设备 我最初的谷歌搜索得到了不同的
  • 添加新行后,UITableView rollToRow 不再适用于 iOS 11

    我注意到一个奇怪的 UITableView 行为似乎只发生在 iOS 11 设备上 插入新行后 更改数据源然后调用 reloadData UITableView调用时不会滚动到该行scrollToRow or scrollToBottom
  • IO 和 Android 之间发送数据? (字节数组)

    我正在 Android 中开发一个网络应用程序 它应该能够与 IO 应用程序进行通信 我正在使用 Appwarps 多人游戏后端 并且有一个发送和接收数据的功能 该函数接受一个字节数组 所以最初我认为我可以将一个 消息 对象序列化为一个字节
  • 使用 PHP 发送器和 Swift 在后台未收到 IOS GCM 推送通知

    我正在努力让后台通知在带有 GCM 的 IOS 上工作 非后台通知已经可以工作了 以下是我集成后台通知的步骤 在 UIBackgroundmodes 中启用远程通知标签 将内容可用密钥添加到我的通知负载中 在我的委托中编写 applicat
  • 显示键盘时 Admob 广告不会出现在 UITableView 页脚中

    我用它在 UITableView 的页脚上显示 Admob 广告 UIView tableView UITableView tableView viewForFooterInSection NSInteger section GADBann
  • 如何在 SpriteKit SKScene 类中启动 ReplayKit 屏幕录制

    我已经实施了ReplayKit in my SpriteKit游戏 但由于一切都在游戏内完成GameViewController录制按钮出现得太早 请看我的GameViewController下面的类 class GameViewContr
  • 将领域列表转换为领域结果

    只是想知道如何将列表转换为结果 因为我正在对区域和区域进行过滤 当用户选择区域时 区域应该仅显示该区域中的那些区域 当我将我的区域分配给定义为的变量时var areas Results area 我得到了编译错误 无法将 列表 类型的值分配
  • 如何快速比较CGPoints?

    我有2个CGPoint like let a CGPoint CGPointMake 1 1 let b CGPoint CGPointMake 1 1 如果两者相同那么我想做点什么 这只是一个例子 但我想比较这两个 CGPoint 我发现
  • 在XCode中快速查看Swift变量的类型

    有没有什么快捷方式可以让我在 XCode 中快速查看 Swift 中任何变量的类型 Alt 单击返回 无快速帮助 类型推断非常棒 但是如果没有这些工具 生活就会变得困难 Either use Alt click to display the
  • 如何制作抗崩溃的ios应用程序

    我现在正在编写 ios 应用程序一段时间 但我的应用程序仍然经常崩溃 并且需要时间才能使它们变得非常稳定 我觉得这很烦人 那么 有没有关于防崩溃编程ios应用程序的编程模式呢 打开编译器警告 删除所有警告 运行静态分析器 删除所有警告 使用
  • 我想通过协议将数据从第二个 ViewController 传递到 TableView 单元

    这是我的ViewController2从我需要传递数据的地方 我如何传递数据 protocol oppo func datapass Name String className String rollnumner String school
  • 错误:“无效数据消息 - 全部长度必须为:8” - PickerIOS

    Edit 似乎如果我注释掉第 63 行 this setState logged in true 行 我就不会收到错误 我的猜测是 我尝试根据用户是否登录来更改渲染函数中显示的内容的方式是导致此错误的原因 有任何想法吗 我感觉 在理解 Re
  • 从底部加载导航视图控制器

    我有四个 ViewControllers 其中 ViewControllers 使用以下方式加载UINavigationController 我能够一一切换到每个 ViewController 问题是 由于我使用的是 NavigationC
  • Swift Joint:在可观察对象中使用计时器发布者

    在这个问题被标记为重复之前这另一个问题 https stackoverflow com questions 57199922 create a timer publisher using swift combine 我试图了解出版商是如何运
  • 橡皮擦在 iOS 绘图中不起作用

    我正在做一个绘图项目 其中有一个橡皮擦选项 下面给出的代码适用于我启动应用程序并绘制一些线条并继续使用橡皮擦时的代码 它工作正常 我得到了橡皮擦效果 现在第二种情况是我画了大约10条线 然后单击 撤消按钮 并撤消整个事情 然后我重做整个事情
  • UISlider 拇指中心位于轨道的起点和终点

    默认行为UISlider是它的拇指没有集中在轨道的开始 结束处 就像下面这样 我想修改它的行为以获得 拇指的中心可以位于起点或终点 我试图用空来覆盖开始 结束UIView 效果是看起来几乎没问题 但是拇指有阴影 显示了我在某些位置的黑客攻击
  • 如何从文本视图制作多页 PDF?

    我从 iPhone 应用程序生成了一个 PDF 文件 虽然大多数文档只有一页 但我希望能够检测文本是否超出 边距 如果是 则将其添加到下一页 我对此很陌生 所以不太确定如何做到这一点 下面是代码 有什么建议么 void drawBorder
  • 哪个 API 可以替代 iCloud 中的 Core Data

    2016 年 6 月更新 截至 NSPersistentStoreCoordinator 的最新文档 与 iCloud 核心数据相关的所有内容都被标记为已弃用 因此 新的开发可能应该避免这种情况 使用 Core Data iCloud 和
  • 需要FTP文件而不存储解释器文件通过Python保存在本地

    我正在尝试做一些图像解释器并尝试将它们直接存储到 FTP 服务器 但我的步骤是从本地文件夹上传图像 然后将其转换为蒙版图像 然后它将获得最终输出 但是在我的蒙版和最终输出场景中 临时图像被保存在本地 这是我不想要的 但如果不将图像存储在本地

随机推荐