Zack, thanks for the great response! I managed to get what I needed. I’ll provide some more info here on the project as well. Perhaps you or others can give some constructive tips?
First, can you explain your code a bit? It did work, and it allowed me to see what my prior error was - I had made the assumption that I was creating a two dimensional array when it was just one. But the compact nature (C++ ?) of your code is not something I have used before.
arr = ListToArray( standardOut, chr( 10 ) );
Create a basic array, char(10) delimiter
st = [=]; // ordered struct
Is this from C++?
I had to google that line and got: “In the context of C++, st = [=]
defines a lambda expression where st
is likely a variable or identifier, and [=]
is the [capture clause]. The [=]
capture clause indicates that all variables used within the lambda’s body should be captured by value. This means the lambda creates a copy of the external variables it uses, rather than directly accessing the originals.”
arrayEach( arr, function( item ) { st [ trim( listFirst( item, ":" ) ) ] = trim( listRest( item, ":" ) ) ;})
Populate the array. And I have used listFirst, listRest before. But it’s the
function( item )
syntax that is new to me and how that works.
Of course it 100% worked and gave me:
Now the final version I need is a bit more formatted. So I add a little more processing (no doubt verbose). Here is the full script:
<!--- string output, not structured, gives GPS data if found --->
<cfexecute name="bash" arguments="/opt/bash-exiftool.sh -a -G -gps* #imageToUse#" timeout="2400" variable="standardOut" errorVariable="returnedError"></cfexecute>
<cfdump var="#standardOut#">
<br />
<br />
<!--- zac's simplified and effecient code; produces simple array with one item per row --->
<cfscript>
arr = ListToArray( standardOut, chr( 10 ) );
st = [=]; // ordered struct
arrayEach( arr, function( item ) {
st [ trim( listFirst( item, ":" ) ) ] = trim( listRest( item, ":" ) ) ;
})
</cfscript>
<cfdump var="#arr#">
<br />
<br />
<!--- my verbose code; produces GPS item name and value per row --->
<cfset standardOut=#replaceNoCase(standardOut, "[", "", "ALL")# />
<cfset standardOut=#replaceNoCase(standardOut, "]", "", "ALL")# />
<cfset standardOut=#replaceNoCase(standardOut, " ; ", ":", "ALL")# />
<!--- single item array from shell scritpt output --->
<cfset standardOutArray = ListToArray( standardOut, chr( 10 ) )>
<!--- array to hold newly structured data from standardOutArray --->
<cfset lattLongArray = arraynew(2) />
<!--- populate lattLongArray --->
<cfloop from="1" to="#arrayLen(standardOutArray)#" index="i">
<cfset lattLongArray[i][1] = trim( listFirst( standardOutArray[i], ":" ) ) />
<cfset lattLongArray[i][2] = trim( listRest( standardOutArray[i], ":" ) ) />
</cfloop>
<!--- output lattLongArray --->
<cfdump var="#lattLongArray#">
Which gives me:
That’s the final form I am looking for.
The project is a basic photo catalog for myself because after testing out NextCloud, Piwigo, Immich (via Docker), and Photoprism, each has its own problems and issues.
So, Lucee (CF) facilitates image data quite easily:
<cfset exifData = imageGetEXIFMetadata(imageToUse)>
<cfscript>
writeDump(serialize(exifData));
</cfscript>
But it doesn’t work with HEIC images. So, I need a way to read the HEIC data from hundreds/thousands of images which is where CFEXECUTE and exiftool come in. And ImageMagick can convert HEIC to JPG when needed.
So, that’s the thing I am trying to do:
- Use Lucee to read a directory of folders and subfolders with images;
- Display the image (use other tools to convert HEIC if needed);
- Send EXIF data to Openstreetmaps or Google map
- Display the map