From dad83306bbff0677bc32c538f8753d714ee3c45b Mon Sep 17 00:00:00 2001 From: Dimitri Lozeve Date: Thu, 16 Apr 2020 15:23:08 +0200 Subject: [PATCH] Add mathpix --- .gitignore | 2 +- init.el | 15 ++++++-- site-lisp/mathpix.el | 90 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 site-lisp/mathpix.el diff --git a/.gitignore b/.gitignore index 8660bba..7b23935 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,4 @@ elpy/ org-clock-save.el forge-database.sqlite custom.el -email.el +secrets.el diff --git a/init.el b/init.el index bc63d02..2e77d38 100644 --- a/init.el +++ b/init.el @@ -386,6 +386,13 @@ :config (setq twittering-reverse-mode t)) +(use-package mathpix.el + :load-path "site-lisp" + ;; You also need to configure `mathpix-app-id` and + ;; `mathpix-app-key`, for instance in secrets.el + :bind + ("C-x m" . mathpix-screenshot)) + ;; Org-mode ;; Pour accéder rapidement à l'organisation (defun gtd () @@ -576,11 +583,11 @@ (kill-ring-save (point-min) (point-max)))) -;; email configuration file -(setq email-file (expand-file-name "email.el" user-emacs-directory)) +;; configuration file for secrets (API keys, etc) +(setq secrets-file (expand-file-name "secrets.el" user-emacs-directory)) -(when (file-exists-p email-file) - (load email-file)) +(when (file-exists-p secrets-file) + (load secrets-file)) ;; config changes made through the customize UI will be stored here diff --git a/site-lisp/mathpix.el b/site-lisp/mathpix.el new file mode 100644 index 0000000..fcd5053 --- /dev/null +++ b/site-lisp/mathpix.el @@ -0,0 +1,90 @@ +;;; mathpix.el --- Mathpix API from Emacs + +;;; Commentary: +;; This package provides an interface similar to the Mathpix snipping tool. +;; +;; mathpix-screenshot prompts for a screenshot, which is sent for processing +;; via Mathpix's API. +;; +;; Heavily adapted from org-download. + +(require 'json) + +(defcustom mathpix-app-id nil + "App ID for Mathpix.") + +(defcustom mathpix-app-key nil + "App key for Mathpix.") + +;; From org-download +(defcustom mathpix-screenshot-method "gnome-screenshot -a -f %s" + "The tool to capture screenshots." + :type '(choice + (const :tag "gnome-screenshot" "gnome-screenshot -a -f %s") + (const :tag "scrot" "scrot -s %s") + (const :tag "gm" "gm import %s") + (const :tag "imagemagick/import" "import %s") + (const :tag "imagemagick/import + xclip to save to clipboard" + "export filename=\"%s\"; import png:\"$filename\" ;xclip -selection clipboard -target image/png -filter < \"$filename\" &>/dev/null") + (const :tag "xfce4-screenshooter" "xfce4-screenshooter -r -o cat > %s") + ;; screenshot method in ms-windows, /capture=4 stands for interactive. + (const :tag "IrfanView" "i_view64 /capture=4 /convert=\"%s\"") + ;; screenshot script in osx, -i stands for interactive, + ;; press space key to toggle between selection and + ;; window/application mode. + (const :tag "screencapture" "screencapture -i %s") + ;; take an image that is already on the clipboard, for Linux + (const :tag "xclip" + "xclip -selection clipboard -t image/png -o > %s") + ;; take an image that is already on the clipboard, for Windows + (const :tag "imagemagick/convert" "convert clipboard: %s") + (function :tag "Custom function"))) + +(defcustom mathpix-screenshot-file + (expand-file-name "mathpix.png" temporary-file-directory) + "The file to capture mathpix screenshots" + :type 'string) + +(defconst mathpix-api-curl-command + "curl -s https://api.mathpix.com/v3/latex -X POST -H \"app_id: %s\" -H \"app_key: %s\" -H \"Content-Type: application/json\" --data \"{\\\"src\\\":\\\"%s\\\",\\\"formats\\\": [\\\"latex_styled\\\"],\\\"format_options\\\":{\\\"latex_styled\\\": {\\\"transforms\\\": [\\\"rm_spaces\\\"]}}}\"" + "The shell executable command to retrieve the results.") + +;; screenshot programs have exit-code of 0 even when screenshotting is cancelled. +;; To save API calls, we use the existence of the file as a check if the user +;; wants to continue. Hence, we must delete the file after each function call. +(defun mathpix-screenshot () + "Capture screenshot and send result to Mathpix API." + (interactive) + (let ((default-directory "~")) + (make-directory (file-name-directory mathpix-screenshot-file) t) + (if (functionp mathpix-screenshot-method) + (funcall mathpix-screenshot-file mathpix-screenshot-file) + (shell-command-to-string + (format mathpix-screenshot-method mathpix-screenshot-file))) + (when (file-exists-p mathpix-screenshot-file) + (insert (mathpix-get-result mathpix-screenshot-file)) + (delete-file mathpix-screenshot-file)))) + + +(defun mathpix-get-b64-image (file) + "Returns the base-64 image string from file." + (with-temp-buffer + (insert-file-contents file) + (base64-encode-string (buffer-string) t))) + +(defun mathpix-get-result (file) + "Sends the image to Mathpix API." + (let* ((file-extension (file-name-extension file)) + (image-data (format "data:image/%s;base64,%s" file-extension (mathpix-get-b64-image file))) + (command (format mathpix-api-curl-command mathpix-app-id mathpix-app-key image-data)) + (result (json-read-from-string (shell-command-to-string command)))) + (let ((error (assoc-default 'error result))) + (if error + (progn + (message "%s" error) + "") + (assoc-default 'latex_styled result))))) + +(provide 'mathpix) + +;;; mathpix.el ends here