How to create a layered PSD file from command line? - command-line

I need to create a layered PSD file with ImageMagick or any other command-line tool available on Linux platform. Since I need to do this on Linux server, I can't use Photoshop scripting.
The ImageMagick command below creates PSD file with a single layer, where two images (here: plasma fractals) are positioned one below another. (I use ImageMagick 6.5.3-10 2009-07-31 Q16, latest available in MacPorts.)
convert -size 100x100 plasma:fractal plasma:fractal -append out.psd
How do I create a PSD file where each image is in its own layer, and one layer is directly above another?
Or, is there any other command line tool that would allow me to do this?
Update: Any other options than GIMP command line?

If ImageMagick won't work, I'd look at Gimp command line.
The following commands created a 2-layer PSD file for me in the interactive console:
> (gimp-image-new 200 200 0)
(1)
> (gimp-layer-new 1 200 200 0 "layer-1" 100 0)
(2)
> (gimp-layer-new 1 200 200 0 "layer-2" 100 0)
(3)
> (file-psd-save 0 1 0 "test.psd" "test.psd" 0 0)
> (gimp-image-add-layer 1 2 -1)
> (gimp-image-add-layer 1 3 -1)
> (file-psd-save 0 1 1 "test.psd" "test.psd" 0 0)
That would need to be converted into a script-fu script (.scm file) and could be executed from the command-line with something like this:
gimp -i -b '(your-script-name "test.psd" 200 200)' -b '(gimp-quit 0)'

I use the command lines below. I have not encountered any issue in opening the generated PSD in Photoshop, however every layer appears as a background layer, and you have to convert it into a true layer first in order to edit the layer ordering.
Here is the command line for Window. Given the list of images (im1.xxx, im2.xxx etc, im1 being the bottom layer,) a list of labels for the layers ("label1", "label2"...) :
convert ^
( ^
-page +0+0 ^
-label "label1" ^
im1.xxx[0] ^
-background none ^
-mosaic ^
-set colorspace RGB ^
) ^
( ^
-page +0+0 ^
-label "label2" ^
"im2.xxx"[0] ^
-background none ^
-mosaic ^
-set colorspace RGB ^
) ^
( ^
-clone 0--1 ^
-background none ^
-mosaic ^
) ^
-alpha Off ^
-reverse ^
"out.psd"
That is, for each layer, you have something like
( ^
-page +0+0 ^
-label "optional_label" ^
im1.xxx[0] ^
-background none ^
-mosaic ^
-set colorspace RGB ^
)
The label/name of the layer is optional (remove -label if none.) The [0] in im1.xxx[0] retrieves the first image in the image file, in case there exist a thumbnail in the Exif.
On Unix/OSX, you have to protect the parenthesis by a backslash, and the line continuation characters change also to \:
\( \
-page +0+0 \
-label "optional_label" \
im1.xxx[0] \
-background none \
-mosaic \
-set colorspace RGB \
\)
If the image names contain special chars, you can protect them with " (eg "c:\my im1.png") without any issue.

You can use the -adjoin to combine an image sequence.
convert -size 100x100 \
-alpha set plasma:fractal \
-alpha set plasma:fractal \
-adjoin \
out.psd
The alpha channels are needed for the PSD coder.
The order of the images is bottom layer to top layer.
There are a lot of compatibility issues with Photoshop and GIMP depending on the settings.
Using:
ImageMagick 6.5.4-6
Photoshop CS2

Here is some useful links to you:
ImageMagick and PSD images with layers
Some PSD Useful Notes
Psd Layers - ImageMagick Forums
The second link is to use with PHP, but it executes ImageMagick, only use the commands, not the all PHP syntax, only the line of exec code.
Hope i'm helping you!

I agree with Jon Galloway, the Gimp console is a better choice. Here is my script:
(define (pngtopsd width height png-paths psd-path)
(define (add-layers image png-paths)
(if (null? png-paths) 0
(let*
((png (car png-paths))
(new-layer (car (gimp-file-load-layer 0 image (car png)))))
(gimp-image-insert-layer image new-layer 0 -1)
(gimp-item-transform-2d new-layer 0 0 1 1 (cadr png) (caddr png) (cadddr png))
(add-layers image (cdr png-paths))
)
))
(let*
((png (car png-paths))
(image (car (gimp-file-load 1 (car png) (car png))))
(drawable (car (gimp-image-get-active-layer image))))
(gimp-image-resize image width height 0 0)
(gimp-item-transform-2d drawable 0 0 1 1 (cadr png) (caddr png) (cadddr png))
(add-layers image (cdr png-paths))
(file-psd-save 0 image drawable psd-path psd-path 1 0)
(gimp-image-delete image)
))
You just need put this script into file with name "pngtopsd.scm" inside your gimp "script" directory ("c:\Program Files\GIMP 2\share\gimp\2.0\scripts\" for Windows) and you can create layered PSD from list of PNG pictures with transformation (translation or rotation) of each layer. Usage sample:
gimp-console-2.8.exe -i -b ^
"(pngtopsd (list ^
(list \"c:/../1.png\" 0 500 500) ^
(list \"c:/.../2.png\" 0.7 200 1000) ^
(list \"c:/.../3.jpg\" -0.5 1000 0)) ^
\"c:/.../result.psd\")"
There (list \"c:/.../2.png\" 0.7 200 1000) means:
0.7 is the rotation angle of picture (in radians)
200 1000 is x and y shift on an image

You can create a layered PSD with ImageMagick, but note the first image is actually used as the preview image (i.e. composite of all the layers).
convert -size 100x100 plasma:fractal plasma:fractal plasma:fractal out.psd
Will create a 2 layered PSD.

Related

ImageMagick command not running in Powershell window but can run in cmd window

This command is to add a watermark to an image
magick nature.jpg -set option:watermarkWidth "%[fx:int(w*0.25)]" -alpha set -background none ( -fill "#FFFFFF80" -stroke "#FF000080" -strokeWidth 3 -undercolor "#FF000080" -size "%[watermarkWidth]x" label:"THIS IS WATERMARK" -gravity center -geometry +10+10 -rotate -30 ) -composite -quality 40 nature_wm.jpg
it can be run on Windows cmd window
But it cannot be run in Powershell window(see the error screenshot)
I also tried to add \ before ( and ) (which should do on macOS or Linux)
magick nature.jpg -set option:watermarkWidth "%[fx:int(w*0.25)]" -alpha set -background none \( -fill "#FFFFFF80" -stroke "#FF000080" -strokeWidth 3 -undercolor "#FF000080" -size "%[watermarkWidth]x" label:"THIS IS WATERMARK" -gravity center -geometry +10+10 -rotate -30 \) -composite -quality 40 nature_wm.jpg
But it throws the same error
error translation: -fill: -fill can not be recognized as cmdlet, function, script file or runnable program. Please check the spelling of the name, and if you include a path, make sure the path is correct, then try again.
I'm sure that the magick directive is in the environment variable
It seems that Powershell can run simple command but not complex command(the following command can be run, no error)
magick nature.jpg -fill yellow nature.png
Anyone who knows how to solve this problem?
Actually I need to run it with golang, by using cmd = exec.Command("cmd", "/k", cmdStr), but it doesn't work if the "cmdStr" cannot be run in Powershell, because the executable the I build with golang need to run on Powershell too(I don't want to run on cmd window, because it's so primitive compared to Powershell).
On quotes and quoting and escapes and escaping ImageMagick commands in bash, CMD32 and Powershell
As a result of its sheer versatility and power, ImageMagick offers a far richer palette of options, switches and parameters than most command-line programs (around 300 options and switches are listed here) and it uses characters and symbols to allow users to express things in a very natural way. As a result, some degree of caution is required when using ImageMagick in the many environments in which it can run, namely:
under bash or other Unix/Linux shells such as zsh, ksh, tcsh,
under Windows CMD32 and in Windows BATCH files,
under Powershell
under things like MinGW, MSYS, Cygwin
For example, in and of itself, disregarding the shell, ImageMagick understands the following:
# or hash, a.k.a. pound sign is used to express hexadecimal colours, in a natural way, like -fill #ff0000 for a red fill colour. However, bash interprets that same character as introducing a comment, so in bash you would normally write -fill '#ff0000'
() or parentheses. ImageMagick uses parentheses to apply processing to a specific image in its stack, also called "aside processing". So, this command loads two images and resizes both magick IMAGE1.PNG IMAGE2.PNG -resize 800x600 ... but if you want to resize only the second, you would do magick IMAGE1.PNG ( IMAGE2.PNG -resize 800x600 ) ... However, bash uses parentheses for sub-processes, so it will think you want to run a sub-process called IMAGE2.PNG unless you escape the parentheses with magick IMAGE1.PNG \( IMAGE2.PNG -resize 800x600 \) .... Likewise, Powershell will object to the parentheses, and you must put a backtick before opening and closing parentheses. CMD32 doesn't treat parentheses as special at all, so they need no escaping in that environment.
() or parentheses. ImageMagick uses these to introduce hex or hsl colours, e.g. -fill RGBA(255,0,0) or -fill hsl(50,60,70). Again, bash will dislike that, thinking you want a sub-shell, so folks write -fill "rgb(255,0,0)". I assume Powershell will not like it either.
% or percent. ImageMagick commonly uses that, and similar, to resize an image to 50% of its original size -resize 50%. But, if you use percent signs in a Windows BATCH file, you need to double them up else it thinks you are referring to its command-line parameters.
< and >, or less than and greater than. ImageMagick uses > to mean you only want a resize applied to images greater than a certain size, e.g. -resize 800> which means you only want images larger than 800 scaled down to 800, but you don't want images under 800 scaled up. Likewise with <. However, bash uses those characters for redirection of input and output, so in bash you would normally write -resize '800>' Likewise in CMD32, you will need to escape both < and > by preceding with a caret ^. And precede with backticks in Powershell.
! or exclamation mark, a.k.a. "bang". ImageMagick uses that to mean "Just do it!". So, for example, -resize 800x600 says you want to resize such that the width doesn't exceed 800 and the height doesn't exceed 600 and the aspect ratio should be respected. However, when you add the bang like this -resize 800x600! you will get exactly 800x600 pixels even if that distorts your image horribly. The shell can interpret the exclamation as introducing some manipulation of its history of previous commands, so you will often see that escaped
[ and ], or square brackets. ImageMagick uses these to refer to a page or subset of pages in a multipage document such as a PDF or a TIFF. For example, the following means the first and last page of a PDF, magick DOCUMENT.PDF[0,-1] ... That can get confused with shell syntax for an alternation if you don't handle it with care
* or asterisk. ImageMagick understands the asterisk as a globbing character to expand the list of all matching files, e.g. *.tif meaning all the TIFF files in the current directory. That is the same as bash, but there are nuances here. If you use magick *.tif ..., the list of TIFFs will be expanded by your shell in bash and that will be subject to your system's ARGMAX. But if you do magick '*.TIF' ... it will be expanded internally by ImageMagick and not be subject to such limits.
General hints for bash and Unix/Linux shells
The line continuation character is the backslash
Opening and closing parentheses must be escaped with backslashes immediately in front of them
Hashes must be within double or single quoted strings
Example of bash command
magick IMAGE1.PNG \
\( IMAGE2.PNG -resize 50% -fill '#ff0000' -colorize 100% \) \
-composite -transparent 'hsl(40,50,60)' result.png
General hints for Windows CMD32
the caret ^ is used as the escape character
CMD32 generally dislikes any usage of single quotes.
Generally, if translating from a bash incantation of ImageMagick, try replacing single quotes with double quotes. The exception to this is when already inside double quotes, where you can use single quotes, e.g. -draw "text 100,100 'Works like magick'"
the caret is used as the line continuation character and may not be followed by any spaces when used that way
percent signs must be doubled up in BATCH
parentheses do not require escaping
Example of Windows CMD32 BATCH command
magick IMAGE1.PNG ^
( IMAGE2.PNG -resize 50%% -fill "#ff0000" -colorize 100% ) ^
-composite -transparent "hsl(40,50,60)" result.png
General hints for Powershell
the backtick is used as the escape character, and the line continuation character
opening and closing parentheses must be escaped with a preceding backtick
Example of Powershell command
magick IMAGE1.PNG `
`( IMAGE2.PNG -resize 50% -fill "#ff0000" -colorize 100% `) `
-composite -transparent "hsl(40,50,60)" result.png
When testing EXE files in PowerShell, EchoArgs.exe is a very useful tool to have on hand. The original source for this tool appears to have disappeared, but you can still download it from ss64.com on this page.
When dealing with complex command lines for EXE files, Stop-parsing token (--%) is a very useful special parsing token to keep in mind.
In the command line execute EchoArgs with your parameters:
EchoArgs nature.jpg -set option:watermarkWidth "%[fx:int(w*0.25)]" -alpha set -background none ( -fill "#FFFFFF80" -stroke "#FF000080" -strokeWidth 3 -undercolor "#FF000080" -size "%[watermarkWidth]x" label:"THIS IS WATERMARK" -gravity center -geometry +10+10 -rotate -30 ) -composite -quality 40 nature_wm.jpg
Record your results:
Arg 0 is <nature.jpg>
Arg 1 is <-set>
Arg 2 is <option:watermarkWidth>
Arg 3 is <%[fx:int(w*0.25)]>
Arg 4 is <-alpha>
Arg 5 is <set>
Arg 6 is <-background>
Arg 7 is <none>
Arg 8 is <(>
Arg 9 is <-fill>
Arg 10 is <#FFFFFF80>
Arg 11 is <-stroke>
Arg 12 is <#FF000080>
Arg 13 is <-strokeWidth>
Arg 14 is <3>
Arg 15 is <-undercolor>
Arg 16 is <#FF000080>
Arg 17 is <-size>
Arg 18 is <%[watermarkWidth]x>
Arg 19 is <label:THIS IS WATERMARK>
Arg 20 is <-gravity>
Arg 21 is <center>
Arg 22 is <-geometry>
Arg 23 is <+10+10>
Arg 24 is <-rotate>
Arg 25 is <-30>
Arg 26 is <)>
Arg 27 is <-composite>
Arg 28 is <-quality>
Arg 29 is <40>
Arg 30 is <nature_wm.jpg>
To avoid problem, use --% in PowerShell at the point where the command line becomes complex:
EchoArgs nature.jpg -set option:watermarkWidth --% "%[fx:int(w*0.25)]" -alpha set -background none ( -fill "#FFFFFF80" -stroke "#FF000080" -strokeWidth 3 -undercolor "#FF000080" -size "%[watermarkWidth]x" label:"THIS IS WATERMARK" -gravity center -geometry +10+10 -rotate -30 ) -composite -quality 40 nature_wm.jpg
Check your results:
Arg 0 is <nature.jpg>
Arg 1 is <-set>
Arg 2 is <option:watermarkWidth>
Arg 3 is <%[fx:int(w*0.25)]>
Arg 4 is <-alpha>
Arg 5 is <set>
Arg 6 is <-background>
Arg 7 is <none>
Arg 8 is <(>
Arg 9 is <-fill>
Arg 10 is <#FFFFFF80>
Arg 11 is <-stroke>
Arg 12 is <#FF000080>
Arg 13 is <-strokeWidth>
Arg 14 is <3>
Arg 15 is <-undercolor>
Arg 16 is <#FF000080>
Arg 17 is <-size>
Arg 18 is <%[watermarkWidth]x>
Arg 19 is <label:THIS IS WATERMARK>
Arg 20 is <-gravity>
Arg 21 is <center>
Arg 22 is <-geometry>
Arg 23 is <+10+10>
Arg 24 is <-rotate>
Arg 25 is <-30>
Arg 26 is <)>
Arg 27 is <-composite>
Arg 28 is <-quality>
Arg 29 is <40>
Arg 30 is <nature_wm.jpg>
But what if you need to dynamically replace part of the parameters after the the Stop-parsing token (--%)? That is doable via environmental variables:
$Env:FirstValue = '%[fx:int(w*0.25)]'
$Env:Alpha = 'set'
$Env:Background = 'none'
$Env:Fill = '#FFFFFF80'
$Env:Stroke = '#FF000080'
$Env:StrokeWidth = '3'
$Env:Undercolor = '#FF000080'
$Env:Size = '%[watermarkWidth]x'
$Env:Label = 'THIS IS WATERMARK'
$Env:Gravity = 'center'
$Env:Geometry = '+10+10'
$Env:Rotate = '-30'
$Env:Quality = '40'
$Env:ImgName = 'nature_wm.jpg'
EchoArgs nature.jpg -set option:watermarkWidth --% "%FirstValue%" -alpha %Alpha% -background %Background% ( -fill "%Fill%" -stroke "%Stroke%" -strokeWidth %StrokeWidth% -undercolor "%Undercolor%" -size "%[watermarkWidth]x" label:"%Label%" -gravity %Gravity% -geometry %Geometry% -rotate %Rotate% ) -composite -quality %Quality% %ImgName%
Again, check your results:
Arg 0 is <nature.jpg>
Arg 1 is <-set>
Arg 2 is <option:watermarkWidth>
Arg 3 is <%[fx:int(w*0.25)]>
Arg 4 is <-alpha>
Arg 5 is <set>
Arg 6 is <-background>
Arg 7 is <none>
Arg 8 is <(>
Arg 9 is <-fill>
Arg 10 is <#FFFFFF80>
Arg 11 is <-stroke>
Arg 12 is <#FF000080>
Arg 13 is <-strokeWidth>
Arg 14 is <3>
Arg 15 is <-undercolor>
Arg 16 is <#FF000080>
Arg 17 is <-size>
Arg 18 is <%[watermarkWidth]x>
Arg 19 is <label:THIS IS WATERMARK>
Arg 20 is <-gravity>
Arg 21 is <center>
Arg 22 is <-geometry>
Arg 23 is <+10+10>
Arg 24 is <-rotate>
Arg 25 is <-30>
Arg 26 is <)>
Arg 27 is <-composite>
Arg 28 is <-quality>
Arg 29 is <40>
Arg 30 is <nature_wm.jpg>
But what if you don't know where the EXE is and have to search for it on the hard drive and call it from a variable? Use The call operator (&):
$Program = 'C:\Program Files\ImageMagick-7.0.11-Q16-HDRI\magick.exe'
$Env:FirstValue = '%[fx:int(w*0.25)]'
$Env:Alpha = 'set'
$Env:Background = 'none'
$Env:Fill = '#FFFFFF80'
$Env:Stroke = '#FF000080'
$Env:StrokeWidth = '3'
$Env:Undercolor = '#FF000080'
$Env:Size = '%[watermarkWidth]x'
$Env:Label = 'THIS IS WATERMARK'
$Env:Gravity = 'center'
$Env:Geometry = '+10+10'
$Env:Rotate = '-30'
$Env:Quality = '40'
$Env:ImgName = 'nature_wm.jpg'
& $Program nature.jpg -set option:watermarkWidth --% "%FirstValue%" -alpha %Alpha% -background %Background% ( -fill "%Fill%" -stroke "%Stroke%" -strokeWidth %StrokeWidth% -undercolor "%Undercolor%" -size "%[watermarkWidth]x" label:"%Label%" -gravity %Gravity% -geometry %Geometry% -rotate %Rotate% ) -composite -quality %Quality% %ImgName%
Now, having said all that, the real test is to actually execute the command and see if it works. I don't have your image file and not really up to doing any experiments with Image Magick. But, in theory, this command should work work for you:
magick nature.jpg -set option:watermarkWidth --% "%[fx:int(w*0.25)]" -alpha set -background none ( -fill "#FFFFFF80" -stroke "#FF000080" -strokeWidth 3 -undercolor "#FF000080" -size "%[watermarkWidth]x" label:"THIS IS WATERMARK" -gravity center -geometry +10+10 -rotate -30 ) -composite -quality 40 nature_wm.jpg
EDIT:
If you ware wanting MagicK to run in GoLang, use the following code:
package main
import (
"fmt"
"os/exec"
)
func main() {
data, err := exec.Command("magick", "nature.jpg", "-set", "option:watermarkWidth", "%[fx:int(w*0.25)]", "-alpha", "set", "-background", "none", "(", "-fill", "#FFFFFF80", "-stroke", "#FF000080", "-strokeWidth", "3", "-undercolor", "#FF000080", "-size", "%[watermarkWidth]x", "label:THIS IS WATERMARK", "-gravity", "center", "-geometry", "+10+10", "-rotate", "-30", ")", "-composite", "-quality", "40", "nature_wm.jpg").Output()
if err != nil {
panic(err)
}
fmt.Println(string(data))
}

Ghostscript -- convert PS to PNG, rotate, and scale

I have an application that creates very nice data plots rendered in PostScript with letter size and landscape mode. An example of the input file is at http://febo.com/uploads/blip.ps. [ Note: this image renders properly in a viewer, but the PNG conversion comes out with the image sideways. ] I need to convert these PostScript files into PNG images that are scaled down and rotated 90 degrees for web presentation.
I want to do this with ghostscript and no other external tool, because the conversion program will be used on both Windows and Linux systems and gs seems to be a common denominator. (I'm creating a perl script with a "PS2png" function that will call gs, but I don't think that's relevant to the question.)
I've searched the web and spent a couple of days trying to modify examples I've found, but nothing I have tried does the combination of (a) rotate, (b) resize, (c) maintain the aspect ratio and (d) avoid clipping.
I did find an example that injects a "scale" command into the postscript stream, and that seems to work well to scale the image to the desired size while maintaining the aspect ratio. But I can't find a way to rotate the resized image so that the, e.g., 601 x 792 point (2504 x 3300 pixel) postscript input becomes an 800 x 608 pixel png output.
I'm looking for the ghostscript/postscript fu that I can pass to the gs command line to accomplish this.
I've tried gs command lines with various combinations of -dFIXEDMEDIA, -dFitPage, -dAutoRotatePages=/None, or /All, -c "<> setpagedevice", changing -dDISPLAYWIDTHPOINTS and -dDISPLAYHEIGHTPOINTS, -g[width]x[height], -dUseCropBox with rotated coordinates, and other things I've forgotten. None of those worked, though it wouldn't surprise me if there's a magic combination of some of them that will. I just haven't been able to find it.
Here is the core code that produces the scaled but not rotated output:
## "$molps" is the input ps file read to a variable
## insert the PS "scale" command
$molps = $sf . " " . $sf . " scale\n" . $molps;
$gsopt1 = " -r300 -dGraphicsAlphaBits=4 -dTextAlphaBits=4";
$gsopt1 = $gsopt1 . " -dDEVICEWIDTHPOINTS=$device_width_points";
$gsopt1 = $gsopt1 . " -dDEVICEHEIGHTPOINTS=$device_height_points";
$gsopt1 = $gsopt1 . " -sOutputFile=" . $outfile;
$gscmd = "gs -q -sDEVICE=pnggray -dNOPAUSE -dBATCH " . $gsopt1 . " - ";
system("echo \"$molps\" \| $gscmd");
$device_width_points and $device_height_points are calculated by taking the original image size and applying the scaling factor $sf.
I'll be grateful to anyone who can show me the way to accomplish this. Thanks!
Better Answer:
You almost had it with your initial research. Just set orientation in the gs call:
... | gs ... -dAutoRotatePages=/None -c '<</Orientation 3>> setpagedevice' ...
cf. discussion of setpagedevice in the Red Book, and ghostscript docs (just before section 6.2)
Original Answer:
As well as "scale", you need "rotate" and "translate", not necessarily in that order.
Presumably these are single-page PostScript files?
If you know the bounding box of the Postscript, and the dimensions of the png, it is not too arduous to calculate the necessary transformation. It'll be about one line of code. You just need to ensure you inject it in the correct place.
Chapter 6 of the Blue Book has lots of details
A ubc.ca paper provides some illustrated examples (skip to page 4)
Simple PostScript file to play around with. You'll just need the three translate,scale,rotate commands in some order. The rest is for demonstrating what's going on.
%!
% function to define a 400x400 box outline, origin at 0,0 (bottom left)
/box { 0 0 moveto 0 400 lineto 400 400 lineto 400 0 lineto closepath } def
box clip % pretend the box is our bounding box
clippath stroke % draw initial black bounding box
(Helvetica) findfont 50 scalefont setfont % setup a font
% draw box, and show some text # 100,100
box stroke
100 100 moveto (original) show
% try out some transforms
1 0 0 setrgbcolor % red
.5 .5 scale
box stroke
100 100 moveto (+scaled) show
0 1 0 setrgbcolor % green
300 100 translate
box stroke
100 100 moveto (+translated) show
0 0 1 setrgbcolor % blue
45 rotate
box stroke
100 100 moveto (+rotated) show
showpage
It may be possible to insert the calculated transformation into the gs commandline like this:
... | gs ... -c '1 2 scale 3 4 translate 5 6 rotate' -# ...
Thanks to JHNC, I think I have it licked now, and for the benefit of posterity, here's what worked. (Please upvote JHNC, not this answer.)
## code to determine original size, scaling factor, rotation goes above
my $device_width_points;
my $device_height_points;
my $orientation;
if ($rotation) {
$orientation = 3;
$device_width_points = $ytotal_png_pt;
$device_height_points = $xtotal_png_pt;
} else {
$orientation = 0;
$device_width_points = $xtotal_png_pt;
$device_height_points = $ytotal_png_pt;
}
my $orientation_string =
" -dAutoRotatePages=/None -c '<</Orientation " .
$orientation . ">> setpagedevice'";
## $ps = .ps file read into variable
## insert the PS "scale" command
$ps = $sf . " " . $sf . " scale\n" . $ps;
$gsopt1 = " -r300 -dGraphicsAlphaBits=4 -dTextAlphaBits=4";
$gsopt1 = $gsopt1 . " -dDEVICEWIDTHPOINTS=$device_width_points";
$gsopt1 = $gsopt1 . " -dDEVICEHEIGHTPOINTS=$device_height_points";
$gsopt1 = $gsopt1 . " -sOutputFile=" . $outfile;
$gsopt1 = $gsopt1 . $orientation_string;
$gscmd = "gs -q -sDEVICE=pnggray -dNOPAUSE -dBATCH " . $gsopt1 . " - ";
system("echo \"$ps\" \| $gscmd");
One of the problems I had was that some options apparently don't play well together -- for example, I tried using the -g option to set the output size in pixels, but in that case the rotation didn't work. Using the DEVICE...POINTS commands instead did work.

ImageMagick using alpha channel to control calculating min, max and mean image values

ImageMagick command identify prints to screen the min, max and mean values of all the pixels in an image - e.g. for an RGB TIF image we can see the mean thus:
identify -verbose -quiet image.tif | grep mean
which lists (for Red Green Blue and Gray):
mean: 122.974 (0.48225)
mean: 107.722 (0.422438)
mean: 84.1278 (0.329913)
mean: 104.941 (0.411534)
Q: if my image has a boolean alpha channel can I use it to limit the calculations to include only those pixels where alpha was set to 1?
I tried using the clip-mask option with either leading - or + but the means didn't change as would be expected.
In ImageMagick, the -scale 1x1! function can be used to compute the mean without including alpha so that you get the mean of only opaque values. So you could do the following:
Create test transparent image:
convert logo: -transparent white logot.png
Compute mean values:
convert logot.png -scale 1x1! -alpha off -format "%[fx:255*u.r], %[fx:255*u.g], %[fx:255*u.b]" info:
100.202, 81.4747, 98.6342
Alternately, you can use the alpha channel as a mask to get the means. You compute the mean of each channel without the alpha channel and the background under the alpha set to black. Then compute the mean of the alpha channel. Then divide each channel mean by the mean of the alpha channel.
convert logo: -transparent white logot.png
convert logot.png -alpha extract alpha.png
means_rgb=$(convert logot.png -background black -alpha background -alpha off -format "%[fx:mean.r],%[fx:mean.g],%[fx:mean.b]" info:)
mean_r=$(echo $means_rgb | cut -d, -f1)
mean_g=$(echo $means_rgb | cut -d, -f2)
mean_b=$(echo $means_rgb | cut -d, -f3)
mean_alpha=$(convert alpha.png -format "%[fx:mean]" info:)
mean_r=$(convert xc: -format "%[fx:255*$mean_r/$mean_alpha]" info:)
mean_g=$(convert xc: -format "%[fx:255*$mean_g/$mean_alpha]" info:)
mean_b=$(convert xc: -format "%[fx:255*$mean_b/$mean_alpha]" info:)
echo "$mean_r, $mean_g, $mean_b"
100.203, 81.4768, 98.6362
To get the min and max, taking the cue from Mark Setchell's idea:
convert logot.png -background black -alpha background -alpha off -format "%[fx:255*maxima.r], %[fx:255*maxima.g], %[fx:255*maxima.b]\n" info:
255, 250, 244
convert logot.png -background white -alpha background -alpha off -format "%[fx:255*minima.r], %[fx:255*minima.g], %[fx:255*minima.b]\n" info:
4, 0, 0

Image with 15 distinct colors, how to save into 15 distinct files by color?

I have a PNG image with 15 distinct colors, you could say just N distinct colors. Is there a command line application which can split this into 15 distinct files each by color and each only retaining that color?
I looked at g'mic and I think maybe gmic file.png -compose_channels
might be the right direction, but it doesn't give me what I want.
You would need to create an image mask for each isolated color, then composite the mask between the original image & (assuming) a grayscale image.
for color in `convert logo: -colors 15 -format %c histogram:info:- | cut -b 28-33`
do
convert logo: -colors 15 -matte \
\( -clone 0 -colorspace gray \) \
\( -clone 0 -fuzz 10% -transparent "#$color" -alpha extract \) \
-composite out_$color.png
done
Command-line Break Down
The convert logo: -colors 15 -format %c histogram:info:- command prints what the 15 colors would be. Example:
9221: ( 9, 11, 12) #090B0C srgb(9,11,12)
5692: ( 34, 38,101) #222665 srgb(34,38,101)
13936: ( 34, 61,145) #223D91 srgb(34,61,145)
661: ( 63, 85,135) #3F5587 srgb(63,85,135)
1595: ( 85, 86, 87) #555657 srgb(85,86,87)
1107: ( 94, 57, 34) #5E3922 srgb(94,57,34)
972: (121,130,118) #798276 srgb(121,130,118)
3264: (155,156,159) #9B9C9F srgb(155,156,159)
596: (199,176, 70) #C7B046 srgb(199,176,70)
1381: (209, 98, 69) #D16245 srgb(209,98,69)
2348: (215,189,184) #D7BDB8 srgb(215,189,184)
2502: (244,229, 50) #F4E532 srgb(244,229,50)
2419: (244,150,101) #F49665 srgb(244,150,101)
3494: (252, 6, 6) #FC0606 srgb(252,6,6)
258012: (255,255,255) #FFFFFF srgb(255,255,255)
The cut -b 28-33 isolates the hex-color column. With an isolated color, ( -clone 0 -colorspace gray) will copy the original image, and convert to black & white (replace this if B/W is not desired.) Finally, ( -clone 0 -fuzz 10% -transparent "#$color" -alpha extract ) cherry-picks the isolated color, and generates a mask.
Edit
If you don't want any of the "other" colors, then apply -compose CopyOpacity for each isolated color.
for color in `convert logo: -colors 15 -format %c histogram:info:- | cut -b 28-33`
do
convert logo: -colors 15 -matte \
\( -clone 0 -fuzz 10% -transparent "#$color" -alpha extract -negate \) \
-compose CopyOpacity -composite out_$color.png
done
Edit 2
As Kurt Pfeifle point out, and in his answer, an existing image with 15 distinct colors can be simplified.
for color in "221F20" "434345" "4965A2" "4B92BF" "552D2A" "625E5A" "6F9563" "966963" "988E72" "A7A199" "AC3939" "C9B4A7" "C9C9B5" "DFC255" "E6E6E2"
do
convert http://i.stack.imgur.com/Xots0.png -matte \
\( -clone 0 -fuzz 10% -transparent "#$color" -alpha extract -negate \) \
-compose CopyOpacity -composite out_$color.png
done
A montage of outputted files would look like...
Since you did not post a sample picture, I'll have to create one for the purpose of demo-ing my procedure for this task.
The base picture is the following. It still has more than 15 colors, of course. It was published on Flickr by atramos under a CreativeCommons license here.
I used the following command to convert it to a PNG using only 15 colors:
convert 6819541499_aa4b1dc049_o_d.jpg -colors 15 15c.png
The resulting image has only 230 kBytes:
Now that we have a PNG with 15 colors, let's look at a potential procedure to extract 15 images which contain only the pixels with one of these unique colors, rendering the other pixels transparent.
Verify that there are really only 15 colors.
Identify the 15 color values.
Identify for each color 1 pixel using exactly that color.
Create an image that contains all pixels with identical colors as the one from step 3.
Verify that there are really only 15 colors
Here is a command that lists the number of unique colors used in an image:
identify -format "%k\n" 15c.png
Running it, confirms that we have 15 colors only:
15
Identify the 15 color values
Here is a command that lists all of these colors by color value:
convert 15c.png -format "%c" histogram:info:-
The result is this table. The left-most column gives the number of pixel using the color specified in the other columns (where each column displays a different syntax for specifying the color):
29035: ( 34, 31, 32) #221F20 srgb(34,31,32)
12056: ( 67, 67, 69) #434345 srgb(67,67,69)
4425: ( 73,101,162) #4965A2 srgb(73,101,162)
2376: ( 75,146,191) #4B92BF srgb(75,146,191)
6607: ( 85, 45, 42) #552D2A srgb(85,45,42)
8306: ( 98, 94, 90) #625E5A srgb(98,94,90)
3923: (111,149, 99) #6F9563 srgb(111,149,99)
4212: (150,105, 99) #966963 srgb(150,105,99)
4692: (152,142,114) #988E72 srgb(152,142,114)
9836: (167,161,153) #A7A199 srgb(167,161,153)
8832: (172, 57, 57) #AC3939 srgb(172,57,57)
6471: (201,180,167) #C9B4A7 srgb(201,180,167)
7080: (201,201,181) #C9C9B5 srgb(201,201,181)
4614: (223,194, 85) #DFC255 srgb(223,194,85)
14895: (230,230,226) #E6E6E2 srgb(230,230,226)
To produce a list containing only the #xxyyzz syntax, I run:
convert 15c.png -format "%c" histogram:info:- | cut -c 28-34
which gives me this list:
221F20
434345
4965A2
4B92BF
552D2A
625E5A
6F9563
966963
988E72
A7A199
AC3939
C9B4A7
C9C9B5
DFC255
E6E6E2
(The cut command is only available by default in Linux, Mac OS X or Unix. On Windows, you'd need a Cygwin environment or at some special command line utilities installed).
Identify for each color 1 pixel using exactly that color
The following command would output each pixel's coordinate and the color associated with it:
convert 15c.png text:-
To show you how this would look like, let's limit it to the first five lines only:
convert 15c.png text:- | head -n 5
# ImageMagick pixel enumeration: 640,199,255,srgb
0,0: (167,161,153) #A7A199 srgb(167,161,153)
1,0: (167,161,153) #A7A199 srgb(167,161,153)
2,0: (167,161,153) #A7A199 srgb(167,161,153)
[...]
(The head command is only available by default in Linux, Mac OS X or Unix. On Windows, you'd need a Cygwin environment or at some special command line utilities installed).
Now the command to identify 1 pixel for each color:
for color in $(echo $(convert 15c.png -format "%c" histogram:info:-|cut -c 28-34)); do
convert 15c.png text:- | grep $color | head -n 1;
done
which returns the following list:
475,0: (34,31,32) #221F20 srgb(34,31,32)
456,0: (67,67,69) #434345 srgb(67,67,69)
12,0: (73,101,162) #4965A2 srgb(73,101,162)
14,0: (75,146,191) #4B92BF srgb(75,146,191)
248,0: (85,45,42) #552D2A srgb(85,45,42)
213,0: (98,94,90) #625E5A srgb(98,94,90)
249,0: (111,149,99) #6F9563 srgb(111,149,99)
241,0: (150,105,99) #966963 srgb(150,105,99)
13,0: (152,142,114) #988E72 srgb(152,142,114)
0,0: (167,161,153) #A7A199 srgb(167,161,153)
146,0: (172,57,57) #AC3939 srgb(172,57,57)
3,0: (201,180,167) #C9B4A7 srgb(201,180,167)
18,0: (201,201,181) #C9C9B5 srgb(201,201,181)
126,0: (223,194,85) #DFC255 srgb(223,194,85)
32,0: (230,230,226) #E6E6E2 srgb(230,230,226)
The first column in this list gives the pixels' coordinates.
Create an image that contains all pixels with identical colors as the one from the previous step
A general command to replace colors in an image is this:
convert some.png -fill red -draw 'color 13,45 replace' out.png
This command defines the fill color as red. Then it looks at the color of the pixels with coordinates 12,45 and replaces that same color for all pixels in the image which are identical to the colors of pixel 12,45.
So what we need to use here is the following approach:
Enable the alpha channel in the PNG for transparency.
Define the fill color as transparent.
Replace the 14 different colors the image with transparent pixels and keep only one color.
Repeat the previous step 15 times.
This command would do it for the first unique color:
convert \
15c.png \
-alpha on \
-fill none \
-draw 'color 456,0 replace' \
-draw 'color 12,0 replace' \
-draw 'color 14,0 replace' \
-draw 'color 248,0 replace' \
-draw 'color 213,0 replace' \
-draw 'color 249,0 replace' \
-draw 'color 241,0 replace' \
-draw 'color 13,0 replace' \
-draw 'color 0,0 replace' \
-draw 'color 146,0 replace' \
-draw 'color 3,0 replace' \
-draw 'color 18,0 replace' \
-draw 'color 126,0 replace' \
-draw 'color 32,0 replace' \
output-color1-pixel-475_0.png
The resulting image is this:
Update:
Here are all 15 images as extracted from the self-created sample image:
The short answer is yes it is possible in OpenCV. Realistically you may want to look somewhere else to find someone that has already solved the problem.
If OpenCV is operational on your machine, and you are able to write a little code, then you should be able to do this one color at a time. I haven't done this before, but if you are interested in learning how to use OpenCV then this method should point you in the right direction.
Load your image into a Mat. We'll call this Mat "A".
If know the the BGR values for the your N distinct colors, it will be something like: Scalar(255,0,0) , then you can use inRange() to get a binary mask for the color you want. This will give you a 1 channel Mat, we'll call this "B".
Do matrix multiplication A*B or if that doesn't work a bitwise A&B. The result should be a black image with patches of only the color you want.

Org mode: describe a chess position and automatically generate image of chessboard

I write articles on chess. I often need to describe a chess position, using a standard format named FEN, and would like it to be automatically converted to a png image, and when I export the org document as LaTeX or html the image to be inlined. I think it can be done because ditaa seems to work similarly.
For example, with the FEN string "8/pppr1kpp/8/8/8/5P2/PPP1RKPP/8 w - - 0 1" as input, I create a tex file named chessboard.tex:
\documentclass[border={0 0 3 0}, convert={density=150}]{standalone}
\usepackage{xskak}
\usepackage{chessboard}
\usepackage{chessfss}
\usepackage{fontspec}
\begin{document}
\setchessboard{normalboard, showmover=true, moverstyle=triangle, label=false}
\setboardfontfamily{merida}
\fenboard{8/pppr1kpp/8/8/8/5P2/PPP1RKPP/8 w - - 0 1} \chessboard
\end{document}
which, with the shell command $> xelatex --shell-escape chessboard.tex, produces the following png image (thanks to the use of the standalone package).
How can I automate this process, so that I could put in an org file something like
#+BEGIN_SRC chessfen
8/pppr1kpp/8/8/8/5P2/PPP1RKPP/8 w - - 0 1
#+END_SRC
and have the above process automated?
Something like this?
#+title: Chess
#+startup: inlineimages
#+property: header-args:latex+ :imagemagick yes :iminoptions -density 300 -resize 400
#+property: header-args:latex+ :headers '("\\usepackage{chessboard}\\usepackage{xskak}\\usepackage{chessfss}") :border 1pt
* Chess
#+begin_src latex :file chess.png :results raw
\setchessboard{normalboard, showmover=true, moverstyle=triangle, label=false}
\fenboard{8/pppr1kpp/8/8/8/5P2/PPP1RKPP/8 w - - 0 1} \chessboard
#+end_src
This modification of rvf0068's answer works for me, after manually installing the necessary LaTeX packages (that can be found by inspecting in the error log output):
#+property: header-args:latex+ :headers '("\\usepackage{chessboard}\\usepackage{xskak}\\usepackage{chessfss}") :border 1pt
#+header: :imagemagick "t"
#+header: :results file raw
#+header: :exports results
#+header: :fit yes :border 0.5cm
#+header: :iminoptions -density 600 :imoutoptions -geometry 600
#+begin_src latex :file alburt_vs_kasparov_1978.png
\setchessboard{normalboard, showmover=false, moverstyle=triangle, label=false}
\fenboard{8/pppr1kpp/8/8/8/5P2/PPP1RKPP/8 w - - 0 1} \chessboard
#+end_src
# Local Variables:
# org-latex-pdf-process: ("xelatex -shell-escape -interaction=nonstopmode -output-directory=%o %f"
# "xelatex -shell-escape -interaction=nonstopmode -output-directory=%o %f"
# "xelatex -shell-escape -interaction=nonstopmode -output-directory=%o %f")
# End:
I use LaTeX environments directly to typeset chess, with no src blocks:
Then, the white brings the king
- to the closest rank to the opposing king and
- to the file one next to that of the opposing king toward the center.
\begin{center}
\fenboard{7k/R7/8/8/8/8/8/7K w - - 0 2}
\mainline{2. Kg2 Kf8 3. Kf3 Ke8 4. Ke4 Kd8 5. Kd5 Kc8 6. Kd6}
\par
\showboard
\end{center}