update at 2026-03-16 09:00:35
This commit is contained in:
@@ -18,6 +18,7 @@ trap 'kill "$SERVER_PID" 2>/dev/null || true' EXIT INT TERM
|
||||
|
||||
sleep 1
|
||||
/usr/bin/swift "$CALENDAR_DIR/scripts/export-kindle-background.swift" "$URL" "$OUT_PNG" "$OUT_REGION"
|
||||
|
||||
node "$CALENDAR_DIR/scripts/generate-dashboard-manifest.mjs" >/dev/null
|
||||
|
||||
cat "$OUT_REGION"
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import AppKit
|
||||
import Foundation
|
||||
import ImageIO
|
||||
import UniformTypeIdentifiers
|
||||
import WebKit
|
||||
|
||||
enum ExportError: Error, CustomStringConvertible {
|
||||
@@ -29,7 +31,8 @@ final class SnapshotExporter: NSObject, WKNavigationDelegate {
|
||||
private let pngOutputURL: URL
|
||||
private let regionOutputURL: URL
|
||||
private let completion: (Result<Void, Error>) -> Void
|
||||
private let targetSize = CGSize(width: 1024, height: 600)
|
||||
// 直接按 Kindle Voyage 的系统屏保尺寸导出,避免额外旋转和补边。
|
||||
private let targetSize = CGSize(width: 1072, height: 1448)
|
||||
|
||||
private lazy var window: NSWindow = {
|
||||
let window = NSWindow(
|
||||
@@ -129,16 +132,52 @@ final class SnapshotExporter: NSObject, WKNavigationDelegate {
|
||||
image.draw(in: NSRect(origin: .zero, size: targetSize))
|
||||
normalizedImage.unlockFocus()
|
||||
|
||||
guard
|
||||
let tiffRepresentation = normalizedImage.tiffRepresentation,
|
||||
let bitmap = NSBitmapImageRep(data: tiffRepresentation),
|
||||
let pngData = bitmap.representation(using: .png, properties: [:])
|
||||
else {
|
||||
guard let sourceCGImage = normalizedImage.cgImage(forProposedRect: nil, context: nil, hints: nil) else {
|
||||
throw ExportError.pngEncodingFailed(url.path)
|
||||
}
|
||||
|
||||
let width = Int(targetSize.width)
|
||||
let height = Int(targetSize.height)
|
||||
let colorSpace = CGColorSpaceCreateDeviceGray()
|
||||
|
||||
// 输出 8-bit 灰度 PNG,但页面本身仍按纯白底和纯黑字设计,避免额外灰阶装饰。
|
||||
guard let context = CGContext(
|
||||
data: nil,
|
||||
width: width,
|
||||
height: height,
|
||||
bitsPerComponent: 8,
|
||||
bytesPerRow: 0,
|
||||
space: colorSpace,
|
||||
bitmapInfo: CGImageAlphaInfo.none.rawValue
|
||||
) else {
|
||||
throw ExportError.pngEncodingFailed(url.path)
|
||||
}
|
||||
|
||||
context.setFillColor(gray: 1, alpha: 1)
|
||||
context.fill(CGRect(x: 0, y: 0, width: width, height: height))
|
||||
context.interpolationQuality = .high
|
||||
context.draw(sourceCGImage, in: CGRect(x: 0, y: 0, width: width, height: height))
|
||||
|
||||
guard let grayscaleImage = context.makeImage() else {
|
||||
throw ExportError.pngEncodingFailed(url.path)
|
||||
}
|
||||
|
||||
try FileManager.default.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true)
|
||||
try pngData.write(to: url)
|
||||
|
||||
guard let destination = CGImageDestinationCreateWithURL(
|
||||
url as CFURL,
|
||||
UTType.png.identifier as CFString,
|
||||
1,
|
||||
nil
|
||||
) else {
|
||||
throw ExportError.pngEncodingFailed(url.path)
|
||||
}
|
||||
|
||||
CGImageDestinationAddImage(destination, grayscaleImage, nil)
|
||||
|
||||
guard CGImageDestinationFinalize(destination) else {
|
||||
throw ExportError.pngEncodingFailed(url.path)
|
||||
}
|
||||
}
|
||||
|
||||
private func saveRegion(region: [String: NSNumber]) throws {
|
||||
|
||||
Reference in New Issue
Block a user