forked from 1b-agent/opencadstudio-upstream
The ad-hoc codesign path signed the whole bundle with one --deep pass, which never carried --entitlements to the QuickLook appex, so PlugInKit silently rejected it as unsandboxed. Sign nested code individually instead, matching the Developer ID path. Separately, ThumbnailProvider drew the extracted preview at its native pixel size anchored at the CGContext origin (bottom-left) instead of scaling it to fill request.maximumSize, producing a small thumbnail stuck in one corner instead of a properly sized, centered icon. Note: Gatekeeper still rejects an ad-hoc or unnotarized Developer-ID signature outright, and PlugInKit periodically re-validates and drops any registered plugin that fails that check — so these fixes are necessary but not sufficient for thumbnails to render from a build that isn't both signed and notarized. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
60 lines
2.5 KiB
Swift
60 lines
2.5 KiB
Swift
// macOS QuickLook thumbnail extension for DWG files.
|
|
//
|
|
// Calls the Rust core (`dwg_thumbnail_png`, linked from libdwg_thumbnailer.a)
|
|
// to extract the embedded preview as PNG, then hands it to QuickLook.
|
|
//
|
|
// Add this file to a "Thumbnail Extension" target, expose the C ABI through a
|
|
// bridging header that #includes `dwg_thumbnailer.h`, and link the static lib
|
|
// (see README). QLSupportedContentTypes must list the DWG UTI (com.autodesk.dwg).
|
|
|
|
import QuickLookThumbnailing
|
|
import CoreGraphics
|
|
import ImageIO
|
|
import Foundation
|
|
|
|
final class ThumbnailProvider: QLThumbnailProvider {
|
|
override func provideThumbnail(
|
|
for request: QLFileThumbnailRequest,
|
|
_ handler: @escaping (QLThumbnailReply?, Error?) -> Void
|
|
) {
|
|
let maxDim = UInt32(max(request.maximumSize.width, request.maximumSize.height))
|
|
|
|
var ptr: UnsafeMutablePointer<UInt8>? = nil
|
|
var len: Int = 0
|
|
let ok = request.fileURL.path.withCString { cpath in
|
|
dwg_thumbnail_png(cpath, maxDim, &ptr, &len)
|
|
}
|
|
guard ok, let p = ptr, len > 0 else {
|
|
handler(nil, nil) // no preview → QuickLook falls back
|
|
return
|
|
}
|
|
let data = Data(bytes: p, count: len)
|
|
dwg_thumbnail_free(p, len)
|
|
|
|
guard
|
|
let src = CGImageSourceCreateWithData(data as CFData, nil),
|
|
let cg = CGImageSourceCreateImageAtIndex(src, 0, nil)
|
|
else {
|
|
handler(nil, nil)
|
|
return
|
|
}
|
|
|
|
// The embedded DWG preview bitmap is often much smaller than the
|
|
// requested icon size. Scale it up (or down) to fit request.maximumSize
|
|
// and center it — otherwise QuickLook draws it at its native pixel size
|
|
// anchored at the CGContext origin (bottom-left), producing a small
|
|
// thumbnail stuck in the corner instead of filling the icon (#365).
|
|
let maxSize = request.maximumSize
|
|
let nativeSize = CGSize(width: cg.width, height: cg.height)
|
|
let scale = min(maxSize.width / nativeSize.width, maxSize.height / nativeSize.height)
|
|
let drawSize = CGSize(width: nativeSize.width * scale, height: nativeSize.height * scale)
|
|
let origin = CGPoint(x: (maxSize.width - drawSize.width) / 2, y: (maxSize.height - drawSize.height) / 2)
|
|
|
|
let reply = QLThumbnailReply(contextSize: maxSize) { (ctx: CGContext) -> Bool in
|
|
ctx.draw(cg, in: CGRect(origin: origin, size: drawSize))
|
|
return true
|
|
}
|
|
handler(reply, nil)
|
|
}
|
|
}
|