When an image has large bits of white color it may merge with the document background. To avoid this lets add a shadow to the image. We can parse the file path from a image object in Markdown file and send it to ImageMagic.
(defun ig/md-imagemagick-add-shadow ()
"Add shadow to a Markdown image element"
(interactive "@*")
;; Look for a Markdown image element before the cursor or immediately
;; after the cursor. Don't look any further than the start of the current
;; paragraph.
(let ((limit (save-excursion
(backward-paragraph)
(point)))
(regexp "\\s-*!\\[\\([^][]*\\)\\](\\([^()]*\\))?"))
(if (and (eq ?! (char-after (1- (point))))
(eq ?\[ (char-after (point))))
(backward-char))
(while (not (looking-at regexp))
(search-backward "![" limit))
;; If the search didn't error out, then we exited the loop with
;; `looking-at' matching `regexp'. The match data therefore contains
;; the parts of the image link.
(skip-syntax-forward "-")
(let ((img-path (match-string 2)))
(shell-command (format "file=%s;
convert $file \\
\\( +clone -background '#A4B1BC' -shadow 100x5+0+0 \\) \\
+swap -background none -layers merge +repage $file;
echo 'Added shadow to:' $file "
(replace-regexp-in-string "%20" "\\\\ " img-path))))))
Some images are just unnecessary wide for a Markdown document. We will specify a max width value and if an image is larger than the specified size we will scale it down.
(defun ig/md-imagemagick-max-w ()
"Scale down image to max width defined by user"
(interactive "@*")
;; Look for a Markdown image element before the cursor or immediately
;; after the cursor. Don't look any further than the start of the current
;; paragraph.
(let ((limit (save-excursion
(backward-paragraph)
(point)))
(regexp "\\s-*!\\[\\([^][]*\\)\\](\\([^()]*\\))?"))
(if (and (eq ?! (char-after (1- (point))))
(eq ?\[ (char-after (point))))
(backward-char))
(while (not (looking-at regexp))
(search-backward "![" limit))
;; If the search didn't error out, then we exited the loop with
;; `looking-at' matching `regexp'. The match data therefore contains
;; the parts of the image link.
(skip-syntax-forward "-")
(let ((img-path (match-string 2)))
(shell-command (format " file=%s; width=%s;
convert \"$file\" -resize \"$width\"x10000\\> \"$file\";
echo Scaled down to W = \"$width\"px \"$file\""
(replace-regexp-in-string "%20" "\\\\ " img-path)
(read-string "Enter max image width:"))))))
Scaling an image size down is not always a best solution. Images of tables will benefit from a liquid scaling.
(defun ig/md-imagemagick-liquid-scale ()
"Scale down image to width defined by user.
Is better to use a percent value"
(interactive "@*")
;; Look for a Markdown image element before the cursor or immediately
;; after the cursor. Don't look any further than the start of the current
;; paragraph.
(let ((limit (save-excursion
(backward-paragraph)
(point)))
(regexp "\\s-*!\\[\\([^][]*\\)\\](\\([^()]*\\))?"))
(if (and (eq ?! (char-after (1- (point))))
(eq ?\[ (char-after (point))))
(backward-char))
(while (not (looking-at regexp))
(search-backward "![" limit))
;; If the search didn't error out, then we exited the loop with
;; `looking-at' matching `regexp'. The match data therefore contains
;; the parts of the image link.
(skip-syntax-forward "-")
(let ((img-path (match-string 2)))
(shell-command (format "file=%s; width=%s;
convert \"$file\" -liquid-rescale \"$width\"x100%%\\! \"$file\"
echo Changed image width to \"$width\"px \"$file\" "
(replace-regexp-in-string "%20" "\\\\ " img-path)
(read-string "Enter max image width:"))))))
Is good to know what size an image has.
(defun ig/md-image-size-info ()
"Show image information, size, with, height"
(interactive "@*")
;; Look for a Markdown image element before the cursor or immediately
;; after the cursor. Don't look any further than the start of the current
;; paragraph.
(let ((limit (save-excursion
(backward-paragraph)
(point)))
(regexp "\\s-*!\\[\\([^][]*\\)\\](\\([^()]*\\))?"))
(if (and (eq ?! (char-after (1- (point))))
(eq ?\[ (char-after (point))))
(backward-char))
(while (not (looking-at regexp))
(search-backward "![" limit))
;; If the search didn't error out, then we exited the loop with
;; `looking-at' matching `regexp'. The match data therefore contains
;; the parts of the image link.
(skip-syntax-forward "-")
(let ((img-path (match-string 2)))
(shell-command (format "magick identify -format 'Image Size:%%b, W:%%[fx:w]px, H:%%[fx:h]px' %s"
(replace-regexp-in-string "%20" "\\\\ " img-path))))))
Not everything can be automated. In some cases I will need to open a image from markdown in an external editor.
(defun ig/md-open-image-in-editor ()
"Open a markdown image in an external editor"
(interactive "@*")
;; Look for a Markdown image element before the cursor or immediately
;; after the cursor. Don't look any further than the start of the current
;; paragraph.
(let ((limit (save-excursion
(backward-paragraph)
(point)))
(regexp "\\s-*!\\[\\([^][]*\\)\\](\\([^()]*\\))?"))
(if (and (eq ?! (char-after (1- (point))))
(eq ?\[ (char-after (point))))
(backward-char))
(while (not (looking-at regexp))
(search-backward "![" limit))
;; If the search didn't error out, then we exited the loop with
;; `looking-at' matching `regexp'. The match data therefore contains
;; the parts of the image link.
(skip-syntax-forward "-")
(let ((img-path (match-string 2)))
(shell-command (format "open %s"
(replace-regexp-in-string "%20" "\\\\ " img-path))))))
(defun ig/md-open-image-in-affinity-designer ()
"Open markdown image under cursor in Affinity Designer"
(interactive "@*")
;; Look for a Markdown image element before the cursor or immediately
;; after the cursor. Don't look any further than the start of the current
;; paragraph.
(let ((limit (save-excursion
(backward-paragraph)
(point)))
(regexp "\\s-*!\\[\\([^][]*\\)\\](\\([^()]*\\))?"))
(if (and (eq ?! (char-after (1- (point))))
(eq ?\[ (char-after (point))))
(backward-char))
(while (not (looking-at regexp))
(search-backward "![" limit))
;; If the search didn't error out, then we exited the loop with
;; `looking-at' matching `regexp'. The match data therefore contains
;; the parts of the image link.
(skip-syntax-forward "-")
(let ((img-path (match-string 2)))
(shell-command (format "open -a 'Affinity Designer' %s"
(replace-regexp-in-string "%20" "\\\\ " img-path))))))
(defun ig/md-open-image-in-affinity-photo ()
"Open markdown image under cursor in Affinity Photo"
(interactive "@*")
;; Look for a Markdown image element before the cursor or immediately
;; after the cursor. Don't look any further than the start of the current
;; paragraph.
(let ((limit (save-excursion
(backward-paragraph)
(point)))
(regexp "\\s-*!\\[\\([^][]*\\)\\](\\([^()]*\\))?"))
(if (and (eq ?! (char-after (1- (point))))
(eq ?\[ (char-after (point))))
(backward-char))
(while (not (looking-at regexp))
(search-backward "![" limit))
;; If the search didn't error out, then we exited the loop with
;; `looking-at' matching `regexp'. The match data therefore contains
;; the parts of the image link.
(skip-syntax-forward "-")
(let ((img-path (match-string 2)))
(shell-command (format "open -a 'Affinity Photo' %s"
(replace-regexp-in-string "%20" "\\\\ " img-path))))))
(defun ig/md-open-image-in-finder ()
"Open a markdown image in Finder"
(interactive "@*")
;; Look for a Markdown image element before the cursor or immediately
;; after the cursor. Don't look any further than the start of the current
;; paragraph.
(let ((limit (save-excursion
(backward-paragraph)
(point)))
(regexp "\\s-*!\\[\\([^][]*\\)\\](\\([^()]*\\))?"))
(if (and (eq ?! (char-after (1- (point))))
(eq ?\[ (char-after (point))))
(backward-char))
(while (not (looking-at regexp))
(search-backward "![" limit))
;; If the search didn't error out, then we exited the loop with
;; `looking-at' matching `regexp'. The match data therefore contains
;; the parts of the image link.
(skip-syntax-forward "-")
(let ((img-path (match-string 2)))
(shell-command (format "open -R %s"
(replace-regexp-in-string "%20" "\\\\ " img-path))))))
(defun ig/md-rename-image ()
"Rename the file pointed by the link under point and update the link."
(interactive)
;; Look for a Markdown image element before the cursor or immediately
;; after the cursor. Don't look any further than the start of the current
;; paragraph.
(let ((limit (save-excursion
(backward-paragraph)
(point)))
(regexp "\\(!\\[[a-z s]*\\](\\)\\([./-a-z0-9]*[.png\|.jpg|.svg]\\)\\()\\)"))
(if (and (eq ?! (char-after (1- (point))))
(eq ?\[ (char-after (point))))
(backward-char))
(while (not (looking-at regexp))
(search-backward "![" limit))
(skip-syntax-forward "-")
(let* ((remove (list (match-beginning 0) (match-end 0)))
(desc (match-string 1))
(filepath (match-string 2))
(path (file-name-directory filepath))
(filename (file-name-nondirectory filepath))
(ext (file-name-extension filepath))
(prompt (read-string (format "New name (was '%s'): " filename)))
(namewithext (concat prompt "." ext))
(newfilename (string-replace " " "-" (downcase namewithext))))
;; Rename file
(rename-file (concat path filename) (concat path newfilename))
;; Update link
(unless (string-empty-p newfilename)
(apply #'delete-region remove)
(insert (concat desc path newfilename ")" ))))))
(defun ig/md-screenshot-from-clipboard ()
"Take image from clipboard and paste it
in the .media folder in the same folder as the current opened file"
(interactive)
(setq filename
(concat
(make-temp-name
(concat ".media/"
(format-time-string "%Y%m%d_%H%M%S_")) ) ".png"))
(unless (file-exists-p (file-name-directory filename))
(make-directory (file-name-directory filename)))
(if (eq system-type 'darwin)
(shell-command(concat "pngpaste " filename)))
(if (eq system-type 'gnu/linux)
(shell-command(concat "xclip -se c -t image/png -o > " filename)))
(if (file-exists-p filename)
(insert (concat "![](" filename ")"))))
(defun ig/md-surrond-images-with-blank-lines ()
"Surround markdown images with blank lines."
(interactive)
(beginning-of-buffer)
(while (re-search-forward "^!\\[")
(save-excursion
(end-of-line 0)
(open-line 1))
(end-of-line)
(open-line 1)))
The code bellow will look for a _images
folder in the current opened file folder.
Next it will generate file name Current Date
and Time
plus Unique name
and File format
e.g. 20201127_193108_UO9Jg4.png
(defun ig/screenshot-from-clipboard ()
"Take image from clipboard and paste it
in the _images folder in the same folder as the current opened file"
(interactive)
(setq filename
(concat
(make-temp-name
(concat "_images/"
(format-time-string "%Y%m%d_%H%M%S_")) ) ".png"))
(unless (file-exists-p (file-name-directory filename))
(make-directory (file-name-directory filename)))
(if (eq system-type 'darwin)
(shell-command(concat "pngpaste " filename)))
(if (eq system-type 'gnu/linux)
(shell-command(concat "xclip -se c -t image/png -o > " filename)))
(if (file-exists-p filename)
(insert (concat "[[file:" filename "]]"))))
This code is similar to the code above only it asks user to select a square area to capture
(defun ig/screenshot-manual ()
"Take image from clipboard and paste it
in the _images folder in the same folder as the current opened file"
(interactive)
(setq filename
(concat
(make-temp-name
(concat "_images/"
(format-time-string "%Y%m%d_%H%M%S_")) ) ".png"))
(unless (file-exists-p (file-name-directory filename))
(make-directory (file-name-directory filename)))
(lower-frame)
(if (eq system-type 'darwin)
(call-process "screencapture" nil nil nil "-i" filename))
(if (eq system-type 'gnu/linux)
(call-process "import" nil nil nil filename))
(raise-frame)
(if (file-exists-p filename)
(insert (concat "[[file:" filename "]]"))))
Select file from a disk and Insert it at the cursor position from drive.
(defun ig/insert-file-from-disk (&optional file)
"Select file from a disk and Insert it at the cursor position from drive.
Asks for file location and optionaly for a label"
(interactive "fSelect a file:")
(setq description (read-string "Enter file name:"))
(if (string-empty-p description)
(insert (concat "[[file:" file "]]"))
(insert (concat "[[file:" file "][" description "]]"))))
(defun ig/org-rename-link ()
"Rename the file pointed by the link under point and update the link."
(interactive)
(when (org-in-regexp org-link-bracket-re 1)
(let* ((remove (list (match-beginning 0) (match-end 0)))
(link (org-link-unescape (match-string-no-properties 1)))
(desc (when (match-end 2) (match-string-no-properties 2)))
(type (progn (string-match "\\`\\([^:]*:\\)?\\([^:]*\\)\\(::.*\\)?"
link)
(match-string 1 link)))
(filepath (match-string 2 link))
(search (match-string 3 link))
(filename (file-name-nondirectory filepath))
(ext (file-name-extension filepath))
(path (file-name-directory filepath))
(prompt (read-string (format "New name (was '%s'): " filename)))
(namewithext (concat prompt "." ext))
(newfilename (string-replace " " "-" (downcase namewithext))))
;; Rename file
(rename-file (concat path filename) (concat path newfilename))
;; Update link
(unless (string-empty-p newfilename)
(apply #'delete-region remove)
(insert (org-link-make-string (concat type path newfilename search) desc))))))