How to remove alpha from bulk images with AppleScript - bash

I have a bulk amount of images, of which i need to remove alpha from each. This is doable from Preview application, but the sheer amount of times i would need to repeat that is way too time consuming.
I have heard about AppleScript and made some feeble attempts at automating the process, currently to no avail.
i am using something like this and then starting a repeat, but it only allows me to loop through one direct folder (also i'm having troubles with menu bar items)
set fl to files of folder POSIX file "/Users/user/Documents/" as alias list
But i have multiple folders within folders which i wish to change an amount of images. the folder structure is like this:
Users/user/folder/ImagesRoot/
in inside ImagesRoot are 3 folders and one txt file. I want to specifically select 2 of the folders called "Icons" and "Screenshots". In "Icons" is 5 images. However "Screenshots" contains 3 subfolders, each with their own 5 images. (can be referred to as "Screensub 1,2,3")
Once receiving the list of images inside such folder, the process would be something like
tell application "Preview"
open the image file
open the file menu
open export...
untick alpha
press save
press replace
close window
end tell
Loop to next one
when looped through all in Icons folder, do all 5 images of each subfolder of screenshot folder
I am told that AppleScript is a good way to do this, but also that bash is a possibility?
However, i have 2% experience with applescript and maybe 4% of bash, and don't know how to approach it.
Any advice or help would be greatly appreciated.
Thanks

As far as I can tell, Preview doesn’t have the ability to change the alpha of a document, even if you enable AppleScripting. In an application that does support it, such as GraphicConverter, this is a fairly simple task:
on open imageFile
tell application "GraphicConverter 9"
open imageFile
tell window 1
set alpha to false
end tell
--save image as needed
end tell
end open
You may find it easier to use Automator. The combination of Get Folder Contents with Repeat for each subfolder found and Alpha Channel set to Remove may be all you need. If you need to exclude some files, Filter Finder Items would do it.
If you want to use Preview, however, you may be able to use System Events. Something like:
on open imageFile
tell application "Preview"
open imageFile
activate
set filename to name of window 1
tell application "System Events"
tell process "Preview"
click menu item "Export…" of menu "File" of menu bar 1
tell sheet 1 of window 1
--rename file
set value of text field 1 to filename & " Alpha Removed"
--uncheck alpha channel
tell checkbox 1 of group 1
click
end tell
--save
click button "Save"
end tell
end tell
end tell
end tell
end open
If you choose the assistive access route, you may find Apple’s help on signing applications useful: http://support.apple.com/kb/HT5914

Related

Applescript - Looping through System Events is killing my Mac

I have a massive spreadsheet with a titanic number of rows/columns (e.g. ~250 columns, many thousands of rows) that I'm trying to convert into PDFs by looping through each row with AppleScript, copying that row's ~250 variables to TextEdit set to Rich Text (for bold formatting etc), and then using System Events to save the txt as a PDF. Here's a summary of the code:
on run
set initialRow to 1
tell application "System Events"
tell application process "TextEdit"
set frontmost to true
end tell
end tell
repeat
tell application "Microsoft Excel"
-- CLEAR MY ~250 VARIABLES FROM PREVIOUS ROW'S VALUES TO MAKE SURE NOTHING IS CARRIED OVER BY MISTAKE
-- THEN SET MY ~250 VARIABLES TO THE NEXT ROW'S VALUES
if exampleValue is "" then exit repeat
end tell
tell application "TextEdit"
set the text of the front document to ""
-- THEN SET FIRST PARAGRAPH TO MY FIRST VARIABLE PLUS A LINE BREAK SO THEN THERE'S A NEW PARAGRAPH FOR THE NEXT VARIABLE, ETC
-- THEN GO THROUGH ALL OF MY VARIABLES TO IMPORT THE IMPORTANT ONES INTO TEXTEDIT, SET SOME FORMATTING, ETC.
end tell
delay 1
tell application "System Events"
click menu item "Export as PDF…" of menu 1 of menu bar item "File" of menu bar 1 of application process "TextEdit"
delay 1
keystroke exampleValue -- SYSTEM EVENTS TYPES THE NAME OF THE PDF
delay 1
key code 36
delay 1
end tell
set myRow to (myRow + 1)
end repeat
end run
This all runs great, no bugs (seemingly!), no issues at all in small doses. The problem, however, is that something happens as the script runs where it seems to be tying up more and more memory somewhere; everything is fine for the first hundred or so rows, but at some point my Mac stops running anything at all, i.e. whether I let the script run until it starts producing super random errors (I could collect them if helpful, but it's like a random different error each time so not much help there) or even if I let the script run for a while and then stop it before it errors out - it will let me stop the script but then I can't actually quit out of Script Editor or TextEdit or Excel, my keyboard stops working, I can't Force Quit anything, can't Reset the computer, etc. It's just a complete meltdown of the machine unlike anything I've encountered, and the only way to get back to work is to force a hard boot with the power button.
I've never had this problem with my other scripts, but I also don't usually use System Events, so my hunch is that it's something to do with that. Do I need to be 'resetting' System Events somehow, or clearing out the memory for some reason, or...? Thanks for the help!!
Figured it out! After trying the script one more time with Activity Monitor running, I discovered that each time it iterates through, 3 new processes were popping up - Core Sync, Dropbox Finder Extension, and SnailSVNLite - and then never going away! So if I ran through the script 500 times, I'd end up with 1500 new processes running, which was almost certainly what was wrecking me though I have no idea why telling System Events anything was doing that. I looked around online, and it turns out those are all Finder Extensions that had been turned on at some point long ago, so just needed to go to System Preferences > Extensions > Added Extensions and then uncheck those 3 extensions - and then problem solved!!

Mac Automator - "Move finder items" using variable

I have a weird issue with mac automator (on Mojave).
What I want: Take a pdf > save each page as png to same folder as pdf
What happens: Takes a pdf > all pngs are saved to desktop
Here is the automator after a test run:
You can see on the screenshot how variable "pdfPath" actually is set correctly to Test folder. But then after moving it does remove the files out of system folder, but not to pdfPath but to Desktop. Important: if I manually pick any folder, it will save it there and not to desktop, so still somehow related to the pdfPath variable?
Anybody an idea why it happens and how to fix?
Automator just gets frustrating like this at times. The Move Finder Items action doesn’t appear to work with variables in this situation, even though you can drag and select them - when using a variable it defaults to the Desktop. As a workaround you can replace the Move Finder Items action with a Get Value of Variable for pdfPath to add it to the input items, then add a Run AppleScript action to do the moving:
on run {input, parameters}
if (count input) < 2 then error "No Items to move.“
set destination to last item of input
tell application "Finder" to move (items 1 thru -2 of input) to destination
end run
You might also have to clean out previous results from the temporary folder to keep the rename action happy.
Ok, I figured it out with some help in the meantime. For anybody coming across and looking for solution, the path I saved in the Applescript part was showing up nicely in the result, but in the end, the path was in the wrong format. Following code works like a charm:
on run {input, parameters}
tell application "Finder" to return POSIX path of (container of (item 1 of input) as alias) as text
end run

AppleScript to download file

I need to write an AppleScript to open Safari and go to https://www.stats.govt.nz/large-datasets/csv-files-for-download/ to download the first csv file
Rather than doing your work for you by providing you with a code snippet to accomplish this task, I will instead provide you with a great resource. Cube MG has a bunch of tutorials that are really helpful for interacting with web page elements via Safari. Check it out here: http://www.cubemg.com/how-to-click-a-button-on-a-web-page-with-applescript/
There are other ways that you could approach something like this such as using the command line but that is a bit more advanced. Check out Cube MG and see what you can learn!
tell application "Safari"
make new document with properties ¬
{URL:"https://www.stats.govt.nz/large-datasets/csv-files-for-download/"}
repeat
if the front document's source contains "What are CSV files?" then ¬
exit repeat
delay 0.5
end repeat
tell the front document to set CSVfiles to ¬
do JavaScript "Array.from(document.links,
x=>x.href)
.filter(x=>x.indexOf('.csv')!=-1);"
end tell
This gets you the links to all the CSV files. To extract the first one, use item 1 of CSVfiles.
NB. Don't forget to enable Allow JavaScript from Apple Events in Developer menu (a hidden menu, made visible through Preferences > Advanced > Show Develop menu in menu bar)

Applescript play music from iTunes URL

The following script will open a track in iTunes
use application "iTunes"
property trackURL : "itmss://itunes.apple.com/us/album/brahms-violin-concerto-in-d-major-op-77-iii-allegro/145533236?i=145533044&uo=4"
open location trackURL
Now, asking "iTunes" to play it does not work because the track is highlighted but not properly selected, i.e., it requires a manual mouse click to select it and play it.
How can I select the highlighted track? Or how could I ask "iTunes" to play the song?! Alternatively, is there a way to add a music to my library from an URL directly?
Disclaimer: I don't have the Apple Music subscription, so the UI on my end may not be exactly the same as yours. However, if I click the "Play" button, I get the little advertisement asking me to sign up for the service, which I assume would just play the music if you had the service. So, these are the steps I've been able to follow to get that box to pop up:
The first, and most convenient from AppleScript, thing to try is just to hit the space bar to start the music playing. This actually works great if I've selected the item manually by clicking on it. However, after open location, it doesn't work, and this appears to be because even though the row is highlighted in the viewer, the actual keyboard focus seems to be on the page itself (the iTunes Store and Apple Music appear to have their entire UI presented as web pages rendered by WebKit). You can verify this by tapping the up and down arrow keys on the keyboard; the page scrolls up and down instead of you switching to adjacent tracks.
My opinion is that this is actually a bug in iTunes; I'd consider the true solution to the problem to be to report this to Apple via the bug reporter. Using open location really should set the keyboard focus to the track you navigated to.
With that said, we can work around it in the short term by simulating a click on the "Play" button. Note that you'll probably need to add your app in System Preferences > Security and Privacy > Accessibility. Note also that this is incredibly fragile, and if Apple ever changes anything in the layout of the web pages they're serving, this whole thing will break. Finally, please note that this code is extremely ugly; the whole thing gives me hives just by looking at it, but it's the only thing I was able to get to work. Side effects of reading this code may include nausea, headaches, and suicidal thoughts. Do not read this code immediately after eating. Consult your doctor before reading this code if you have a history of depression or obsessive-compulsive disorder.
property trackURL : "itmss://itunes.apple.com/us/album/brahms-violin-concerto-in-d-major-op-77-iii-allegro/145533236?i=145533044&uo=4"
property trackTitle : "III. Allegro giocoso, ma non troppo vivace"
tell application "iTunes"
activate
open location trackURL
delay 1 -- give the page a second to load
end tell
tell application "System Events"
tell process "iTunes"
set theRows to the rows of table 1 of UI element 1 of scroll area 1 of group 1 of group 1 of front window
-- "repeat with eachRow in theRows" isn't working. I don't know why. Freaking AppleScript
repeat with i from 1 to the number of theRows
set eachRow to item i of theRows
if exists group 2 of UI element 2 of eachRow then
if value of static text 1 of group 1 of group 2 of UI element 2 of eachRow is trackTitle then
tell group 1 of UI element 2 of eachRow to click
end if
end if
end repeat
end tell
end tell
If Apple ever fixes the bug, of course, we should be able to just:
tell application "iTunes"
activate
open location trackURL
delay 1 -- give the page a second to load
end tell
tell application "System Events" to keystroke space

How to activate full screen apps in background via Apple Script

I've been working on an application in Automator that changes the desktop background to the album art of the current song playing in iTunes.
You can download my first version here.
The most annoying issue I have found is that when there is a full screen app open on the same display being updated, whenever the song changes the background flickers between the current song and the previous.
This is my current code (Updated from version 1.0 above):
You may need to scroll within the code to see all of it.
tell application "System Events"
set fileName to (((path to desktop) as text) & ".iTunesArt2-1.jpg")
set oldFile to open for access file fileName with write permission
write 0 to oldFile
close access oldFile
delete file fileName
if process "iTunes" exists then
tell application "iTunes"
if (player state is not stopped) then
-- get the raw bytes of the artwork into a var
tell application "iTunes" to tell artwork 1 of current track
set srcBytes to raw data
end tell
-- write to file
set outFile to open for access file fileName with write permission
-- truncate the file
set eof outFile to 0
-- write the image bytes to the file
write srcBytes to outFile
close access outFile
end if
end tell
tell desktop 2
set picture to fileName
end tell
end if
set fileName to (((path to desktop) as text) & ".iTunesArt2-2.jpg")
set oldFile to open for access file fileName with write permission
write 0 to oldFile
close access oldFile
delete file fileName
if process "iTunes" exists then
tell application "iTunes"
if (player state is not stopped) then
-- get the raw bytes of the artwork into a var
tell application "iTunes" to tell artwork 1 of current track
set srcBytes to raw data
end tell
-- write to file
set outFile to open for access file fileName with write permission
-- truncate the file
set eof outFile to 0
-- write the image bytes to the file
write srcBytes to outFile
close access outFile
end if
end tell
tell desktop 2
set picture to fileName
end tell
end if
end tell
I got the actual code that saves the artwork to a file from here.
The desktop will not update unless you give it a new file name to update, therefore I have duplicated the process with "iTunesArt2-1" and "iTunesArt2-1".
The first 2 in '2-1' or '2-2' simply means the second desktop, as I have two different applications to change each desktop, and use my 2nd desktop for testing.
The entire application is set to loop for 1000 years, using three separate Loop functions in Automator (720 minutes, 730 times & 1000 times).
When first trying to debug this issue, the process was duplicated into four separate scripts, one for saving the image, then setting as background, and two more scripts to repeat the process with a new file name.
Here's an example of my debugging:
I remove the opening period from ".iTunesArt##.jpg" so that I can see the files on my desktop.
I play a Coldplay song and run the application in Automator to set the background.
"iTunesArt2-1.jpg" and "iTunesArt2-2.jpg" are shown on my desktop with the correct album art.
I stop the application, and play a Paramore song.
I run the first script of the application (Saves the album art).
"iTunesArt2-1.jpg" is updated to the Paramore artwork.
I run the second script of the application (Sets background image).
Note, this script should be setting the background to the Paramore image.
The background remains set to the Coldplay image.
At first I think this is only because the background image was already set to "iTunesArt2-1.jpg", and therefore the system will not try to update it again, not knowing the data in the file has been changed.
So I run the next script which should force the background to update:
I run the third script in the application.
"iTunesArt2-2.jpg" is updated to the Paramore artwork.
I run the forth script in the application.
The desktop background is updated to the Paramore artwork.
So, we can confirm that scripts 3 & 4 worked correctly.
According to the code, when the application loops back to scripts 1 & 2, the desktop background should remain as the Paramore artwork.
BUT...
I run the first script in the application.
"iTunesArt2-1.jpg" remains the Paramore artwork (as it should).
I run the second script in the application.
This script should update the desktop background from ""iTunesArt2-2.jpg" (Paramore) to "iTunesArt2-1.jpg" (Paramore).
The desktop background changes to the Coldplay artwork.
Now that makes zero sense at all.
This will happen every time I loop through the scripts.
Script 4 will change the desktop to Paramore and script 2 will change it back to Coldplay.
Remember this issue only happens when there is a full screen app open on the same display being updated. ie. A full screen app open on my primary display doesn't matter.
I have found sometimes that sliding over to the full screen app and 'activating' it will stop the flickering, and the background will be set correctly.
There surely is nothing 'wrong' with my code is there? If not, I need a way to get around this issue.
Specifically, is there a way of 'activating' every full screen app in the background without moving to those spaces?
I would love anyone who wants it to have this program, but it needs to be able to run under all circumstances.
Any help would be greatly appreciated.
Found a work around which creates a random file name each time, meaning the desktop can't get confused as to which image it is supposed to display.
screenNum refers to which screen the desktop is being set to.
set randID to screenNum
set randLoop to 0
repeat while randLoop is not 9
set randNum to (random number from 0 to 9) as text
set randID to randID & randNum
set randLoop to randLoop + 1
end repeat
Then included randID in the file name upon its creation.
Have not noticed any flickering using this method.
Note: This solves my problem, but does not answer my initial question of how one can activate a full screen app in the background.

Resources