|
#!/bin/env bash
|
|
|
|
# Add CR2 tags: Baseline, Subject (to distinguish Single & Dual ISOs)
|
|
# Copyright (C) 2017,2023 Pekka Helenius
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
###############################################
|
|
|
|
# We get the directory just from the first filename.
|
|
INPUT_DIR=$(dirname "${1}")
|
|
DIR_BASENAME=$(echo "${INPUT_DIR}" | rev | cut -d/ -f 1 | rev)
|
|
|
|
# Camera resolution in pixels (absolute limit, we can't exceed these pixel values!)
|
|
C5DMK3_WIDTH=5796
|
|
C5DMK3_HEIGHT=3870
|
|
|
|
# In a case or emergency (can't open a picture etc), revert these values to 5760 x 3840.
|
|
|
|
################################################################################################
|
|
|
|
# PROGRESSBAR CODE - BEGIN
|
|
|
|
LABELTEXT="Processing RAW images..."
|
|
numargs=$# # Number of all files
|
|
tics=100 # Percentage tics
|
|
inc=0 # Current file number
|
|
mltp=1000 # Percentage multiplier for bash
|
|
|
|
dbusRef=$(
|
|
kdialog \
|
|
--title "EXIF Tags (folder: ${DIR_BASENAME})" \
|
|
--progressbar "$LABELTEXT" "${tics}"
|
|
)
|
|
|
|
qdbus $dbusRef showCancelButton true
|
|
|
|
# PROGRESSBAR CODE - END
|
|
|
|
while \
|
|
[[ $# -gt 0 ]] && \
|
|
[[ $(qdbus $dbusRef wasCancelled) == "false" ]]
|
|
do
|
|
|
|
################################################################
|
|
|
|
# Values that change during the while loop (differ from file to file)
|
|
|
|
INPUT="${1}"
|
|
|
|
INPUT_BASENAME=$(basename "${INPUT}" | cut -f 1 -d '.')
|
|
|
|
# Get the correct file extension for an input file, to be used for the new file.
|
|
INPUT_EXTENSION=$(echo $(basename "${INPUT}" | cut -f 2 -d '.' | sed -e '/^\s*$/d' -e 's/\(.*\)/\U\1/'))
|
|
|
|
SUBJECT=$(exiftool "${INPUT}" | grep "Subject")
|
|
SUBJECT_SINGLEISO=$(exiftool "${INPUT}" | grep "Subject" | grep "Single ISO")
|
|
SUBJECT_DUALISO=$(exiftool "${INPUT}" | grep "Subject" | grep "Dual ISO")
|
|
|
|
# This is just for compatibility.
|
|
SUBJECT_DUALISO_OLD=$(exiftool "${INPUT}" | grep "Subject" | grep "Dual-ISO")
|
|
|
|
BASELINES=$(exiftool "${INPUT}" | grep "Baseline Exposure")
|
|
|
|
C5DMK3_CHECK=$(exiftool "${INPUT}" |grep -i "5D Mark III" |wc -l)
|
|
CROPHEIGHT_CHECK_VALUE=$(echo -n $(exiftool "${INPUT}" |grep -i "Cropped Image Height" | sed 's/[^0-9]*//g'))
|
|
|
|
ISO_VALUE=$(echo -n $(exiftool "${INPUT}" | grep "Recommended Exposure Index" | grep -v "Sensitivity Type" | sed 's/[^0-9]*//g'))
|
|
|
|
################################################################
|
|
|
|
# FIRST CHECK FOR INDIVIDUAL FILE
|
|
|
|
################################
|
|
# CR2 FILES
|
|
#
|
|
# Input file is CR2 or cr2
|
|
|
|
if [[ "${INPUT_EXTENSION}" == "CR2" ]]
|
|
then
|
|
|
|
# Dual ISO - unprocessed CR2 (NOTE: THIS CHECK IS SLOW)
|
|
# Test an input file for Dual ISO.
|
|
if [[ $(cr2hdr --dry-run "${INPUT}" | grep "Interlaced ISO detected" | wc -l) -eq 1 ]]
|
|
then
|
|
echo "${INPUT_BASENAME}: Dual ISO CR2 image. Skipping."
|
|
IS_SINGLE_CR2=false
|
|
else
|
|
IS_SINGLE_CR2=true
|
|
fi
|
|
|
|
# Single ISO - CR2
|
|
if [[ "${IS_SINGLE_CR2}" == true ]]
|
|
then
|
|
|
|
# Subject Tag
|
|
if [[ $(echo "${SUBJECT}" | sed '/^\s*$/d' | wc -l) -eq 0 ]]
|
|
then
|
|
echo "${INPUT_BASENAME}: Add a new Subject tag."
|
|
SUBJECT_TAG="Single ISO CR2"
|
|
PROCESS_SUBJECT=true
|
|
else
|
|
echo "${INPUT_BASENAME} is a Single ISO image and has a Subject tag already."
|
|
PROCESS_SUBJECT=false
|
|
fi
|
|
|
|
# Baseline Tags
|
|
if [[ $(echo "${BASELINES}" | sed '/^\s*$/d' | wc -l) -eq 0 ]]
|
|
then
|
|
echo "${INPUT_BASENAME}: Add new Baseline tags."
|
|
PROCESS_BASELINE=true
|
|
else
|
|
echo "${INPUT_BASENAME}: Baseline tags exist. Skipping."
|
|
PROCESS_BASELINE=false
|
|
fi
|
|
|
|
# Image size
|
|
if [[ "${CROPHEIGHT_CHECK_VALUE}" -ne "${C5DMK3_HEIGHT}" ]]
|
|
then
|
|
echo "${INPUT_BASENAME}: New resolution, ${C5DMK3_WIDTH} x ${C5DMK3_HEIGHT}."
|
|
PROCESS_SIZE=true
|
|
else
|
|
echo "${INPUT_BASENAME}: Has correct resolution already."
|
|
PROCESS_SIZE=false
|
|
fi
|
|
|
|
fi
|
|
|
|
################################
|
|
# DNG FILES
|
|
#
|
|
# Input file is DNG or dng
|
|
|
|
elif [[ "${INPUT_EXTENSION}" == "DNG" ]]
|
|
then
|
|
|
|
###########
|
|
# DNG with missing Subject Tag
|
|
|
|
if [[ $(echo "${SUBJECT}" | sed '/^\s*$/d' | wc -l) -eq 0 ]]
|
|
then
|
|
|
|
echo "${INPUT_BASENAME}: Add a new Subject tag."
|
|
SUBJECT_TAG="Single ISO CR2"
|
|
PROCESS_SUBJECT=true
|
|
|
|
# We don't update size tags. See reason below.
|
|
# Baseline tags have already been written by Adobe converter.
|
|
PROCESS_SIZE=false
|
|
PROCESS_BASELINE=false
|
|
|
|
###########
|
|
# DNG with updated Subject Tag
|
|
|
|
elif [[ $(echo "${SUBJECT_SINGLEISO}" | sed '/^\s*$/d' | wc -l) -ne 0 ]]
|
|
then
|
|
echo "${INPUT_BASENAME}: Subject tag exists. Skipping."
|
|
PROCESS_SUBJECT=false
|
|
|
|
# We don't update size tags. See reason below.
|
|
# Baseline tags have already been written by Adobe converter.
|
|
PROCESS_SIZE=false
|
|
PROCESS_BASELINE=false
|
|
|
|
###########
|
|
# New Dual ISO - DNG
|
|
|
|
elif [[ $(echo "${SUBJECT_DUALISO}" | sed '/^\s*$/d' | wc -l) -ne 0 ]]
|
|
then
|
|
|
|
echo "${INPUT_BASENAME}: Dual ISO image with proper tags. Skipping."
|
|
|
|
# Tags have already be written by updated cr2hdr.
|
|
PROCESS_SUBJECT=false
|
|
PROCESS_SIZE=false
|
|
PROCESS_BASELINE=false
|
|
|
|
###########
|
|
# Old Dual ISO - DNG
|
|
|
|
elif [[ $(echo "${SUBJECT_DUALISO_OLD}" | sed '/^\s*$/d' | wc -l) -ne 0 ]]
|
|
then
|
|
|
|
echo "${INPUT_BASENAME}: old Dual ISO image. Update Subject & Baseline tags."
|
|
exiftool -xmp:subject= "${INPUT}" -overwrite_original #Clear old tag
|
|
|
|
PROCESS_SUBJECT=true
|
|
SUBJECT_TAG="Dual ISO DNG"
|
|
|
|
PROCESS_SIZE=false
|
|
|
|
# Old dual ISOs don't have this one.
|
|
PROCESS_BASELINE=true
|
|
|
|
fi
|
|
fi
|
|
|
|
################################################################
|
|
|
|
# Suffix for the new file name
|
|
|
|
# U = Uncropped (PROCESS_SIZE)
|
|
# S = Subject Tag (PROCESS_SUBJECT)
|
|
# B = Baseline Tags (PROCESS_BASELINE)
|
|
|
|
# false, false, false
|
|
if \
|
|
[[ "${PROCESS_SUBJECT}" == false ]] && \
|
|
[[ "${PROCESS_BASELINE}" == false ]] && \
|
|
[[ "${PROCESS_SIZE}" == false ]]
|
|
then
|
|
SUFFIX=
|
|
|
|
# true, true, true
|
|
elif \
|
|
[[ "${PROCESS_SUBJECT}" == true ]] && \
|
|
[[ "${PROCESS_BASELINE}" == true ]] && \
|
|
[[ "${PROCESS_SIZE}" == true ]]
|
|
then
|
|
SUFFIX=_USB
|
|
|
|
# true, true, false
|
|
elif \
|
|
[[ "${PROCESS_SUBJECT}" == true ]] && \
|
|
[[ "${PROCESS_BASELINE}" == true ]] && \
|
|
[[ "${PROCESS_SIZE}" == false ]]
|
|
then
|
|
SUFFIX=_SB
|
|
|
|
# false, true, true
|
|
elif \
|
|
[[ "${PROCESS_SUBJECT}" == false ]] && \
|
|
[[ "${PROCESS_BASELINE}" == true ]] && \
|
|
[[ "${PROCESS_SIZE}" == true ]]
|
|
then
|
|
SUFFIX=_UB
|
|
|
|
# true, false, true
|
|
elif \
|
|
[[ "${PROCESS_SUBJECT}" == true ]] && \
|
|
[[ "${PROCESS_BASELINE}" == false ]] && \
|
|
[[ "${PROCESS_SIZE}" == true ]]
|
|
then
|
|
SUFFIX=_US
|
|
|
|
# false, true, false
|
|
elif \
|
|
[[ "${PROCESS_SUBJECT}" == false ]] && \
|
|
[[ "${PROCESS_BASELINE}" == true ]] && \
|
|
[[ "${PROCESS_SIZE}" == false ]]
|
|
then
|
|
SUFFIX=_B
|
|
|
|
# true, false, false
|
|
elif \
|
|
[[ "${PROCESS_SUBJECT}" == true ]] && \
|
|
[[ "${PROCESS_BASELINE}" == false ]] && \
|
|
[[ "${PROCESS_SIZE}" == false ]]
|
|
then
|
|
SUFFIX=_S
|
|
|
|
# false, false, true
|
|
elif \
|
|
[[ "${PROCESS_SUBJECT}" == false ]] && \
|
|
[[ "${PROCESS_BASELINE}" == false ]] && \
|
|
[[ "${PROCESS_SIZE}" == true ]]
|
|
then
|
|
SUFFIX=_U
|
|
|
|
fi
|
|
|
|
################################################################
|
|
|
|
# RESOLUTION TAGS MANIPULATION - non-Dual ISO CR2 only
|
|
|
|
# 1) Check if Size process variable is true
|
|
# 2) If question "Do we have a 5D Mark string in the file?" does not
|
|
# return 0, E.G. the camera model is 5D Mark 3.
|
|
|
|
if \
|
|
[[ "${PROCESS_SIZE}" == true ]] && \
|
|
[[ "${C5DMK3_CHECK}" -ne 0 ]]
|
|
then
|
|
|
|
# According to file analysis done with CR2 and DNG files,
|
|
# Cropped & Exif Width/Height tags should be written into CR2 files.
|
|
# CR2 files require only Cropped Image Height/Width values,
|
|
# but if we convert an uncropped CR2 file into DNG, we get wrong picture size.
|
|
# To correct this for DNG files, Exif Height/Witdh values are required, too.
|
|
|
|
# WHY WE DON'T CHANGE EXIF TAGS FOR DNG FILES HERE?
|
|
# We can't uncrop DNG file procuded by Adobe algorithms (Adobe DNG Converter or raw2dng).
|
|
# This is because Adobe's method writes a tag name "Default Crop Size" which can't be
|
|
# changed afterwards without rendering the image unusable in Adobe Camera Raw software.
|
|
#
|
|
# My hypothesis about the issue is as follows:
|
|
# Camera Raw may do some comparison check between dimensions defined in "Default Crop Size"
|
|
# and some of the exif-unwritable Width/Height values. If there's a mismatch, the file can't
|
|
# be opened in Adobe Camera Raw software. An image that can't be opened in ACR, is still
|
|
# usable in some other RAW processing software (because their check for EXIF value tags differ).
|
|
#
|
|
# Every time I edited "Default Crop Size" value in DNG file, ACR gave me an error about
|
|
# unsupported or corrupted file.
|
|
|
|
exiftool \
|
|
-CroppedImageWidth="${C5DMK3_WIDTH}" \
|
|
-CroppedImageHeight="${C5DMK3_HEIGHT}" \
|
|
-ExifImageWidth="${C5DMK3_WIDTH}" \
|
|
-ExifImageHeight="${C5DMK3_HEIGHT}" \
|
|
"${INPUT}" \
|
|
-overwrite_original
|
|
|
|
echo -e "${INPUT_BASENAME}: Image dimensions updated to ${C5DMK3_WIDTH} x ${C5DMK3_HEIGHT}.\n"
|
|
|
|
# Other useful Height/Width tags are as follows:
|
|
|
|
# -OriginalImageWidth
|
|
# -OriginalImageHeight
|
|
|
|
# -RelatedImageWidth
|
|
# -RelatedImageHeight
|
|
|
|
fi
|
|
|
|
################################################################
|
|
|
|
# BASELINE TAGS ADDITION - non-Dual ISO CR2 only
|
|
|
|
# 1) We can request that PROCESS variable returns true though it's set to
|
|
# false in Dual ISO CR2 images too. These CR2 images have Baseline values
|
|
# already added into EXIF metadata since 01/07/2017 (cr2hdr code patched).
|
|
|
|
# 2) We check for Canon 5D Mark 3 here
|
|
|
|
# NOTE: We don't care about the image resolution here.
|
|
|
|
if \
|
|
[[ "${PROCESS_BASELINE}" == true ]] && \
|
|
[[ "${C5DMK3_CHECK}" -ne 0 ]]
|
|
then
|
|
|
|
# The following tags (with their respective values) are being used in DNG files
|
|
# converted from CR2 files of Canon 5D Mark 3. Because CR2 files are mostly
|
|
# equal to DNG files but these tags don't exist inside CR2 files, we can add them
|
|
# as shown in the following section.
|
|
|
|
# ######################################################
|
|
#
|
|
# Camera Model: Canon EOS 5D Mark III
|
|
|
|
# ISO Value Baseline Exposure Value
|
|
#
|
|
# 100 0.25
|
|
# 125 0.25
|
|
# 200 0.25
|
|
# 250 0.25
|
|
# 400 0.25
|
|
# 500 0.25
|
|
# 800 0.25
|
|
# 1000 0.25
|
|
# 1600 0.25
|
|
# 2000 0.25
|
|
# 3200 0.25
|
|
# 4000 0.25
|
|
# 6400 0.25
|
|
# 8000 0.25
|
|
# 12800 0.25
|
|
# 16000 0.25
|
|
# 25600 0.25
|
|
#
|
|
# 50 -0.75
|
|
# 160 0.02
|
|
# 320 0.01
|
|
# 640 0.01
|
|
# 1250 0.01
|
|
# 2500 0.01
|
|
# 5000 0.01
|
|
# 10000 0.01
|
|
# 20000 0.01
|
|
# 51200 0.36
|
|
# 102400 0.36
|
|
#
|
|
# ######################################################
|
|
#
|
|
# Same values for all ISOs:
|
|
#
|
|
# Baseline Noise 0.8
|
|
# Baseline Sharpness 1.2
|
|
# Bayer Green Split 100
|
|
#
|
|
# ######################################################
|
|
#
|
|
# Camera Profiles in Adobe Camera RAW - Baseline Exposure Offsets:
|
|
#
|
|
# All Canon EOS 5D Mark 3 profiles (Standard, Neutral, Landscape etc.): -0.25
|
|
# Adobe Standard Profile: 0.00
|
|
#
|
|
# ######################################################
|
|
|
|
# We Do ISO check with Exposure Index value (It returns the same
|
|
# value than used ISO, and works with ISO 102400, too).
|
|
|
|
if [[ "${ISO_VALUE}" -eq 50 ]]
|
|
then
|
|
BL_EXP=-0.75
|
|
|
|
elif [[ "${ISO_VALUE}" -eq 160 ]]
|
|
then
|
|
BL_EXP=0.02
|
|
|
|
elif \
|
|
[[ "$ISO_VALUE}" -eq 51200 ]] || \
|
|
[[ "$ISO_VALUE}" -eq 102400 ]]
|
|
then
|
|
BL_EXP=0.36
|
|
|
|
elif \
|
|
[[ "${ISO_VALUE}" -eq 320 ]] || \
|
|
[[ "${ISO_VALUE}" -eq 640 ]] || \
|
|
[[ "${ISO_VALUE}" -eq 1250 ]] || \
|
|
[[ "${ISO_VALUE}" -eq 2500 ]] || \
|
|
[[ "${ISO_VALUE}" -eq 5000 ]] || \
|
|
[[ "${ISO_VALUE}" -eq 10000 ]] || \
|
|
[[ "${ISO_VALUE}" -eq 20000 ]]
|
|
then
|
|
BL_EXP=0.01
|
|
|
|
else
|
|
BL_EXP=0.25
|
|
fi
|
|
|
|
exiftool \
|
|
-BaselineExposure="${BL_EXP}" \
|
|
-BaselineNoise=0.8 \
|
|
-BaselineSharpness=1.2 \
|
|
-BayerGreenSplit=100 \
|
|
"${INPUT}" \
|
|
-overwrite_original
|
|
|
|
echo -e "${INPUT_BASENAME}: Baseline tags added.\n"
|
|
|
|
fi
|
|
|
|
################################################################
|
|
|
|
# SUBJECT TAG ADDITION
|
|
|
|
if \
|
|
[[ "${PROCESS_SUBJECT}" == true ]] && \
|
|
[[ "${C5DMK3_CHECK}" -ne 0 ]]
|
|
then
|
|
exiftool -xmp:subject="${SUBJECT_TAG}" "${INPUT}" -overwrite_original
|
|
echo -e "${INPUT_BASENAME}: New Subject tag added: $SUBJECT_TAG\n"
|
|
fi
|
|
|
|
################################################################
|
|
|
|
# FILE SUFFIX ADDITION
|
|
|
|
exiftool "-FileModifyDate<EXIF:DateTimeOriginal" "${INPUT}"
|
|
|
|
NEWFILE="${INPUT_DIR}"/"${INPUT_BASENAME}${SUFFIX}"."${INPUT_EXTENSION}"
|
|
|
|
mv "${INPUT}" "${NEWFILE}"
|
|
|
|
exiftool '-FileName<DateTimeOriginal' -d '%Y%m%d-%f%%-c.%%e' "${NEWFILE}"
|
|
|
|
if [[ "${2}" != "" ]]; then
|
|
echo "Moving to the next file."
|
|
fi
|
|
|
|
################################################################
|
|
|
|
# PROGRESSBAR CODE - BEGIN
|
|
|
|
let inc++
|
|
|
|
# Percentage needs to be calculated like this due to bash rounding limitations.
|
|
PERCENT_VALUE=$(((${mltp}*${tics})/(200*${numargs}/${inc} % 2 + ${mltp}*${numargs}/${inc})))
|
|
# Output: 20, 40, 59, 80, 100 etc.
|
|
|
|
qdbus $dbusRef Set "" "value" "${PERCENT_VALUE}";
|
|
qdbus $dbusRef setLabelText "${LABELTEXT} (${inc}/${numargs})";
|
|
|
|
# PROGRESSBAR CODE - END
|
|
|
|
# Move to the next file.
|
|
shift
|
|
done
|
|
|
|
##############################################
|
|
|
|
# Close processing window if cancelled event has been triggered.
|
|
|
|
# PROGRESSBAR CODE - BEGIN
|
|
|
|
# If the process was cancelled, remove tmp file and exit the script.
|
|
if [[ ! $(qdbus $dbusRef wasCancelled) == "false" ]]; then
|
|
exit 0
|
|
fi
|
|
|
|
#Close processing window if not cancelled and processing finished.
|
|
|
|
qdbus $dbusRef close
|
|
|
|
# PROGRESSBAR CODE - END
|
|
|
|
exit 0
|