How to create drop shadow on resized image with an extension?

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: How to create drop shadow on resized image with an extension?

Post by fmw42 »

You have to adjust the computations of the offsets for the size of the input image.

# get the dimension of the input

Code: Select all

convert 4x5.jpg -format "%wx%h" info:
1024x820 <-- landscape

# use the dimensions with size 88 to compute the resized dimensions and then the offsets
new width = 88
new height = 88*height/width = 88*820/1024 = 70
xoffset = (100-88)/2 - 1 = 5
yoffset = (100-70)/2 - 1 = 14

Code: Select all

convert 4x5.jpg -resize 88x88 ^
( +clone -background black -shadow 63x3+5+5 ) ^
+swap -background none -layers merge +repage ^
-background "#c2c5cc" -layers flatten +repage ^
( -size 100x100 xc:"#c2c5cc" ) ^
+swap -gravity northwest -geometry +5+14 -compose over -composite ^
4x5_result.png
Works for me!

If portrait, then

new height = 88
new width = 88*width/height
etc.


Alternately, you can do the resize to get the new dimenions and not have to worry about portrait or landscape

Code: Select all

convert 4x5.jpg -resize 88x88 -format "%wx%h" info:
88x70

xoffset = (100-88)/2 - 1 = 5
yoffset = (100-70)/2 - 1 = 15

Code: Select all

convert 4x5.jpg -resize 88x88 ^
( +clone -background black -shadow 63x3+5+5 ) ^
+swap -background none -layers merge +repage ^
-background "#c2c5cc" -layers flatten +repage ^
( -size 100x100 xc:"#c2c5cc" ) ^
+swap -gravity northwest -geometry +5+15 -compose over -composite ^
4x5_result.png

Or even save the resized image and use it later

Code: Select all

convert 4x5.jpg -resize 88x88 +write 4x5_resize.png -format "%wx%h" info:
88x70

xoffset = (100-88)/2 - 1 = 5
yoffset = (100-70)/2 - 1 = 15

Code: Select all

convert 4x5_resize.png ^
( +clone -background black -shadow 63x3+5+5 ) ^
+swap -background none -layers merge +repage ^
-background "#c2c5cc" -layers flatten +repage ^
( -size 100x100 xc:"#c2c5cc" ) ^
+swap -gravity northwest -geometry +5+15 -compose over -composite ^
4x5_result.png


If using ImageMagick 7, then this works for landscape or portrait

Code: Select all

magick 4x5.jpg -resize 88x88 \
-set option:xoffset "%[fx:floor((100-w)/2-1)]" ^
-set option:yoffset "%[fx:floor((100-h)/2-1)]" ^
( +clone -background black -shadow 0x3+5+5 ) ^
+swap -background none -layers merge +repage ^
-background "#c2c5cc" -layers flatten +repage ^
( -size 100x100 xc:"#c2c5cc" ) ^
+swap -gravity northwest -geometry "+%[xoffset]+%[yoffset]" -compose over -composite ^
4x5_result.png
TomXampp
Posts: 26
Joined: 2015-12-02T00:21:23-07:00
Authentication code: 1151

Re: How to create drop shadow on resized image with an extension?

Post by TomXampp »

Great! The result of your routine is better than mine, and the routine does seem configurable.

There seems to be one fly left in the ointment: If I change the X and Y offsets of the -shadow to 2 and 2, like this:

-shadow 63x3+2+2

...then the image is no longer centered:

Image

What needs to be tweaked in the formula? If I change the other parameters of the -shadow command, is there anything else needed to tweaked in the formula?
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: How to create drop shadow on resized image with an extension?

Post by fmw42 »

The issue is that there is padding from the shadow process at the top and left that I did not realize happened and it varies depending upon the shadow arguments. This is a guess at what to do based upon some tests with your image. Note I remove one extra line of commands that was redundant. I have left it in from your original code and it was not needed.

Code: Select all

convert 4x5.jpg -resize 88x88 -format "%wx%h" info:
88x70

shadow args = 3+5+5
xoffset = (100-88)/2 - 1 = 5
yoffset = (100-70)/2 - 1 = 15
shave = (4*3 - 2*5)/2 = (12-10)/2 = 2/2 = 1

Code: Select all

convert 4x5.jpg -resize 88x88 ^
( +clone -background black -shadow 63x3+5+5 ) ^
+swap -background none -layers merge +repage -shave 1x1 ^
( -size 100x100 xc:"#c2c5cc" ) ^
+swap -gravity northwest -geometry +5+15 -compose over -composite ^
4x5_result_5.png


shadow args = 3+2+2
xoffset = (100-88)/2 - 1 = 5
yoffset = (100-70)/2 - 1 = 15
shave = (4*3 - 2*2)/2 = (12-4)/2 = 8/2 = 4

Code: Select all

convert 4x5.jpg -resize 88x88 \
( +clone -background black -shadow 63x3+2+2 ) ^
+swap -background none -layers merge +repage -shave 4x4 ^
( -size 100x100 xc:"#c2c5cc" ) ^
+swap -gravity northwest -geometry +5+15 -compose over -composite ^
4x5_result_2.png
TomXampp
Posts: 26
Joined: 2015-12-02T00:21:23-07:00
Authentication code: 1151

Re: How to create drop shadow on resized image with an extension?

Post by TomXampp »

It seems we need to subtract 1 from the SHAVE variable, just as we did before with the XOFFSET and YOFFSET variables, so SHAVE should be:

shave = ((4*3 - 2*5)/2) -1

It's clear that the "3" is the opacity in the formula (from 3+5+5), but is the "5" the x-offset or the y-offset? And does it switch depending on landscape vs. portrait (in case the shadow is 3+5+2, etc.)?

(I'm constructing a batch file with variables that I'll post here once done, and I'm trying to make it all-purpose.)
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: How to create drop shadow on resized image with an extension?

Post by fmw42 »

If the +X+Y in the shadow arguments are different, compute the shave values separately with the same formula. It is the same for landscape or portrait. The shave AxB where A is the amount to shave on the left and right sides and would be computed from +X. Likewise, the B is the amount to shave on the top and bottom and are computed from +Y.

I did not notice that one had to subtract 1 from the shave values. I was not looking for that. I was just trying to keep the image from shifting.
TomXampp
Posts: 26
Joined: 2015-12-02T00:21:23-07:00
Authentication code: 1151

Re: How to create drop shadow on resized image with an extension?

Post by TomXampp »

FMW42, thank you! You've helped me solve a vexing problem! It all works now, and I've compiled it into a configurable Windows batch file. In case this should help someone else who's trying to solve this or a similar problem, here's the batch code, whose environment variable could be set to parameter used when calling the batch file, etc.:

Code: Select all

@echo off
set INPUT=input.jpg
set OUTPUT=output.jpg
set TEMP=$$temp$$.jpg
set BACKGROUND=#c2c5cc
set WIDTH=88
set HEIGHT=88
set /A THUMBNAIL_WIDTH=100
set /A THUMBNAIL_HEIGHT=100
REM -shadow 50x10+15+20: drop shadow with 50% opacity, 10% size and x = +15%, y = +20%
set SHADOW_OPACITY=63
set SHADOW_SIZE=3
set SHADOW_X_OFFSET=+2
set SHADOW_Y_OFFSET=+5

cls
if not exist "%INPUT%" goto NoInputFile

echo Creating %WIDTH%x%HEIGHT% version of %INPUT%...

convert %INPUT% -resize %WIDTH%x%HEIGHT% %TEMP%

for /f %%i in ('convert %TEMP% -format %%w info:') do set /A IMAGE_WIDTH=%%i
for /f %%i in ('convert %TEMP% -format %%h info:') do set /A IMAGE_HEIGHT=%%i

set /A X_OFFSET = (%THUMBNAIL_WIDTH% - %IMAGE_WIDTH%) / 2 - 1
set /A Y_OFFSET = (%THUMBNAIL_HEIGHT% - %IMAGE_HEIGHT%) / 2 - 1

set /A SHAVE_X = (((4 * %SHADOW_SIZE%) - (2 * %SHADOW_X_OFFSET%)) / 2) - 1
set /A SHAVE_Y = (((4 * %SHADOW_SIZE%) - (2 * %SHADOW_Y_OFFSET%)) / 2) - 1

echo Creating drop shadowed and placed version of %INPUT% in %OUTPUT%...

convert %TEMP% ^
( +clone -background black -shadow %SHADOW_OPACITY%x%SHADOW_SIZE%%SHADOW_X_OFFSET%%SHADOW_Y_OFFSET% ) ^
+swap -background none -layers merge +repage ^
-background "%BACKGROUND%" -layers flatten +repage -shave %SHAVE_X%x%SHAVE_Y% ^
( -size %THUMBNAIL_WIDTH%x%THUMBNAIL_HEIGHT% xc:"%BACKGROUND%" ) ^
+swap -gravity northwest -geometry +%X_OFFSET%+%Y_OFFSET% -compose over -composite ^
%OUTPUT%

del %TEMP%

echo Created %OUTPUT%
echo Done.

goto end

:NoInputFile

echo.
echo Input file %INPUT% does not exist
echo.
goto end

:end
Post Reply