I can't get out from lisp, to pass to bash, in the same script...
#!/bin/bash
{
gimp -n -i -b - <<EOF
(let* ( (file's (cadr (file-glob "*.xcf" 1))) (filename "") (image 0) (number 0) (condition 0) (testo "") )
(while (pair? file's)
...
(gimp-quit 0)
)
EOF
}
echo $testo;
The value of testo in your gimp code will not be reflected in your shell's environment. To do that, you would need to print the value and capture the output.
The general way of doing that in shell is var=$(command) (this sets the value of var to the standard output from command).
Related
AFAIK, it should be possible. I know that convert of ImageMagick makes this task trivial, but I cannot use ImageMagick, therefore I am leaning towards Gimp (on Windows).
I have tried with this Guile script:
(define (resize-image filename new-filename scale)
(let* ((image (car (gimp-file-load RUN-NONINTERACTIVE filename filename)))
(drawable (car (gimp-image-get-active-layer image)))
(width (gimp-image-width image))
(height (gimp-image-height image)))
(gimp-image-scale-full image (* width scale) (* height scale) INTERPOLATION-CUBIC)
(gimp-file-save RUN-NONINTERACTIVE image drawable new-filename new-filename)
(gimp-image-delete image)))
that I run with:
gimp-2.8 -i -b "(resize-image \"image.jpg\" \"image-small.jpg\" 0.5)" -b "(gimp-quit 0)"
but I get this error:
(gimp-2.8:22244): LibGimpBase-WARNING **: gimp-2.8: gimp_wire_read(): error
(gimp-2.8:22244): LibGimpBase-WARNING **: gimp-2.8: gimp_wire_read(): error
batch command experienced an execution error:
Error: ( : 1) *: argument 1 must be: number
My solution has been inspired by this post:
http://warunapw.blogspot.it/2010/01/batch-resize-images-in-gimp.html
The shortest code to scale down an image:
image=pdb.gimp_file_load('/tmp/bigger.png','/tmp/bigger.png')
image.scale(int(image.width*.5),int(image.height*.5))
pdb.gimp_file_save(image, image.active_layer, '/tmp/smaller.png','/tmp/smaller.png')
So, you can still put everything in a one liner. In Linux, that gives (brace yourself):
gimp -idf --batch-interpreter python-fu-eval -b 'image=pdb.gimp_file_load("/tmp/bigger.png","/tmp/bigger.png");image.scale(int(image.width*.5),int(image.height*.5));pdb.gimp_file_save(image, image.active_layer, "/tmp/smaller.png","/tmp/smaller.png")' -b 'pdb.gimp_quit(1)'
IIRC, due to how to the Windows shell uses quotes, you have to use double quotes to delimit shell parameters so things are easier if you use single quotes around Python strings (untested):
gimp -idf --batch-interpreter python-fu-eval -b "image=pdb.gimp_file_load('/tmp/bigger.png','/tmp/bigger.png');image.scale(int(image.width*.5),int(image.height*.5));pdb.gimp_file_save(image, image.active_layer, '/tmp/smaller.png','/tmp/smaller.png')" -b "pdb.gimp_quit(1)"
However, there is significant overhead when starting Gimp (especially on WIndows), so if you need to process several files, you may be better off writing code that loops over files in a directory. This gets a bit bigger and may want to keep the code in a module. From my archives from a former life as a windows user:
Assume you have a batch.py file like this (you'll obviously have to improve the process() function, in particular pass parameters to it:
#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
import os,glob,sys,time
from gimpfu import *
def process(infile):
print "Processing file %s " % infile
image=pdb.gimp_file_load('/tmp/bigger.png','/tmp/bigger.png');
image.scale(int(image.width*.5),int(image.height*.5));
pdb.gimp_file_save(image, image.active_layer, '/tmp/smaller.png','/tmp/smaller.png')
pdb.gimp_image_delete(image)
def run(directory):
start=time.time()
print "Running on directory \"%s\"" % directory
for infile in glob.glob(os.path.join(directory, '*.jpg')):
process(infile)
end=time.time()
print "Finished, total processing time: %.2f seconds" % (end-start)
if __name__ == "__main__":
print "Running as __main__ with args: %s" % sys.argv
You would call it (in Windows) as:
gimp -idf --batch-interpreter python-fu-eval -b "import sys;sys.path=['.']+sys.path;import batch;batch.run('./images')" -b "pdb.gimp_quit(1)"
I have a file myfile which has some text like this:
self.Server('10.0.0.1', '00:00:00:00:00:01', 1)
self.Server('10.0.0.2', '00:00:00:00:00:01', 2)
I have written a shell script to write into myfile. The script has some variables defined:
hosts=100
servers=20
......
I want to modify the line self.Server('10.0.0.x', '00:00:00:00:00:0x', x) in myfile and write it as many times as the value of the variable servers, where x ranges from 1 to value of servers(20 in this case).
Note: myfile might already have some of the entries. For example if previous value of servers was 4 and new value is 6, only two entries need to be added. Also, if the previous value was 6 and the new value is 3, first 3 entries need to be removed.
Can someone please guide how can I achieve it?
Thanks.
#!/bin/bash
servers=20
for ((i=1; i<=servers; i++));; do
printf "%s%02d%s\n" "self.Server('10.0.0.$i', '00:00:00:00:00:" "$i" "', $i)" >> myfile
done
Run result:
self.Server('10.0.0.1', '00:00:00:00:00:01', 1)
self.Server('10.0.0.2', '00:00:00:00:00:02', 2)
self.Server('10.0.0.3', '00:00:00:00:00:03', 3)
self.Server('10.0.0.4', '00:00:00:00:00:04', 4)
self.Server('10.0.0.5', '00:00:00:00:00:05', 5)
self.Server('10.0.0.6', '00:00:00:00:00:06', 6)
self.Server('10.0.0.7', '00:00:00:00:00:07', 7)
self.Server('10.0.0.8', '00:00:00:00:00:08', 8)
self.Server('10.0.0.9', '00:00:00:00:00:09', 9)
self.Server('10.0.0.10', '00:00:00:00:00:10', 10)
self.Server('10.0.0.11', '00:00:00:00:00:11', 11)
self.Server('10.0.0.12', '00:00:00:00:00:12', 12)
self.Server('10.0.0.13', '00:00:00:00:00:13', 13)
self.Server('10.0.0.14', '00:00:00:00:00:14', 14)
self.Server('10.0.0.15', '00:00:00:00:00:15', 15)
self.Server('10.0.0.16', '00:00:00:00:00:16', 16)
self.Server('10.0.0.17', '00:00:00:00:00:17', 17)
self.Server('10.0.0.18', '00:00:00:00:00:18', 18)
self.Server('10.0.0.19', '00:00:00:00:00:19', 19)
self.Server('10.0.0.20', '00:00:00:00:00:20', 20)
The script would look like:
#!/bin/bash
hosts=100
servers=20
for ((x = 1; x < $servers + 1; x++))
do
temp=`printf "%02d" $x`
echo "self.Server('10.0.0.$x', '00:00:00:00:00:$temp', $x)" >> myfile
done
In emacs org-mode with iimage-mode enabled, it can show an inline image from a relative file path, like:
[[file:images/foo.jpg]]
What I want is: how can it shows an image locates in an zip archive, like this:
[[file:images.zip/foo.jpg]]
Is there a way to do this?
Rules for this to work:
If you have a zip file zippedimg.zip containing the image myimage.png, you should reference it in the org mode file as [[./zippedimg_zip/myimage.png]]. Note that I have replaced the . in zippedimg.zip to _.
The reason for doing so is that I am creating the same directory as mentioned within the [[ and ]]. But as the zippedimg.zip file exists, emacs does not allow creating a directory with the same name. So for zippedimg.zip file, I am extracting ONLY the image in it while preserving the path inside the zip into a zippedimg_zip directory.
Here is a mininum working org file to test it out:
#+TITLE: Image from archive
#+STARTUP: inlineimages
#+NAME: fig:myimage
#+HEADER: :extractfromarchive t
# The below caption line is optional
#+CAPTION: My image myimage.png inside ./zippedimg.zip
[[./zippedimg_zip/myimage.png]]
Here is the code you need to put somewhere in your emacs init:
;; Execute the `modi/org-include-img-from-archive' function just before saving the file
(add-hook 'before-save-hook #'modi/org-include-img-from-archive)
;; Execute the `modi/org-include-img-from-archive' function before processing the
;; file for export
(add-hook 'org-export-before-processing-hook #'modi/org-include-img-from-archive)
(defun modi/org-include-img-from-archive (&rest ignore)
"Extract image files from the archive files. Only .zip files are supported
as of now.
Only looks at #HEADER: lines that have \":extractfromarchive t\".
This function does nothing if not in org-mode, so you can safely
add it to `before-save-hook'."
(interactive)
(when (derived-mode-p 'org-mode)
(save-excursion
(goto-char (point-min)) ; go to the beginning of the buffer
(while (search-forward-regexp
"^\\s-*#\\+HEADER:.*\\s-:extractfromarchive\\s-+t"
nil :noerror)
(let (;; only .zip supported as of now
(search-expr "\\[\\[\\(.*?\\)_zip/\\(.*?\\)\\([^/]+\\..*\\)\\]\\]")
arc-file
path-in-arc-file
img-file img-file-full-path
dest-dir dest-dir-full-path
cmd)
;; Keep on going on to the next line till it finds a line with
;; `[[./path/to/zip-file/path/inside/zip/to/the/image]]'
(while (progn
(forward-line 1)
(or (not (looking-at search-expr))
(eobp))))
(when (looking-at search-expr)
(setq arc-file (expand-file-name
(concat (match-string-no-properties 1) ".zip")))
(setq path-in-arc-file (match-string-no-properties 2))
(setq img-file (match-string-no-properties 3))
(setq dest-dir (concat "./" (file-name-base arc-file)
"_zip/" path-in-arc-file))
(setq dest-dir-full-path (concat (file-name-sans-extension arc-file)
"_zip/" path-in-arc-file))
(setq img-file-full-path (expand-file-name img-file dest-dir))
;; (message (concat "arc-file: %s\npath-in-arc-file: %s\n"
;; "img-file: %s\nimg-file-full-path: %s\n"
;; "dest-dir: %s\ndest-dir-full-path: %s")
;; arc-file path-in-arc-file
;; img-file img-file-full-path
;; dest-dir dest-dir-full-path)
(when (file-newer-than-file-p arc-file img-file-full-path)
;; This block is executed only if arc-file is newer than
;; img-file-full-path
;; or if img-file does not exist
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Testing-Accessibility.html
(when (file-exists-p dest-dir-full-path)
(delete-directory dest-dir-full-path t t))
(make-directory dest-dir-full-path t)
(setq cmd (format "unzip -j %s %s%s -d ./%s."
arc-file path-in-arc-file img-file
(concat (file-name-base arc-file) "_zip/"
path-in-arc-file)))
(message "%s" cmd)
(shell-command cmd)
(shell-command (concat "touch " img-file-full-path)))))))))
thanks kaushalmodi,
below is what I did, by following the answer in this question how to display pdf images in org mode. As this is the first time I do lisp programming, the code maybe not well designed.
(add-hook 'org-mode-hook #'modi/org-include-img-from-zip)
(defun modi/org-include-img-from-zip (&rest ignore)
"extract images from zip an archive.
This function does nothing if not in org-mode."
(interactive)
(when (derived-mode-p 'org-mode)
(save-excursion
(goto-char (point-min))
(while (search-forward-regexp
"^\\s-*#\\+STARTUP:.*\\s-convertfromzip"
nil 'noerror)
(let* (filenoext imgext imgfile imgfilename zipfile imgpath cmd)
(setq zipfile "arc.zip")
;; Keep on going on to the next line till it finds a line with
;; `[[FILE]]'
(while (progn
(forward-line 1)
(not (looking-at "\\[\\[\\(.*\\)\\.\\(.*\\)\\]\\]"))))
(when (looking-at "\\[\\[file:\\(.*\\)\\.\\(.*\\)\\]\\]")
(setq filenoext (match-string-no-properties 1))
(setq imgext (match-string-no-properties 2))
(setq imgpath (concat filenoext "." imgext))
(setq imgfile (expand-file-name (concat filenoext "." imgext)))
(setq imgfilename (file-name-nondirectory imgfile))
(when (string= (substring imgpath 0 1) "~")
(setq imgpath (concat "%HOME%" (substring imgpath 1 nil)))
(setq imgpath (file-name-directory imgpath))
(setq cmd (concat "7z e " zipfile " -y -o"imgpath " " imgfilename " " imgfilename ))
(with-temp-buffer (shell-command cmd t))
)
))))))
I've got this function in my .bash_rc:
function ForwardSearchXdvi {
latex -src *.tex;
for i in *.dvi; do xdvi -sourceposition "$1 ${i/.dvi/.tex}" $i; done ;
}
it works... I call it by command line with the $1 argument (the target line number in my file.tex) and it's fine.
I'd like to run it directly from emacs so I made this command:
(defun ForwardXdviSearch ()
(interactive)
(shell-command (format "bash -ic %s" (shell-quote-argument "latex -src J[HCI]*.tex; for i in J[HCI]*.dvi; do xdvi -sourceposition \"$1 ${i/.dvi/.tex}\" $i; done ;")))
)
How can I pass the argument $1 to the function when I call it with "M-x Function" ?
You would need to use special form interactive for reading arguments. Something like this untested code:
(defun forward-xdvi-search (line-number)
(interactive "nForward to line: ")
(shell-command
(format "bash -ic %s"
(shell-quote-argument
(format "latex -src J[HCI]\*.tex; for i in J[HCI]\*.dvi; do xdvi -sourceposition \"%d ${i/.dvi/.tex}\" $i; done ;"
line-number)))))
Edited with the improvement suggested by #phils
I call git get the toplevel dir (according to
Is there a way to get the git root directory in one command?
).
(let ((tmpbuffer (get-buffer-create (make-temp-name "git"))))
(call-process "git" nil tmpbuffer nil "rev-parse" "--show-toplevel")
(with-current-buffer tmpbuffer
(with-output-to-string
(princ (buffer-string))
(kill-buffer))))
But there's a trailing newline in the string returned. I'm not sure how to get rid of it.
I think you can do
(replace-regexp-in-string "\n$" ""
(shell-command-to-string "git rev-parse --show-toplevel"))
If you only want to remove a newline at the very end of the output, use
(replace-regexp-in-string "\n\\'" ""
(shell-command-to-string "git rev-parse --show-toplevel"))
The accepted answer also replaces pairs of newlines ("\n\n") in the output by single newlines ("\n"), because $ matches at the end of the string or after a newline, while \\' only matches at the end of the string.
Assuming it is stored in a variable output-string, the final newline at the end can be removed this way:
(substring output-string 0 -1)
With the shell-command way, it would look like this:
(substring
(shell-command-to-string "git rev-parse --show-toplevel")
0 -1)
If You are OK with awesome external package.
use s-trim
ELISP> (shell-command-to-string "light -G")
"60.00\n"
ELISP> (s-trim (shell-command-to-string "light -G"))
"60.00"