在MacOS和Linux上使用ImageMagick,Vapor 3和Swift对照片加水印

回顾过去(您还记得Web 2.0吗?😉),我过去经常围绕照片进行编程。 在格式之间调整大小,缩放,旋转和转换。 最近,我不得不创建一个Web服务,该服务使用Vapor生成带水印的图像。 事实证明,还没有太多用于图像处理的库,因此这个简单的任务成为研究中一个有趣的问题。

有两个主要的图像处理库:GD和ImageMagick。 ImageMagick有点像高级库,所以我决定首先使用它。 ImageMagick有一个有趣的Swift包装器,称为MagickWand。 不幸的是,它根本不支持文本操作,因此我不得不更深入地研究。 我找不到任何有用的东西,所以我想:“为什么不在Swift中只使用一些ImageMagick C函数呢?”事实证明,这很容易做到!

安装ImageMagick

在ImageMagick网站的开发部分中,您可以找到MagickWand和MagickCore的文档。 这些是用C编写的用于与ImageMagick处理库进行交互的接口。 将其包装到Swift包中非常容易,但是首先让我们安装ImageMagick。

让我们从macOS开始。 您可以自己编译ImageMagick,但对于macOS,仅使用Homebrew会更容易。

  ➜brew安装imagemagick @ 6 

如果未指定@6 ,则默认情况下将安装最新版本。 我在Linux上的版本7遇到问题,因此我决定将macOS和Linux都使用旧版本。

安装后,您会注意到自制软件未创建符号链接(有关以下信息:仅桶依赖项)。 为了获得有关ImageMagick所需的信息,此部分很重要:

 为了使pkg-config查找[受电子邮件保护],您可能需要设置: 
导出PKG_CONFIG_PATH =“ / usr / local / opt / imagemagick @ 6 / lib / pkgconfig”

您可以只在终端中在每个pkg-config命令之前添加PKG_CONFIG_PATH ,但是如果使用zsh只需运行,则永久添加它更容易:

  ➜echo'export PKG_CONFIG_PATH =“ / usr / local / opt / imagemagick @ 6 / lib / pkgconfig:$ PKG_CONFIG_PATH”'>>〜/ .zshrc 

对于Linux,我使用的是带有Swift 4.2 Ubuntu 18.04 。 如果您已预先安装ImageMagick,最好在编译之前将其删除:

  ➜apt-get remove imagemagick && apt-get autoremove 

您可以在此处获取ImageMagick软件包。

  ➜wget https://www.imagemagick.org/download/ImageMagick-6.9.10-12.tar.gz 
➜tar xzvf ImageMagick-6.9.10-12.tar.gz
➜cd ImageMagick-6.9.10-12

在ImageMagick的源目录中运行:

  ➜./配置 

配置完成后,请找到“ Delegate Library Configuration ”部分,并检查是否存在JPEGPNG support 。 如果在第三列上看不到no ,则可能没有必需的依赖项,例如libpng12-devlibjpeg-dev 。 您可以使用apt-get轻松安装它们。

如果配置正确,只需编译源代码:

  ➜使 

并安装:

  ➜进行安装 

要确认安装正确完成,请运行:

  ➜convert --version 

如果看到此错误:

 转换:加载共享库时出错:libMagickCore-6.Q16.so.6:无法打开共享库文件:没有这样的文件或目录 

赶紧跑:

  ➜ldconfig / usr / local / lib / 

已安装ImageMagick。 现在我们可以从有趣的部分开始

将ImageMagick包装为Swift包

要在Swift代码中使用ImageMagick您需要将其包装到Swift系统模块包中。 通过公开头文件,您的Swift代码将能够使用所有ImageMagick函数。

让我们开始创建一个名为SwiftImageMagick的新目录,并使用Swift包管理器初始化新的Swift系统模块:

  ➜mkdir SwiftImageMagick 
➜cd SwiftImageMagick
➜swift package init --type系统模块

打开module.modulemap文件。 您应该看到SPM生成的代码:

 模块SwiftImageMagick [system] { 
标题“ /usr/include/SwiftImageMagick.h”
链接“ SwiftImageMagick”
出口 *
}

让我们先从macOS开始。 将模块的名称更改为SwiftImageMagick > SwiftImageMagickMac

现在,为了告诉您如何编译和链接所有软件包,您需要使用pkg-config工具。 您应该已经拥有它,如果不仅仅使用brew安装它:

  ➜brew安装pkg-config 

如前所述,您需要设置PKG_CONFIG_PATH以便pkg-config可以找到ImageMagick

  ➜pkg-config --list-all |  grep -i魔术师 

您应该看到几个软件包:

  ➜〜pkg-config --list-all |  grep -i魔术师 
Magick ++ Magick ++-Magick ++-用于ImageMagick的C ++ API(ABI Q16)
Wand-6.Q16 MagickWand-MagickCore-ImageMagick的C API(ABI Q16)
ImageMagick ++ ImageMagick ++-Magick ++-用于ImageMagick的C ++ API(ABI Q16)
MagickWand MagickWand-MagickWand-用于ImageMagick的C API(ABI Q16)
ImageMagick ImageMagick-ImageMagick-转换,编辑和合成图像(ABI Q16)
MagickCore-6.Q16 MagickCore-MagickCore-ImageMagick的C API(ABI Q16)
Magick ++-6.Q16 Magick ++-Magick ++-用于ImageMagick的C ++ API(ABI Q16)
魔杖MagickWand-MagickCore-ImageMagick的C API(ABI Q16)
MagickWand-6.Q16 MagickWand-MagickWand-用于ImageMagick的C API(ABI Q16)
ImageMagick ++-6.Q16 ImageMagick ++-Magick ++-用于ImageMagick的C ++ API(ABI Q16)
ImageMagick-6.Q16 ImageMagick-ImageMagick-转换,编辑和合成图像(ABI Q16)
MagickCore MagickCore-MagickCore-ImageMagick的C API(ABI Q16)

查找ImageMagick的头文件路径:

  ➜〜pkg-config --cflags-only-I MagickWand 
-I/usr/local/Cellar/imagemagick@6/6.9.10-12/include/ImageMagick-6

在此目录/usr/local/Cellar/[email protected]/6.9.10-12/include/ImageMagick-6您会找到/usr/local/Cellar/[email protected]/6.9.10-12/include/ImageMagick-6标题: wand/MagickWand.h

和链接器标志:

  ➜〜pkg-config --libs MagickWand 
-L/usr/local/Cellar/imagemagick@6/6.9.10-12/lib -lMagickWand-6.Q16 -lMagickCore-6.Q16

再次打开module.modulemap ,添加标题和链接:

 模块SwiftImageMagickMac [系统] { 
标题“ /usr/local/Cellar/imagemagick@6/6.9.10-12/include/ImageMagick-6/wand/MagickWand.h”
链接“ MagickWand-6.Q16”
链接“ MagickCore-6.Q16”
出口 *
}

让我们为Linux做同样的事情。 您还应该在Linux机器上安装pkg-config ,如果不仅仅使用:

  ➜apt-get install pkg-config 

让我们检查一下pkg-config看到的内容:

  pkg-config --list-all |  grep -i魔术师 

root @ 8cc05b6015fc:〜#pkg-config --list-all | grep -i魔术师
Wand-6.Q16 MagickWand-MagickCore-ImageMagick的C API(ABI Q16)
ImageMagick ++-6.Q16 ImageMagick ++-Magick ++-用于ImageMagick的C ++ API(ABI Q16)
MagickWand-6.Q16 MagickWand-MagickWand-用于ImageMagick的C API(ABI Q16)
ImageMagick ImageMagick-ImageMagick-转换,编辑和合成图像(ABI Q16)
魔杖MagickWand-MagickCore-ImageMagick的C API(ABI Q16)
ImageMagick-6.Q16 ImageMagick-ImageMagick-转换,编辑和合成图像(ABI Q16)
MagickCore MagickCore-MagickCore-ImageMagick的C API(ABI Q16)
Magick ++-6.Q16 Magick ++-Magick ++-用于ImageMagick的C ++ API(ABI Q16)
MagickWand MagickWand-MagickWand-用于ImageMagick的C API(ABI Q16)
ImageMagick ++ ImageMagick ++-Magick ++-用于ImageMagick的C ++ API(ABI Q16)
Magick ++ Magick ++-Magick ++-用于ImageMagick的C ++ API(ABI Q16)
MagickCore-6.Q16 MagickCore-MagickCore-ImageMagick的C API(ABI Q16)

从标题开始:

  root @ 8cc05b6015fc:〜#pkg-config --cflags-only-I MagickWand 
-I / usr / local / include / ImageMagick-6

和链接器标志:

  root @ 8cc05b6015fc:〜#pkg-config --libs MagickWand 
-L / usr / local / lib -lMagickWand-6.Q16 -lMagickCore-6.Q16

在macOS部分下面的module.modulemap中添加linux模块:

 模块SwiftImageMagickMac [系统] { 
标题“ /usr/local/Cellar/imagemagick@6/6.9.10-12/include/ImageMagick-6/wand/MagickWand.h”
链接“ MagickWand-6.Q16”
链接“ MagickCore-6.Q16”
出口 *
}

模块SwiftImageMagickLinux [系统] {
标题“ /usr/local/include/ImageMagick-6/wand/MagickWand.h”
链接“ MagickWand-6.Q16”
链接“ MagickCore-6.Q16”
出口 *
}

请记住从Package.swift删除依赖项部分:

  // swift-tools-version:4.2 
// swift-tools-version声明构建此软件包所需的最低Swift版本。

导入PackageDescription

让包=包(
名称:“ SwiftImageMagick”

现在,一切就绪后,不要忘记创建git存储库并提交更改。

  ➜git init 
➜git add。
➜git commit -m“初始提交”。

现在我们的包已经准备好了。 我们来用吧😄

如何在Swift中使用ImageMagick

现在,让我们创建一个简单的测试应用程序,该应用程序将导入ImageMagick库并创建一个用红色背景填充的100x100px图像,以确保我们的程序包可以正常工作。

  ➜mkdir MagicTest 
➜cd MagicTest
➜swift软件包init --type可执行文件

创建可执行包:MagicTest
创建Package.swift
创建README.md
创建.gitignore
创建源/
创建Sources / MagicTest / main.swift
创建测试/
创建测试/LinuxMain.swift
创建测试/ MagicTestTests /
创建测试/MagicTestTests/MagicTestTests.swift
创建测试/MagicTestTests/XCTestManifests.swift

SPM将为您创建基本结构; --type executable将告诉SPM创建命令行工具。

首先,您需要将SwiftImageMagick添加为Package.swift的依赖项。 您可以将其添加为本地git存储库的路径:

  // swift-tools-version:4.2 
// swift-tools-version声明构建此软件包所需的最低Swift版本。

导入PackageDescription

让包=包(
名称:“ MagicTest”,
依赖项:[
.package(URL:“ ../SwiftImageMagick”,.branch(“ master”)),
],
目标:[
。目标(
名称:“ MagicTest”,
依赖项:[]),
.testTarget(
名称:“ MagicTestTests”,
依赖项:[“ MagicTest”]),
]

编译它以确保您的依赖项可以访问:

  Test MagicTest快速构建 
抓取/用户/麦克/文档/项目/游乐场/ SwiftImageMagick
在0.35秒内完成分辨率
克隆/用户/麦克/文档/项目/游乐场/ SwiftImageMagick
解决主用户的/ Users / mike / Documents / projects / playground / SwiftImageMagick
'SwiftImageMagick'/Users/mike/Documents/projects/playground/MagicTest/.build/checkouts/SwiftImageMagick-2878331876767139303:警告:系统软件包已弃用; 改用系统库目标
编译Swift模块'MagicTest'(1源码)
链接./.build/x86_64-apple-macosx10.10/debug/MagicTest

如果您使用的是Swift 4.2您还将看到以下内容: warning: system packages are deprecated; use system library targets instead warning: system packages are deprecated; use system library targets instead –这与系统库目标有关。

然后,在应用程序的主文件( ./Sources/MagicTest/main.swift )中,删除所有内容并导入ImageMagick库。

  #if os(Linux) 
导入SwiftImageMagickLinux
#其他
导入SwiftImageMagickMac
#万一

您可以使用Swift构建配置导入测试来判断您的程序是在Linux上还是在macOS上运行。

现在要编译该应用程序,还需要提供标题和链接器的路径,这与您上一次使用pkg-config获得的路径相同。 检查是否还需要提供其他标志也是一个好主意:

  Test MagicTest pkg-config --cflags-only-other ImageMagick 
-DMAGICKCORE_HDRI_ENABLE = 0 -DMAGICKCORE_QUANTUM_DEPTH = 16

让我们把它们全部加起来:

  ➜swift build -Xswiftc -I/usr/local/Cellar/imagemagick@6/6.9.10-12/include/ImageMagick-6 -Xlinker -L/usr/local/Cellar/imagemagick@6/6.9.10-12/ lib -Xlinker -lMagickWand-6.Q16 -Xlinker -lMagickCore-6.Q16 -Xcc -DMAGICKCORE_HDRI_ENABLE = 0 -Xcc -DMAGICKCORE_QUANTUM_DEPTH = 16 
抓取/用户/麦克/文档/项目/游乐场/ SwiftImageMagick
在0.35秒内完成分辨率
克隆/用户/麦克/文档/项目/游乐场/ SwiftImageMagick
解决主用户的/ Users / mike / Documents / projects / playground / SwiftImageMagick
'SwiftImageMagick'/Users/mike/Documents/projects/playground/MagicTest/.build/checkouts/SwiftImageMagick--9014361064470696861:警告:系统软件包已弃用; 改用系统库目标
编译Swift模块'MagicTest'(1源码)
链接./.build/x86_64-apple-macosx10.10/debug/MagicTest

成功! 😄库正在运行,现在让我们创建一个Xcode项目文件并添加一些代码。

  ➜swift包generate-xcodeproj 

使用Xcode 10运行./MagicTest.xcodeproj

当您尝试使用Xcode进行编译时,您将看到与终端相同的错误:

实际上很容易修复。 只需打开构建设置并找到Header search path并添加路径:

Library search path执行相同的操作:

不要忘记添加Other Swift Flags

Cmd + R ,一切都应该编译并运行,没有任何警告。

当然,当您以后希望重新生成xcodeproj时,所有这些更改都将消失。 您可以使用xcconfig来存储它们,但请注意Xcode 10存在一些奇怪的问题(雷达报告的错误)。

创建一个新文件: Package.xcconfig

  LIBRARY_SEARCH_PATHS = / usr / local /地窖/imagemagick@6/6.9.10-12/lib 
HEADER_SEARCH_PATHS = /usr/local/Cellar/imagemagick@6/6.9.10-12/include/ImageMagick-6
OTHER_SWIFT_FLAGS = -Xcc -DMAGICKCORE_HDRI_ENABLE = 0 -Xcc -DMAGICKCORE_QUANTUM_DEPTH = 16

然后生成xcode项目文件:

  ➜swift软件包generate-xcodeproj --xcconfig-覆盖Package.xcconfig 

现在,该项目应编译而没有任何错误或警告。

当您的xcode项目正常工作时,请再次打开: Sources/MagicTest/main.swift

ImageMagick import下面,添加以下内容:

  MagickWandGenesis() 

让魔杖= NewMagickWand()
让像素= NewPixelWand()

MagickWandGenesis初始化MagickWand环境。 完成工作后,还需要终止环境。 NewMagickWand创建新的魔杖资源,该资源表示包含图像的结构。 NewPixelWand创建负责颜色操纵的新像素棒​​。

  PixelSetColor(像素,“红色”) 
MagickSetBackgroundColor(wand,pixel)

PixelSetColor将设置像素棒的颜色。 使用名称- "red" ,十六进制值#FF0000或rbg- rgb(255,0,0) 。 如果将其另存为png,则甚至可以使用“透明”来制作透明背景。

现在,将颜色应用于魔杖后,只需创建一个新图像并将其保存:

  MagickNewImage(wand,100,100,pixel) 
MagickWriteImage(wand,“ test.jpg”)

您也可以提供图像的绝对路径,但是如果不这样做,请记住该文件将在Xcode DerivedData目录中创建。

差不多完成了:只释放棒,像素的内存并终止环境:

 摧毁魔杖(魔杖) 
DestroyPixelWand(像素)
MagickWandTerminus()

现在运行该应用程序。 我已将整个示例应用程序上传到GitHub。

如果未提供文件的绝对路径,则可以打开“ Products ,选择程序名称,然后单击Show in Finder 。 您将在此处找到test.jpg

test.jpg应该看起来像这样:

因此,ImageMagick正常工作。 让我们创建新的Vapor应用并添加水印文本😄

在这篇文章的开头,我以为我会创建一个用于图像处理的帮助程序库,但是这篇文章已经太长了,因此让我们保持简单并在Vapor中使用ImageMagick命令。 图像处理库将是下一篇文章的好话题

在蒸气中提供带水印的照片

这将非常简单,只需创建一个新的Vapor项目:

  ➜蒸气新的WatermarkPhotos 

默认情况下, vapor new将基于api模板创建一个项目。 现在,您需要添加ImageMagick包装器依赖项。 如果Package.swift文件中的Swift版本仍为3.0.0 ,最好将Swift版本更新为4.2并将Vapor更新为3.1.0

  // swift-tools-version:4.2 
导入PackageDescription

让包=包(
名称:“ WatermarkPhotos”,
依赖项:[
//💧服务器端Swift Web框架。
.package(URL:“ https://github.com/vapor/vapor.git”,来自:“ 3.1.0”),

//🔵基于SQLite 3构建的Swift ORM(查询,模型,关系等)
.package(网址:“ https://github.com/vapor/fluent-sqlite.git”,来自“ 3.0.0”),

//🎨ImageMagick包装器
.package(URL:“ https://github.com/mikina/SwiftImageMagick”,.branch(“ master”))
],
目标:[
.target(name:“ App”,依赖项:[“ FluentSQLite”,“ Vapor”]),
.target(name:“ Run”,依赖项:[“ App”]),
.testTarget(name:“ AppTests”,依赖项:[“ App”])
]

生成Xcode项目文件并打开它:

  ➜cd水印照片/ 
➜蒸气xcode -y

可能需要一段时间才能获取所有依赖项。

至此,您已经具备了入门所需的一切。 让我们编写一个非常简单的测试。 很难将图像与图像进行比较,因为这会使您的测试不稳定,所以我们只检查水印端点响应是否为:

  • 返回状态码200 .ok
  • 内容类型设置为image/jpeg
  • 内容长度大于零

创建一个新的测试文件: /Tests/AppTests/PhotoTests.swift

 导入XCTest 
@testable进口蒸气
@testable导入应用

最终课程PhotoTests:XCTestCase {

}

不幸的是, Vapor 3.1还没有用于测试的任何帮助程序,但是您可以使用一些用于测试Vapor本身的扩展。 你可以在这里找到。

创建一个新的测试助手: /Tests/AppTests/TestsHelper.swift并复制此私有应用程序扩展。 不要忘记将其公开,以便其他测试可以看到它。 它应该看起来像这样。

现在回到PhotoTests.swift并添加以下简单测试:

 导入XCTest 
@testable进口蒸气
@testable导入应用

最终课程PhotoTests:XCTestCase {
func testGetWatermakedPhoto()抛出{
让app =尝试Application.makeTest(路线:路线)

尝试app.test(.GET,“ / photos / show / barcelona”){在
XCTAssertEqual(response.http.status,.ok)
XCTAssertEqual(response.http.contentType,MediaType.jpeg)
让length = response.http.headers [“ content-length”]。first!
XCTAssertGreaterThan(Int(length)!, 0)
}
}

静态让allTests = [
(“ testGetWatermakedPhoto”,testGetWatermakedPhoto)
]
}

当然,此测试将立即失败,因为还没有光控器,因此让我们创建一个。

创建文件: /Sources/App/Controllers/PhotoController.swift

 进口蒸气 
进口基金会

最终课程PhotoController {
func show(_ req:Request)抛出->响应{
返回响应(使用:req)
}
}

另外,在/Sources/App/routes.swift添加路由。

 进口蒸气 

///在这里注册您的应用程序的路由。
公共功能路由(_路由器:路由器)抛出{
//照片控制器
让photoController = PhotoController()
router.get(“ photos”,“ show”,String.parameter,使用:photoController.show)
}

如果您不熟悉路由,则String.parameter意味着您可以在路由内部传递一个字符串值,它将在控制器内部用作请求参数。

您的照片网址如下所示:

  http:// localhost:8080 / photos / show / barcelona 

此时,它只是以一个空白页进行响应。 让我们回到/Sources/App/Controllers/PhotoController.swift并添加一些代码。

在现实生活中的应用程序中,您需要将数据库中的照片列表和实际文件保存在外部存储(例如AWS S3中。 但是对于此演示,我们让它保持简单,只需在主项目目录中创建一个名为photos新目录,然后在其中添加一些照片即可。

PhotoController.swift内部添加照片列表:

 私人let photosList = [“ barcelona.jpg”,“ oslo.jpg”,“ porto.jpg”,“ rome.jpg”] 
private let photosDirectory =“照片”

您可以从请求parameters获取照片名称:

 让名称=尝试req.parameters.next(String.self) 
让filename = name.lowercased()。appending(“。jpg”)

只需检查文件是否在列表中:

 保护photosList.contains(filename)else { 
抛出Abort(.notFound,原因:“未找到照片”)
}

在将水印添加到照片之前,让我们从磁盘中加载水印并作为响应发送。

在Vapor 3.1中,存在DirectoryConfig结构,该结构可以帮助您获取工作目录的路径。

 让目录= DirectoryConfig.detect() 
让workingDirectory = URL(fileURLWithPath:directory.workDir)

警告:

当您将通过Xcode运行应用程序时,您需要做的一件事。 如果检查了DirectoryConfig,则可能会看到有一个用于目录检测的函数: detect() 。 有一个条件编译标志: #if Xcode

您需要在Active Compilation Conditions定义它:

或者只是将其添加到Package.xcconfig

  SWIFT_ACTIVE_COMPILATION_CONDITIONS [config = Debug] = Xcode 

并生成xcodeproject文件:

  ➜swift包generate-xcodeproj --xcconfig-overrides = Package.xcconfig 

当然,它不会影响linux构建。

你快到了 现在,使用文件内容创建Data并将其作为jpeg响应返回:

 让数据=尝试数据(contentsOf:workingDirectory.appendingPathComponent(photosDirectory,isDirectory:true).appendingPathComponent(filename)) 
返回req.response(数据,如.jpeg)

PhotoController将如下所示:

  func show(_ req:Request)抛出->响应{ 

让名称=尝试req.parameters.next(String.self)
让filename = name.lowercased()。appending(“。jpg”)

保护photosList.contains(filename)else {
抛出Abort(.notFound,原因:“未找到照片”)
}

让目录= DirectoryConfig.detect()
让workingDirectory = URL(fileURLWithPath:directory.workDir)

让数据=尝试数据(contentsOf:workingDirectory.appendingPathComponent(photosDirectory,isDirectory:true).appendingPathComponent(filename))
返回req.response(数据,如.jpeg)
}

在Xcode中运行应用程序并打开url:

  http:// localhost:8080 / photos / show / barcelona 

现在是最后一步的时候了:添加水印。

创建模型文件: /Sources/App/Models/Photo.swift

像在示例项目中一样,导入Vapor,Foundation和ImageMagick标头:

  #if os(Linux) 
导入SwiftImageMagickLinux
#其他
导入SwiftImageMagickMac
#万一

进口蒸气
进口基金会

您可能会看到类似以下的错误:

 找不到'magick / magick-config.h'文件 

这与示例应用程序中的错误相同。 只需添加Package.xcconfig并重新生成xcode项目文件:

 快速软件包generate-xcodeproj --xcconfig-overrides = Package.xcconfig 

使用文件属性创建类Photo:

 最终课程照片{ 
私人租赁文件:URL

init(文件:URL)引发{

保护FileManager.default.fileExists(atPath:file.path)else {
引发Abort(.internalServerError,原因:“找不到照片文件”)
}

self.file =文件
}

检查文件是否存在是个好主意,因为ImageMagick的错误报告并不总是最好的。

现在创建一个将返回带水印的照片的函数:

 带水印的公共功能(字体:URL,文本:String)引发->数据{ 

保护FileManager.default.fileExists(atPath:font.path)else {
抛出Abort(.internalServerError,原因:“找不到字体文件”)
}

它使用将使用的字体文件的URL和输入的水印文本。

准备魔术堆栈:

  MagickWandGenesis() 

让魔杖= NewMagickWand()
让像素= NewPixelWand()
让draw = NewDrawingWand()

我已经描述了那些方法。 这里的新功能是绘图棒:它将用于在图像上绘图,或者在这种情况下将水印文本附加到图像上。

将图像加载到Magick Wand中:

  MagickReadImage(wand,file.path) 

并准备绘图棒:

  PixelSetColor(像素,“白色”) 
DrawSetFillColor(绘制像素)
DrawSetFont(draw,font.path)
DrawSetFontSize(draw,70)
DrawSetGravity(draw,CenterGravity)
DrawAnnotation(draw,0,0,text)

这很简单。 像素棒被设置为白色并附着在绘图棒上。 字体,重力参数和大小也应用于绘图棒。 DrawAnnotation将水印文本附加到绘图棒。

这里值得一提的是您可以设置不同的重力。 重力告诉ImageMagick它应该在哪里放置图形,因此您不必计算它。 使用CenterGravity将在图像的中心绘制水印文本。 将其设置为SouthWestGravity将在左下角绘制水印。 无需手动计算边界框和在屏幕上的位置。

画水印文字:

  MagickDrawImage(想要绘制) 

您还需要在获取数据之前设置图像格式和压缩质量:

  MagickSetImageCompressionQuality(wand,85) 
MagickSetImageFormat(wand,“ jpg”)

要从ImageMagick获取数据,只需调用MagickGetImageBlob

  var length = 0 

保护卫队形象= MagickGetImageBlob(wand,&length)else {
引发Abort(.internalServerError,原因:“无法从ImageMagick获取图像。”)
}

MagickGetImageBlob将返回UnsafeMutablePointer ,您要做的就是使用bytes创建Data

 让数据=数据(字节:图像,计数:长度) 

不要忘记清理并返回数据:

 摧毁魔杖(魔杖) 
DestroyPixelWand(像素)
DestroyDrawingWand(绘制)
MagickRelinquishMemory(图像)
MagickWandTerminus()

返回数据

您的模型现在一切都很好。 让我们回到控制器并使用它。

在使用模型之前,您需要下载将用于创建水印的字体。 您可以从GoogleFont库中获得许多不同的字体。 我正在使用Open Sans。 只需下载ttf文件,然后将其放在项目内的fonts目录中即可。

PhotoController.swift ,添加字体目录的属性和水印文本的属性:

 最终课程PhotoController { 

私人let photosList = [“ barcelona.jpg”,“ oslo.jpg”,“ porto.jpg”,“ rome.jpg”]
private let photosDirectory =“照片”
private let fontsDirectory =“字体”
私人let watermarkText =“ ImageMagick \ nVapor”

show(_ req: Request)函数中,用您的Photo模型替换当前加载的照片:

 让文件= workingDirectory.appendingPathComponent(photosDirectory,isDirectory:true).appendingPathComponent(filename) 
让字体= workingDirectory.appendingPathComponent(fontsDirectory,isDirectory:true).appendingPathComponent(“ OpenSans-Regular.ttf”)

让照片=尝试照片(文件:文件)
let watermarkedPhoto =试试photo.watermarked(with:font,and:watermarkText)

整个PhotoController应该看起来像这样。

现在,在Xcode中运行该应用程序,然后再次打开该URL:

  http:// localhost:8080 / photos / show / barcelona 

当我最近尝试在Vapor项目中使用ImageMagick时,我花了几个小时试图弄清楚如何将ImageMagick设置并包装到Swift包中。 文件丢失和链接器错误有很多问题。 解决了所有这些问题之后,使用ImageMagick变得非常简单明了

我们从这里去哪里?

我强烈建议您与ImageMagick一起玩。 您可以创建一个非常方便且量身定制的库,可以在Vapor项目中重复使用。

如果您还没有尝试过,也应该尝试在Linux上运行它。 我正在使用Docker进行开发,我将在下一篇博客文章中介绍如何在Vapor上使用它。

你觉得这个怎样? 您是否已经尝试将ImageMagick与Vapor结合使用? 您遇到任何问题了吗? 在Twitter @mikemikina 上让我知道您的问题,评论或反馈

快乐编码😊


最初发布于 mikemikina.com