mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-13 01:35:07 +00:00
App/ 根目录原有 73 个散落源文件,已无法从目录读出任何分组信息。 按「目录即分层」重组为 Composition / Application / Presentation / UI / PlatformEffects / Resources 六个目录,UI 层再按子视图分目录(Workspace、 Home、Servers(含 Plugin)、Subscriptions、Rules、Settings、Diagnostics、 StatusMenu)。纯移动:类型名、模块名与 import 均未改动,App/ 根层不再有 散落文件。 配套改动: - project.yml:Core 测试镜像的 excludes 由裸文件名改为 `**/` 递归形式。 XcodeGen 的 exclude 不跨 `/`,裸名只匹配 App 根层;MainApp.swift 下移后 旧写法会静默失效,把 @main 组合根编进测试镜像。info.path 与 entitlements.path 指向 App/Resources/;并排除 `**/*.md`——App/ 下任何 非源码文件都会被 XcodeGen 收进 Resources 阶段并封进签名后的 bundle。 - SkeletonTests 的架构守卫由「默认扫描全部 App/ + 7 个豁免文件 + 1 个豁免 前缀 + 4 个豁免目录」改为正面圈定 App/UI/,豁免登记全部删除;新增运行时 适配器放进 Application/ 即自动落在扫描范围外,无需再登记。 - README 工程结构说明同步;根 .gitignore 的生成物路径随 Resources/ 归位。 验证:clean build 0 error;task test 1022 用例全通过(含两个架构守卫); task format 无改动(证明纯移动);task lint 与移动前同为 21 条内容型 warning;packaging-gate.sh ALL CHECKS PASSED,确认 plist/entitlements 归位 后签名与 entitlements 语义不变。 注意:迁移时须先删旧的生成物再 xcodegen generate,否则遗留的 App/Info.plist 会被当作普通资源扫进 Resources 阶段。
49 lines
1.9 KiB
Swift
49 lines
1.9 KiB
Swift
import AppKit
|
|
import CoreImage
|
|
import Foundation
|
|
import Vision
|
|
|
|
/// 二维码编解码(issue #32:分享生成二维码、识别二维码图片导入)。生成走
|
|
/// CoreImage `CIQRCodeGenerator`(纠错级 M),识别走 Vision 条码检测,返回
|
|
/// 全部文本负载。屏幕扫码明确不做(spec #21 D11),此处只处理静态图片。
|
|
enum QrCodeCodec {
|
|
enum QrCodeError: Error, Equatable {
|
|
/// 系统二维码滤镜产出为空(理论不可达,防御位)。
|
|
case generationFailed
|
|
/// 输入不是可解码的位图。
|
|
case undecodableImage
|
|
}
|
|
|
|
/// 生成二维码 PNG 数据;`scale` 控制输出像素密度(每个模块的像素数)。
|
|
static func generatePNG(for payload: String, scale: CGFloat = 8) throws -> Data {
|
|
guard let filter = CIFilter(name: "CIQRCodeGenerator") else {
|
|
throw QrCodeError.generationFailed
|
|
}
|
|
filter.setValue(Data(payload.utf8), forKey: "inputMessage")
|
|
filter.setValue("M", forKey: "inputCorrectionLevel")
|
|
guard let output = filter.outputImage else { throw QrCodeError.generationFailed }
|
|
let scaled = output.transformed(by: CGAffineTransform(scaleX: scale, y: scale))
|
|
let context = CIContext()
|
|
guard let cgImage = context.createCGImage(scaled, from: scaled.extent) else {
|
|
throw QrCodeError.generationFailed
|
|
}
|
|
let rep = NSBitmapImageRep(cgImage: cgImage)
|
|
guard let png = rep.representation(using: .png, properties: [:]) else {
|
|
throw QrCodeError.generationFailed
|
|
}
|
|
return png
|
|
}
|
|
|
|
/// 识别静态图片中的全部二维码/条码文本负载。
|
|
static func detectPayloads(in imageData: Data) throws -> [String] {
|
|
let request = VNDetectBarcodesRequest()
|
|
let handler = VNImageRequestHandler(data: imageData, options: [:])
|
|
do {
|
|
try handler.perform([request])
|
|
} catch {
|
|
throw QrCodeError.undecodableImage
|
|
}
|
|
return request.results?.compactMap(\.payloadStringValue) ?? []
|
|
}
|
|
}
|