使用命令列腳本從 OmniGraffle 匯出

2018 年 8 月 21 日

時不時我會在 OmniGraffle 中繪製一堆圖表,然後需要將它們全部轉換成可以在網頁中顯示的格式。如果我只有一或兩個,每次執行都可以。但是如果我有十幾個或更多,那麼我發現使用腳本會比較容易。這樣一來,我可以在需要時安全地匯出所有圖表。

幸運的是,Omnigraffle 提供自動化介面,讓我可以透過 AppleScript 與它對話,讓這件事成為可能。它會隨著時間而改變,今天早上我花了好幾個小時才讓它順利運作。因此,我想記下我的筆記,以防其他人也想這麼做。

最終可能會出現更好的方法來執行這項工作。Omni Group 正在建構一個更豐富的自動化環境,可以從 JavaScript 呼叫。在我撰寫這篇文章時,無法從 JavaScript 存取匯出功能,所以我改用 AppleScript 路徑。

我不熟悉 AppleScript,而且在使用時也不太喜歡它。因此,我喜歡將 AppleScript 中的任何程式碼保持在最低限度。我做了例行的 Google 搜尋,拼湊出一個小型腳本,用來匯出目前的前端文件。它假設檔案中只有一個畫布,這適用於我正在處理的檔案。

omni2png.scpt…

  on convertGraffleFile(outputFile)
    tell application "OmniGraffle"
      export front document scope "all graphics" as "SVG" to file outputFile
      close front document
    end tell
  end convertGraffleFile
  
  on run argv
     convertGraffleFile(item 1 of argv)
  end run

我想對符合特定名稱模式的特定資料夾中的所有檔案執行這項工作。我想要用熟悉的語言處理這大部分的邏輯,而我用 ruby 來執行此類腳本。

omni.rb…

  module Omni
    def self.convert_file folder, name
      input = folder + (name + ".graffle")
      return unless input.exist?
      output = folder + (name + ".svg")
      return if FileUtils::uptodate?(output.to_s, [input.to_s])
      system "open #{input}"
      call_conversion(macpath(output))
    end
  
    def self.convert_rgram folder
      convert_file folder, "rgram2"
    end
  
    def self.call_conversion output
      cmd = "osascript lib/omni2png.scpt #{output}"
      result = system cmd
      puts "error processing #{output}" unless result
    end
  
    def self.convert_all_rgrams
      Pathname('catalog').children
        .select {|p| p.directory?}
        .each {|p| convert_rgram p }
    end
  
    def self.macpath arg
      return arg.expand_path.to_s.tr("/", ":")[1..-1]
    end
  end

這段程式碼會查看catalog的所有子目錄,對於每個包含ggram.graffle的子目錄,會匯出成類似名稱的png檔案。它只會在日期顯示需要重新撰寫png檔案時執行。

你可能會覺得奇怪,我使用命令列呼叫 (system) 開啟檔案,而不是在 AppleScript 腳本中開啟檔案。我這樣做的原因是,我有時會在 AppleScript 中開啟 OmniGraffle 文件時出現惱人的錯誤 (它說有權限錯誤,但如果我手動或透過命令列開啟,則沒有問題)


重大修訂

2018 年 8 月 21 日:更新為 OmniGraffle 已變更其匯出方法,以使用新的「匯出」動詞(而非使用儲存)

2017 年 10 月 31 日:原始文章