MakePlatformBannerImages
Back to ListDescription: Full package for adding plattform banners overlay on product images. Uses ImageMagic
FileMaker Prototype:
Set Variable [$res; ACF_Run("MakePlatformBannerImages"; string_srcImagePath; string_templatesFolder; string_outFolder; string_optionsJSON)]
Category: UTILITY
Function source:
Package ImageManipulation "Functions to manipulate images";
use bootstrap; // GetFileNameFromPath, GetExtentionFromPath
// ==============================
// Helpers (top-level functions)
// ==============================
// filename without extension
function ACF_BaseNameNoExt ( string path ) // -> string
string name = GetFileNameFromPath(path); // e.g. "photo.jpg"
string ext = GetExtentionFromPath(path); // from bootstrap (NOTE: ext from full path)
return substitute(name, "." + ext, "");
end
function GetDirectoriesFromPath2 ( string path )
if (isMac) then
path = substitute ( path, ":", "/");
end if
path = substitute ( path, "\\", "/");
return regex_replace("^(.+)/(.+\..+)$", path, "\1");
end
// parent folder
function ACF_ParentDir ( string path ) // -> string
return GetDirectoriesFromPath2(path);
end
// --- OS helpers ---
// Escaped parentheses for the current shell (needed when we use (...) in IM)
// mac(zsh/bash): \( \) | Windows(cmd.exe): ^( ^)
function ACF_ParenOpenEsc() // -> string
if ( isWindows ) then return "^("; end if
return "\\(";
end
function ACF_ParenCloseEsc() // -> string
if ( isWindows ) then return "^)"; end if
return "\\)";
end
// normalize odd absolute paths on macOS
function ACF_EnsureVolPrefix ( string p ) // -> string
if ( isMac && left(p,1)=="/" && left(p,8)!="/Volumes" && left(p,6)!="/Users" ) then
return "/Volumes" + p;
end if
return p;
end
// ensure directory exists
function ACF_EnsureDir ( string dirPath ) // -> bool
if ( directory_exists(dirPath) ) then return true; end if
string xx = create_directory(dirPath);
return directory_exists(dirPath);
end
// find magick binary; prefer explicit paths, then PATH resolution
function ACF_FindMagickBin () // -> string
if ( isMac ) then
if ( file_exists("/opt/homebrew/bin/magick") ) then return "/opt/homebrew/bin/magick"; end if
if ( file_exists("/usr/local/bin/magick") ) then return "/usr/local/bin/magick"; end if
if ( file_exists("/usr/local/bin/convert") ) then return "/usr/local/bin/convert"; end if
if ( file_exists("/opt/homebrew/bin/convert") ) then return "/opt/homebrew/bin/convert"; end if
// final fallback — rely on PATH
return "magick";
end if
// Windows: ImageMagick usually adds magick.exe to PATH
return "magick";
end
// Build an ImageMagick command for compositing with gravity/offset/resize/rotate
function ACF_BuildCompositeCmd (
string exe, string src, string overlay, string out,
string gravity, int dx, int dy, string resize, int rotate
) // -> string
// Geometry offset (inset from chosen corner)
string geo = "";
if ( dx != 0 || dy != 0 ) then
geo = format(" -geometry +%d+%d", dx, dy);
end if
// Build overlay modifiers (resize and/or rotate)
string mods = "";
if ( resize != "" ) then
mods += format(" -resize %s", resize);
end if
if ( rotate != 0 ) then
mods += format(" -rotate %d", rotate);
end if
// If we have any overlay modifiers, wrap overlay with escaped parentheses for the current shell
string ovl;
if ( mods != "" ) then
string po = ACF_ParenOpenEsc();
string pc = ACF_ParenCloseEsc();
ovl = format(' %s "%s"%s %s ', po, overlay, mods, pc);
else
ovl = format(' "%s" ', overlay);
end if
bool useMagick = (( right(exe, 6) == "magick" ) || ( lower(GetFileNameFromPath(exe)) == "magick.exe" ));
string exeOS = (isWindows?exe+".exe":exe);
if ( useMagick ) then
// IMv7: magick <src> (<overlay mods>) -gravity ... -compose over -composite <out>
return format('"%s" "%s"%s-gravity %s%s -compose over -composite "%s"',
exeOS, src, ovl, gravity, geo, out);
end if
// Legacy convert fallback
return format('"%s" "%s"%s-gravity %s%s -compose over -composite "%s"',
exeOS, src, ovl, gravity, geo, out);
end
// Convenience: build options JSON as text
function MakeBannerOptionJSON (string resize, string dx, string dy, string gravity)
if (dx == "") then dx = "0"; end if
if (dy == "") then dy = "0"; end if
if (gravity == "") then gravity = "northeast"; end if
return string(JSON ("resize", resize, "dx", dx, "dy", dy, "gravity", gravity));
end
// ==============================
// Main
// ==============================
//
// MakePlatformBannerImages (with options)
// Params:
// 1) srcImagePath (required)
// 2) templatesFolder (optional) default: <src dir>/templates
// 3) outFolder (optional) default: <src dir>
// 4) options JSON (optional) keys: gravity, dx, dy, resize
//
// Returns JSON: { ok, message, tool, outputs:{win,mac,macwin}, used:{gravity,dx,dy,resize}, cmdOutput:{r1,r2,r3} }
//
function MakePlatformBannerImages ( string srcImagePath, string templatesFolder, string outFolder, string optionsJSON )
bool haveOptions = false;
JSON optionsJS;
if ( left(optionsJSON,1) == "{" ) then
optionsJS = optionsJSON;
haveOptions = true;
end if
if ( srcImagePath == "" ) then
return JSON ( "ok", false, "message", "Missing srcImagePath" );
end if
// Normalize mac paths only on macOS
if ( isMac ) then
srcImagePath = ACF_EnsureVolPrefix(srcImagePath);
end if
if ( !file_exists(srcImagePath) ) then
return JSON ( "ok", false, "message", "Source image not found", "path", srcImagePath );
end if
// Default folders
if ( templatesFolder == "" ) then
templatesFolder = ACF_ParentDir(srcImagePath) + "/templates";
end if
if ( isMac ) then templatesFolder = ACF_EnsureVolPrefix(templatesFolder); end if
if ( outFolder == "" ) then
outFolder = ACF_ParentDir(srcImagePath);
end if
if ( isMac ) then outFolder = ACF_EnsureVolPrefix(outFolder); end if
if ( !ACF_EnsureDir(outFolder) ) then
return JSON ( "ok", false, "message", "Failed to create output folder", "outFolder", outFolder );
end if
// Options with sane defaults
string gravity = "northeast";
int dx = 0;
int dy = 0;
string resize = "";
if ( haveOptions ) then
string gr = optionsJS["gravity"];
string sdx = optionsJS["dx"];
string sdy = optionsJS["dy"];
string srs = optionsJS["resize"];
if ( gr != "?" ) then gravity = lower(gr); end if
if ( sdx != "?" ) then dx = int(sdx); end if
if ( sdy != "?" ) then dy = int(sdy); end if
if ( srs != "?" ) then resize = srs; end if
end if
// Clamp gravity to allowed set
if ( pos("|northwest|northeast|southwest|southeast|center|", "|" + gravity + "|") < 0 ) then
gravity = "northeast";
end if
// Template files + rotate per corner family
string tWin, tMac, tMacWin;
int rotate = 0;
case
:(gravity == "northeast")
tWin = templatesFolder + "/banner-win.png";
tMac = templatesFolder + "/banner-mac.png";
tMacWin = templatesFolder + "/banner-macwin.png";
:((gravity == "southwest"))
tWin = templatesFolder + "/sw/banner-win.png";
tMac = templatesFolder + "/sw/banner-mac.png";
tMacWin = templatesFolder + "/sw/banner-macwin.png";
:(gravity == "northwest")
tWin = templatesFolder + "/banner-win.png";
tMac = templatesFolder + "/banner-mac.png";
tMacWin = templatesFolder + "/banner-macwin.png";
rotate = -90;
:((gravity == "southeast"))
tWin = templatesFolder + "/sw/banner-win.png";
tMac = templatesFolder + "/sw/banner-mac.png";
tMacWin = templatesFolder + "/sw/banner-macwin.png";
rotate = -90;
default // "center" or any other, fall back to NE set
tWin = templatesFolder + "/banner-win.png";
tMac = templatesFolder + "/banner-mac.png";
tMacWin = templatesFolder + "/banner-macwin.png";
end case
if ( !file_exists(tWin) || !file_exists(tMac) || !file_exists(tMacWin) ) then
return JSON (
"ok", false,
"message", "Missing one or more template files (banner-win.png, banner-mac.png, banner-macwin.png)",
"templatesFolder", templatesFolder
);
end if
// Locate ImageMagick
string magickBin = ACF_FindMagickBin();
if ( magickBin == "" ) then
return JSON ( "ok", false, "message", "ImageMagick not found. Install ImageMagick 7 and ensure 'magick' is on PATH." );
end if
// Outputs (PNG)
string stem = ACF_BaseNameNoExt(srcImagePath);
string outWin = outFolder + "/" + stem + "-win.png";
string outMac = outFolder + "/" + stem + "-mac.png";
string outMacWin = outFolder + "/" + stem + "-macwin.png";
// Build commands (with options)
string cmd1 = ACF_BuildCompositeCmd(magickBin, srcImagePath, tWin, outWin, gravity, dx, dy, resize, rotate);
string cmd2 = ACF_BuildCompositeCmd(magickBin, srcImagePath, tMac, outMac, gravity, dx, dy, resize, rotate);
string cmd3 = ACF_BuildCompositeCmd(magickBin, srcImagePath, tMacWin, outMacWin, gravity, dx, dy, resize, rotate);
// Execute (echo commands for easy debugging if you capture stdout)
string r1 = SystemCommand("echo " + cmd1 + " && " + cmd1);
string r2 = SystemCommand("echo " + cmd2 + " && " + cmd2);
string r3 = SystemCommand("echo " + cmd3 + " && " + cmd3);
// Validate outputs
if ( !file_exists(outWin) || !file_exists(outMac) || !file_exists(outMacWin) ) then
string failMsg = "Composite failed. Verify ImageMagick install, template sizes/alpha, and write permissions.";
return JSON (
"ok", false,
"message", failMsg,
"tool", ( right(magickBin,6) == "magick" ? "magick" : "convert" ),
"debug", cmd1 + "\n" + cmd2 + "\n" + cmd3
);
end if
return JSON (
"ok", true,
"message", "3 images written",
"tool", ( right(magickBin,6) == "magick" ? "magick" : "convert" ),
"outputs", JSON(
"win", outWin,
"mac", outMac,
"macwin", outMacWin
),
"used", JSON(
"gravity", gravity,
"dx", dx,
"dy", dy,
"resize", resize
),
"cmdOutput", JSON ("r1", r1, "r2", r2, "r3", r3)
);
end
The MakePlatformBannerImages Function
Example
Set Variable [$res; ACF_Run("MakePlatformBannerImages"; string_srcImagePath; string_templatesFolder; string_outFolder; string_optionsJSON)]
See the linkedin Article to explanation on use.

