xargs is the tool for the job. That, or find with -exec … {} +. These tools run a command several times, with as many arguments as can be passed in one go.
Both methods are easier to carry out when the variable argument list is at the end, which isn't the case here: the final argument to mv is the destination. With GNU utilities (i.e. on non-embedded Linux or Cygwin), the -t option to mv is useful, to pass the destination first.
If the file names have no whitespace nor any of \"' and don't start with -¹, then you can simply provide the file names as input to xargs (the echo command is a bash builtin, so it isn't subject to the command line length limit; if you see !: event not found, you need to enable globbing syntax with shopt -s extglob):
echo !(*.jpg|*.png|*.bmp) | xargs mv -t targetdir --
You can use the -0 option to xargs to use null-delimited input instead of the default quoted format.
printf '%s\0' !(*.jpg|*.png|*.bmp) | xargs -0 mv -t targetdir --
Alternatively, you can generate the list of file names with find. To avoid recursing into subdirectories, use -type d -prune. Since no action is specified for the listed image files, only the other files are moved.
find . -name . -o -type d -prune -o \ -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o \ -exec mv -t targetdir/ {} +
(This includes dot files, unlike the shell wildcard methods.)
If you don't have GNU utilities, you can use an intermediate shell to get the arguments in the right order. This method works on all POSIX systems.
find . -name . -o -type d -prune -o \ -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o \ -exec sh -c 'mv "$@" "$0"' targetdir/ {} +
In zsh, you can load the mv builtin:
setopt extended_glob zmodload zsh/files mv -- ^*.(jpg|png|bmp) targetdir/
or if you prefer to let mv and other names keep referring to the external commands:
setopt extended_glob zmodload -Fm zsh/files b:zf_\* zf_mv -- ^*.(jpg|png|bmp) targetdir/
or with ksh-style globs:
setopt ksh_glob zmodload -Fm zsh/files b:zf_\* zf_mv -- !(*.jpg|*.png|*.bmp) targetdir/
Alternatively, using GNU mv and zargs:
autoload -U zargs setopt extended_glob zargs -- ./^*.(jpg|png|bmp) -- mv -t targetdir/ --
¹ with some xargs implementations, file names must also be valid text in the current locale. Some would also consider a file named _ as indicating the end of input (can be avoided with -E '')