diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..28bf1b0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,60 @@
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## Build generated
+build/
+DerivedData/
+
+## Various settings
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata/
+
+## Other
+*.moved-aside
+*.xcuserstate
+
+## Obj-C/Swift specific
+*.hmap
+*.ipa
+*.dSYM.zip
+*.dSYM
+
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+Pods/
+
+# Carthage
+#
+# Add this line if you want to avoid checking in source code from Carthage dependencies.
+# Carthage/Checkouts
+
+Carthage/Build
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
+# screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
+
+fastlane/report.xml
+fastlane/screenshots
+
+#Code Injection
+#
+# After new code Injection tools there's a generated folder /iOSInjectionProject
+# https://github.com/johnno1962/injectionforxcode
+
+iOSInjectionProject/
diff --git a/Info.plist b/Info.plist
new file mode 100644
index 0000000..2356308
--- /dev/null
+++ b/Info.plist
@@ -0,0 +1,63 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDocumentTypes
+
+
+ CFBundleTypeName
+ Adobe XD Project
+ LSHandlerRank
+ Default
+ CFBundleTypeRole
+ QLGenerator
+ LSItemContentTypes
+
+ com.adobe.xd.project
+
+
+
+ CFBundleExecutable
+ ${EXECUTABLE_NAME}
+ CFBundleIconFile
+
+ CFBundleIdentifier
+ ${PRODUCT_BUNDLE_IDENTIFIER}
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ ${PRODUCT_NAME}
+ CFBundleVersion
+ 1.0
+ CFPlugInDynamicRegisterFunction
+
+ CFPlugInDynamicRegistration
+ NO
+ CFPlugInFactories
+
+ ${PRODUCT_BUNDLE_IDENTIFIER}
+ QuickLookGeneratorPluginFactory
+
+ CFPlugInTypes
+
+ 5E2D9680-5022-40FA-B806-43349622E5B9
+
+ ${PRODUCT_BUNDLE_IDENTIFIER}
+
+
+ CFPlugInUnloadFunction
+
+ QLNeedsToBeRunInMainThread
+
+ QLPreviewHeight
+ 800
+ QLPreviewWidth
+ 600
+ QLSupportsConcurrentRequests
+
+ QLThumbnailMinimumSize
+ 17
+
+
diff --git a/Podfile b/Podfile
new file mode 100644
index 0000000..c6ddb9c
--- /dev/null
+++ b/Podfile
@@ -0,0 +1,11 @@
+# Uncomment the next line to define a global platform for your project
+platform :macos, '10.15'
+
+target 'QuickLookXD' do
+ # Comment the next line if you don't want to use dynamic frameworks
+ use_frameworks!
+
+ # Pods for QuickLookXD
+ pod 'SSZipArchive', '~> 2.5.0'
+
+end
diff --git a/Podfile.lock b/Podfile.lock
new file mode 100644
index 0000000..82f3899
--- /dev/null
+++ b/Podfile.lock
@@ -0,0 +1,16 @@
+PODS:
+ - SSZipArchive (2.5.4)
+
+DEPENDENCIES:
+ - SSZipArchive (~> 2.5.0)
+
+SPEC REPOS:
+ trunk:
+ - SSZipArchive
+
+SPEC CHECKSUMS:
+ SSZipArchive: 285b618a158ebc421039c22db5b77d345c7c03db
+
+PODFILE CHECKSUM: 3dd765180780ef3cfaca81d033308cbde625cb20
+
+COCOAPODS: 1.12.1
diff --git a/QuickLookXD.xcodeproj/project.pbxproj b/QuickLookXD.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..39b86bb
--- /dev/null
+++ b/QuickLookXD.xcodeproj/project.pbxproj
@@ -0,0 +1,503 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 53;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 14677FF62A56BEB000DAB587 /* GenerateThumbnailForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 14677FD72A56B97700DAB587 /* GenerateThumbnailForURL.m */; };
+ 14677FF72A56BEB100DAB587 /* GeneratePreviewForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 14677FD32A56B3D000DAB587 /* GeneratePreviewForURL.m */; };
+ 14677FFE2A56C24800DAB587 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 14677FFD2A56C24800DAB587 /* main.c */; };
+ 146780002A56D26900DAB587 /* Document.m in Sources */ = {isa = PBXBuildFile; fileRef = 14677FFF2A56D26900DAB587 /* Document.m */; };
+ 1497C49D2A55C6CE004C4C03 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E452A5529B2001221C8 /* Cocoa.framework */; };
+ 1497C49E2A55C6CE004C4C03 /* Cocoa.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E452A5529B2001221C8 /* Cocoa.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 1497C4A02A55C6CF004C4C03 /* Pods_QuickLookXD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AD71E06BE3F3F49B5B83F4D /* Pods_QuickLookXD.framework */; };
+ 1497C4A12A55C6CF004C4C03 /* Pods_QuickLookXD.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1AD71E06BE3F3F49B5B83F4D /* Pods_QuickLookXD.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 1497C4A22A55C6D0004C4C03 /* QuickLook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F28CFC020A3EC0C6000ABFF5 /* QuickLook.framework */; };
+ 1497C4A32A55C6D0004C4C03 /* QuickLook.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = F28CFC020A3EC0C6000ABFF5 /* QuickLook.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 1497C4A42A55C6D1004C4C03 /* QuickLookThumbnailing.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E302A552562001221C8 /* QuickLookThumbnailing.framework */; };
+ 1497C4A52A55C6D1004C4C03 /* QuickLookThumbnailing.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E302A552562001221C8 /* QuickLookThumbnailing.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 1497C4A62A55C6D2004C4C03 /* QuickLookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E322A552579001221C8 /* QuickLookUI.framework */; };
+ 1497C4A72A55C6D2004C4C03 /* QuickLookUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E322A552579001221C8 /* QuickLookUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 1497C4A82A55C6D3004C4C03 /* SSZipArchive.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 149F81532A5532B4003078F1 /* SSZipArchive.framework */; };
+ 1497C4A92A55C6D3004C4C03 /* SSZipArchive.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 149F81532A5532B4003078F1 /* SSZipArchive.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 14F06C002A572C1C007D7E47 /* docs in Resources */ = {isa = PBXBuildFile; fileRef = 14F06BFF2A572C1C007D7E47 /* docs */; };
+ 440BBDE80B0537AC0075B7E5 /* QuickLookXD.qlgenerator in Copy Files */ = {isa = PBXBuildFile; fileRef = 8D576316048677EA00EA77CD /* QuickLookXD.qlgenerator */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+ 8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8D5B49A704867FD3000E48DA /* InfoPlist.strings */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 1497C49F2A55C6CE004C4C03 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = ./Frameworks;
+ dstSubfolderSpec = 6;
+ files = (
+ 1497C49E2A55C6CE004C4C03 /* Cocoa.framework in Embed Frameworks */,
+ 1497C4A92A55C6D3004C4C03 /* SSZipArchive.framework in Embed Frameworks */,
+ 1497C4A72A55C6D2004C4C03 /* QuickLookUI.framework in Embed Frameworks */,
+ 1497C4A12A55C6CF004C4C03 /* Pods_QuickLookXD.framework in Embed Frameworks */,
+ 1497C4A32A55C6D0004C4C03 /* QuickLook.framework in Embed Frameworks */,
+ 1497C4A52A55C6D1004C4C03 /* QuickLookThumbnailing.framework in Embed Frameworks */,
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 440BBDFA0B0537B10075B7E5 /* Copy Files */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "${HOME}/Library/QuickLook";
+ dstSubfolderSpec = 0;
+ files = (
+ 440BBDE80B0537AC0075B7E5 /* QuickLookXD.qlgenerator in Copy Files */,
+ );
+ name = "Copy Files";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 14677FD32A56B3D000DAB587 /* GeneratePreviewForURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = GeneratePreviewForURL.m; path = src/GeneratePreviewForURL.m; sourceTree = ""; };
+ 14677FD72A56B97700DAB587 /* GenerateThumbnailForURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = GenerateThumbnailForURL.m; path = src/GenerateThumbnailForURL.m; sourceTree = ""; };
+ 14677FFD2A56C24800DAB587 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = src/main.c; sourceTree = ""; };
+ 14677FFF2A56D26900DAB587 /* Document.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Document.m; path = src/Document.m; sourceTree = ""; };
+ 146780012A56DACF00DAB587 /* Document.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Document.h; path = src/Document.h; sourceTree = ""; };
+ 1497C49C2A55C356004C4C03 /* Pods_QuickLookXD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Pods_QuickLookXD.framework; path = "/Users/Emmanuel/Library/Developer/Xcode/DerivedData/QuickLookXD-anldcwhcionfhrehdwpudqytenml/Build/Products/Debug/Pods_QuickLookXD.framework"; sourceTree = ""; };
+ 149F81532A5532B4003078F1 /* SSZipArchive.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = SSZipArchive.framework; path = SSZipArchive/SSZipArchive.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 149F81602A55BE6B003078F1 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = ""; };
+ 14CD3E302A552562001221C8 /* QuickLookThumbnailing.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLookThumbnailing.framework; path = /System/Library/Frameworks/QuickLookThumbnailing.framework; sourceTree = ""; };
+ 14CD3E322A552579001221C8 /* QuickLookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLookUI.framework; path = /System/Library/Frameworks/QuickLookUI.framework; sourceTree = ""; };
+ 14CD3E452A5529B2001221C8 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; };
+ 14CD3E4B2A552BFB001221C8 /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = ""; };
+ 14E6041629207D6600F29499 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
+ 14F06BFF2A572C1C007D7E47 /* docs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = docs; sourceTree = ""; };
+ 14F06C012A572C3C007D7E47 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
+ 1AD71E06BE3F3F49B5B83F4D /* Pods_QuickLookXD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_QuickLookXD.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 622150340BBDD60C00126F4B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 7216DC60EEF9EF77E634BEDF /* Pods-QuickLookXD.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QuickLookXD.debug.xcconfig"; path = "Target Support Files/Pods-QuickLookXD/Pods-QuickLookXD.debug.xcconfig"; sourceTree = ""; };
+ 8D576316048677EA00EA77CD /* QuickLookXD.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QuickLookXD.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; };
+ B552E3B261F2B53BF191EFD1 /* Pods-QuickLookXD.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QuickLookXD.release.xcconfig"; path = "Target Support Files/Pods-QuickLookXD/Pods-QuickLookXD.release.xcconfig"; sourceTree = ""; };
+ F28CFC020A3EC0C6000ABFF5 /* QuickLook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLook.framework; path = /System/Library/Frameworks/QuickLook.framework; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8D576313048677EA00EA77CD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1497C4A02A55C6CF004C4C03 /* Pods_QuickLookXD.framework in Frameworks */,
+ 1497C4A82A55C6D3004C4C03 /* SSZipArchive.framework in Frameworks */,
+ 1497C49D2A55C6CE004C4C03 /* Cocoa.framework in Frameworks */,
+ 1497C4A42A55C6D1004C4C03 /* QuickLookThumbnailing.framework in Frameworks */,
+ 1497C4A62A55C6D2004C4C03 /* QuickLookUI.framework in Frameworks */,
+ 1497C4A22A55C6D0004C4C03 /* QuickLook.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 089C166AFE841209C02AAC07 /* QuickLookXD */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB77AFFE84173DC02AAC07 /* Quick Look Generator */,
+ 089C167CFE841241C02AAC07 /* Resources */,
+ 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */,
+ 19C28FB6FE9D52B211CA2CBB /* Products */,
+ C7DC56FC83F8B07BBB1A97F8 /* Pods */,
+ B22F00DD4297C5607BDD3806 /* Frameworks */,
+ );
+ name = QuickLookXD;
+ sourceTree = "";
+ };
+ 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 14CD3E452A5529B2001221C8 /* Cocoa.framework */,
+ 149F81602A55BE6B003078F1 /* CoreServices.framework */,
+ 14CD3E4B2A552BFB001221C8 /* ApplicationServices.framework */,
+ F28CFC020A3EC0C6000ABFF5 /* QuickLook.framework */,
+ 14CD3E322A552579001221C8 /* QuickLookUI.framework */,
+ 14CD3E302A552562001221C8 /* QuickLookThumbnailing.framework */,
+ 1497C49C2A55C356004C4C03 /* Pods_QuickLookXD.framework */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "";
+ };
+ 089C167CFE841241C02AAC07 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 14F06BFF2A572C1C007D7E47 /* docs */,
+ 622150340BBDD60C00126F4B /* Info.plist */,
+ 14F06C012A572C3C007D7E47 /* README.md */,
+ 8D5B49A704867FD3000E48DA /* InfoPlist.strings */,
+ );
+ name = Resources;
+ sourceTree = "";
+ };
+ 08FB77AFFE84173DC02AAC07 /* Quick Look Generator */ = {
+ isa = PBXGroup;
+ children = (
+ 14677FFD2A56C24800DAB587 /* main.c */,
+ 14677FD32A56B3D000DAB587 /* GeneratePreviewForURL.m */,
+ 14677FD72A56B97700DAB587 /* GenerateThumbnailForURL.m */,
+ 14677FFF2A56D26900DAB587 /* Document.m */,
+ 146780012A56DACF00DAB587 /* Document.h */,
+ );
+ name = "Quick Look Generator";
+ sourceTree = "";
+ };
+ 19C28FB6FE9D52B211CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8D576316048677EA00EA77CD /* QuickLookXD.qlgenerator */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ B22F00DD4297C5607BDD3806 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1AD71E06BE3F3F49B5B83F4D /* Pods_QuickLookXD.framework */,
+ 149F81532A5532B4003078F1 /* SSZipArchive.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ C7DC56FC83F8B07BBB1A97F8 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 7216DC60EEF9EF77E634BEDF /* Pods-QuickLookXD.debug.xcconfig */,
+ B552E3B261F2B53BF191EFD1 /* Pods-QuickLookXD.release.xcconfig */,
+ );
+ path = Pods;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 8D57630E048677EA00EA77CD /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 8D57630D048677EA00EA77CD /* QuickLookXD */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2CA3261E0896AD4900168862 /* Build configuration list for PBXNativeTarget "QuickLookXD" */;
+ buildPhases = (
+ FF58800300124DF6D6902D34 /* [CP] Check Pods Manifest.lock */,
+ 8D57630E048677EA00EA77CD /* Headers */,
+ 8D57630F048677EA00EA77CD /* Resources */,
+ 8D576311048677EA00EA77CD /* Sources */,
+ 8D576313048677EA00EA77CD /* Frameworks */,
+ 8D576315048677EA00EA77CD /* Rez */,
+ 1497C49F2A55C6CE004C4C03 /* Embed Frameworks */,
+ 440BBDFA0B0537B10075B7E5 /* Copy Files */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = QuickLookXD;
+ productInstallPath = /Library/Spotlight;
+ productName = QuickLookXD;
+ productReference = 8D576316048677EA00EA77CD /* QuickLookXD.qlgenerator */;
+ productType = "com.apple.product-type.bundle";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 089C1669FE841209C02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = YES;
+ LastSwiftUpdateCheck = 1430;
+ LastUpgradeCheck = 1430;
+ TargetAttributes = {
+ 8D57630D048677EA00EA77CD = {
+ LastSwiftMigration = 1430;
+ };
+ };
+ };
+ buildConfigurationList = 2CA326220896AD4900168862 /* Build configuration list for PBXProject "QuickLookXD" */;
+ compatibilityVersion = "Xcode 2.4";
+ developmentRegion = en;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 089C166AFE841209C02AAC07 /* QuickLookXD */;
+ productRefGroup = 19C28FB6FE9D52B211CA2CBB /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8D57630D048677EA00EA77CD /* QuickLookXD */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D57630F048677EA00EA77CD /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */,
+ 14F06C002A572C1C007D7E47 /* docs in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ 8D576315048677EA00EA77CD /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ FF58800300124DF6D6902D34 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-QuickLookXD-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8D576311048677EA00EA77CD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 14677FFE2A56C24800DAB587 /* main.c in Sources */,
+ 146780002A56D26900DAB587 /* Document.m in Sources */,
+ 14677FF62A56BEB000DAB587 /* GenerateThumbnailForURL.m in Sources */,
+ 14677FF72A56BEB100DAB587 /* GeneratePreviewForURL.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 8D5B49A704867FD3000E48DA /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 14E6041629207D6600F29499 /* en */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 2CA3261F0896AD4900168862 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7216DC60EEF9EF77E634BEDF /* Pods-QuickLookXD.debug.xcconfig */;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEAD_CODE_STRIPPING = NO;
+ DEVELOPMENT_TEAM = 54HE8SFBAE;
+ EAGER_LINKING = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "${inherited}",
+ "${FRAMEWORK_SEARCH_PATHS_QUOTED_1}",
+ );
+ FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"${SYSTEM_LIBRARY_DIR}/Frameworks\"";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ INFOPLIST_FILE = Info.plist;
+ INFOPLIST_KEY_NSPrincipalClass = "";
+ INSTALL_PATH = /Library/QuickLook;
+ LIBRARY_STYLE = Bundle;
+ MACOSX_BUILD_TARGET = 10.15;
+ MACOSX_DEPLOYMENT_TARGET = "${MACOSX_BUILD_TARGET}";
+ PLUGIN_ID = "74565352-F5FE-4DAD-9FDE-BF4791F600F8";
+ PRELINK_LIBS = SSZipArchive;
+ "PRELINK_LIBS[arch=*]" = SSZipArchive;
+ PRODUCT_BUNDLE_IDENTIFIER = com.qbrkts.quicklookxd;
+ PRODUCT_NAME = QuickLookXD;
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_OBJC_BRIDGING_HEADER = "";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ WRAPPER_EXTENSION = qlgenerator;
+ ZERO_LINK = YES;
+ };
+ name = Debug;
+ };
+ 2CA326200896AD4900168862 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = B552E3B261F2B53BF191EFD1 /* Pods-QuickLookXD.release.xcconfig */;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = NO;
+ DEVELOPMENT_TEAM = 54HE8SFBAE;
+ EAGER_LINKING = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "${inherited}",
+ "${FRAMEWORK_SEARCH_PATHS_QUOTED_1}",
+ );
+ FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"${SYSTEM_LIBRARY_DIR}/Frameworks\"";
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ INFOPLIST_FILE = Info.plist;
+ INFOPLIST_KEY_NSPrincipalClass = "";
+ INSTALL_PATH = /Library/QuickLook;
+ LIBRARY_STYLE = Bundle;
+ MACOSX_BUILD_TARGET = 10.15;
+ MACOSX_DEPLOYMENT_TARGET = "${MACOSX_BUILD_TARGET}";
+ PLUGIN_ID = "74565352-F5FE-4DAD-9FDE-BF4791F600F8";
+ PRELINK_LIBS = SSZipArchive;
+ PRODUCT_BUNDLE_IDENTIFIER = com.qbrkts.quicklookxd;
+ PRODUCT_NAME = QuickLookXD;
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_OBJC_BRIDGING_HEADER = "";
+ SWIFT_VERSION = 5.0;
+ WRAPPER_EXTENSION = qlgenerator;
+ };
+ name = Release;
+ };
+ 2CA326230896AD4900168862 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD)";
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ DEAD_CODE_STRIPPING = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = "${MACOSX_BUILD_TARGET}";
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
+ 2CA326240896AD4900168862 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD)";
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ DEAD_CODE_STRIPPING = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = "${MACOSX_BUILD_TARGET}";
+ SDKROOT = macosx;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 2CA3261E0896AD4900168862 /* Build configuration list for PBXNativeTarget "QuickLookXD" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2CA3261F0896AD4900168862 /* Debug */,
+ 2CA326200896AD4900168862 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2CA326220896AD4900168862 /* Build configuration list for PBXProject "QuickLookXD" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2CA326230896AD4900168862 /* Debug */,
+ 2CA326240896AD4900168862 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 089C1669FE841209C02AAC07 /* Project object */;
+}
diff --git a/QuickLookXD.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/QuickLookXD.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..fce45f3
--- /dev/null
+++ b/QuickLookXD.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..9b59d84
--- /dev/null
+++ b/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/QuickLookXD.xcodeproj/xcshareddata/xcschemes/QuickLookXD.xcscheme b/QuickLookXD.xcodeproj/xcshareddata/xcschemes/QuickLookXD.xcscheme
new file mode 100644
index 0000000..e3556f3
--- /dev/null
+++ b/QuickLookXD.xcodeproj/xcshareddata/xcschemes/QuickLookXD.xcscheme
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/QuickLookXD.xcworkspace/contents.xcworkspacedata b/QuickLookXD.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..d447b08
--- /dev/null
+++ b/QuickLookXD.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/QuickLookXD.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/QuickLookXD.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/QuickLookXD.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/QuickLookXD.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/QuickLookXD.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..0c67376
--- /dev/null
+++ b/QuickLookXD.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3560d85
--- /dev/null
+++ b/README.md
@@ -0,0 +1,47 @@
+# AdobeXD MacOS Quick Look Plugin
+
+Enables previews of XD files [(Adobe Experience Designer)][adobe-xd].
+
+[QL plugin discussion][ql-win-issue].
+
+Based on [QuickLookASE][ql-ase].
+
+[XD format reference][xd-format-reference].
+
+
+
+## Notes
+
+How to find the UTI of a file:
+
+```sh
+$ mdls -name kMDItemContentType ./docs/example/file01.xd
+kMDItemContentType = "com.adobe.xd.project"
+```
+
+## Demo
+
+
+
+
+
+[adobe-xd]: https://www.adobe.com/ca/products/xd.html
+[xd-format-reference]: https://docs.fileformat.com/web/xd
+[ql-win-issue]: https://github.com/QL-Win/QuickLook/issues/307#issuecomment-1473989813
+[ql-ase]: https://github.com/rsodre/QuickLookASE
diff --git a/docs/example/file01.xd b/docs/example/file01.xd
new file mode 100644
index 0000000..c6fa2b9
Binary files /dev/null and b/docs/example/file01.xd differ
diff --git a/docs/example/file02.xd b/docs/example/file02.xd
new file mode 100644
index 0000000..de98fc8
Binary files /dev/null and b/docs/example/file02.xd differ
diff --git a/docs/example/screenshot01.png b/docs/example/screenshot01.png
new file mode 100644
index 0000000..66afc9e
Binary files /dev/null and b/docs/example/screenshot01.png differ
diff --git a/en.lproj/InfoPlist.strings b/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000..cfb1402
Binary files /dev/null and b/en.lproj/InfoPlist.strings differ
diff --git a/src/Document.h b/src/Document.h
new file mode 100644
index 0000000..65db982
--- /dev/null
+++ b/src/Document.h
@@ -0,0 +1,19 @@
+//
+// Document.h
+// QuickLookXD
+//
+// Created by Ogbizi on 2023-07-06.
+//
+
+#ifndef Document_h
+#define Document_h
+
+
+#endif /* Document_h */
+
+// Constants
+#define IMAGE_PREVIEW_FILENAME @"preview.png"
+#define IMAGE_THUMBNAIL_FILENAME @"thumbnail.png"
+
+/// Get preview or thumbnail image from adobe xd file
+CGImageRef GetImageFromDocument(NSURL* docURL, NSString *imageFileName, NSString *fallbackImageFileName);
diff --git a/src/Document.m b/src/Document.m
new file mode 100644
index 0000000..be30f3d
--- /dev/null
+++ b/src/Document.m
@@ -0,0 +1,47 @@
+//
+// Document.m
+// QuickLookXD
+//
+// Created by Ogbizi on 2023-07-06.
+//
+
+#include
+#include
+#include "SSZipArchive.h"
+#include "Document.h"
+
+
+CGImageRef GetImageFromDocument(NSURL* docURL, NSString *imageFileName, NSString *fallbackImageFileName) {
+ // path to local XD file
+ NSString *zipPath = docURL.path;
+ // folder to unzip the file into
+ NSString *zipFileName = [docURL.pathComponents lastObject];
+ // full path to unzip location in the user tmp directory
+ NSString *unzippedPath = [NSString stringWithFormat:@"%@/%@/", NSTemporaryDirectory(), zipFileName];
+ // unzip the file and check for success
+ BOOL success = [SSZipArchive unzipFileAtPath:zipPath toDestination:unzippedPath];
+ if (!success) {
+ NSLog(@"Failed to unzip the file at path: %@", zipPath);
+ }
+
+ NSString *imageFilePath = [unzippedPath stringByAppendingPathComponent:imageFileName];
+ BOOL imageFileExists = [[NSFileManager defaultManager] fileExistsAtPath:imageFilePath];
+
+ if (!imageFileExists) {
+ NSLog(@"No image file found at: %@", imageFilePath);
+
+ imageFilePath = [unzippedPath stringByAppendingPathComponent:fallbackImageFileName];
+ imageFileExists = [[NSFileManager defaultManager] fileExistsAtPath:imageFilePath];
+
+ if (!imageFileExists) {
+ NSLog(@"No image file found at: %@", imageFilePath);
+ return NULL;
+ }
+ }
+
+ NSLog(@"Found image file at: %@", imageFilePath);
+
+ CGDataProviderRef provider = CGDataProviderCreateWithFilename(imageFilePath.UTF8String);
+ CGImageRef image = CGImageCreateWithPNGDataProvider(provider, NULL, true, kCGRenderingIntentDefault);
+ return image;
+}
diff --git a/src/GeneratePreviewForURL.m b/src/GeneratePreviewForURL.m
new file mode 100644
index 0000000..f041858
--- /dev/null
+++ b/src/GeneratePreviewForURL.m
@@ -0,0 +1,48 @@
+#include
+#include
+#include
+#include
+#include "Document.h"
+
+
+/* -----------------------------------------------------------------------------
+ Generate a preview for file
+
+ This function's job is to create preview for designated file
+ ----------------------------------------------------------------------------- */
+
+OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options)
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ CGImageRef image = GetImageFromDocument((NSURL *)url, IMAGE_PREVIEW_FILENAME, IMAGE_THUMBNAIL_FILENAME);
+
+ if (!image) {
+ [pool release];
+ NSLog(@"Exiting because no image retrieved from document.");
+ return noErr;
+ }
+
+ CGSize imageSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
+
+ // Preview will be drawn in a vectorized context
+ // Here we create a graphics context to draw the Quick Look Preview in
+ CGContextRef cgContext = QLPreviewRequestCreateContext(preview, imageSize, false, NULL);
+ if(cgContext) {
+ CGRect canvas = CGRectMake(0, 0, imageSize.width, imageSize.height);
+ CGContextDrawImage(cgContext, canvas, image);
+
+ // When we are done with our drawing code QLPreviewRequestFlushContext() is called to flush the context
+ QLPreviewRequestFlushContext(preview, cgContext);
+
+ CFRelease(cgContext);
+ }
+
+ [pool release];
+ return noErr;
+}
+
+void CancelPreviewGeneration(void* thisInterface, QLPreviewRequestRef preview)
+{
+ // implement only if supported
+}
diff --git a/src/GenerateThumbnailForURL.m b/src/GenerateThumbnailForURL.m
new file mode 100644
index 0000000..07c582c
--- /dev/null
+++ b/src/GenerateThumbnailForURL.m
@@ -0,0 +1,44 @@
+#include
+#include
+#include
+#include
+#include "Document.h"
+
+OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize)
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ CGImageRef image = GetImageFromDocument((NSURL *)url, IMAGE_THUMBNAIL_FILENAME, IMAGE_PREVIEW_FILENAME);
+
+ if (!image) {
+ [pool release];
+ NSLog(@"Exiting because no image retrieved from document.");
+ return noErr;
+ }
+
+ CGSize imageSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
+ CGFloat scaleFactor = MIN(maxSize.width / imageSize.width, maxSize.height / imageSize.height);
+ CGSize canvasSize = CGSizeMake(imageSize.width * scaleFactor, imageSize.height * scaleFactor);
+
+ // Thumbnail will be drawn with maximum resolution for desired thumbnail request
+ // Here we create a graphics context to draw the Quick Look Thumbnail in.
+ CGContextRef cgContext = QLThumbnailRequestCreateContext(thumbnail, canvasSize, false, NULL);
+ if(cgContext) {
+ CGRect canvas = CGRectMake(0, 0, canvasSize.width, canvasSize.height);
+ CGContextDrawImage(cgContext, canvas, image);
+
+ // When we are done with our drawing code QLThumbnailRequestFlushContext() is called to flush the context
+ QLThumbnailRequestFlushContext(thumbnail, cgContext);
+
+ CFRelease(cgContext);
+ }
+
+ [pool release];
+ return noErr;
+}
+
+void CancelThumbnailGeneration(void* thisInterface, QLThumbnailRequestRef thumbnail)
+{
+ // implement only if supported
+}
+
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..296ed7a
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,203 @@
+#include
+#include
+#include
+#include
+
+// -----------------------------------------------------------------------------
+// constants
+// -----------------------------------------------------------------------------
+
+// Using plugin product identifier
+#define PLUGIN_ID "com.qbrkts.quicklookxd"
+
+//
+// Below is the generic glue code for all plug-ins.
+//
+// You should not have to modify this code aside from changing
+// names if you decide to change the names defined in the Info.plist
+//
+
+
+// -----------------------------------------------------------------------------
+// typedefs
+// -----------------------------------------------------------------------------
+
+// The thumbnail generation function to be implemented in GenerateThumbnailForURL.c
+OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize);
+void CancelThumbnailGeneration(void* thisInterface, QLThumbnailRequestRef thumbnail);
+
+// The preview generation function to be implemented in GeneratePreviewForURL.c
+OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options);
+void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview);
+
+// The layout for an instance of QuickLookGeneratorPlugIn
+typedef struct __QuickLookGeneratorPluginType
+{
+ void *conduitInterface;
+ CFUUIDRef factoryID;
+ UInt32 refCount;
+} QuickLookGeneratorPluginType;
+
+// -----------------------------------------------------------------------------
+// prototypes
+// -----------------------------------------------------------------------------
+// Forward declaration for the IUnknown implementation.
+//
+
+QuickLookGeneratorPluginType *AllocQuickLookGeneratorPluginType(CFUUIDRef inFactoryID);
+void DeallocQuickLookGeneratorPluginType(QuickLookGeneratorPluginType *thisInstance);
+HRESULT QuickLookGeneratorQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv);
+void *QuickLookGeneratorPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID);
+ULONG QuickLookGeneratorPluginAddRef(void *thisInstance);
+ULONG QuickLookGeneratorPluginRelease(void *thisInstance);
+
+// -----------------------------------------------------------------------------
+// myInterfaceFtbl definition
+// -----------------------------------------------------------------------------
+// The QLGeneratorInterfaceStruct function table.
+//
+static QLGeneratorInterfaceStruct myInterfaceFtbl = {
+ NULL,
+ QuickLookGeneratorQueryInterface,
+ QuickLookGeneratorPluginAddRef,
+ QuickLookGeneratorPluginRelease,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+
+// -----------------------------------------------------------------------------
+// AllocQuickLookGeneratorPluginType
+// -----------------------------------------------------------------------------
+// Utility function that allocates a new instance.
+// You can do some initial setup for the generator here if you wish
+// like allocating globals etc...
+//
+QuickLookGeneratorPluginType *AllocQuickLookGeneratorPluginType(CFUUIDRef inFactoryID)
+{
+ QuickLookGeneratorPluginType *theNewInstance;
+
+ theNewInstance = (QuickLookGeneratorPluginType *)malloc(sizeof(QuickLookGeneratorPluginType));
+ memset(theNewInstance,0,sizeof(QuickLookGeneratorPluginType));
+
+ /* Point to the function table Malloc enough to store the stuff and copy the filler from myInterfaceFtbl over */
+ theNewInstance->conduitInterface = malloc(sizeof(QLGeneratorInterfaceStruct));
+ memcpy(theNewInstance->conduitInterface,&myInterfaceFtbl,sizeof(QLGeneratorInterfaceStruct));
+
+ /* Retain and keep an open instance refcount for each factory. */
+ theNewInstance->factoryID = CFRetain(inFactoryID);
+ CFPlugInAddInstanceForFactory(inFactoryID);
+
+ /* This function returns the IUnknown interface so set the refCount to one. */
+ theNewInstance->refCount = 1;
+ return theNewInstance;
+}
+
+// -----------------------------------------------------------------------------
+// DeallocQuickLookGeneratorPluginType
+// -----------------------------------------------------------------------------
+// Utility function that deallocates the instance when
+// the refCount goes to zero.
+// In the current implementation generator interfaces are never deallocated
+// but implement this as this might change in the future
+//
+void DeallocQuickLookGeneratorPluginType(QuickLookGeneratorPluginType *thisInstance)
+{
+ CFUUIDRef theFactoryID;
+
+ theFactoryID = thisInstance->factoryID;
+ /* Free the conduitInterface table up */
+ free(thisInstance->conduitInterface);
+
+ /* Free the instance structure */
+ free(thisInstance);
+ if (theFactoryID){
+ CFPlugInRemoveInstanceForFactory(theFactoryID);
+ CFRelease(theFactoryID);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// QuickLookGeneratorQueryInterface
+// -----------------------------------------------------------------------------
+// Implementation of the IUnknown QueryInterface function.
+//
+HRESULT QuickLookGeneratorQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv)
+{
+ CFUUIDRef interfaceID;
+
+ interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault,iid);
+
+ if (CFEqual(interfaceID,kQLGeneratorCallbacksInterfaceID)){
+ /* If the Right interface was requested, bump the ref count,
+ * set the ppv parameter equal to the instance, and
+ * return good status.
+ */
+ ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->GenerateThumbnailForURL = GenerateThumbnailForURL;
+ ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->CancelThumbnailGeneration = CancelThumbnailGeneration;
+ ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->GeneratePreviewForURL = GeneratePreviewForURL;
+ ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->CancelPreviewGeneration = CancelPreviewGeneration;
+ ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType*)thisInstance)->conduitInterface)->AddRef(thisInstance);
+ *ppv = thisInstance;
+ CFRelease(interfaceID);
+ return S_OK;
+ }else{
+ /* Requested interface unknown, bail with error. */
+ *ppv = NULL;
+ CFRelease(interfaceID);
+ return E_NOINTERFACE;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// QuickLookGeneratorPluginAddRef
+// -----------------------------------------------------------------------------
+// Implementation of reference counting for this type. Whenever an interface
+// is requested, bump the refCount for the instance. NOTE: returning the
+// refcount is a convention but is not required so don't rely on it.
+//
+ULONG QuickLookGeneratorPluginAddRef(void *thisInstance)
+{
+ ((QuickLookGeneratorPluginType *)thisInstance )->refCount += 1;
+ return ((QuickLookGeneratorPluginType*) thisInstance)->refCount;
+}
+
+// -----------------------------------------------------------------------------
+// QuickLookGeneratorPluginRelease
+// -----------------------------------------------------------------------------
+// When an interface is released, decrement the refCount.
+// If the refCount goes to zero, deallocate the instance.
+//
+ULONG QuickLookGeneratorPluginRelease(void *thisInstance)
+{
+ ((QuickLookGeneratorPluginType*)thisInstance)->refCount -= 1;
+ if (((QuickLookGeneratorPluginType*)thisInstance)->refCount == 0){
+ DeallocQuickLookGeneratorPluginType((QuickLookGeneratorPluginType*)thisInstance );
+ return 0;
+ }else{
+ return ((QuickLookGeneratorPluginType*) thisInstance )->refCount;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// QuickLookGeneratorPluginFactory
+// -----------------------------------------------------------------------------
+void *QuickLookGeneratorPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID)
+{
+ QuickLookGeneratorPluginType *result;
+ CFUUIDRef uuid;
+
+ /* If correct type is being requested, allocate an
+ * instance of kQLGeneratorTypeID and return the IUnknown interface.
+ */
+ if (CFEqual(typeID,kQLGeneratorTypeID)){
+ uuid = CFUUIDCreateFromString(kCFAllocatorDefault,CFSTR(PLUGIN_ID));
+ result = AllocQuickLookGeneratorPluginType(uuid);
+ CFRelease(uuid);
+ return result;
+ }
+ /* If the requested type is incorrect, return NULL. */
+ return NULL;
+}