这个功能不是项目必须的模块,没有开发时间的强制要求,大可以一边慢慢查资料一边写代码。
刚好突然想起来五年前转行时,我是跟着 《C Primer Plus》 这本书从写 C 语言代码开始学编程的,敲了几个月 C 代码最后学了一点点 C++,没成想找到工作后一直写 C++,于是我决定用 C 写一下这个功能,找回一下 C 的手感。
开发过程中的问题
图片存储格式的知识我以前是毫不了解,所以写这个程序时免不了查阅大量的资料。如果是以前,我大概率会查看各种博客了解一下大致情况然后找到官方文档,参照文档中的明确定义编写代码。
最近两年以来,AI 逐渐取代了搜索引擎,成为了我获取知识的主要途径。特别是那种本来就表达不明白的问题,我可以从含糊的概念开始,不断从 AI 的回答中修正和深入挖掘,这个过程舒适且高效,传统的搜索引擎检索方式很难实现这样的体验。
但是完全信任 AI 得到的结论我认为也是不可取的,所以每次搜索一些专业领域的知识,我都会要求 AI 提供官方文档依据或者它得出结论的信息来源,我会跟进去浏览一下,确认信息可靠再采用,毕竟搜索过程相对 AI 时代之前节省了不少时间,最后花些时间核实也不会让我变得效率低下。正是这个核实环节,让我多次发现 AI 擅长使用令人信服的展现方式展示错误的知识:一个完全错误或者真假混杂的结论,AI 能够以非常确信的口吻回答出来,甚至辅以图表详细说明。有时候当我打开它提供的信息来源时,发现只不过是一篇某野鸡网站上的连语句都没理顺的文章,AI 将这样的垃圾堂而皇之地包装得像是在权威文章上摘抄下来的段落一样呈现给我。
我很喜欢的 kurzgesagt 组织 最近发布的一个 视频。对 AI 时代互联网的未来,他们表达了诸多担忧,通过大量的调查取证和数据分析,他们发现越来越多由 AI 创建的难辨真伪的知识正在快速涌入人类的互联网知识库,互联网信任危机正在不断加剧。
作为一个普通人,这些宏大的叙事总是没有日常生活的柴米油盐更让我们关注,但它们最终肯定会影响到我们生活的细枝末节,希望最终都能往好的方向发展。
遗留问题
代码里面的解析逻辑都是现学现卖,难免疏漏,而且测试覆盖率比较低,肯定会有一些 bug。比如使用调色板的图片计算色深的逻辑没有仔细研究,可能存在问题;多页 tif 文件,手头弄不到测试数据,是否写的有问题是未知的。
还有一些已知问题,是由于比较懒只考虑普遍情况。比如 jpeg 图片只读取第一个 SOF0 字段来获取信息,听说移动端的 jpeg 图片首个 SOF0 可能存储的是缩略图信息;还有就是如果文件存储的信息出现前后不一致时,直接视为解析错误。
由于 tif 文件分普通格式和 big tif 格式,两种格式流程基本一致,但是细节有区别(主要是解析时使用的数据类型不同),考虑过用宏来生成两份代码,但是需要写几百行的宏,比较丑陋,就直接写了两份重复度极高的代码,如果是用 C++ 编写,可以只写一份模板代码,减少一些重复。
这里吐槽一下 tif 格式,我想它应该是那些设计数据库的人设计的,文件内部的数据存储形式极其灵活,只要你愿意,可以把任何类型的数据塞到一个 tif 文件内。解析程序必须在它的 IFD(Image File Directory) 中遍历,取出每个 IFD 内的 DE(Directory Entry),根据 DE 的 tag 获取解析数据类型,而后再根据数据大小决定是在 DE 内部读取还是根据 DE 的偏移值跳转到文件的另一个位置读取。这仅仅是我解析 tif 文件头时需要的操作,如果要写一个完全的解析器,复杂度会更高。stb_image 的作者 Sean Barrett 就曾多次提到为了维持解析器的轻量简洁,不会增加对更多图片格式的支持(虽然未专门提及,但是 tif 的复杂程度肯定和他的意愿相悖),幸好我不用写这样的一个解析器。
最终代码
目前代码支持解析 jpeg、bmp、tif、png,除 tif 格式组织形式麻烦一点外,其他几个格式只需要极少量的解析代码,最后添加了一层简单的 C++ 封装用于自动内存管理(其实除了多页 tif 外,其他格式无需自动内存释放)。
后续考虑增加更多图片格式的支持。项目代码在 这里。