transform png images to gif

The bash shell command Sips supports gif, but i’ve no idea how to create a working gif from a series of png images, using only bash shell scripting or ASObjC

I checked online for solutions but did not find anything useful. Simple image conversions don’t do the trick, as a gif is a short animation and not only a single still image.

Here is a script grabbed on the web years ago

-- Created 2015-08-05  by Takaaki Naganoya
-- Modified 2015-08-06  by Shane Stanley
-- 2015 Piyomaru Software

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set targFormat to "gif" -- was "pdf"
set aImage to choose file of type {"public.image"} with prompt ("Choose image file to convert to " & targFormat & ".")
set aRes to convertImageToANY(aImage, targFormat) of me
--> "/Users/me/Desktop/301b3607.pdf"
--> "/Users/me/Desktop/301b3607_1.pdf" (同一ファイルの変換を2度行った結果、子番号を付与して衝突を回避, 

--指定の画像をsipsで別形式に変換する
on convertImageToANY(aImage as alias, outFormat as text)
	
	set aExt to chkExtension(outFormat) of me
	if aExt = false then return false
	
	tell application "Finder"
		set bExt to name extension of aImage
	end tell
	--指定画像と変換後の画像フォーマットが同じだった
	set bExt to chkExtension(bExt) of me
	if aExt = bExt then return "There is no need to convert (same format)"
	if bExt = false then return false --出力ファイルフォーマットエラ
	
	--変換後のファイル名として、オリジナルの拡張子を新規拡張子に付け替え
	set bImagePosix to POSIX path of aImage
	set bPathString to current application's NSString's stringWithString:bImagePosix
	set newPath to ((bPathString's stringByDeletingPathExtension()) as text) & "." & aExt
	
	--新規ファイル作成時にファイルの重複があるかチェック。存在する場合にはファイル名に子番号を付与して重複を回避する
	set newPath to chkExistAndAddIncrementalChildNumber(newPath)
	
	set sText to "sips -s format " & aExt & " " & quoted form of POSIX path of aImage & " --out " & quoted form of newPath
	
	try
		do shell script sText
	on error erM
		return false --shell scriptの実行時にエラーが発生した
	end try
	
	return newPath
	
end convertImageToANY


--複数表記形式のファイル名拡張子のチェックおよびsipsが受付可能なものに変換
on chkExtension(aExtension)
	set formatList to {{"jpeg", "jpg"}, {"tiff", "tif"}, {"png"}, {"gif", "giff"}, {"jp2"}, {"pict"}, {"bmp"}, {"qtif"}, {"psd"}, {"sgi"}, {"tga"}, {"pdf"}}
	set hitF to false
	
	ignoring case
		repeat with i in formatList
			set j to contents of i
			if aExtension is in j then
				set aExt to contents of first item of j
				set hitF to true
				exit repeat
			end if
		end repeat
	end ignoring
	
	if hitF = false then
		return false --No Hit	
	else
		return aExt --Hit
	end if
	
end chkExtension


--連番の追加によるファイル名の重複回避
on chkExistAndAddIncrementalChildNumber(aa)
	set aStr to current application's NSString's stringWithString:aa
	
	--ファイルパス(フルパス)からファイル名部分を取得
	set bStr to aStr's lastPathComponent()
	--ファイル名から拡張子を取得
	set cStr to (bStr's pathExtension()) as text
	--ファイル名から拡張子を削除
	set dStr to (bStr's stringByDeletingPathExtension()) as text
	--ファイルパス(フルパス)から親フォルダを取得(ただし末尾はスラッシュになっていない
	set eStr to (aStr's stringByDeletingLastPathComponent()) as text
	set aManager to current application's NSFileManager's defaultManager()
	set aRes to (aManager's fileExistsAtPath:aStr) as boolean
	if aRes = false then return aa --重複がない場合、与えられたフルパスをそのまま返す
	
	
	--ファイル名の重複があった場合の重複回避処理	
	set hitF to false
	repeat with i from 1 to 65535
		
		set tmpPath to (eStr & "/" & dStr & "_" & (i as text) & "." & cStr)
		set tmpStr to (current application's NSString's stringWithString:tmpPath)
		set aRes to (aManager's fileExistsAtPath:tmpStr) as boolean
		
		if aRes = false then
			set hitF to true
			exit repeat
		end if
		
	end repeat
	
	if hitF = false then return false --65,535回繰り返したがファイル名の衝突を回避できなかった、など
	
	return tmpStr as text
	
end chkExistAndAddIncrementalChildNumber

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) samedi 27 juin 2020 16:40:25

I don’t think there’s any scripting way of producing animated gifs, other than scripting some app that produces them.

@Shane Stanley
That’s a pity, and sounds definitive.
I read Takaaki’s code moments ago, it converts single images only
Thanks for clarifying

@Yvan
Thanks nevertheless

You can generate animation gif by using convert comannd a part of Image Magic.

https://askubuntu.com/questions/648244/how-do-i-create-an-animated-gif-from-still-images-preferably-with-the-command-l

Cocoa seems not to supply animation gif generation method.

Some Objective-C projects are seen on Github.

I tried Maro’s suggestion of Image Magick and it works well. I have Image Magick installed using Homebrew. The below example works for a sequence of numbered tifs (“testgif” folder on external disk “HD1”, files named “testgif001.tif”, “testgif002.tif” etc.) but should automatically work using png files.

Here is the shell command in Terminal:

 convert -delay 20 -loop 0 '/Volumes/HD1/testgif/testgif*.tif' '/Volumes/HD1/testgif.gif'

which can be used in a “do shell script” command in Applescript.

More info: http://www.imagemagick.org/Usage/anim_basics/

Browser: Safari 605.1.15
Operating System: macOS 10.14

– So I got interested in making an animated gif palindrome. The result is this script, which I’m sure someone could improve.


-- Example to make an animated gif palindrome
-- kerflooey 20200701a
-- requires homebrew installation of imagemagick
-- "palindrome:" is a disk image volume
-- my image sequence was exported from QT Player 7 as .jpgs

-------------------------------------------------------- set up
set gif_frames_in_FD to "palindrome:gif_frames_in:" as alias
set gif_frames_out_FD to "palindrome:gif_frames_out:" as alias
set gif_palindromeFP to "/Volumes/palindrome/palindrome.gif" --can change filename after created

-------------------------------------------------------- get the frame files in the folder
set all_Files_List to {}
get_All_Files_of_Folder(gif_frames_in_FD, all_Files_List)

-------------------------------------------------------- get rid of DS_Store invisible file. todo: does not begin with period
set allFPs to {}
repeat with aFile in all_Files_List
	if path of aFile does not contain "DS_Store" then
		set end of allFPs to (path of aFile)
	end if
end repeat
-- now we have all the full paths of the frame files


set part1 to simple_sort(allFPs) -- ensure alphabetical sequence

-------------------------------------------------------- need a new file for each frame going backward, except first and last
set part2 to reverse of items 2 thru -2 of allFPs

set allFPs to (part1 & part2) -- now we have the file sequence list; ready to rename and animate

set countFrames to (count allFPs)

-------------------------------------------------------- build matching list of new filenames
set newNamesList to {}
repeat with i from 1 to countFrames
	set newNamesList to ((newNamesList & ("pal_" & ((1000 + i) as string) & ".jpg")))
end repeat

-------------------------------------------------------- dupe and rename
-------------------------------------------------------- ensure gif_frames_out folder is empty before running script
tell application "Finder"
	repeat with i from 1 to countFrames
		set newFile to duplicate ((item i of allFPs) as «class furl») to gif_frames_out_FD with replacing
		set name of newFile to (item i of newNamesList)
	end repeat
end tell

-------------------------------------------------------- make the gif; Q: Will command path be changed w updates?
do shell script ("/usr/local/Cellar/imagemagick/7.0.10-0/bin/convert" & " " & "-delay 10 -loop 0" & " " & "'/Volumes/palindrome/gif_frames_out/*.jpg'" & " " & gif_palindromeFP)



-------------------------------------------------------- HANDLERS

on get_All_Files_of_Folder(gif_frames_in_FD, all_Files_List)
	tell application "System Events"
		--Check each of the files in this disk/folder
		set files_list to (every file of gif_frames_in_FD)
		repeat with i from 1 to (count files_list)
			set end of all_Files_List to item i of files_list
		end repeat
		set sub_folders_list to folders of gif_frames_in_FD
		repeat with the_sub_folder_ref in sub_folders_list
			my get_All_Files_of_Folder(the_sub_folder_ref, all_Files_List)
		end repeat
	end tell
end get_All_Files_of_Folder

on simple_sort(my_list)
	set the index_list to {}
	set the sorted_list to {}
	repeat (the number of items in my_list) times
		set the low_item to ""
		repeat with i from 1 to (number of items in my_list)
			if i is not in the index_list then
				set this_item to item i of my_list as text
				if the low_item is "" then
					set the low_item to this_item
					set the low_item_index to i
				else if this_item comes before the low_item then
					set the low_item to this_item
					set the low_item_index to i
				end if
			end if
		end repeat
		set the end of sorted_list to the low_item
		set the end of the index_list to the low_item_index
	end repeat
	return the sorted_list
end simple_sort


Browser: Safari 605.1.15
Operating System: macOS 10.14