--!parent
-- ************************************************************************
-- Animated GIF Encoder
--
-- @author Valentin Schmidt
-- @version 0.2
-- @requires xtra "ImgXtra", xtra "Shell", convert.exe (ImageMagick)
-- ************************************************************************
property _ix
property _sx
property _tmp_dir
property _tmp_name
property _tmp_type
property _params
property _num_frames
property _palette_colors
-- constants for dispose_op parameter
property DISPOSE_OP_NONE
property DISPOSE_OP_BACKGROUND
property DISPOSE_OP_PREVIOUS
----------------------------------------
-- @constructor
----------------------------------------
on new (me)
me._ix = xtra("ImgXtra").new()
me._sx = xtra("Shell").new()
me._tmp_dir = me._sx.shell_getEnvVar("TMP")
me._tmp_type = ".png" -- BMP is faster, but doesn't support transparency
-- no disposal is done on this frame before rendering the next; the contents
-- of the output buffer are left as is.
me.DISPOSE_OP_NONE = 1
-- the frame's region of the output buffer is to be cleared to fully
-- transparent black before rendering the next frame.
me.DISPOSE_OP_BACKGROUND = 2
-- the frame's region of the output buffer is to be reverted to the previous
-- contents before rendering the next frame.
me.DISPOSE_OP_PREVIOUS = 3
return me
end
----------------------------------------
-- Utility function: pass a "typical" image for the animation; returns a palette as list of colors
-- @param {image} master_image
-- @param {integer} [palette_size=256]
-- @return {list|FALSE}
----------------------------------------
on findPalette (me, master_image, palette_size)
props = [:]
props["image"] = master_image
if integerP(palette_size) then props["palette_size"] = palette_size
img = me._ix.ix_quantizeImage(props)
if ilk(img)<>#image then return FALSE
palette_colors = me._ix.ix_getPaletteColors(["palette":img.paletteRef])
img.paletteRef.erase()
return palette_colors
end
----------------------------------------
-- Starts a new animated GIF
-- @param {list} palette_colors
-- @param {integer} [num_plays=0] - how often to loop, 0 means endless looping (default)
----------------------------------------
on init (me, palette_colors, num_plays)
if voidP(num_plays) then num_plays = 0
me._palette_colors = palette_colors
me._params = "-loop " & num_plays & " "
me._tmp_name = random(9999) & "_"
me._num_frames = 0
end
----------------------------------------
-- Adds new frame
-- @param {image} frame_image - the frame as Lingo image object
-- @param {integer} ms - duration of the frame in milliseconds
-- @param {integer} [x=0] - x-offset of the image
-- @param {integer} [y=0] - y-offset of the image
-- @param {integer} [dispose_op=1] - how frame is disposed, see comments above
-- @param {integer} [trans] - index of transparency in palette color list
-- @return {bool} success
----------------------------------------
on addFrame (me, frame_image, ms, x, y, dispose_op, trans)
if voidP(x) then x = 0
if voidP(y) then y = 0
-- map to color palette
props = [:]
props["image"] = frame_image
props["reserved_colors"] = me._palette_colors
frame_image_indexed = me._ix.ix_quantizeImage(props)
-- export image as temporary image file in TMP dir
fn = me._tmp_name & me._num_frames & me._tmp_type
props = [:]
props["image"] = frame_image_indexed
props["filename"] = me._tmp_dir & "\" & fn
props["palette"] = me._palette_colors
if not voidP(trans) then props["transparency"] = 256 - trans -- fix in ImgXtra ???
ok = me._ix.ix_saveImage(props)
if not ok then return FALSE
put "-delay "&integer(ms/10)&" " after _params
if not voidP(dispose_op) then put "-dispose " & dispose_op & " " after _params
if x>0 or y>0 then
put "-page +" & x & "+" & y & " " after _params
end if
put fn & " " after _params
me._num_frames = me._num_frames + 1
return TRUE
end
----------------------------------------
-- Saves animation as GIF file
-- @param {string} gif_file
-- @return {bool} success
----------------------------------------
on writeFile (me, gif_file)
me._sx.shell_setCurrentDir(me._tmp_dir)
-- run convert.exe
props = [:]
props["show_cmd"] = 0
props["wait"] = 1
props["parameters"] = me._params & QUOTE & gif_file & QUOTE
exit_code = me._sx.shell_execex(the moviePath & "bin\convert.exe", props)
ok = (exit_code=0)
-- delete temporary files
cmd = "del /Q " & QUOTE & "%TMP%\" & me._tmp_name & "*" & me._tmp_type & QUOTE
me._sx.shell_cmd(cmd)
return ok
end