Created
May 27, 2024 07:31
-
-
Save jkitching/3fa5a0c238fa825278db83acd05d7742 to your computer and use it in GitHub Desktop.
Combine a photo (HEIC or JPEG) and a video into a file which Google Photos will recognize as a motion photo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Inline XMP data | |
inline_xmp='<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.1.0-jc003"> | |
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> | |
<rdf:Description rdf:about="" | |
xmlns:GCamera="http://ns.google.com/photos/1.0/camera/" | |
xmlns:Container="http://ns.google.com/photos/1.0/container/" | |
xmlns:Item="http://ns.google.com/photos/1.0/container/item/" | |
xmlns:xmpNote="http://ns.adobe.com/xmp/note/" | |
GCamera:MotionPhoto="1" | |
GCamera:MotionPhotoVersion="1" | |
GCamera:MotionPhotoPresentationTimestampUs="0"> | |
<Container:Directory> | |
<rdf:Seq> | |
<rdf:li rdf:parseType="Resource"> | |
<Container:Item | |
Item:Mime="image/jpeg" | |
Item:Semantic="Primary" | |
Item:Length="0" | |
Item:Padding="0"/> | |
</rdf:li> | |
<rdf:li rdf:parseType="Resource"> | |
<Container:Item | |
Item:Mime="video/mp4" | |
Item:Semantic="MotionPhoto" | |
Item:Length="0" | |
Item:Padding="0"/> | |
</rdf:li> | |
</rdf:Seq> | |
</Container:Directory> | |
</rdf:Description> | |
</rdf:RDF> | |
</x:xmpmeta>' | |
# Check if both photo and video files are provided and exist | |
if [ "$#" -lt 2 ] || [ ! -e "$1" ] || [ ! -e "$2" ]; then | |
echo "Usage: $0 <photo_file> <video_file> [<output_file>]" | |
echo "Both files must be provided and exist." | |
exit 1 | |
fi | |
temporary_file=$(mktemp /tmp/combined_image_XXXXXX.jpg) | |
# Check if the input file is in HEIC format | |
if [[ $(file -b --mime-type "$1") == "image/heic" ]]; then | |
# Convert HEIC to JPEG using the "convert" command and save to a temporary file | |
convert "$1" "$temporary_file" | |
else | |
# If not HEIC, copy the JPEG to the temporary file | |
cp "$1" "$temporary_file" | |
fi | |
# Create a temporary file for XMP data | |
xmp_file=$(mktemp /tmp/xmp_data_XXXXXX.xml) | |
# Write inline XMP data to the temporary XMP file | |
echo "$inline_xmp" > "$xmp_file" | |
# Check for existing XMP data and print a warning to stderr | |
existing_xmp_data=$(exiftool -a -xmp "$temporary_file" 2>&1) | |
if [ -n "$existing_xmp_data" ]; then | |
echo "Warning: Existing XMP data found in $1. It will be replaced." >&2 | |
fi | |
# Drop all XMP data in the JPEG file and add new XMP data | |
exiftool -q -XMP:all= "$temporary_file" | |
exiftool -q "-xmp<=$xmp_file" "$temporary_file" | |
# Determine output destination (stdout or specified file) | |
output_file="/dev/stdout" | |
if [ "$#" -eq 3 ]; then | |
output_file="$3" | |
fi | |
# Concatenate the temporary file with XMP and the video file together and write to stdout | |
cat "$temporary_file" "$2" > "$output_file" | |
# Clean up temporary files | |
rm -f "$temporary_file" "$xmp_file" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment