Terminal: Use image information from sips for renaming files - bash

The command sips has a great option to read information from files. The following command loops through all images and shows information on the width or height:
for i in *.jpg; do sips -g pixelWidth $i;done
for i in *.jpg; do sips -g pixelHeight $i;done
Now I would like to read this information and use it with mv to rename the images like so:
image-widthxheight.jpg
image-1600x900.jpg
The final thing I want accomplish is, to use sips to resize images and write the new information directly into the filename.
Has anybody an idea, how I can extract the information from width and height and use it together with mv?

I found it out myself. It's a nice bash script now. Maybe not so elegant, but it works – It's also available as a gist on GitHub.
NEW VERSION THANKS TO THE ADVICE – SEE COMMENTS
#!/bin/bash
#
# 1. This script copies all *.jpg-files to a new folder
# 2. Jumps into folder and resizes all files with sips
# 3. Renames all files and uses information from sips
#
folder="resized_and_renamed"
mkdir -p "$folder"
cp *.jpg "$folder"
cd "$folder"
# RESIZE ALL IMAGES TO MAXIMUM WIDTH/HEIGHT OF 360
sips -Z 360 *.jpg
# RENAME FILES WITH INFORMATION FROM SIPS
for i in *.jpg
do
pixelWidth=$(sips -g pixelWidth "$i" | awk '/pixelWidth:/{print $2}')
pixelHeight=$(sips -g pixelHeight "$i" | awk '/pixelHeight:/{print $2}')
# REMOVE EXTENSION
filename=${i%.jpg}
# NOW RENAME
mv $i ${filename##*/}-${pixelWidth}x${pixelHeight}.jpg
done

Related

SoX batch convert adding white noise

I'm trying to add white noise to hundreds of files. I find a command but don't know how to adapt it.
There is a source folder with files and an empty destination folder. Could someone help me with the right command?
I'm using OSX.
http://linguistics.berkeley.edu/plab/guestwiki/index.php?title=Sox_in_phonetic_research#Add_noise_to_an_audio_file
You should put the command in a for loop, then refer to the for variable as file name.
I assume that the source folder and the destination folder are on the same level.
for file in *.wav; do sox "$file" -p synth whitenoise vol 0.02 | sox -m "$file" - "../DESTINATION/$file"; done
In addition, if you want to use a suffix in the name of the output files, use basename to exclude the extension:
for file in *.wav; do sox "$file" -p synth whitenoise vol 0.02 | sox -m "$file" - "../DESTINATION/$(basename $file)_output.wav"; done

Code must find all MP4 files within subdirectory to compress using ffmpeg

I have a drive with a lot of MP4 files which are tough to go through folder by folder and compress.
I'm trying to make a script that runs in terminal that will open a designated folder, find all .mp4 files in the subfolder, and compress the files using specs I designate with ffmpeg. Obviously, the output files should be much lower in size if done right. I'm drafting a code which I have an idea about below but I'm not too good with BASH and/or PERL.
for f in $(find ../ -iname '*.avi'); do
n=$(echo $f|sed -e 's/.avi/_cbr.mp4/i');
echo "ffmpeg [options] -i $f $n";
done
output:
ffmpeg [options] -i ../1hourjob/videncode/sound10s.avi ../1hourjob/videncode/sound10s_cbr.mp4
ffmpeg [options] -i ../1hourjob/videncode/t003.avi ../1hourjob/videncode/t003_cbr.mp4
ffmpeg [options] -i ../ffmpeg/Masha.avi ../ffmpeg/Masha_cbr.mp4
ffmpeg [options] -i ../ffmpeg/window.avi ../ffmpeg/window_cbr.mp4
I'm wondering if I can even make some sort of GUI for this too. I feel a bit lost.
You can recursively traverse the directories in bash like this:
avi_to_mp4() {
cd "$1"
for f in *; do
if [[ -d "$f" ]]; then
avi_to_mp4 "$f"
elif [[ "$f" == *.avi ]]; then
newf="${f:0: -4}.mp4"
echo "$f" to "$newf" # run your command here
fi
done
cd ..
}
avi_to_mp4 "$1"

Converting *.wma to *.mp3 by SHELL-script with mplayer, lame, and find

I want to convert my older *.wma files into *.mp3. For that purpose I found a short script to convert with using mplayer + lame (found here: https://askubuntu.com/questions/508625/python-v2-7-requires-to-install-plugins-to-play-media-files-of-the-following-t).
This works fine in a single directory. Now I wanted to improve it that way, that it's able to work with 'find'. Its intended to find a *.wma-file and then calling the script to convert that file to *.mp3.
Here is the script:
FILENAME=$1
FILEPATH="$(dirname $1)"
BASENAME="$(basename $1)"
mplayer -vo null -vc dummy -af resample=44100 -ao pcm:waveheader "$FILENAME"
lame -m j -h --vbr-new -b 320 audiodump.wav -o "`basename "$FILENAME" .wma`.mp3"
echo "Path: $FILEPATH" # just to see if its correct
echo "File: $BASENAME" # just to see if its correct
rm -f audiodump.wav
rm -f "$FILENAME"
At the moment I'm dealing with the issue, that the script put the converted *.mp3 in the directory which the console is working with (e.g. /home/user/ instead of /home/user/files/ where the *.wma comes from).
What can I do to let the script putting the new *.mp3 into the same directory as the *.wma?
If I want to use 'mv' within the script I get trouble with embedded spaces in the *.wma-filenames.
Thanks for any hints. I thought about setting the IFS to tab or newline, but I wounder if there is a better way to deal with this.
Here's something that uses ffmpeg for the conversion (after using ffprobe for figuring out what the bit_rate should be). It's based off of what I found in (https://askubuntu.com/questions/508278/how-to-use-ffmpeg-to-convert-wma-to-mp3-recursively-importing-from-txt-file). But I didn't have access to avprobe, so had to hunt for an alternative.
First navigate to the directory with all your files and run the following from your shell:
find . -type f | grep wma$ > wma-files.txt
Once that's done, you can put this into a script and run it:
#!/usr/bin/env bash
readarray -t files < wma-files.txt
ffprobe=<your_path_here>/ffprobe
ffmpeg=<your_path_here>/ffmpeg
for file in "${files[#]}"; do
out=${file%.wma}.mp3
bit_rate=`$ffprobe -v error -show_entries format=bit_rate -of default=noprint_wrappers=1:nokey=1 "$file"`
$ffmpeg -i "$file" -vn -ar 44100 -ac 2 -ab "$bit_rate" -f mp3 "$out"
done
This will save the mp3 files alongside the wma ones.
The problem is that basename is stripping both the .wma extension and the path leading to the file. And you only want the .wma stripping.
So the answer is not to use basename and instead just do the .wma stripping yourself (with Parameter Expansion).
outfile=${FILENAME%.wma}
lame -m j -h --vbr-new -b 320 audiodump.wav -o "$outfile.mp3"
(Note that I used lowercase $outfile. Generally $ALL_CAPS variables are reserved for the shell/terminal/environment and should be avoided in scripts.)

HandBrakeCLI bash script convert all videos in a folder

Firstly, I searched around for my problem. But none can solve it.
I want to convert all videos file in a directory and the output will be saved in another directory. I got a bash script from somewhere I dont remember.
#!/bin/bash
SRC="/home/abc/public_html/filex/store/vids/toriko/VIDEOS HERE"
DEST="/home/abc/public_html/filex/store/vids/toriko/51-100"
DEST_EXT=mp4
HANDBRAKE_CLI=HandBrakeCLI
PRESET="iPhone & iPod Touch"
for FILE in "`ls $SRC`"
do
filename=$(basename $FILE)
extension=${filename##*.}
filename=${filename%.*}
$HANDBRAKE_CLI -i "$SRC"/$FILE -o "$DEST"/"$filename".$DEST_EXT "$PRESET"
done
the problem is, the output of the file will be without filename.. only ".mp4".
and, there is only 1 file generated.. means, from 50 videos in the folder, only 1 files generated with name ".mp4" and after that, HandBrakeCLI exit.
can anyone fix my code?
I got no experince in bash coding.. so, the right script giiven will be appreciate :)
Your line
for FILE in "`ls $SRC`"
effectively creates only one iteration where FILE contains the list of the files (and it is not able to handle the space in $SRC). Better replace it with
for FILE in "$SRC"/*
Example:
$ ls test
1.txt 2.txt
$ SRC=test; for f in "`ls $SRC`" ; do echo $f; done
1.txt 2.txt
$ SRC=test; for f in "$SRC"/* ; do echo $f; done
test/1.txt
test/2.txt
Side note: you can have a space in there with no problem
$ ls "the test"
1.txt 2.txt
$ SRC="the test"; for f in "$SRC"/* ; do echo $f; done
the test/1.txt
the test/2.txt
I tried this script, and others like it, but I wanted to convert recursive directory tree's and have files placed in the same directory with .mp4 extension and delete .avi files, after much trial and error I gave up on this code and searched for a new code, id like to credit
http://www.surlyjake.com/blog/2010/08/10/script-to-run-handbrake-recursively-through-a-folder-tree/
For the original code!
Here is my modified script, barely modified BTW this script is short, sweet and easy to understand.
#!/bin/bash
# This Script Goes in Root Folder of TV show -- Example Folder Structure
# /Stargate/Season\ 1/Epiosde.avi
# /Stargate/Season\ 2/Epiosde.avi
# /Stargate/handbrake_folder.script
# Outputs all Files back inside same dir's and does all folders inside Startgate DIR
# /Stargate/Season\ 1/Epiosde.mp4
# /Stargate/Season\ 2/Epiosde.mp4
# PRESET = -o flags for CLI can be got from GUI under Activity Log or from https://trac.handbrake.fr/wiki/CLIGuide OR you can use actual Presets!
# PRESET="iPhone & iPod Touch"
PRESET="--modulus 2 -e x264 -q 20 --vfr -a 1 -E ac3 -6 5point1 -R Auto -B 384 -D 0 --gain 0 --audio-fallback ac3 --encoder-preset=veryfast --encoder-level="5.2" --encoder-profile=high --verbose=1"
if [ -z "$1" ] ; then
TRANSCODEDIR="."
else
TRANSCODEDIR="$1"
fi
find "$TRANSCODEDIR"/* -type f -name "*.avi" -exec bash -c 'HandBrakeCLI -i "$1" -o "${1%\.*}".mp4 --preset="$PRESET"' __ {} \; && find . -name '*.avi' -exec rm -r {} \;
BE WARNED: THIS WILL CONVERT THEN DELETE ALL .AVI FILES ABOVE THE SCRIPT IN FILE TREE!
Feel free to remove the
[-name "*.avi"] & [&& find . -name '*.avi' -exec rm -r {} \;]
to disable only converting .avi and removal of .avi or modify to suite another extension.
I have found the solution:
#!/bin/bash
SRC="/home/abc/public_html/filex/store/vids/toriko/VIDEOS HERE"
DEST="/home/abc/public_html/filex/store/vids/toriko/51-100"
DEST_EXT=mp4
HANDBRAKE_CLI=HandBrakeCLI
for FILE in "$SRC"/*
do
filename=$(basename "$FILE")
extension=${filename##*.}
filename=${filename%.*}
$HANDBRAKE_CLI -i "$FILE" -o "$DEST"/"$filename".$DEST_EXT
done
I just tried using this script with the modification suggested above. I found I need to to put double quotes around the two uses of $FILE in order to handle file names with spaces.
So...
filename=$(basename "$FILE")
and
$HANDBRAKE_CLI -i "$SRC"/"$FILE" -o "$DEST"/"$filename".$DEST_EXT "$PRESET"
I'd rather prefer this solution:
#!/bin/bash
SRC="$1"
DEST="$2"
EXT='mp4'
PRESET='iPhone & iPod Touch'
#for FILE in "`ls $SRC`"; do
for FILE in `find . -type f`; do
FILE=$(basename "$FILE")
filename=$(basename "$FILE")
extension=${filename##*.}
filename=${filename%.*}
HandBrakeCLI -i "$SRC"/$FILE -o "$DEST"/"$filename"."$EXT" "$PRESET"
done

Improving process for using ImageMagick to batch convert TIFF to PNG and resample

I have several folders of 600 dpi TIFFs (CCITT Group IV, so black & white) that I need to convert to screen resolution PNGs - so in ImageMagick terms, I need to convert the format and resample the images to ~80 dpi. My first approach was to perform this in a single mogrify command (this is in bash on Mac OS X):
for folder in $(find * -maxdepth 0 -type d ); \
do mogrify -path "$folder/medium" -format png -resample 31.5% "$folder/tiff/*.tif"; \
done
But the result was awful. The text in the resulting image was completely illegible. So I changed this to a two step process, (1) converting the TIFF to PNG at original resolution, then (2) downsizing the resolution:
for folder in $(find * -maxdepth 0 -type d ); \
do mogrify -path "$folder/medium" -format png "$folder/tiff/*.tif"; \
mogrify -resample 31.5% "$folder/medium/*.png"; \
done
While this process resulted in nice and crisp results at 80 dpi, the process was much slower, since I'm now writing the full resolution file to disk before downsizing the resolution.
Does anyone have a suggestion for the best way to accomplish a conversion and downsizing of resolution in a single step?
The sips tool can be used as follows:
sips -s format png -s dpiHeight 80 -s dpiWidth 80 -z 1200 1600 test.tiff --out test.png
Having said that in the resulting .png, the DPI settings don't seem to have been changed.
Also when resizing, it looks like you can only specify absolute pixel dimensions of the output image, and not a percentage of the input image. So you would have to grab the dimensions of the input image and calculate the new size explicitly:
#!/bin/bash
infile=test.tiff
outfile=test.png
pct=31 # only whole numbers for bash arithmetic
height=$(sips -g pixelHeight $infile | tail -1 | cut -d: -f2)
width=$(sips -g pixelWidth $infile | tail -1 | cut -d: -f2)
sips -s format png -s dpiHeight 180 -s dpiWidth 180 -z $((height*pct/100)) $((width*pct/100)) 1600 $infile --out $outfile
I know I am late to the party, but I was looking at this and wondered why you get poor quality when doing both setps in one go. I wondered if it was maybe down to using mogrify rather than convert, so I set about trying to improve it. So, this would be my first and best attempt:
#!/bin/bash
for f in */tiff/*.tif; do
out="${f%tif}png" # replace "tif" suffix with "png"
out=${out/tiff/medium} # replace "tiff" directory with "medium"
convert "$f" -resample 31.5% "$out"
done
And, if that still doesn't work, I could go for a second attempt which avoids writing the file to disk and then resampling it, and instead writes a PNG to stdout and then pipes that to a second convert that resamples and writes to disk - thereby avoiding the writing to disk of the big, intermediate PNG.
#!/bin/bash
for f in */tiff/*.tif; do
out="${f%tif}png" # replace "tif" suffix with "png"
out=${out/tiff/medium} # replace "tiff" directory with "medium"
convert "$f" PNG:- | convert - -resample 31.5% "$out"
done

Resources