Create Canon DSLR CR2 image statistics (exiftool & GNU Plot) and convert ML dual ISO CR2 files painlessly for post-processing
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

520 lines
15 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. #!/bin/env bash
  2. # Add CR2 tags: Baseline, Subject (to distinguish Single & Dual ISOs)
  3. # Copyright (C) 2017,2023 Pekka Helenius
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU General Public License
  7. # as published by the Free Software Foundation; either version 2
  8. # of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. #
  19. ###############################################
  20. # We get the directory just from the first filename.
  21. INPUT_DIR=$(dirname "${1}")
  22. DIR_BASENAME=$(echo "${INPUT_DIR}" | rev | cut -d/ -f 1 | rev)
  23. # Camera resolution in pixels (absolute limit, we can't exceed these pixel values!)
  24. C5DMK3_WIDTH=5796
  25. C5DMK3_HEIGHT=3870
  26. # In a case or emergency (can't open a picture etc), revert these values to 5760 x 3840.
  27. ################################################################################################
  28. # PROGRESSBAR CODE - BEGIN
  29. LABELTEXT="Processing RAW images..."
  30. numargs=$# # Number of all files
  31. tics=100 # Percentage tics
  32. inc=0 # Current file number
  33. mltp=1000 # Percentage multiplier for bash
  34. dbusRef=$(
  35. kdialog \
  36. --title "EXIF Tags (folder: ${DIR_BASENAME})" \
  37. --progressbar "$LABELTEXT" "${tics}"
  38. )
  39. qdbus $dbusRef showCancelButton true
  40. # PROGRESSBAR CODE - END
  41. while \
  42. [[ $# -gt 0 ]] && \
  43. [[ $(qdbus $dbusRef wasCancelled) == "false" ]]
  44. do
  45. ################################################################
  46. # Values that change during the while loop (differ from file to file)
  47. INPUT="${1}"
  48. INPUT_BASENAME=$(basename "${INPUT}" | cut -f 1 -d '.')
  49. # Get the correct file extension for an input file, to be used for the new file.
  50. INPUT_EXTENSION=$(echo $(basename "${INPUT}" | cut -f 2 -d '.' | sed -e '/^\s*$/d' -e 's/\(.*\)/\U\1/'))
  51. SUBJECT=$(exiftool "${INPUT}" | grep "Subject")
  52. SUBJECT_SINGLEISO=$(exiftool "${INPUT}" | grep "Subject" | grep "Single ISO")
  53. SUBJECT_DUALISO=$(exiftool "${INPUT}" | grep "Subject" | grep "Dual ISO")
  54. # This is just for compatibility.
  55. SUBJECT_DUALISO_OLD=$(exiftool "${INPUT}" | grep "Subject" | grep "Dual-ISO")
  56. BASELINES=$(exiftool "${INPUT}" | grep "Baseline Exposure")
  57. C5DMK3_CHECK=$(exiftool "${INPUT}" |grep -i "5D Mark III" |wc -l)
  58. CROPHEIGHT_CHECK_VALUE=$(echo -n $(exiftool "${INPUT}" |grep -i "Cropped Image Height" | sed 's/[^0-9]*//g'))
  59. ISO_VALUE=$(echo -n $(exiftool "${INPUT}" | grep "Recommended Exposure Index" | grep -v "Sensitivity Type" | sed 's/[^0-9]*//g'))
  60. ################################################################
  61. # FIRST CHECK FOR INDIVIDUAL FILE
  62. ################################
  63. # CR2 FILES
  64. #
  65. # Input file is CR2 or cr2
  66. if [[ "${INPUT_EXTENSION}" == "CR2" ]]
  67. then
  68. # Dual ISO - unprocessed CR2 (NOTE: THIS CHECK IS SLOW)
  69. # Test an input file for Dual ISO.
  70. if [[ $(cr2hdr --dry-run "${INPUT}" | grep "Interlaced ISO detected" | wc -l) -eq 1 ]]
  71. then
  72. echo "${INPUT_BASENAME}: Dual ISO CR2 image. Skipping."
  73. IS_SINGLE_CR2=false
  74. else
  75. IS_SINGLE_CR2=true
  76. fi
  77. # Single ISO - CR2
  78. if [[ "${IS_SINGLE_CR2}" == true ]]
  79. then
  80. # Subject Tag
  81. if [[ $(echo "${SUBJECT}" | sed '/^\s*$/d' | wc -l) -eq 0 ]]
  82. then
  83. echo "${INPUT_BASENAME}: Add a new Subject tag."
  84. SUBJECT_TAG="Single ISO CR2"
  85. PROCESS_SUBJECT=true
  86. else
  87. echo "${INPUT_BASENAME} is a Single ISO image and has a Subject tag already."
  88. PROCESS_SUBJECT=false
  89. fi
  90. # Baseline Tags
  91. if [[ $(echo "${BASELINES}" | sed '/^\s*$/d' | wc -l) -eq 0 ]]
  92. then
  93. echo "${INPUT_BASENAME}: Add new Baseline tags."
  94. PROCESS_BASELINE=true
  95. else
  96. echo "${INPUT_BASENAME}: Baseline tags exist. Skipping."
  97. PROCESS_BASELINE=false
  98. fi
  99. # Image size
  100. if [[ "${CROPHEIGHT_CHECK_VALUE}" -ne "${C5DMK3_HEIGHT}" ]]
  101. then
  102. echo "${INPUT_BASENAME}: New resolution, ${C5DMK3_WIDTH} x ${C5DMK3_HEIGHT}."
  103. PROCESS_SIZE=true
  104. else
  105. echo "${INPUT_BASENAME}: Has correct resolution already."
  106. PROCESS_SIZE=false
  107. fi
  108. fi
  109. ################################
  110. # DNG FILES
  111. #
  112. # Input file is DNG or dng
  113. elif [[ "${INPUT_EXTENSION}" == "DNG" ]]
  114. then
  115. ###########
  116. # DNG with missing Subject Tag
  117. if [[ $(echo "${SUBJECT}" | sed '/^\s*$/d' | wc -l) -eq 0 ]]
  118. then
  119. echo "${INPUT_BASENAME}: Add a new Subject tag."
  120. SUBJECT_TAG="Single ISO CR2"
  121. PROCESS_SUBJECT=true
  122. # We don't update size tags. See reason below.
  123. # Baseline tags have already been written by Adobe converter.
  124. PROCESS_SIZE=false
  125. PROCESS_BASELINE=false
  126. ###########
  127. # DNG with updated Subject Tag
  128. elif [[ $(echo "${SUBJECT_SINGLEISO}" | sed '/^\s*$/d' | wc -l) -ne 0 ]]
  129. then
  130. echo "${INPUT_BASENAME}: Subject tag exists. Skipping."
  131. PROCESS_SUBJECT=false
  132. # We don't update size tags. See reason below.
  133. # Baseline tags have already been written by Adobe converter.
  134. PROCESS_SIZE=false
  135. PROCESS_BASELINE=false
  136. ###########
  137. # New Dual ISO - DNG
  138. elif [[ $(echo "${SUBJECT_DUALISO}" | sed '/^\s*$/d' | wc -l) -ne 0 ]]
  139. then
  140. echo "${INPUT_BASENAME}: Dual ISO image with proper tags. Skipping."
  141. # Tags have already be written by updated cr2hdr.
  142. PROCESS_SUBJECT=false
  143. PROCESS_SIZE=false
  144. PROCESS_BASELINE=false
  145. ###########
  146. # Old Dual ISO - DNG
  147. elif [[ $(echo "${SUBJECT_DUALISO_OLD}" | sed '/^\s*$/d' | wc -l) -ne 0 ]]
  148. then
  149. echo "${INPUT_BASENAME}: old Dual ISO image. Update Subject & Baseline tags."
  150. exiftool -xmp:subject= "${INPUT}" -overwrite_original #Clear old tag
  151. PROCESS_SUBJECT=true
  152. SUBJECT_TAG="Dual ISO DNG"
  153. PROCESS_SIZE=false
  154. # Old dual ISOs don't have this one.
  155. PROCESS_BASELINE=true
  156. fi
  157. fi
  158. ################################################################
  159. # Suffix for the new file name
  160. # U = Uncropped (PROCESS_SIZE)
  161. # S = Subject Tag (PROCESS_SUBJECT)
  162. # B = Baseline Tags (PROCESS_BASELINE)
  163. # false, false, false
  164. if \
  165. [[ "${PROCESS_SUBJECT}" == false ]] && \
  166. [[ "${PROCESS_BASELINE}" == false ]] && \
  167. [[ "${PROCESS_SIZE}" == false ]]
  168. then
  169. SUFFIX=
  170. # true, true, true
  171. elif \
  172. [[ "${PROCESS_SUBJECT}" == true ]] && \
  173. [[ "${PROCESS_BASELINE}" == true ]] && \
  174. [[ "${PROCESS_SIZE}" == true ]]
  175. then
  176. SUFFIX=_USB
  177. # true, true, false
  178. elif \
  179. [[ "${PROCESS_SUBJECT}" == true ]] && \
  180. [[ "${PROCESS_BASELINE}" == true ]] && \
  181. [[ "${PROCESS_SIZE}" == false ]]
  182. then
  183. SUFFIX=_SB
  184. # false, true, true
  185. elif \
  186. [[ "${PROCESS_SUBJECT}" == false ]] && \
  187. [[ "${PROCESS_BASELINE}" == true ]] && \
  188. [[ "${PROCESS_SIZE}" == true ]]
  189. then
  190. SUFFIX=_UB
  191. # true, false, true
  192. elif \
  193. [[ "${PROCESS_SUBJECT}" == true ]] && \
  194. [[ "${PROCESS_BASELINE}" == false ]] && \
  195. [[ "${PROCESS_SIZE}" == true ]]
  196. then
  197. SUFFIX=_US
  198. # false, true, false
  199. elif \
  200. [[ "${PROCESS_SUBJECT}" == false ]] && \
  201. [[ "${PROCESS_BASELINE}" == true ]] && \
  202. [[ "${PROCESS_SIZE}" == false ]]
  203. then
  204. SUFFIX=_B
  205. # true, false, false
  206. elif \
  207. [[ "${PROCESS_SUBJECT}" == true ]] && \
  208. [[ "${PROCESS_BASELINE}" == false ]] && \
  209. [[ "${PROCESS_SIZE}" == false ]]
  210. then
  211. SUFFIX=_S
  212. # false, false, true
  213. elif \
  214. [[ "${PROCESS_SUBJECT}" == false ]] && \
  215. [[ "${PROCESS_BASELINE}" == false ]] && \
  216. [[ "${PROCESS_SIZE}" == true ]]
  217. then
  218. SUFFIX=_U
  219. fi
  220. ################################################################
  221. # RESOLUTION TAGS MANIPULATION - non-Dual ISO CR2 only
  222. # 1) Check if Size process variable is true
  223. # 2) If question "Do we have a 5D Mark string in the file?" does not
  224. # return 0, E.G. the camera model is 5D Mark 3.
  225. if \
  226. [[ "${PROCESS_SIZE}" == true ]] && \
  227. [[ "${C5DMK3_CHECK}" -ne 0 ]]
  228. then
  229. # According to file analysis done with CR2 and DNG files,
  230. # Cropped & Exif Width/Height tags should be written into CR2 files.
  231. # CR2 files require only Cropped Image Height/Width values,
  232. # but if we convert an uncropped CR2 file into DNG, we get wrong picture size.
  233. # To correct this for DNG files, Exif Height/Witdh values are required, too.
  234. # WHY WE DON'T CHANGE EXIF TAGS FOR DNG FILES HERE?
  235. # We can't uncrop DNG file procuded by Adobe algorithms (Adobe DNG Converter or raw2dng).
  236. # This is because Adobe's method writes a tag name "Default Crop Size" which can't be
  237. # changed afterwards without rendering the image unusable in Adobe Camera Raw software.
  238. #
  239. # My hypothesis about the issue is as follows:
  240. # Camera Raw may do some comparison check between dimensions defined in "Default Crop Size"
  241. # and some of the exif-unwritable Width/Height values. If there's a mismatch, the file can't
  242. # be opened in Adobe Camera Raw software. An image that can't be opened in ACR, is still
  243. # usable in some other RAW processing software (because their check for EXIF value tags differ).
  244. #
  245. # Every time I edited "Default Crop Size" value in DNG file, ACR gave me an error about
  246. # unsupported or corrupted file.
  247. exiftool \
  248. -CroppedImageWidth="${C5DMK3_WIDTH}" \
  249. -CroppedImageHeight="${C5DMK3_HEIGHT}" \
  250. -ExifImageWidth="${C5DMK3_WIDTH}" \
  251. -ExifImageHeight="${C5DMK3_HEIGHT}" \
  252. "${INPUT}" \
  253. -overwrite_original
  254. echo -e "${INPUT_BASENAME}: Image dimensions updated to ${C5DMK3_WIDTH} x ${C5DMK3_HEIGHT}.\n"
  255. # Other useful Height/Width tags are as follows:
  256. # -OriginalImageWidth
  257. # -OriginalImageHeight
  258. # -RelatedImageWidth
  259. # -RelatedImageHeight
  260. fi
  261. ################################################################
  262. # BASELINE TAGS ADDITION - non-Dual ISO CR2 only
  263. # 1) We can request that PROCESS variable returns true though it's set to
  264. # false in Dual ISO CR2 images too. These CR2 images have Baseline values
  265. # already added into EXIF metadata since 01/07/2017 (cr2hdr code patched).
  266. # 2) We check for Canon 5D Mark 3 here
  267. # NOTE: We don't care about the image resolution here.
  268. if \
  269. [[ "${PROCESS_BASELINE}" == true ]] && \
  270. [[ "${C5DMK3_CHECK}" -ne 0 ]]
  271. then
  272. # The following tags (with their respective values) are being used in DNG files
  273. # converted from CR2 files of Canon 5D Mark 3. Because CR2 files are mostly
  274. # equal to DNG files but these tags don't exist inside CR2 files, we can add them
  275. # as shown in the following section.
  276. # ######################################################
  277. #
  278. # Camera Model: Canon EOS 5D Mark III
  279. # ISO Value Baseline Exposure Value
  280. #
  281. # 100 0.25
  282. # 125 0.25
  283. # 200 0.25
  284. # 250 0.25
  285. # 400 0.25
  286. # 500 0.25
  287. # 800 0.25
  288. # 1000 0.25
  289. # 1600 0.25
  290. # 2000 0.25
  291. # 3200 0.25
  292. # 4000 0.25
  293. # 6400 0.25
  294. # 8000 0.25
  295. # 12800 0.25
  296. # 16000 0.25
  297. # 25600 0.25
  298. #
  299. # 50 -0.75
  300. # 160 0.02
  301. # 320 0.01
  302. # 640 0.01
  303. # 1250 0.01
  304. # 2500 0.01
  305. # 5000 0.01
  306. # 10000 0.01
  307. # 20000 0.01
  308. # 51200 0.36
  309. # 102400 0.36
  310. #
  311. # ######################################################
  312. #
  313. # Same values for all ISOs:
  314. #
  315. # Baseline Noise 0.8
  316. # Baseline Sharpness 1.2
  317. # Bayer Green Split 100
  318. #
  319. # ######################################################
  320. #
  321. # Camera Profiles in Adobe Camera RAW - Baseline Exposure Offsets:
  322. #
  323. # All Canon EOS 5D Mark 3 profiles (Standard, Neutral, Landscape etc.): -0.25
  324. # Adobe Standard Profile: 0.00
  325. #
  326. # ######################################################
  327. # We Do ISO check with Exposure Index value (It returns the same
  328. # value than used ISO, and works with ISO 102400, too).
  329. if [[ "${ISO_VALUE}" -eq 50 ]]
  330. then
  331. BL_EXP=-0.75
  332. elif [[ "${ISO_VALUE}" -eq 160 ]]
  333. then
  334. BL_EXP=0.02
  335. elif \
  336. [[ "$ISO_VALUE}" -eq 51200 ]] || \
  337. [[ "$ISO_VALUE}" -eq 102400 ]]
  338. then
  339. BL_EXP=0.36
  340. elif \
  341. [[ "${ISO_VALUE}" -eq 320 ]] || \
  342. [[ "${ISO_VALUE}" -eq 640 ]] || \
  343. [[ "${ISO_VALUE}" -eq 1250 ]] || \
  344. [[ "${ISO_VALUE}" -eq 2500 ]] || \
  345. [[ "${ISO_VALUE}" -eq 5000 ]] || \
  346. [[ "${ISO_VALUE}" -eq 10000 ]] || \
  347. [[ "${ISO_VALUE}" -eq 20000 ]]
  348. then
  349. BL_EXP=0.01
  350. else
  351. BL_EXP=0.25
  352. fi
  353. exiftool \
  354. -BaselineExposure="${BL_EXP}" \
  355. -BaselineNoise=0.8 \
  356. -BaselineSharpness=1.2 \
  357. -BayerGreenSplit=100 \
  358. "${INPUT}" \
  359. -overwrite_original
  360. echo -e "${INPUT_BASENAME}: Baseline tags added.\n"
  361. fi
  362. ################################################################
  363. # SUBJECT TAG ADDITION
  364. if \
  365. [[ "${PROCESS_SUBJECT}" == true ]] && \
  366. [[ "${C5DMK3_CHECK}" -ne 0 ]]
  367. then
  368. exiftool -xmp:subject="${SUBJECT_TAG}" "${INPUT}" -overwrite_original
  369. echo -e "${INPUT_BASENAME}: New Subject tag added: $SUBJECT_TAG\n"
  370. fi
  371. ################################################################
  372. # FILE SUFFIX ADDITION
  373. exiftool "-FileModifyDate<EXIF:DateTimeOriginal" "${INPUT}"
  374. NEWFILE="${INPUT_DIR}"/"${INPUT_BASENAME}${SUFFIX}"."${INPUT_EXTENSION}"
  375. mv "${INPUT}" "${NEWFILE}"
  376. exiftool '-FileName<DateTimeOriginal' -d '%Y%m%d-%f%%-c.%%e' "${NEWFILE}"
  377. if [[ "${2}" != "" ]]; then
  378. echo "Moving to the next file."
  379. fi
  380. ################################################################
  381. # PROGRESSBAR CODE - BEGIN
  382. let inc++
  383. # Percentage needs to be calculated like this due to bash rounding limitations.
  384. PERCENT_VALUE=$(((${mltp}*${tics})/(200*${numargs}/${inc} % 2 + ${mltp}*${numargs}/${inc})))
  385. # Output: 20, 40, 59, 80, 100 etc.
  386. qdbus $dbusRef Set "" "value" "${PERCENT_VALUE}";
  387. qdbus $dbusRef setLabelText "${LABELTEXT} (${inc}/${numargs})";
  388. # PROGRESSBAR CODE - END
  389. # Move to the next file.
  390. shift
  391. done
  392. ##############################################
  393. # Close processing window if cancelled event has been triggered.
  394. # PROGRESSBAR CODE - BEGIN
  395. # If the process was cancelled, remove tmp file and exit the script.
  396. if [[ ! $(qdbus $dbusRef wasCancelled) == "false" ]]; then
  397. exit 0
  398. fi
  399. #Close processing window if not cancelled and processing finished.
  400. qdbus $dbusRef close
  401. # PROGRESSBAR CODE - END
  402. exit 0