I have written the following script which uses the ImageMagick* convert utility to append axis labels to an existing image.
LEFT_="l -30,0 +2,+2 -6,-2 +6,-2 -2,+2 z"
RIGHT_="l 30,0 -2,+2 +6,-2 -6,-2 +2,+2 z"
convert -size 240x160 pattern:SMALLFISHSCALES \
-pointsize 16 -fill black -background white \
-gravity SouthEast -splice 0x20 \
-draw "translate 40,0 text 0,0 'Time' stroke red path 'm 5,2 $RIGHT_'" \
-gravity NorthWest -splice 20x0 \
-draw "rotate +90 translate 40,-10 text 0,0 'Value' path 'm -5,2 $LEFT_'" \
example.png
Which produces the following image:
This is almost exactly what I am after, except that the red arrow is out of place. I expected the red arrow to appear next to the Time label, since its start point is specified as a relative position in the same draw command. Unfortunately, it looks like the -gravity option is affecting the text primitive, but not the path primitive.
Is there a way to reference the SouthEast corner, or the Time text label when specifying the start position of the red arrow? I can't use absolute coordinates, because the size of the image varies.
*ImageMagick 6.7.8-9 on CentOS 7
Updated Answer
Maybe you can make Unicode text arrows like this then they will be affected by gravity...
perl -e 'binmode(STDOUT,":utf8"); print "Time ... \x{2192}\x{2191}";'|
convert -font TimesNewRoman -pointsize 36 label:#- arrows.png
Depending on your OS, the following may do as a replacement for the Perl above...
printf "%b" "\u2192" | convert ...
Original Answer
I am not at all familiar with paths, but I can suggest a way to achieve what you want that doesn't use gravity at all, and maybe that will help.
Rather than use -splice, you can clone your original image and crop it to the size you planned to splice on, and then -append the strips that label the axes. It is easier to show you the command than explain it!
convert -size 240x160 pattern:SMALLFISHSCALES \
\( +clone -crop x20+0+0 -fill blue -colorize 100% \) \
-append \
\( +clone -crop 20x+0+0 -fill red -colorize 100% \) \
+swap +append result.png
I have filled the x-axis blue, but remove that and add whatever labelling and arrows you need, and I filled the y-axis red, but likewise remove that and add labelling and arrows - rotating as necessary.
Two tricky things to note...
-append will append the second image below the first
+append will append the second image to the right of the first, so I +swap beforehand to put it on the left side.
Related
To demonstrate.
Original:
After ImageMagick:
I have some ideas:
Duplicate the image, crop the duplicate, then flatten the images together
Reverse mask?
Does anyone have any suggestions?
Although this has been successfully answered, I'll offer another simple approach using IMv6...
convert pasta.jpg -fill white \
\( +clone -evaluate set 25% -draw "roundrectangle 20,20 80,80 15,15" \) \
-compose multiply -composite result.png
After reading in the input image, in parentheses it clones the input and uses -evaluate to set the entire clone to 25% gray. A white "roundrectangle" is drawn on that gray image in the area you want to preserve. The mask looks like this...
Then after the parentheses, that mask and the input image are composited with -compose multiply. That leaves the white rectangle area as it was in the original input, and the rest of the image is multiplied by 0.25, leaving it darkened. The result...
This command should work just the same in IMv7 by changing "convert" to "magick". And it should work as well on Windows CLI by changing the continued-line backslashes "\" to carets "^", and removing any backslashes before the parentheses, so this "\(...\)" to this "(...)".
You can do that in Imagemagick by darkening the whole image, creating a round rectangle mask image, then composite the original with the darkened using the mask image.
Input:
convert pasta.jpg \
\( -clone 0 -brightness-contrast -75,0 \) \
\( -clone 0 -fill white -colorize 100 -fill black -draw "roundrectangle 20,20 80,80 15,15" -alpha off \) \
-compose over -composite \
pasta_rect.jpg
Result:
How do I adjust the color ratio of a gradient?
I currently use the following to create my gradient.
convert -size 200x600 gradient:none-black output.png
Although at least one acceptable solution has been provided, here are a couple other ideas...
Example 1: This command creates a red-blue gradient of the finished dimensions, crops it into a top and bottom half, resizes them to 40 and 60 percent of the input height, and appends them back to make a single image. What started as the color at the exact vertical center is now at 40% down from the top with clean gradients going up and down from there.
convert -size 200x600 gradient:red-blue -crop 1x2# \
\( -clone 0 -resize 100x40% \) \( -clone 1 -resize 100x60% \) \
-delete 0,1 -append result.png
That splits the gradient image into a top and bottom half, then inside parentheses it resizes each to the required proportion. After that it deletes the 50/50 crops from before the parentheses, appends the two resized remaining images, and writes the output.
Example 2: This next example starts by creating the red-blue gradient in the final dimensions, then sets variables to hold the top color, the exact middle color, and the bottom color.
Then inside the first parentheses it clones and crops the image to 60% its original height. It uses "-sparse-color" to fill that with a gradient from "color1" to "color2".
Inside the second parentheses it clones and crops the image to 40% its original height, and using "-sparse-color" again it fills it with a gradient from "color2" to "color3".
After creating those two gradients, delete the original, append the other two together, and write the output.
convert -size 200x600 gradient:red-blue \
-set option:color1 "%[pixel:p{0,0}]" \
-set option:color2 "%[pixel:p{0,h/2}]" \
-set option:color3 "%[pixel:p{0,h}]" \
\( -clone 0 -extent 100x60% \
-sparse-color barycentric "0,0 %[color1] 0,%[h] %[color2]" \) \
\( -clone 0 -extent 100x40% \
-sparse-color barycentric "0,0 %[color2] 0,%[h] %[color3]" \) \
-delete 0 -append result.png
Maybe you want this, where you get to the half-red/half-blue colour just 20% of the way down the height of the image. It is done by creating two gradients of different lengths and putting them back-to-back:
midcolour="rgb(127,0,127)"
convert -size 100x20 gradient:red-"$midcolour" \
-size 100x80 gradient:"$midcolour"-blue \
-append result.png
Another way is to put 3 single pixels together in a row and then resize that up to what you want. I know you want the middle to be 40% red and 60% blue, but, for ease of viewing, I'll make it lime green:
convert -size 1x1 xc:red xc:lime xc:blue -append -resize 100x100\! result.png
You would change lime to something like "rgb(100,0,155)".
I am not quite sure I understand. But if you want to start with 90% transparent (10% opaque black) and end with black. You can do:
convert -size 200x600 gradient:"graya(0,0.1)-black" output.png
graya means gray with alpha. So graya(0,0.1) is gray(0) or black with 0.1 fraction opacity, so 90% transparent.
Perhaps this is what you want:
Normal 50-50:
convert -size 200x600 gradient:red-blue red_blue1.png
60-40:
rr=`convert xc: -format "%[fx:0.6*255]" info:`
bb=`convert xc: -format "%[fx:0.4*255]" info:`
convert -size 200x600 gradient:"rgb($rr,0,$bb)-rgb(0,0,255)" red_blue2.png
Or perhaps this is what you want:
bb=`convert xc: -format "%[fx:0.1*255]" info:`
convert -size 200x600 gradient:"rgb(255,0,$bb)-rgb(0,0,255)" red_blue3.png
I have an Imagemagick bash shell script called, multigradient, which may do what you want. It allows you to create gradients of many colors each with stops to set where they start. For example:
multigradient -w 200 -h 600 -s "blue 0 red 80" -d to-top result.png
The first color must start at 0, but the direction can be many options. Here I go from bottom to top with pure blue at the bottom and pure red starting at 80 up from the bottom going to the top
(See)
I already have the normalized vertices of my selected bounding box (e.g xmin: 0.68, ymin: 0.47, xmax: 0.94, ymax: 0.82) and I want to save this box in an other .jpg file. Furthermore, in the original image I want to make this highlighted box all white. Is this possible using Imagemagick?
Starting with this:
and knowing the top-left corner of the monument is at 400,10 and the bottom-right is at 500,200, you can extract the monument to a file with:
magick photo.jpg -crop 100x190+400+10 extract.jpg
and overpaint in white with:
magick photo.jpg -fill white -draw "rectangle 400,10 500,200" overpainted.jpg
Or, for extra fun, overpaint in semi-transparent white with:
magick photo.jpg -fill "rgba(255,255,255,0.5)" -draw "rectangle 400,10 500,200" overpainted.jpg
You can do both operations in one go with:
magick photo.jpg \( +clone -fill white -draw "rectangle 400,10 500,200" -write overpainted.jpg +delete \) -crop 100x190+400+10 extract.jpg
Using ImageMagick version 6, the command below will create two output images. (An example command for ImageMagick version 7 is further down in the reply.)
The first output image will be cropped from the input image using the bounding box starting at w*0.68xh*0.47 and ending at w*0.94xh*0.82.
The second output will be the input with a white section corresponding to the sub-image cropped out to make the first image.
convert input.png \
-set option:distort:viewport "%[fx:(w*0.94)-(w*0.68)]x%[fx:(h*0.82)-(h*0.47)]" \
\( +clone -distort affine "0,0 -%[fx:w*0.68],-%[fx:h*0.47]" \
-write result1.png -fill white -colorize 100 \) \
-set page "%[fx:u.w]x%[fx:u.h]+%[fx:t*(u.w*0.68)]+%[fx:t*(u.h*0.47)]" \
-flatten result2.png
That starts by reading the input image and calculating the viewport, the dimensions of the sub-image to crop, according to the bounding box dimensions you've provided.
Then inside the parentheses it creates a clone and does a "-distort affine" which, in effect, crops the image and locates it properly in that viewport. It writes that result to the first output image "result1.png". Then, still inside the parentheses, it fills that cropped piece with white.
After that it sets the paging geometry so that white piece can eventually be composited back into its original location over the input image.
It finishes by flattening the white piece onto the input image, and writes the second output image "result2.png".
The same thing can be done using ImageMagick version 7 with a slightly less complicated command...
magick input.png \
\( +clone \
-crop "%[fx:(w*0.94)-(w*0.68)]x%[fx:(h*0.82)-(h*0.47)]+%[fx:w*0.68]+%[fx:h*0.47]" \
-write result1.png -fill white -colorize 100 \) \
-flatten result2.png
That does the calculations directly in the "-crop" operation, and the paging geometry is saved in the cropped piece so it can be flattened back to its original position without resetting the geometry.
Those are in *nix syntax. To make it work in Windows change the continued line backslashes "\" to carets "^", and eliminate those backslashes that escape the parentheses "\(...\)".
Here is one other variation in ImageMagick 6. It crops the image and saves it and then deletes it. Then it use -region to write white into that bounding box.
This is Unix syntax. For Windows, remove \ from parenthesis and change end of line \ to ^.
Input:
convert img.jpg \
\( +clone -crop 100x190+400+10 +repage +write result1.jpg +delete \) \
-region 100x190+400+10 -fill white -colorize 100 +region result2.jpg
convert inputImage.jpeg -gravity South -size x32 label:"Morning in paradise" -geometry +0+40 -composite starImage.png -composite finalImage.png
With this command, I can add text at the bottom of inputImage and another image on this text. But how can I set (or prefix) the starImage image to the left of the text that has a dynamic width and fixed height. I have attached some images below to explain what I want to do.
Obtained result
Expected result
You can read the star image, create the text label, and append them together inside parentheses. Then composite that assembled star-text image over the main input image. A command like this should get pretty near what you described.
convert inputImage.jpeg -gravity center -size x32 \
\( starImage.png label:"Morning in paradise" +append \) \
-geometry +0+40 -gravity South -composite finalImage.png
If you want a star on both sides of the line of text, you can read the "starImage.png" in once more after creating the label and before appending.
I think what you should do using Imagemagick is to set the width you want for the text so that there is room for the star image to be append on each side and have some padding as well. Here is how I would do it. Since you did not provide your input or star image, I have simulated the image as a blue image and taken some graphic image that I had around to simulate your star or logo. I first measure the desired width. The width is 70% of the difference is width between the large blue image and twice the width of the logo. I append the logo on each side of the text image, then composite that near the bottom of the blue image to create your final image. If this were in Imagemagick 7, it could be done in one command. This is Unix syntax.
Image:
Logo:
width=`convert background.jpg logo.png -format "%[fx:0.70*(u.w-2*v.w)]\n" info: | head -n1`
convert background.jpg \
\( logo.png \
-size ${width}x -background none -fill black -font Arial -gravity center label:"THIS IS A TEST" \
logo.png \
+append \) \
-gravity south -geometry +0+50 \
-compose over -composite \
result.jpg
I understand -trim can be used to remove extra whitespace.
How can Imagemagick be used to convert:
Note: The size of the bottom border to be removed is not known.
to
Note: the default -trim flag does not work.
The output of convert -trim pre-trim.png post-trim.png is:
which is missing the borders on the left and right.
Updated Answer
You can add some strips of colour down one side to protect the other 3 sides, then trim the side you want to trim and then remove the protective strips.
magick frame.png -gravity north \
-background cyan -splice x10 \
-background magenta -splice x10 \
-rotate 90 -trim +repage \
-gravity east -chop 10x -rotate -90 result.png
Here is the intermediate image of how it looks with the protective strips prior to trimming:
Kudos to Anthony Thyssen for his excellent ImageMagick Usage pages here.
Original Answer
You can chop 68 pixels off the bottom with:
convert frame.png -gravity south -chop x68 result.png