一个纯 Swift 语言实现的 互联网打印协议 (IPP),基于 swift-nio 和 async-http-client。
这个库允许您直接与几乎任何网络打印机通信,无需任何驱动程序或操作系统依赖。它提供了一个简单的 API,用于编码和交换 IPP 1.1 请求和响应,以及一种灵活、Swift 风格的方式来处理强类型属性。
警告: 这个软件包是全新出炉的,您将成为测试阶段的一部分。请参阅下面的 实现状态。
// Add to package dependencies
.package(url: "https://github.com/sliemeobn/ipp-nio.git", from: "0.1.0"),
// Add to your target depencies
dependencies: [
.product(name: "IppClient", package: "ipp-nio"),
]
该库的功能集大致分为四个层次
import struct Foundation.Data
import IppClient
let printer = IppPrinter(
httpClient: HTTPClient(configuration: .init(certificateVerification: .none)),
uri: "ipps://my-printer/ipp/print"
)
let pdf = try Data(contentsOf: .init(fileURLWithPath: "myfile.pdf"))
let response = try await printer.printJob(
documentFormat: "application/pdf",
data: .bytes(pdf)
)
if response.statusCode.class == .successful {
print("Print job submitted")
} else {
print("Print job failed with status \(response.statusCode) \(response[operation: \.statusMessage])")
}
var jobAttributes = IppAttributes()
jobAttributes[\.jobTemplate.copies] = 2
jobAttributes[\.jobTemplate.orientationRequested] = .landscape
jobAttributes["some-custom-thing"] = .init(.keyword("some-value"))
let response = try await printer.printJob(
documentName: "myfile.pdf",
jobAttributes: jobAttributes,
data: .stream(myFileAsStream)
)
let response = try await printer.printJob(data: .bytes(myData))
guard let jobId = response[job: \.jobId] else { exit(1) }
let job = printer.job(jobId)
while true {
let response = try await job.getJobAttributes(requestedAttributes: [.jobState])
guard let jobState = response[job: \.jobState] else {
print("Failed to get job state")
exit(1)
}
switch jobState {
case .aborted, .canceled, .completed:
print("Job ended with state \(jobState)")
exit(0)
default:
print("Job state is \(jobState)")
}
try await Task.sleep(for: .seconds(3))
}
// "basic" mode
let printer = IppPrinter(
httpClient: HTTPClient(configuration: .init(certificateVerification: .none)),
uri: "ipps://my-printer/ipp/print",
authentication: .basic(username: "user", password: "top-secret")
)
// "requesting-user" mode
let printer = IppPrinter(
httpClient: HTTPClient(configuration: .init(certificateVerification: .none)),
uri: "ipps://my-printer/ipp/print",
authentication: .requestingUser(username: "user")
)
import IppProtocol
import NIOCore
var request = IppRequest(
version: .v1_1,
operationId: .holdJob,
requestId: 1
)
request[.operation][.attributesCharset] = .init(.charset("utf-8"))
request[.operation][.attributesNaturalLanguage] = .init(.naturalLanguage("en-us"))
request[.operation][.printerUri] = .init(.uri("ipp://:631/printers/ipp-printer"))
request[.job]["my-crazy-attribute"] = .init(.enumValue(420), .enumValue(69))
var bytes = ByteBuffer()
request.write(to: &bytes)
let read = try! IppRequest(buffer: &bytes)
print(request == read) // true
大多数打印机都可以通过 DNS-SD/Bonjour 发现,任何 DNS-SD 浏览器都应该显示它们的信息。(例如:macOS 的 Discovery)。
rp
值是 URL 路径(通常是 /ipp/print
),方案始终是 ipp://
或 ipps://
。
在 macOS 上,共享打印机也通过 IPP 公开。(即:任何打印机都可以是网络打印机,中间有一个服务器)
基本的、低级编码和传输是健壮的,应该可以满足所有需求。语义模型目前仅涵盖最基本的属性,但可以根据需要轻松扩展。
由于该库在编写时考虑了自定义扩展,因此即使没有直接支持,也应该很容易扩展到任何用例。
缺失
您想添加任何内容吗?请随时联系我,也欢迎 “pull request” ^^