From: Colin Clark Date: Tue, 3 Jan 2023 16:17:51 +0000 (+0000) Subject: Fix #990: Display full-resolution embedded jpg from CR3 files X-Git-Tag: v2.1~111 X-Git-Url: http://geeqie.org/cgi-bin/gitweb.cgi?p=geeqie.git;a=commitdiff_plain;h=c45c933d29159b81aab97ee4f99b00267d41746a Fix #990: Display full-resolution embedded jpg from CR3 files https://github.com/BestImageViewer/geeqie/issues/990 - Use libraw in preference to exiv2, as it will extract the largest preview image from a .cr3 file - Revise export-jpeg plugin to also use exiftool when it detects a larger number of preview images than exiv2, and additionally include image auto-rotate --- diff --git a/doc/diagrams.dox b/doc/diagrams.dox index 3ea62697..0fc6948a 100644 --- a/doc/diagrams.dox +++ b/doc/diagrams.dox @@ -362,8 +362,8 @@ * object image_loader_setuploader * circle "il->memory_mapped" * object exif_get_preview_ - * object exif_get_preview * object libraw_get_preview + * object exif_get_preview * * image_change : image.cc * image_change_complete : image.cc @@ -376,12 +376,12 @@ * image_loader_setuploader : - * image_loader_setuploader : Select backend using magic * image_loader_setup_source : image-load.cc + * libraw_get_preview : image-load-libraw.cc * exif_get_preview : exiv2.cc * exif_get_preview : EXIV2_TEST_VERSION(0,17,90) * exif_get_preview_ : exif.cc * exif_get_preview_ : - * exif_get_preview_ : If exiv2 not installed - * libraw_get_preview : image-load-libraw.cc * * image_change --> image_change_complete * image_change_complete --> image_load_begin @@ -390,8 +390,8 @@ * image_loader_start_thread --> image_loader_thread_run * image_loader_start_thread --> image_loader_setup_source * image_loader_setup_source --> exif_get_preview_ - * image_loader_setup_source --> exif_get_preview - * image_loader_setup_source --> libraw_get_preview : Try libraw if exiv2 fails + * image_loader_setup_source --> exif_get_preview : Try exiv2 if libraw fails + * image_loader_setup_source --> libraw_get_preview * exif_get_preview_ ..> "il->memory_mapped" * exif_get_preview ..> "il->memory_mapped" * libraw_get_preview ..> "il->memory_mapped" diff --git a/plugins/export-jpeg/geeqie-export-jpeg b/plugins/export-jpeg/geeqie-export-jpeg index 088979a1..cf83ca54 100755 --- a/plugins/export-jpeg/geeqie-export-jpeg +++ b/plugins/export-jpeg/geeqie-export-jpeg @@ -3,80 +3,231 @@ ## @file ## @brief Extract embedded jpegs from a raw file ## +## Use exiftool if it detects a higher number of preview +## images, otherwise use exiv2 if available +## - exiv2 does not see the largest preview image in a .cr3 file. +## +## Note that exiftool is noticeably slower than exiv2 +## ## - Display a list of the embedded files ## - Extract the selected image to a tmp folder +## - Rotate image if exif data is available ## - If jpgicc is installed, correct for currently selected rendering intent -## and store in a new file +## - Store in a new file ## - Set Geeqie focus to the newly generated image ## -if ! [ -x "$(command -v exiv2)" ] +use_exiftool="false" + +if ! [ -x "$(command -v exiftool)" ] then - zenity --info --width=300 --height=100 --text="Export jpeg from raw file\n\nexiv2 is not installed" --title="Geeqie export jpeg" 2>/dev/null - exit 1 + if ! [ -x "$(command -v exiv2)" ] + then + zenity --info --width=300 --height=100 --text="Export jpeg from raw file\n\nNeither exiftoool nor exiv2 are installed" --title="Geeqie export jpeg" 2> /dev/null + exit 1 + fi fi if ! [ -x "$(command -v jpgicc)" ] then - zenity --info --width=300 --height=100 --text="Export jpeg from raw file\n\njpgicc is not installed\ncolor corrections will not be made\nYou may install via liblcms2-utils" --title="Geeqie export jpeg" 2>/dev/null + zenity --info --width=300 --height=100 --text="Export jpeg from raw file\n\njpgicc is not installed\ncolor corrections will not be made\nYou may install via liblcms2-utils" --title="Geeqie export jpeg" 2> /dev/null +fi + +IFS=' +' + +exiv2_count=0 +if list=$(exiv2 --print preview "$1") +then + if [ "$(echo "$list" | wc --words)" -gt 1 ] + then + exiv2_count=$(echo "$list" | wc --lines) + fi +fi + +exiftool_count=0 +in_list=$(exiftool -veryshort -preview:all -orientation# "$1") +if echo "$in_list" | grep --quiet Orientation - +then + exiftool_count=$(($(echo "$in_list" | wc --lines) - 1)) +else + exiftool_count=$(echo "$in_list" | wc --words) +fi + +if [ "$exiftool_count" -gt "$exiv2_count" ] +then + use_exiftool="true" + count="$exiftool_count" +else + count="$exiv2_count" +fi + +if [ "$use_exiftool" = "true" ] +then + # An integer value is returned by a # suffix + in_list=$(exiftool -veryshort -preview:all -orientation# "$1") + + if [ "$(echo "$in_list" | wc --lines)" -gt 0 ] + then + # $in_list is in the form of lines e.g. + # + # OtherImage: (Binary data 138367 bytes, use -b option to extract) + # PreviewImage: (Binary data 138367 bytes, use -b option to extract) + # ... + # Orientation: 8 + + if echo "$in_list" | grep --quiet Orientation - + then + orientation=$(echo "$in_list" | tail --lines=1 | cut --delimiter=' ' --fields=2) + count=$(($(echo "$in_list" | wc --lines) - 1)) + list=$(echo "$in_list" | head --lines=-1 | sort --field-separator=: --key=2 --sort=human-numeric --reverse) + else + orientation=0 + list="$in_list" + fi + else + count=0 + fi +else + orientation_str=$(exiv2 -g Exif.Image.Orientation -pv "$1") + + # orientation in the form e.g. + # 0x0112 Image Orientation Short 1 8 + + orientation=$(echo "$orientation_str" | tr --squeeze-repeats ' ' | cut --delimiter=' ' --fields=6) fi -count=$(exiv2 -pp "$1" | wc -l) if [ "$count" -eq 0 ] then - zenity --info --width=300 --height=100 --text="Export jpeg from raw file\n\nFile contains no embedded images" --title="Geeqie export jpeg" 2>/dev/null - exit 1 + zenity --info --width=300 --height=100 --text="Export jpeg from raw file\n\nFile contains no embedded images" --title="Geeqie export jpeg" 2> /dev/null + exit 0 fi -IFS=' -' +case "$orientation" in + 2) + rotation="-flop" + ;; + 3) + rotation="-rotate 180" + ;; + 4) + rotation="-flip" + ;; + 5) + rotation="-transpose" + ;; + 6) + rotation="-rotate 90" + ;; + 7) + rotation="-transverse" + ;; + 8) + rotation="-rotate -90" + ;; + *) + rotation="" + ;; +esac -list=$(exiv2 -pp "$1") -image_list="" n=1 +image_list="" for image in $list do - if [ "$n" -eq "$count" ] + if [ "$use_exiftool" = "true" ] then - image_list="${image_list:+${image_list}}TRUE\n$image\n$n" + # $image is in the form of e.g. + # OtherImage: (Binary data 138367 bytes, use -b option to extract) + + preview_name_colon=$(echo "$image" | cut --delimiter=' ' --fields=1) + preview_name=$(echo "$preview_name_colon" | cut --delimiter=':' --fields=1) + bytes=$(echo "$image" | cut --delimiter=' ' --fields=4) + + params=$(exiftool -b -"$preview_name" "$1" | exiftool -veryshort -short -ImageSize -MIMEType -) + size=$(echo "$params" | head -1) + mime=$(echo "$params" | tail -1) + + if [ "$n" -eq "$count" ] + then + image_list="${image_list:+${image_list}}TRUE\nPreview $n: $mime,\t $size pixels,\t $bytes bytes\n$n:$preview_name:$mime" + else + image_list="${image_list:+${image_list}}FALSE\nPreview $n: $mime,\t $size pixels,\t $bytes bytes\n$n:$preview_name:$mime\n" + fi else - image_list="${image_list:+${image_list}}FALSE\n$image\n$n\n" + if [ "$n" -eq "$count" ] + then + image_list="${image_list:+${image_list}}TRUE\n$image\n$n" + else + image_list="${image_list:+${image_list}}FALSE\n$image\n$n\n" + fi fi + n=$((n + 1)) done -image_selected=$(echo "$image_list" | zenity --width=500 --height=250 --title="Geeqie export jpeg" --list --text "Select embedded image" --radiolist --column "Select" --column "Image" --column "n" --hide-column=3 --print-column=3 2>/dev/null) +image_selected=$(echo "$image_list" | zenity --width=500 --height=250 --title="Geeqie export jpeg" --list --text "Select embedded image" --radiolist --column "Select" --column "Image" --column "n" --hide-column=3 --print-column=3 2> /dev/null) if [ -n "$image_selected" ] then tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/geeqie.XXXXXXXXXX") - exiv2 --location "$tmpdir" -ep"$image_selected" "$1" + if [ "$use_exiftool" = "true" ] + then + # $image_selected is in the form e.g. + # 4:jpegfromraw:image/jpeg - render_str=$(geeqie --remote --get-render-intent) + image_no=$(echo "$image_selected" | cut --delimiter=':' --fields=1) + image_id=$(echo "$image_selected" | cut --delimiter=':' --fields=2) + image_mime=$(echo "$image_selected" | cut --delimiter=':' --fields=3) + image_extension=$(echo "$image_mime" | cut --delimiter='/' --fields=2) + base_name=$(basename "$1") + image_name="${base_name%.*}" + exiftool -b -"$image_id" "$1" > "$tmpdir/$image_name-preview$image_no.$image_extension" + else + exiv2 --location "$tmpdir" -ep"$image_selected" "$1" + fi - case $render_str in - "Perceptual" ) - render_key=0;; - "Relative Colorimetric" ) - render_key=1;; - "Saturation" ) - render_key=2;; - "Absolute Colorimetric" ) - render_key=3;; - esac + if [ -n "$rotation" ] + then + command_str="mogrify $rotation \"$tmpdir/*\"" + sh -c "$command_str" + fi + + base_name=$(basename "$tmpdir/"*) + image_extension="${base_name##*.}" - filename=$(basename "$tmpdir/"* ".jpg") - if [ -x "$(command -v jpgicc)" ] + if echo "$base_name" | grep --quiet --ignore-case "\.jpeg$" || echo "$base_name" | grep --quiet --ignore-case "\.jpg$" then - filename_ri="$tmpdir/""$filename""-ri.jpg" - jpgicc -t $render_key "$tmpdir/""$filename"".jpg" "$filename_ri" + render_str=$(geeqie --remote --get-render-intent) - rm "$tmpdir/""$filename"".jpg" + case $render_str in + "Perceptual") + render_key=0 + ;; + "Relative Colorimetric") + render_key=1 + ;; + "Saturation") + render_key=2 + ;; + "Absolute Colorimetric") + render_key=3 + ;; + *) + render_key=0 + ;; + esac - geeqie --remote view:"$filename_ri" - else - geeqie --remote view:"$tmpdir/""$filename"".jpg" + filename=$(basename "$tmpdir/"* ".$image_extension") + if [ -x "$(command -v jpgicc)" ] + then + filename_ri="$tmpdir/""$filename""-ri.jpg" + jpgicc -t "$render_key" "$tmpdir/""$filename"".$image_extension" "$filename_ri" + + rm "$tmpdir/$filename.$image_extension" + fi fi + + geeqie --remote view:"$tmpdir/" fi diff --git a/src/image-load.cc b/src/image-load.cc index 8516ef28..44db91e2 100644 --- a/src/image-load.cc +++ b/src/image-load.cc @@ -1008,7 +1008,7 @@ static gboolean image_loader_setup_source(ImageLoader *il) } else { - il->mapped_file = exif_get_preview(exif, (guint *)&il->bytes_total, 0, 0); /* get the largest available preview image or NULL for normal images*/ + il->mapped_file = libraw_get_preview(il, (guint *)&il->bytes_total); if (il->mapped_file) { @@ -1020,25 +1020,27 @@ static gboolean image_loader_setup_source(ImageLoader *il) } else { - il->preview = IMAGE_LOADER_PREVIEW_EXIF; + il->preview = IMAGE_LOADER_PREVIEW_LIBRAW; } } } - /* If exiv2 does not find a thumbnail, try libraw (which may be slower) */ + /* If libraw does not find a thumbnail, try exiv2 */ if (!il->mapped_file) { - il->mapped_file = libraw_get_preview(il, (guint *)&il->bytes_total); + il->mapped_file = exif_get_preview(exif, (guint *)&il->bytes_total, 0, 0); /* get the largest available preview image or NULL for normal images*/ if (il->mapped_file) { + /* Both exiv2 and libraw sometimes return a pointer to a file + * section that is not a jpeg */ if (!(il->mapped_file[0] == 0xFF && il->mapped_file[1] == 0xD8)) { il->mapped_file = NULL; } else { - il->preview = IMAGE_LOADER_PREVIEW_LIBRAW; + il->preview = IMAGE_LOADER_PREVIEW_EXIF; } } }