Fill a region of an image using AppleScript

Discuss Pixelmator Pro tutorials and share useful resources.
User avatar

2021-02-09 20:50:14

I have modest experience with Pixelmator and with AppleScript, but not together. In ApplesScript, I would like to:

1. Open an existing image file (most likely a PNG file).
2. Move to a specific location on that image
3. Color fill the contiguous area at that location with some tolerance (range).
4. Close and save the image

I have managed to get this far:
tell application "Pixelmator Pro"

	set brainRegions to open file ((path to desktop as text) & "Cortical_Areas.png")
	tell brainRegions
		set {644, 377} to position of layer named "Background Layer"
		select color range color {44799, 43263, 29951} range 30
		fill layer named "Background Layer" with color {0, 0, 50000, 32768} with preserve transparency
	end tell
	export brainRegions to file ((path to desktop as text) & "Cortical_Areas_Colored.png") as PNG
        quit saving yes
end tell
However, select color range selects all areas of a specified color match. I only want to fill the region "around" a defined point that has contiguous color matching. Any help would be greatly appreciated! Thanks!

Using Pixelmator Pro V2.0.5
User avatar

2021-02-10 16:23:19

Hi Peter, Select Color Range currently selects non-contiguously, so this is tricky – there's no built-in way to do it just using just Pixelmator Pro terms. However, using a combination of AppleScript and a Python shell script (cheers to the folks on the MacScripter forum for that), I was able to whip something up. Here's the script:
tell application "Pixelmator Pro"
	tell the front document
		tell application "System Events" to tell process "Pixelmator Pro"
			click menu item "Color Selection" of menu of menu item "Select" of menu "Tools" of menu bar item "Tools" of menu bar 1
		end tell
		my mouseDrag(600, 600, 600, 620, 0)
	end tell
end tell

on mouseDrag(xDown, yDown, xUp, yUp, delayTime)
	-- delayTime because the drag may fail if the UI isn't fast enough without a delay. For what I do, .1 works.
	do shell script "
/usr/bin/python <<END

from Quartz.CoreGraphics import CGEventCreateMouseEvent
from Quartz.CoreGraphics import CGEventCreate
from Quartz.CoreGraphics import CGEventPost
from Quartz.CoreGraphics import kCGEventLeftMouseDown
from Quartz.CoreGraphics import kCGEventLeftMouseUp
from Quartz.CoreGraphics import kCGMouseButtonLeft
from Quartz.CoreGraphics import kCGHIDEventTap
from Quartz.CoreGraphics import kCGEventLeftMouseDragged
import time

def mouseEvent(type, posx, posy):

          theEvent = CGEventCreateMouseEvent(None, type, (posx,posy), kCGMouseButtonLeft)

          CGEventPost(kCGHIDEventTap, theEvent)

def mousemove(posx,posy):

          mouseEvent(kCGEventMouseMoved, posx,posy);

def mousedrag(posx,posy):

          mouseEvent(kCGEventLeftMouseDragged, posx,posy);

def mousedown(posxdown,posydown):

          mouseEvent(kCGEventLeftMouseDown, posxdown,posydown);

def mouseup(posxup,posyup):

      mouseEvent(kCGEventLeftMouseUp, posxup,posyup);

ourEvent = CGEventCreate(None);

mousedown(" & xDown & "," & yDown & ");
time.sleep(" & (delayTime as text) & ");
mousedrag(" & xUp & "," & yUp & ");
time.sleep(" & (delayTime as text) & ");
mouseup(" & xUp & "," & yUp & ");

end mouseDrag
The fifth item in the handle is a delay which I've set to 0, it looks like decimal values don't work, but I have to admit I don't know why. I guess it might be tricky to select the right area (because these coordinates are global to your screen and not local to the document) and getting the right amount of tolerance might also require some thinking, but whatever you need to do should be doable.

Hope that helps!
User avatar

2021-02-10 20:01:26

Thanks very much!! Unfortunately, I cannot not reply on Python being available (long story). I guess that I will just have to write this functionality in my app. But again thanks for the reply.