I'm looking for a solution that can save me from maintaining two versions of the same image, one for Retina displays (aka #2x), one another for non-Retina displays. My goal is to maintain the "2x" images only, and have some 'magic tool' resize all of them with a single click or even better upon building in XCode. Like "set it and forget it".
Can you help me? Thanks in advance.
If you just want to downscale them, you can have Xcode automatically generate all non-retina images during the build process. This example script uses "sips" because that is preinstalled on Macs.
The Script
#!/bin/bash
# Downsamples all retina ...#2x.png images.
echo "Downsampling retina images..."
dir=$(pwd)
find "$dir" -name "*#2x.png" | while read image; do
outfile=$(dirname "$image")/$(basename "$image" #2x.png).png
if [ "$image" -nt "$outfile" ]; then
basename "$outfile"
width=$(sips -g "pixelWidth" "$image" | awk 'FNR>1 {print $2}')
height=$(sips -g "pixelHeight" "$image" | awk 'FNR>1 {print $2}')
sips -z $(($height / 2)) $(($width / 2)) "$image" --out "$outfile"
test "$outfile" -nt "$image" || exit 1
fi
done
Automatic Execution
Create a new "Aggregate Target", name it "Downsample images".
Add a "Run script" phase to this target that runs the script.
Add the "Downsample images" target as a "Target Dependency" in your app target(s).
Notes
Remember to still add your 1x images to the Xcode project. Depending on your needs you might also want to:
exclude certain files from conversion
add the generated files to your .gitignore file
use ImageMagick's "convert" instead of "sips". (sips seems to fail for some indexed PNGs.)
run optipng
ImageMagick comes with a "compare" command if you want to check the downsampled versions.
This is quite an old thread, but I stumbled onto it, so I can elaborate on maintaining more than one size automatically.
Performance-wise, I'm not sure using the automatic downscaling is a wise idea, as it has to be done in real-time, but it should work on simpler cases.
Now, to convert these #2ximages automatically, a simple bash script should do the trick. l4u's solution works, but for guys with simpler needs who do not want to install guard, this also works (you still need to install ImageMagick, though) :
for f in $(find . -name '*#2x.png'); do
echo "Converting $f..."
convert "$f" -resize '50%' "$(dirname $f)/$(basename -s '#2x.png' $f).png"
done
It's trivial:
Only include #2x images in your project.
Make sure those images have the #2x suffix.
The system will automatically downscale for non-retina devices.
The only exception is if you are doing manual, low level Core Graphics drawing. You need to adjust the scale if so. 99.9% though, you don't have to worry about this.
u can simply use only *#2x.png images for your app.
but you must set the content mode = UIViewContentModeAspectfit for the imageviews,
then it will automatically fix the image to the releventimageviews.
Or what you can also do is: Have only the #2x images in your app's bundle then on the first launch. Take all the #2x photos and downsize them by 1/2 and store them in the documents directory. Then when you need your photos for a UIImageView say, just grab them for the documents directory and set it to your UIImageView using code and not Interface Builder!
I was wondering this a few weeks ago too and I realized that this is pretty much the only way to really do what you are looking for!
I've created http://l4u.github.com/blog/2012/04/02/resizing-retina-images-with-guard-for-cocos2d-iphone-slash-cocos2d-x/ to generate non-hd images on the fly when -hd images are created/updated. It uses guard, guard-shell and imagemagick
You can replace -hd with #2x.
Try Resource Helper on the Mac App Store
http://itunes.apple.com/us/app/resourcehelper/id521474600
It costs $10.49 but it's worth it. Checks if your images are Retina friendly (i.e. even numbered width/height dimensions) and generates the corresponding image inline. Also handles creation of ~ipad and #2x~ipad graphics as needed.
EDIT: I am not affiliated with the authors of Resource Helper.
What I've been doing for our applications is asking our designer to export everything twice as big as it needs to be, then running a little node script to resize the images (anything named #2x in the directory where you run the script). Presently, we're just running the script when every time we deploy (it's idempotent), but it could easily be incorporated into forever -w or some other file-change-watching library like guard.
Old thread, but I found a use for #nschum's script - I noticed though that it doesn't round numbers for the #1x images if it's dividing an odd number. If I recall correctly this introduces a performance hit; wound up slightly revising it as below. Alters the awk call slightly to do the division there and round it accordingly, and won't re-create #1x images if one already exists (you might want to remove that, dunno).
At this point we've pretty much hit the point where non-retina isn't a big deal (the iPad 2 is all that remains...? The original Mini too, I guess), so meh. Throwing it up for posterity.
#!/bin/bash
# Downsamples all retina ...#2x.png images.
dir=$(pwd)
echo "Downsampling Retina images..."
find "$dir" -name "*#2x.png" | while read image; do
outfile=$(dirname "$image")/$(basename "$image" #2x.png).png
if [ "$image" -nt "$outfile" ] && [ ! -f "$outfile" ]; then
if [[ $(dirname "$image") =~ "Images.xcassets" ]]; then
echo "Skipping Image XCode Assets directory"
else
basename "$outfile"
width=$(sips -g "pixelWidth" "$image" | awk 'FNR>1 {printf "%.0f\n", $2/2}')
height=$(sips -g "pixelHeight" "$image" | awk 'FNR>1 {printf "%.0f\n", $2/2}')
sips -z "$height" "$width" "$image" --out "$outfile"
test "$outfile" -nt "$image" || exit 1
fi
fi
done
echo "Finished downsampling Retina images"
Related
I have a file that does not have an extension and would like to add an extension to it programmatically. I know the file command gives information about the extension of a file. How can I utilize this to add the extension to a file? The files I'm downloading can be assumed to be image files (png, jpg, etc.)
My desired outcome would be:
Input: filename
Output: filename.ext
All inside a bash script
Something like this should get you started:
#!/bin/bash
for f in "$#"; do
if [[ $f == *'.'* ]]; then continue; fi # Naive check to make sure we don't add duplicate extensions
ext=''
case $(file -b "$f") in
*ASCII*) ext='.txt' ;;
*JPEG*) ext='.jpg' ;;
*PDF*) ext='.pdf' ;;
# etc...
*) continue ;;
esac
mv "${f}" "${f}${ext}"
done
You'll have to check the output of file for each potential file type to find an appropriate case label.
You can try to find or create a map of file-type to file extension name but there's no universal way. Think about JPEG images, you can either have .jpg or .jpeg extension, and they both mean the same thing. Same for MP4 video containers...
Also, on linux the file extension doesn't even matter to most programs so you could just not care about it, but if you still want to do it for certain types of files, you can check this answer : https://stackoverflow.com/a/6115923/9759362
I've been tinkering with a script that uses sips to adjust JPEG file compression conveniently from within the Finder as a Service. It maintains file stamps unlike the simple Automator compression/rescaling functions.
Alas, it stumbles over certain file names, e.g. ones with a space and doesn't rescale them presumably because the file output chokes on the space character. So, it proceeds as expected on a file like "DSC03761.JPG" but not on "DSC03761 2.JPG". It also fails if the path contains spaces, if for example the file resides in a folder called "my Pictures".
Since I'm a noob, I haven't figured out how to adjust the script. You probably have a better idea?
screenshot of script
bash script below:
for f in "$#"; do
# Save creation date time stamp of the target file in 't'.
t="$(/usr/bin/GetFileInfo -d "$f")"
# Compress the target file. Level 0-100 or low/normal=50/high/best
filename=$f
#/usr/bin/sips --setProperty formatOptions 60 $f --out ${filename%.*}.jpg
/usr/bin/sips --setProperty formatOptions normal $f --out ${filename%.*}.jpg
# Set the modified and creation date time stamps to 't'.
/usr/bin/SetFile -m "$t" "$f"
/usr/bin/SetFile -d "$t" "$f"
done
# Notify user that operation is finished with a sound.
/usr/bin/afplay "/System/Library/Sounds/Purr.aiff"
Here, you correctly but unnecessaily quote an expansion:
t="$(/usr/bin/GetFileInfo -d "$f")"
But here, where you would need to use quotes, you don't:
/usr/bin/sips --setProperty formatOptions 60 $f --out ${filename%.*}.jpg
The latter should be
/usr/bin/sips --setProperty formatOptions 60 "$f" --out "${filename%.*}.jpg"
So after exporting a video to a image sequence, I have ended up with way more images than I needed. I would like to trim this down. The images are named 1.png, up to 959.png. Is there a convenient way of doing this with a bash/zsh script? Something like removing every other image and renaming the next to keep the order?
Thanks in advance.
Alright so I found somewhat of a solution.
#!/bin/zsh
c=0
cc=0
ext=".png"
for file in `ls | sort -V`
do
let c=c+1;
let cc=cc+1;
if [ $c -eq 2 ]; then
rm -f $file
c=0
else
let cc=cc-1;
new="$cc$ext"
mv $file $new
fi
done
This will list out all the files in the current directory and loop through them, deleting every other and renaming the next. Just be aware that this will rename the script file too, so you might want to create some logic to avoid that.
A pretty basic question but I'm new to
Imagemagick (and bash) and I'm having trouble batch cropping images in a folder. I've tried using a loop:
for image in '/home/donald/Desktop/New Folder'*.jpg; do
convert "$image" -gravity center -crop 95X95% "${image%.jpg}"-modified.jpg
done
but it returns:
convert.im6: unable to open image `/home/donald/Desktop/New Folder/*.jpg': No such file or directory # error/blob.c/OpenBlob/2638.
convert.im6: no images defined `/home/donald/Desktop/New Folder/*-modified.jpg' # error/convert.c/ConvertImageCommand/3044."
What would be the proper way of doing this?
Edit: Apparently a space in the folder name was causing problems I deleted it and things seem to be working.Apparently if you want to use a folder with a space name in bash you need to escape the space.
I believe you have no jpg files in the /home/donald/Desktop/New Folder/ directory. The shell will interpret it as the literal string /home/donald/Desktop/New Folder/*.jpg if there are no files matching the wildcard-ed string.
See this example:
$ for f in *.jpg*; do echo $f; done
file.jpg
file2.jpg
$ for f in *.jpgg; do echo $f; done
*.jpgg
See how that last one is the literal string and not a real file? It should have been displayed the first time too if it was (notice the trailing asterix symbol in *.jpg*).
You can fix this by checking if the file exists before executing the command, using [ -f "${file}" ]. For instance:
for image in '/home/donald/Desktop/New Folder'*.jpg; do
[ -f "${image}" ] && convert "$image" -gravity center -crop 95X95% "${image%.jpg}"-modified.jpg
done
This will check if the file image exists (-f) and execute the following statement only if true is returned &&. Had you written || instead of && then the following statement would be executed when false was returned.
Note that bash doesn't return true or false but it's the easiest way to explain and comprehend the notation.
I have large number of files with .gif extension. I would like to move all animated gifs to another directory. How can I do this using linux shell?
Basically, if identify returns more than one line for a GIF, it's likely animated because it contains more than one image. You may get false positives, however.
Example use in shell:
for i in *.gif; do
if [ `identify "$i" | wc -l` -gt 1 ] ; then
echo move "$i"
else
echo dont move "$i"
fi
done