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.

519 lines
18 KiB

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