Label images that aren't quality

Hello,
I’m trying to write a script that checks images in a folder and labels the images red if they are less than 1500 pixels width or height.

here is what i have so far:


set startFolder to (choose folder with prompt "Choose a folder of images you want to check")
tell application "Finder" to set fileList to every file in folder startFolder
set minValue to 1500
repeat with aFile in fileList
	tell application "Image Events"
		-- start the Image Events application
		launch
		-- open the image file
		set thisImage to open aFile
		set the props_rec to the properties of thisImage
		close thisImage
		-- extract the property value
		copy (dimensions of props_rec) to {x, y}
		if x is less than minValue then
			tell application "Finder" to set label index of file (startFolder & fileName) to 2
		end if
		if y is less than minValue then
			tell application "Finder" to set label index of file (startFolder & fileName) to 2
		end if
	end tell
end repeat

I’m getting: error “The variable thisImage is not defined.” number -2753 from “thisImage”

I’ve defined “thisImage” as the current open image file. So why does it say that it’s not defined?

Also, I set up two if statements to check the width and height. There’s gotta be a more concise/better way to do that.

Thanks for your help!

You are asking ImageEvents to open a file defined by a Finder Reference which it can’t treat.

set startFolder to (choose folder with prompt "Choose a folder of images you want to check")
tell application "Finder" to set fileList to every file in folder startFolder
set minValue to 1500
repeat with aFile in fileList
	set aFile to aFile as alias # coerce the Finder reference into an alias which is a known object for ImageEvents
	tell application "Image Events"
		-- start the Image Events application
		launch
		-- open the image file
		set thisImage to open aFile
		set the props_rec to the properties of thisImage
		close thisImage
		-- extract the property value
		copy (dimensions of props_rec) to {x, y}
		if x is less than minValue then
			--		tell application "Finder" to set label index of file (startFolder & fileName) to 2 # FileName is not defined here
			tell application "Finder" to set label index of aFile to 2
		end if
		if y is less than minValue then
			--	tell application "Finder" to set label index of file (startFolder & fileName) to 2 # FileName is not defined here
			tell application "Finder" to set label index of aFile to 2
		end if
	end tell
end repeat

Yvan KOENIG running Sierra 10.12.3 in French (VALLAURIS, France) mercredi 25 janvier 2017 17:54:12

Hey Folks,

Seems to me that using Image Events is overkill.


-------------------------------------------------------------------------------------------
# User Settings:
-------------------------------------------------------------------------------------------
set imageFolderPath to "~/test_directory/Image_Test_Folder/"
set labelIndex to 6
-------------------------------------------------------------------------------------------

tell application "System Events" to set imageFolderPath to POSIX path of disk item imageFolderPath
set imageFolderHFS to ((POSIX file imageFolderPath) as alias) as text
set shCMD to "
cd " & quoted form of imageFolderPath & "
mdls -name kMDItemFSName -name kMDItemPixelWidth -name kMDItemPixelHeight * | sed -E 's!^.+= !!; s!\"!!g'
"
set dataList to paragraphs of (do shell script shCMD)

tell application "Finder"
	repeat with i from 1 to (length of dataList) by 3
		set {fileName, pixelHeight, pixelWidth} to (items i thru (i + 2) of dataList)
		if (pixelHeight as integer < 1500) or (pixelWidth as integer < 1500) or (pixelHeight = "(null)") or (pixelWidth = "(null)") then
			set theFile to (imageFolderHFS & fileName) as alias
			set label index of theFile to labelIndex
		end if
	end repeat
	
	update alias imageFolderHFS
	
end tell
-------------------------------------------------------------------------------------------


Chris

{ MacBookPro6,1 · 2.66 GHz Intel Core i7 · 8GB RAM · OSX 10.12.2 }

Edit 2017/01/28 07:47 CST:
¢ Changed ˜ kMDItemDisplayName’ to ˜kMDItemFSName’ “ per Shane Stanley’s advice.
Edit 2017/01/28 08:25 CST:
¢ Allowed for NULL pixel width and heights “ again per Shane’s advice.
¢ Made the user-settings a little more obvious.

Yep – but doesn’t mdls return a recursive result? That might be overkill of a different sort.

Later…

There are a couple of other issues, too. The name being returned won’t match if you have extensions always showing but it’s been set to hidden for a file – I think you need to use kMDItemPath instead. And it probably needs to allow for files with a pixelHeight and width of “(null)”.

Indeed. Replace

set imageFolderPath to "~/test_directory/Image_Test_Folder/"
tell application "System Events" to set imageFolderPath to POSIX path of disk item imageFolderPath

set imageFolderHFS to ((POSIX file imageFolderPath) as alias) as text

with


set imageFolderHFS to (path to home folder as text) & "test_directory:Image_Test_Folder:"
set imageFolderPath to  POSIX path of imageFolderHFS

Hey all,
So, I tried StefanK’s changes to ccstones. Returns an error:

error “Can’t make {alias "Macintosh HD:Users:admin:Desktop:Incoming Images:Raw:2017-01-13:", "1000-2475.png"} into type alias.” number -1700 from {alias “Macintosh HD:Users:admin:Desktop:Incoming Images:Raw:2017-01-13:”, “1000-2475.png”} to alias

now, It’s not always going to be the same folder so, i modified it to choose the folder.


set labelIndex to 6
set imageFolderHFS to (choose folder with prompt "Choose a folder of images you want to check")
set imageFolderPath to POSIX path of imageFolderHFS

set shCMD to "
cd " & quoted form of imageFolderPath & "
mdls -name kMDItemDisplayName -name kMDItemPixelWidth -name kMDItemPixelHeight * | sed -E 's!^.+= !!; s!\"!!g'
"
set dataList to paragraphs of (do shell script shCMD)

tell application "Finder"
	repeat with i from 1 to (length of dataList) by 3
		set {fileName, pixelHeight, pixelWidth} to (items i thru (i + 2) of dataList)
		if pixelHeight as integer < 1500 or pixelWidth as integer < 1500 then
			set theFile to (imageFolderHFS & fileName) as alias
			set label index of theFile to labelIndex
		end if
	end repeat
	
	update alias imageFolderHFS
	
end tell

any thoughts?

You are trying to concatenate two items which you can’t.

   set theFile to (imageFolderHFS & fileName) as alias

As you (me too) aren’t allowed to concatenate these objects you get a list : {alias "Macintosh HD:Users:admin:Desktop:Incoming Images:Raw:2017-01-13:", "1000-2475.png"} which means nothing usable.
I repeat that you (me too) must coerce the first component into a string (text means the same).

   set theFile to ((imageFolderHFS as text) & fileName) as alias

I guess that you missed the fact that choose folder returns an alias, not a string.

From my point of view there is a better scheme. At the very beginning, use :

set imageFolderHFS to (choose folder with prompt "Choose a folder of images you want to check") as text

The two added words make the difference.
The instruction used just below :

set imageFolderPath to POSIX path of imageFolderHFS

Apply flawlessly upon a path defined by a string

With that, in your loop you will no longer have to repeatedly coerce an alias into a string because the variable imageFolderHFS would be already a text object.

I hope that this time you will understand why you got odd results.

Yvan KOENIG running Sierra 10.12.3 in French (VALLAURIS, France) jeudi 26 janvier 2017 15:54:09

This is a variation on Chris’s approach – it ignores files in subfolders, and handles hidden extensions and files without width and height values. It’s also uses ASObjC rather than shell scripting and Finder.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

-- build search folder URL
set folderPath to POSIX path of (choose folder)
set theURL to current application's |NSURL|'s fileURLWithPath:folderPath
if folderPath ends with "/" then set folderPath to text 1 thru -2 of folderPath -- used later to eliminate nested files
-- some house-keeping; resolves these keys once to save time later
set NSMetadataItemPathKey to current application's NSMetadataItemPathKey
set NSMetadataItemPixelWidthKey to current application's NSMetadataItemPixelWidthKey
set NSMetadataItemPixelHeightKey to current application's NSMetadataItemPixelHeightKey
set NSURLLabelNumberKey to current application's NSURLLabelNumberKey
set requiredKeys to {NSMetadataItemPathKey, NSMetadataItemPixelWidthKey, NSMetadataItemPixelHeightKey}
-- build query and run it
set thePred to current application's NSPredicate's predicateWithFormat:"kMDItemContentTypeTree CONTAINS 'public.image'"
set theQuery to current application's NSMetadataQuery's new()
theQuery's setPredicate:thePred
theQuery's setSearchScopes:{theURL}
theQuery's startQuery()
repeat while theQuery's isGathering() as boolean
	delay 0.01
end repeat
theQuery's stopQuery()
-- loop through results
set theCount to theQuery's resultCount()
repeat with i from 1 to theCount
	set aResult to (theQuery's resultAtIndex:(i - 1))
	-- get the values we're interested in
	set theValues to (aResult's valuesForAttributes:requiredKeys)
	set theWidth to (theValues's objectForKey:NSMetadataItemPixelWidthKey)
	if theWidth is not missing value then -- ignore files with no pixel value; they're not bitmap format
		set thePath to (theValues's objectForKey:NSMetadataItemPathKey)
		-- check the file is directly in the folder, and not a subfolder
		if (thePath's stringByDeletingLastPathComponent()'s isEqualToString:folderPath) as boolean then
			if theWidth as real < 1500 or (theValues's objectForKey:NSMetadataItemPixelHeightKey) as real < 1500 then
				-- if we get here, we need to change the label
				set thisURL to (current application's |NSURL|'s fileURLWithPath:thePath)
				(thisURL's setResourceValue:6 forKey:NSURLLabelNumberKey |error|:(missing value))
			end if
		end if
	end if
end repeat

Edit: Fixed label index.

Hey Stefan,

No, I wrote it that way very deliberately to make it less confusing to a neophyte user.

I use relative-aliases for everything on my own system (unless I have a good reason to do otherwise), but I find that other users (especially new ones) are confused by them.

-Chris

Hey Shane,

No “ recursion is not available in mdls.

That’s a good point, but kMDItemFSName should be sufficient. (Now changed in the script.)

I suppose. I don’t have one handy to test with though. (Nevertheless “ changed in the script.)

-Chris

No offense but your “construct” is much much much more confusing “ and more coercion-expensive “ than using the built-in relative paths

For example:

Your syntax:

[format]“~/Pictures/jpgs” → POSIX path
disk item imageFolderPath → System Events specifier (expands tilde)
POSIX path of → POSIX path
POSIX file → file URL
as alias → alias
as text → HFS path[/format]

Built-in relative paths syntax:

[format](path to pictures folder as text) & “jpgs”[/format]

Yes. I’ve been using relative-aliases routinely since 1996 and am fully aware of the advantages.

I’ve also been teaching people AppleScript for nearly that long, and your average person is quite confused by them.

These days it’s generally easier to start people off with POSIX Paths and $HOME-based POSIX Paths.

Most of them didn’t grow up on HFS paths, and for that matter Mac users are often confused by path strings to begin with.

-Chris

Hey Folks,

My script rewritten pretty much the way I’d use it at home.

Shane’s suggestions are incorporated.

Added is a test for ˜public.image’

I switched from sed to Perl, so I could more easily deal with the kMDItemContentTypeTree tree.

Choose Folder is the default, although there’re lines demonstrating the use of a relative-alias and the Finder’s insertion location.


-------------------------------------------------------------------------------------------
# User Settings:
-------------------------------------------------------------------------------------------
set labelIndex to 6
-------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------
--» Choose Folder or Relative-Alias or Finder Insertion Location ” take your pick.
-------------------------------------------------------------------------------------------
set imageFolderAlias to choose folder
-------------------------------------------------------------------------------------------
# set imageFolderAlias to alias ((path to home folder as text) & "test_directory:Image_Test_Folder:")
-------------------------------------------------------------------------------------------
# tell application "Finder" to set imageFolderAlias to insertion location as alias
-------------------------------------------------------------------------------------------

set imageFolderPath to POSIX path of imageFolderAlias
set imageFolderHFS to imageFolderAlias as text
set shCMD to "
	cd " & quoted form of imageFolderPath & ";
	mdls -raw -name kMDItemContentTypeTree -name kMDItemFSName -name kMDItemPixelWidth -name kMDItemPixelHeight * \\
	| perl -0777 -ne '
		s!\\x{00}!\\n!g;
		s!^[()]\\n?!!mg;
		s!^[[:blank:]]*|\"$!!mg;
		s!^\"!!mg;
		s!\"(,)\\n!$1 !mg;
		print;
	'"
set dataList to paragraphs of (do shell script shCMD)

tell application "Finder"
	repeat with i from 1 to (length of dataList) by 4
		set {fileTypes, fileName, pixelHeight, pixelWidth} to (items i thru (i + 3) of dataList)
		if (fileTypes contains "public.image") then
			if (pixelHeight as integer < 1500) or (pixelWidth as integer < 1500) or (pixelHeight = "(null)") or (pixelWidth = "(null)") then
				set theFile to (imageFolderHFS & fileName) as alias
				set label index of theFile to labelIndex
			end if
		end if
	end repeat
	
	update alias imageFolderHFS
	
end tell

-------------------------------------------------------------------------------------------

I don’t like fooling around with file dialogs and try to avoid them, so when possible I usually use insertion location in the Finder to operate on the front Finder window.

The script runs in about 5 seconds on a closed folder containing 650 files (on my system) “ with the folder open it takes about 8 seconds.

Operating on 100 files in the front Finder window takes ~1.2 seconds.

I reckon Shane’s script will be a bit faster “ especially as the number of files goes up.


Chris
··················································································
{ MacBookPro6,1 · 2.66 GHz Intel Core i7 · 8GB RAM · OSX 10.12.2 }

EDIT 2017/01/30 05:06
- Somehow kMDItemDisplayName snuck in from the first script “ I’ve replaced it with kMDItemFSName.