How to extract meta information using ExifTool

ExifTool is a library for reading, writing and editing meta information for a wide variety of files. It is also available as a command-line application.

Here we use ExifTool as a command-line application to extract meta information about a picture and get the number of megapixels. This assumes ExifTool is already installed.

First we need a picture. We use a demo picture already available in the Glamorous Toolkit Book:

pictureFile := GtResourcesUtility default 
	resourceAtPath: Path * 'feenkcom' / 'gtoolkit-demos' / 'data' / 'faceapi' 
		/  'unsplash-crop60' / 'photo-1501622549218-2c3ef86627cb.jpeg'.

We create an instance of GtSubprocessWithInMemoryOutput Object subclass: #GtSubprocessWithInMemoryOutput instanceVariableNames: 'builder shellCommand process errorBlock command envVariables semaphore stdoutStream stderrStream stdoutBuffer stderrBuffer outputPoll terminateOnShutdown stdinStream retryCount pollException' classVariableNames: '' poolDictionaries: 'LibCSignalSharedPool' package: 'GToolkit-Utility-System' and configure it to run exiftool with the path of the file on disk as an argument.

process := GtSubprocessWithInMemoryOutput new
	command: 'exiftool';
	arguments: { pictureFile fullName}.
process errorBlock: [ :proc | self error: 'Failed to run exiftool' ].

Next we run the command, wait for the result and store the content printed to stdout into a variable.

process runAndWait.
output := process stdout.

To process the output in a simpler way we parse it and create a dictionary/hash map with the values.

variablesList := output lines collect: [ :currentLine |
	| separatorIndex name value |
	separatorIndex := currentLine indexOf: $:.
	name := (currentLine copyFrom: 1 to: separatorIndex - 1) trimBoth.
	value := (currentLine 
		copyFrom: separatorIndex + 1  
		to: currentLine size) trimBoth.
	name -> value ].
metadata := variablesList asOrderedDictionary

To end we get the Megapixels value if present.

	at: 'Megapixels'
	ifPresent: [ :aMegapixelsString | aMegapixelsString asNumber ]
	ifAbsent: [ self error: 'Missing Megapixels value.']