Imageflow:用于 Web 服务器的现代化、更快速、更安全的图像处理

Imageflow 是一款令人兴奋的新项目,它可以提供高达 17 倍于 ImageMagick 的速度提升,同时拥有更小的攻击面。 ImageMagick 中众多最近发现的漏洞 表明了在服务器上使用桌面工具包所带来的高风险。

Web 服务器的典型操作(如缩放、编辑和优化图像)普遍存在需求,这需要一种更加专注的技术,并配备合适的接口(JSON、REST)。Imageflow 满足了这些需求。

Imageflow

Imageflow 由 Nathanael Jones 创建,他是 ImageResizer(一个巨大的成功)的作者,因此他在该领域的履历无可挑剔。这个开源项目目前正在通过 Kickstarter 众筹活动 筹集资金,因此,如果您或您的公司拥有一个图像质量和速度至关重要的网站(如电子商务网站),您可能需要认真考虑支持它。Nathanael 还提供数量有限的现场咨询和集成支持合同(在撰写本文时还剩 2 个)。

Imageflow 依赖项

主要依赖项

有很多优秀的开源图像编解码器,因此 imageflow 使用它们(并向上游贡献改进)。其中包括:

  • libpng。规范的 PNG 库,用于 Chrome 和 Firefox。
  • libjpeg-turbo。libjpeg 实现最受欢迎的分支,使用 SIMD 指令优化速度,也用于 Firefox、Chrome 和许多 Linux 发行版…
  • giflib。gif 格式图像的原始参考库,尽管 giflib 很快会被 Rust 实现取代。
  • LittleCMS。标准的开源颜色管理引擎,专注于准确性和性能。

我们还为 Cap'n Proto 和 Jansson 设置了打包,尽管这些库的使用尚未进入 Imageflow 的主分支。

测试依赖项

为了运行软件的自动测试,imageflow 使用:

  • Catch。Phil Nash 开发的现代化、仅限头文件的 C++ 测试框架。
  • libcurl。广泛使用的库(和工具),用于通过多种协议在网络上传输数据。
  • theft。一个属性测试框架(类似于模糊测试),类似于 QuickCheck。

传递依赖项

上面需要的依赖项也有自己的依赖项,即使 imageflow 没有明确要求,但实际上构建和测试项目也需要它们。

  • OpenSSL,流行的 SSL 实现,是 curl 所需的。
  • ZLib,无处不在的解压缩/压缩库,libpng 和 OpenSSL 都需要它。
  • Electric Fence 实用程序(Windows 中不可用),用于检测与内存相关的错误。

使用 Conan 管理依赖项

以上只是一些需要处理的依赖项,可能看起来数量不多,但其中涉及许多挑战。

  • 多种构建系统。源代码使用了不同的构建系统。其中一些使用 CMake,另一些使用 Makefile 等。甚至 OpenSSL 在 Windows 中构建也需要 Perl!对于基于单个构建系统的包管理器来说,快速提供所有这些依赖项将非常困难。
  • 不同平台的不同构建系统。不仅需要 Win、Linux 和 Mac 构建,而且许多依赖项在不同的操作系统中构建方式也不同。例如,有些在 Windows 中使用 CMake,在 Linux 中使用 Makefile。
  • 条件依赖项。我们不希望总是获取所有依赖项。其中一些仅在测试时需要,而另一些,如 electric-fence,例如在 Windows 中不可用(无法工作)。
  • 链接和ABI 不兼容性。即使在同一操作系统上并使用相同的构建系统,不兼容性问题也很重要。使用特定编译器版本构建的 C++ 项目可能无法链接到同一编译器的另一个版本。或者调试构建可能与发布构建不兼容(MSVC,我正在看着你)。
  • 始终从源代码构建速度慢。始终从源代码构建可以解决不兼容性问题,但这会使构建速度变得非常慢。由于我们希望尽可能快地在尽可能多的配置中构建和测试 Imageflow,因此这似乎不是一个解决方案。它的扩展性非常差。

创建包依赖项

好吧,conan 解决了上述所有挑战,在一位 conan 开发人员的帮助下,Imageflow 在很短的时间内就拥有了所有所需的依赖项,这些依赖项已为大量配置(调试/发布、32/64、共享/静态、不同的编译器和版本……)构建完成。

Imageflow 使用的依赖项的包二进制文件的总数超过 1000 个! 这仅计算 Imageflow 当前使用的版本。这些库在 conan 中也可能具有其他版本的包。

这些包是由一位开发人员快速轻松地创建的,并且使用 travis 和 appveyor 持续集成非常容易维护。库的新版本有时只需几分钟的工作即可转换为包(是的,可能在 CI 中需要很长时间构建)。

需要注意的一件非常重要的事情是,为了创建这些包,conan 不需要分叉任何原始源代码。它总是从 github、sourceforge 或原始网站检索源代码来构建包。

构建和测试 Imageflow 项目

使用 conan 包最简单的方法是通过 conanfile.txt 文件。但在 Imageflow 中,我们需要更强大的功能来表达我们拥有的条件依赖项,因此我们使用了它的 python conanfile.py 对应项。事实证明,使用它还可以更轻松地在许多不同的配置中构建和测试项目。这是构建和测试 Imageflow 所需的完整 conanfile.py。例如,阅读 config() 方法。即使您不了解 conan,您也可能能够理解其逻辑。

from conans import ConanFile, CMake
import os

class ImageFlowConan(ConanFile):
    settings = "os", "compiler", "build_type", "arch"
    requires = "littlecms/2.7@lasote/stable", "libpng/1.6.21@lasote/stable", \
               "libjpeg-turbo/1.4.2@imazen/testing" , "giflib/5.1.3@lasote/stable"
    options = {"build_tests": [True, False], "profiling": [True, False], "coverage": [True, False]}
    generators = "cmake"
    default_options = "build_tests=True", "coverage=False", "profiling=False", "libjpeg-turbo:shared=False", \
                      "libpng:shared=False", "zlib:shared=False", "libcurl:shared=False", \
                      "OpenSSL:shared=True"

    def config(self):
        if self.settings.os != "Windows":  #giflib must be shared on windows?
            self.options["giflib"].shared = False

        if self.options.build_tests or self.options.profiling:
            self.requires("libcurl/7.47.1@lasote/stable")
            if self.settings.os == "Macos":
                self.options["libcurl"].darwin_ssl = False
                self.options["libcurl"].custom_cacert = True

        if self.options.build_tests:
            self.requires("catch/1.3.0@TyRoXx/stable")
            if self.settings.os != "Windows":  # Not supported in windows
                self.requires("theft/0.2.0@lasote/stable")
                self.requires("electric-fence/2.2.0@lasote/stable") ##### SLOWS IT DOWN

    def imports(self):
        self.copy("*.so", dst="bin", src="bin")  # From bin to bin
        self.copy("*.dll", dst="bin", src="bin")  # From bin to bin
        self.copy("*.dylib*", dst="bin", src="lib")  # From lib to bin
        self.copy("*cacert.pem", dst="bin")  # Allows use libcurl with https without problems - except on darwin
        self.copy("*cacert.pem", dst=".")  # Allows use libcurl with https without problems

    def build(self):
        if not os.path.exists("./build"):
            os.mkdir("./build")
        os.chdir("./build")
        cmake = CMake(self.settings)
        cmake_settings = ""
        if self.options.coverage:
            cmake_settings += " -DCOVERAGE=ON"
        if self.options.build_tests:
            cmake_settings += " -DENABLE_TEST=ON"
        if self.options.profiling:
            cmake_settings += " -DSKIP_LIBRARY=ON -DENABLE_TEST=OFF -DENABLE_PROFILING=ON"

        cmake_command = 'cmake "%s" %s %s' % (self.conanfile_directory, cmake.command_line, cmake_settings)
        cmake_build_command = 'cmake --build . %s' % cmake.build_config
        self.output.warn(cmake_command)
        self.run(cmake_command)
        self.output.warn(cmake_build_command)
        self.run(cmake_build_command)
        if self.options.build_tests:
            self.run('ctest -V -C Release')

同样,在 travis 和 appveyor 的帮助下,Imageflow 使用多个不同的编译器(clang、MSVC、gcc)和编译器版本在 Windows、Linux 和 Mac 上构建和测试。您可以检查这些构建,只需转到 imageflow github 存储库 并关注 travis 和 appveyor 徽章。请注意构建时间很短,这要归功于构建使用了来自 conan.io 的编译二进制文件。

结论

Conan 帮助 Imageflow 在 Windows、Linux 和 Mac 上实现了跨平台的便捷构建、测试和 CI。为这些依赖项创建大量包二进制文件是一条相对简单快速的途径,一位开发人员可以在短时间内完成,并且无需努力即可维护数千个二进制包。Imageflow 使用这些包也很直观和简单。

Conan 将继续为该项目提供支持。

  • 我们已上传了 pngquant 库的测试包,该库可能会在不久的将来被 imageflow 使用。
  • 最近,conan 通过 conan Rust 生成器帮助提供了对命令行的 Rust 支持。这是一个有趣的话题,因此我们很快就会为此写一篇专门的文章,因为 Imageflow 将更多 Rust 和 C11 代码融合在一起。

这将是我们对下一代 Web 图像处理器的贡献。

别忘了查看 Imageflow支持 Kickstarter!