feat(thumbnails): embed DWG previews and wire cross-platform file thumbnails
Round-trip a raster preview through the DWG's embedded preview slot and
surface it to the OS file managers, so drawings show their contents in
Explorer / Finder / Nautilus instead of a generic document icon.
OCS:
* io::thumbnail — rasterize the scene to a BMP DIB on save (embedded via
acadrust's new Preview type) and read it back on open for the Start
page recent list; `--dwg-thumbnail IN OUT SIZE` CLI extracts a badged
PNG for external thumbnailers.
* io::file_association::install_thumbnailer — self-install the OS
integration on startup: Linux writes a .thumbnailer + hicolor mimetype
icons; Windows registers the IThumbnailProvider DLL under HKCU.
Shared core:
* crates/dwg-thumbnailer — lean (image-only) preview extractor + the
`badge_dwg` full-width "DWG" band, used by every platform so the
ribbon is single-sourced. Ships an rlib+staticlib.
* crates/dwg-thumbnailer-win — IThumbnailProvider COM in-proc server
(cfg(windows), CI-built as a workspace member).
* macos/ — QuickLook thumbnail extension (Swift + C-ABI bridge to the
core staticlib), assembled into a .appex.
Icons & packaging (single SVG source -> per-platform assets in CI):
* assets/mimetypes/image-vnd.{dwg,dxf}.svg — themed file icons.
* packaging: WiX ships dwg/dxf.ico + the thumbnail DLL and points the
ProgIds at them; Info.plist gets CFBundleTypeIconFile + the QuickLook
extension in Contents/PlugIns.
* release.yml — generate .ico (Windows) and .icns (macOS) from the SVGs,
build the QuickLook .appex, and bundle everything.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
5c4ba97c5f
commit
ba3b3202e8
20 changed files with 1085 additions and 76 deletions
42
crates/dwg-thumbnailer/macos/Info.plist
Normal file
42
crates/dwg-thumbnailer/macos/Info.plist
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<!-- Info.plist for the DWG QuickLook Thumbnail Extension (.appex). -->
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>DWG Thumbnails</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>DWGThumbnail</string>
|
||||
<!-- Must be prefixed with the host app id so it registers as its extension. -->
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>io.github.HakanSeven12.OpenCadStudio.DWGThumbnail</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>DWGThumbnail</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>__VERSION__</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>__VERSION__</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.quicklook.thumbnail</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>DWGThumbnail.ThumbnailProvider</string>
|
||||
<key>NSExtensionAttributes</key>
|
||||
<dict>
|
||||
<key>QLSupportedContentTypes</key>
|
||||
<array>
|
||||
<string>com.autodesk.dwg</string>
|
||||
</array>
|
||||
<key>QLThumbnailMinimumDimension</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
49
crates/dwg-thumbnailer/macos/ThumbnailProvider.swift
Normal file
49
crates/dwg-thumbnailer/macos/ThumbnailProvider.swift
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// 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
|
||||
}
|
||||
|
||||
let size = CGSize(width: cg.width, height: cg.height)
|
||||
let reply = QLThumbnailReply(contextSize: size) { (ctx: CGContext) -> Bool in
|
||||
ctx.draw(cg, in: CGRect(origin: .zero, size: size))
|
||||
return true
|
||||
}
|
||||
handler(reply, nil)
|
||||
}
|
||||
}
|
||||
18
crates/dwg-thumbnailer/macos/dwg_thumbnailer.h
Normal file
18
crates/dwg-thumbnailer/macos/dwg_thumbnailer.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* Bridging header for the macOS QuickLook extension.
|
||||
* Exposes the Rust core's C ABI (built as `libdwg_thumbnailer.a`). */
|
||||
#ifndef DWG_THUMBNAILER_H
|
||||
#define DWG_THUMBNAILER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Extract a DWG preview, encoded as PNG. On success writes a malloc'd buffer to
|
||||
* *out_ptr / *out_len (free with dwg_thumbnail_free) and returns true. */
|
||||
bool dwg_thumbnail_png(const char *path_utf8, uint32_t max_dim,
|
||||
uint8_t **out_ptr, size_t *out_len);
|
||||
|
||||
/* Free a buffer returned by dwg_thumbnail_png. */
|
||||
void dwg_thumbnail_free(uint8_t *ptr, size_t len);
|
||||
|
||||
#endif /* DWG_THUMBNAILER_H */
|
||||
Loading…
Reference in a new issue