├── Convert Video to GIF App Custom.zip ├── Convert Video to GIF App.zip ├── Convert Video to GIF.zip ├── LICENSE ├── README.md ├── tests ├── expected_result.txt ├── test.sh └── test_video.mov └── video_to_gif_osx.sh /Convert Video to GIF App Custom.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minimaxir/video-to-gif-osx/88593fbec3e20d33a0ca3d8e8fb58dffeff14366/Convert Video to GIF App Custom.zip -------------------------------------------------------------------------------- /Convert Video to GIF App.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minimaxir/video-to-gif-osx/88593fbec3e20d33a0ca3d8e8fb58dffeff14366/Convert Video to GIF App.zip -------------------------------------------------------------------------------- /Convert Video to GIF.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minimaxir/video-to-gif-osx/88593fbec3e20d33a0ca3d8e8fb58dffeff14366/Convert Video to GIF.zip -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Max Woolf 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Convert Video to GIF on OSX 2 | 3 | This repository contains a set of utilities that allow the user to easily convert video files to high-quality, low file size GIFs on OS X. This post is a complement to my blog post [Making a Video-to-GIF Right-Click Menu Item in OS X](http://minimaxir.com/2015/08/gif-to-video-osx/) 4 | 5 | ![](http://minimaxir.com/img/video-to-gif-osx/convert_to_gif.gif) 6 | 7 | The primary intent for this tool is used with Quicktime Movie files obtained from using the Screen Recording feature on OS X or iOS input. 8 | 9 | The tool comes in three forms, depending on user needs: 10 | 11 | * **[Convert Video to GIF](https://github.com/minimaxir/video-to-gif-osx/raw/master/Convert%20Video%20to%20GIF.zip)** - A OS X Service which adds a "Convert Video to GIF" right-click menu item to all video files, which outputs a GIF of the video in the same folder of the source(s). (file must be unzipped on desktop) 12 | * **[video_to_gif_osx.sh](https://raw.githubusercontent.com/minimaxir/video-to-gif-osx/master/video_to_gif_osx.sh)** - A Shell script which accepts video(s) as parameter(s) and outputs a GIF of the video in the same folder of the source(s). 13 | * **[Convert Video to GIF App](https://github.com/minimaxir/video-to-gif-osx/raw/master/Convert%20Video%20to%20GIF%20App.zip)** - An Application which prompts the user for video(s) and outputs a GIF of the video in the same folder of the source(s). (file must be unzipped on desktop; when prompted for security warning go to "Security and Privacy" in System Preference and allow Convert Video to GIF App to run) 14 | 15 | There is also a special fourth tool, [Convert Video to GIF App Custom](https://github.com/minimaxir/video-to-gif-osx/raw/master/Convert%20Video%20to%20GIF%20App%20Custom.zip) app, which is less streamlined but also allows you to specify a custom start time, end time, maximum width, frame rate, and # of colors. For example, here's a GIF of [Freedom Planet](https://en.wikipedia.org/wiki/Freedom_Planet) from a test video of 2:00 to 2:05, a max width of 640px, and 4 colors: 16 | 17 | ![](http://i.imgur.com/ZSY6RM7.gif) 18 | 19 | ## Installation 20 | 21 | *Note: Installation may have issues depending on system config, particularly step #2. If you run into issues, let me know.* 22 | 23 | 1. Open up Terminal and install [Homebrew](http://brew.sh) by running this command and following the instructions: 24 | 25 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 26 | 27 | 2. Install the three GIF-making applications using this Homebrew command: 28 | 29 | brew install ImageMagick mplayer gifsicle 30 | 31 | 3. Download the tool of choice. To install the Convert Video to GIF Service, download and double-click. 32 | 33 | ## Tests 34 | 35 | When running into the script, you may run into an issue where the .GIF is generated, but the file size is zero bytes. That means the script errored out at some point except the "create a GIF" line. 36 | 37 | The `tests` folder contains a basic test case to debug the script. To activate the test, `cd` into the folder and run: 38 | 39 | sh test.sh test_video.mov 40 | 41 | This outputs a `test_results.txt` in addition to the test GIF. If `test_results.txt` matches `expected_results.txt`, you should be good to go. If there is a discrepency, send me the output of `test_results.txt`. 42 | 43 | ## Notes 44 | 45 | All forms have a max GIF width of 480px; this is a value chosen to both manage file size and compatability with all applications. If you wish to create larger GIFs, open up the tool and change the value of `GIF_MAX_SIZE` at the beginning of the file. 46 | 47 | ## Known Issues 48 | 49 | * If the video has unusual dimensions (e.g. 7.00 aspect ratio), the GIF output will not be resized correctly. (in fairness, you probably do not want a GIF with an unusual aspect ratio) 50 | * If the video file or the parent directory has spaces, the tool may throw errors. 51 | * Convert Video to GIF Custom has no sanity check for input validation yet. (e.g. don't increase the frame rate beyond 60fps or bad things happen). If you encounter any issues *specific to the Custom app*, let me know. 52 | 53 | ## Maintainer 54 | * Max Woolf [(@minimaxir)](http://minimaxir.com) 55 | -------------------------------------------------------------------------------- /tests/expected_result.txt: -------------------------------------------------------------------------------- 1 | Programs installed: 2 | mplayer 1.1.1 3 | ImageMagick 6.8.9-8 4 | gifsicle 1.86 5 | 6 | Path: test_video.mov 7 | Directory: . 8 | File Name: test_video.mov 9 | 10 | Video Width: 1216 11 | Video Height: 908 12 | Aspect Ratio: 1.33921 13 | 14 | Final Width: 480 15 | Final Height: 358 16 | 17 | mplayer number of video frames: 432. 18 | 19 | ImageMagick convert file size: 111354 .temp.gif 20 | 21 | gifsicle optimization file size: 73553 test_video.gif 22 | 23 | -------------------------------------------------------------------------------- /tests/test.sh: -------------------------------------------------------------------------------- 1 | rm test_result.txt 2 | touch test_result.txt 3 | 4 | echo "Programs installed:" >> test_result.txt 5 | /usr/local/bin/brew ls --versions mplayer ImageMagick gifsicle >> test_result.txt 6 | 7 | touch ~/.bash_profile 8 | source ~/.bash_profile 9 | 10 | for f 11 | do 12 | # Change this value to increase maximum size 13 | GIF_MAX_SIZE=480 14 | 15 | echo "\nPath: $f" >> test_result.txt 16 | 17 | dir="$(dirname "$f")" 18 | echo "Directory: $dir" >> test_result.txt 19 | 20 | name="$(basename "$f")" 21 | echo "File Name: $name\n" >> test_result.txt 22 | 23 | 24 | cd "$dir" 25 | 26 | video_properties=$(/usr/local/bin/mplayer -really-quiet -ao null -vo null -identify -frames 0 "$f") 27 | #echo "Parsed Video Properties.\n" >> test_result.txt 28 | 29 | video_width=$(echo $video_properties | sed -e 's/.*\ID_VIDEO_WIDTH=\([0-9]*\).*/\1/') 30 | video_height=$(echo $video_properties | sed -e 's/.*\ID_VIDEO_HEIGHT=\([0-9]*\).*/\1/') 31 | aspect_ratio=$(echo "$video_width $video_height" | awk '{printf "%.5f", $1/$2}') 32 | 33 | echo "Video Width: $video_width" >> test_result.txt 34 | echo "Video Height: $video_height" >> test_result.txt 35 | echo "Aspect Ratio: $aspect_ratio\n" >> test_result.txt 36 | 37 | # shrink larger dimension to GIF_MAX_SIZE; 38 | if [ $video_height -lt $video_width ] 39 | then 40 | final_width=$GIF_MAX_SIZE 41 | final_height=$(echo "$final_width $aspect_ratio" | awk '{printf "%3.0f", $1/$2}') 42 | else 43 | final_height=$GIF_MAX_SIZE 44 | final_width=$(echo "$final_height $aspect_ratio" | awk '{printf "%3.0f", $1/(1/$2)}') 45 | fi 46 | 47 | echo "Final Width: $final_width" >> test_result.txt 48 | echo "Final Height: $final_height\n" >> test_result.txt 49 | 50 | # Don't change dimensions if both are below GIF_MAX_SIZE 51 | if [$video_width -lt $GIF_MAX_SIZE] && [$video_height -lt $GIF_MAX_SIZE] 52 | then 53 | final_width=$video_width 54 | final_height=$video_height 55 | fi 56 | 57 | /usr/local/bin/mplayer -ao null -vo png:z=1:outdir=.temp -vf scale=$final_width:$final_height "$f" 58 | 59 | num_renders=$(ls -l .temp | wc -l) 60 | #echo "mplayer renders successful." >> test_result.txt 61 | echo "mplayer number of video frames: $num_renders.\n" >> test_result.txt 62 | 63 | /usr/local/bin/convert +repage -fuzz 1.6% -delay 1.7 -loop 0 .temp/*.png -layers OptimizePlus -layers OptimizeTransparency .temp.gif 64 | 65 | file_size_imagemagick=$(wc -c .temp.gif) 66 | #echo "ImageMagick convert successful." >> test_result.txt 67 | echo "ImageMagick convert file size: $file_size_imagemagick\n" >> test_result.txt 68 | 69 | /usr/local/bin/gifsicle -O3 --colors 256 .temp.gif > "${name%.*}.gif" 70 | 71 | file_size_gifsicle=$(wc -c "${name%.*}.gif") 72 | #echo "gifsicle optimization successful." >> test_result.txt 73 | echo "gifsicle optimization file size: $file_size_gifsicle\n" >> test_result.txt 74 | 75 | # Cleanup 76 | rm -rf .temp 77 | rm -rf .temp.gif 78 | 79 | done -------------------------------------------------------------------------------- /tests/test_video.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minimaxir/video-to-gif-osx/88593fbec3e20d33a0ca3d8e8fb58dffeff14366/tests/test_video.mov -------------------------------------------------------------------------------- /video_to_gif_osx.sh: -------------------------------------------------------------------------------- 1 | for f 2 | do 3 | 4 | # Change this value to increase maximum size 5 | GIF_MAX_SIZE=480 6 | 7 | dir="$(dirname "$f")" 8 | name="$(basename "$f")" 9 | 10 | cd "$dir" 11 | 12 | video_properties=$(/usr/local/bin/mplayer -really-quiet -ao null -vo null -identify -frames 0 "$f") 13 | 14 | video_width=$(echo $video_properties | sed -e 's/.*\ID_VIDEO_WIDTH=\([0-9]*\).*/\1/') 15 | video_height=$(echo $video_properties | sed -e 's/.*\ID_VIDEO_HEIGHT=\([0-9]*\).*/\1/') 16 | aspect_ratio=$(echo "$video_width $video_height" | awk '{printf "%.5f", $1/$2}') 17 | 18 | # shrink larger dimension to GIF_MAX_SIZE; 19 | if [ $video_height -lt $video_width ] 20 | then 21 | final_width=$GIF_MAX_SIZE 22 | final_height=$(echo "$final_width $aspect_ratio" | awk '{printf "%3.0f", $1/$2}') 23 | else 24 | final_height=$GIF_MAX_SIZE 25 | final_width=$(echo "$final_height $aspect_ratio" | awk '{printf "%3.0f", $1/(1/$2)}') 26 | fi 27 | 28 | # Don't change dimensions if both are below GIF_MAX_SIZE 29 | if [$video_width -lt $GIF_MAX_SIZE] && [$video_height -lt $GIF_MAX_SIZE] 30 | then 31 | final_width=$video_width 32 | final_height=$video_height 33 | fi 34 | 35 | /usr/local/bin/mplayer -ao null -vo png:z=1:outdir=.temp -vf scale=$final_width:$final_height "$f" 36 | 37 | /usr/local/bin/convert +repage -fuzz 1.6% -delay 1.7 -loop 0 .temp/*.png -layers OptimizePlus -layers OptimizeTransparency .temp.gif 38 | 39 | /usr/local/bin/gifsicle -O3 --colors 256 .temp.gif > "${name%.*}.gif" 40 | 41 | # Cleanup 42 | rm -rf .temp 43 | rm -rf .temp.gif 44 | 45 | done --------------------------------------------------------------------------------