Импорт фотографий из цифровых камер с использованием gphoto2 посредством PTP и /bin/bash

Attachments: 2009/07/gnome-volume-properties.png, /images/gnome-dialog-1.png, /images/gnome-dialog-2.png, /images/import-photos-1.png, /images/import-photos-2.png, /images/import-photos-3.png, /images/import-photos-4.png, /images/import-photos-5.png, /images/import-photos-6.png

Набрел я как то на французском форуме убунту на очень интересную ветку Script bash - Importer automatiquement les photos d’un appareil

Собственно сама идея меня захватила тем более что media-libs/libgphoto2 и media-gfx/gphoto2 в сумме все равно меньше чем к примеру media-gfx/f-spot которому еще и нужен dev-lang/mono

Итак для начала я просто локализовал то что было сделано до меня французами

#!/bin/bash
#Licence GPL
#Version 2 : Refonte du programme, ajout de la creation de catalogue
#
#
#Version 1 : Importe des photos via PTP ou un repertoire quelconque (dont appareil monté en USB mass-storage),
#            renomme les photos selon les exifs, avec choix de methode de renommage,
#            pivote les photos selon les exifs (avec jpegtran)
#            trie les photos selon la date des exifs avec choix de l'arborescence de tri,
#            modifie le LensType des .CR2 (Utile pour un canon 350D pour retoucher la photo avec DPP (wine) (correction de l'objectif accessible))
#
#Necessite : exiftool, zenity, gphoto2, jpegtran
#
# aide de zenity : yelp file:///usr/share/gnome/help/zenity/fr/zenity.xml
#

###########
#IMPORTANT#
###########
#choses à modifier selon l'appareil : - les champs exifs dependent de l'appareil photo. il est preferable de les verifier, particulierement le champ de modele de l'appareil (selon ce que vous voulez que ca affiche. Pour moi, ca affiche "350D" alors que le champ complet est "Canon EOS 350D DIGITAL").
#                                     - la fonction de changement de lenstype n'est pas utile a tous le monde...


#############
##Fonctions##
#############

####Pivoter selon exifs
function pivot {
orient="$(exiftool -orientation $i | cut -d " " -f24)"
if [ "$orient" = "90" ]; then
 jpegtran -rotate 90 -copy all $i > tmp
 mv tmp $i
 exiftool -orientation="Horizontal (normal)" -overwrite_original $i
elif [ "$orient" = "270" ]; then
 jpegtran -rotate 270 -copy all $i > tmp
 mv tmp $i
 exiftool -orientation="Horizontal (normal)" -overwrite_original $i
fi
}

####Modifier le LensType
function LType {
lens=$(exiftool -Lens $i)
if [ "$(echo $lens | cut -d " " -f3-5)" = "18.0 - 55.0mm" ]; then
 exiftool -LensType="Canon EF-S 18-55mm f/3.5-5.6" $i
elif [ "$(echo $lens | cut -d " " -f3)" = "200.0mm" ]; then
 exiftool -LensType="Canon EF 200mm f/2.8L II" $i
elif [ "$(echo $lens | cut -d " " -f3)" = "50.0mm" ]; then
 exiftool -LensType="Canon EF 50mm f/1.8" $i
fi
}

####Sortie volontaire par le bouton annuler
function sortie {
zenity --warning --text="Не указан каталог \nДальнейшая работа сценария невозможна."
exit
}


######################
##Début du Programme##
######################

#detection de l'appareil photo : gphoto2 => si il y a quelque chose, proposer de prendre l'appareil photo detecte et alors -> action.
if [ "$(gphoto2 --auto-detect | wc -l)" -ge 3 ]; then
 apn="$(gphoto2 --auto-detect)"
 zenity --question --text="Камера обнаружена ? \n\n$apn" --title="Автоматическое обнаружение"
 okgphoto=$?
else
 okgphoto=1
fi

#Si pas d'appareil detecté ou annulation, choisir un repertoire avec zenity --file-selection --directory contenant des photos (ou alors selectionner les photos), puis action
if [ "$okgphoto" = "1" ]; then
 rep=$(zenity --file-selection --directory --title="Выбор каталога для импорта")
 if [ "$rep" = "" ]; then
  sortie
 fi
fi

#choix des actions a effectuer
action=$(zenity --list --checklist\
     --width=390 --height=290\
     --title="Что делать?"\
     --text="Выберите действия для выполнения либо нажмите отменить"\
     --column=" " --column="Описание"\
     TRUE    "Импорт фотографий"\
     FALSE    "Удаление файлов на устройстве"\
     FALSE    "Переименование фотографий"\
     TRUE    "Организовать фотографии"\
     TRUE    "Поворот jpeg согласно exifs"\
     FALSE    "Создать файл каталога"\
     TRUE    "Установите тип цели в EXIFS из .cr2")
import=$(echo "$action" | grep "Импорт фотографий")
if [ "$action" = "" ]; then
 sortie
elif [ "$import" = "" ]; then
 zenity --warning --text="Нечего делать, \nДальнейшая работа сценария невозможна."
 exit
fi
#choix du repertoire de base
repbase=$(zenity --file-selection --directory --title="Выбор целевого каталога" --text="Выбрать базовый каталог, куда фотографии будут скопированы :")
if [ "$repbase" = "" ]; then
  sortie
fi

#import des photos dans le repertoire de base
cd $repbase
supprime=$(echo "$action" | grep "Удаление файлов на устройстве")
if [ "$supprime" = "" ]; then
 if [ "$okgphoto" = "1" ]; then  #pas PTP
  cp -v "$rep"/*.jpg "$rep"/*.JPG "$rep"/*.cr2 "$rep"/*.CR2 . | zenity --progress --text="Пожалуйста, подождите\nИмпорт текущих фото..." --pulsate --auto-close
 else #PTP
  gphoto2 --get-all-files | zenity --progress --text="Пожалуйста, подождите\nИмпорт текущих фото..." --pulsate --auto-close
 fi
else
 if [ "$okgphoto" = "1" ]; then  #pas PTP
  mv -v "$rep"/*.jpg "$rep"/*.JPG "$rep"/*.cr2 "$rep"/*.CR2 . | zenity --progress --text="Пожалуйста, подождите\nПеремещение фотографий..." --pulsate --auto-close
 else #PTP
  gphoto2 --get-all-files | zenity --progress --text="Пожалуйста, подождите\nИмпорт текущих фото..." --pulsate --auto-close
  gphoto2 --delete-all-files --recurse | zenity --progress --text="Пожалуйста, подождите\nУдаление текущей фотографии..." --pulsate --auto-close
 fi
fi
if [ "$?" != "0" ]; then
 zenity --error --text="Произошла ошибка при импорте камеры.\nОстановить сценарий." --title="Ошибка"
 exit
fi


###########################
##Préparation des actions##
###########################

#Modifier le LensType
modifltype=$(echo "$action" | grep "Установите тип цели в EXIFS из .cr2")

#Renommage
renommer=$(echo "$action" | grep "Переименование фотографий")
if [ "$renommer" != "" ]; then
 zenity --info --text="В следующем окне выберите как переименовать фотографии. Эти данные (год, месяц, день, ...), взяты из информации exifs каждой фотографии.\n\nВарианты :\n%a : Аббревиатура дней (например Пн)\n%A : День (например Понедельник)\n%b : Абберевиатура месяца (например Ян)\n%B : Месяц\n%d : День месяца (например 01)\n%H : Часы\n%M : Минуты\n%m : Месяц по счету\n%y : Последние две цифры года (например 90)'\n%Y : Год (например 2600)\n%P : Модель камеры \n\nНапример : %P-%H-%M для имен типа : Модель-Часы-Минуты"
 renom=$(zenity --entry \
     --title="Классификация" \
     --text="Укажите как переименовывать фотографии (например %P-%H-%M) :"\
     --entry-text "%P-%H-%M")
fi

#Pivoter
pivoter=$(echo "$action" | grep "Поворот jpeg согласно exifs")

#Tri
classer=$(echo "$action" | grep "Организовать фотографии")
if [ "$classer" != "" ]; then
 zenity --info --text="В следующем окне выберите как классифицировать каталог. Эти данные (год, месяц, день, ...), взяты из информации exifs каждой фотографии.\n\nВарианты :\n%a : Аббревиатура дней (например Пн)\n%A : День (например Понедельник)\n%b : Абберевиатура месяца (например Ян)\n%B : Месяц\n%d : День месяца (например 01)\n%H : Часы\n%M : Минуты\n%m : Месяц по счету\n%y : Последние две цифры года (например 90)'\n%Y : Год (например 2600)\n%P : Модель камеры \n\nНапример : %Y/%B/%d/ для имен типа : путь/к/базе/год/месяц/день/"
 Class=$(zenity --entry \
     --title="Классификация" \
     --text="Укажите как организовать базу (например %Y/%B/%d/) :"\
     --entry-text "%Y/%B/%d/")
fi

#Catalogue
cata=$(echo "$action" | grep "Создать файл каталога")
if [ "$cata" != "" ]; then
 cat=$(zenity --entry \
       --title="Каталог" \
       --text="Введите имя каталога :")
 repcat=""$repbase"/"$cat""
 imagescat=$(zenity --file-selection --multiple --title="Выбор картинок для каталога" --text="Выберите изображения, которые будут находиться в каталоге :")
 if test ! -e "$repcat"; then
  mkdir -p "$repcat"
 fi
else
 imagescat=""
fi

#Nombre d'images
njpg=$(ls *.jpg *.JPG | wc -w)
ncr2=$(ls *.CR2 *.cr2 | wc -w)

###########################
####Programme par image####
###########################

ajpg=0
for i in *.jpg *.JPG; do
#variables contenant les differents exifs
 exiftime=$(exiftool -CreateDate -d "%a %A %b %B %d %H %m %y %Y %M" $i)
 a="$(echo $exiftime | cut -d " " -f4)"
 A="$(echo $exiftime | cut -d " " -f5)"
 b="$(echo $exiftime | cut -d " " -f6)"
 B="$(echo $exiftime | cut -d " " -f7)"
 d="$(echo $exiftime | cut -d " " -f8)"
 H="$(echo $exiftime | cut -d " " -f9)"
 m="$(echo $exiftime | cut -d " " -f10)"
 y="$(echo $exiftime | cut -d " " -f11)"
 Y="$(echo $exiftime | cut -d " " -f12)"
 M="$(echo $exiftime | cut -d " " -f13)"
 P="$( exiftool -Model $i | cut -d " " -f21)"
#renommage
 if [ "$renommer" != "" ]; then
  nom=$(echo "$renom" | sed s/"%a"/"$a"/ | sed s/"%A"/"$A"/ | sed s/"%b"/"$b"/ | sed s/"%B"/"$B"/ | sed s/"%d"/"$d"/ | sed s/"%H"/"$H"/ | sed s/"%m"/"$m"/ | sed s/"%y"/"$y"/ | sed s/"%Y"/"$Y"/ | sed s/"%M"/"$M"/ | sed s/"%P"/"$P"/)-$(echo "$i" | cut -d "_" -f2)
  mv $i $nom
  i="$nom"
 fi
#pivotage
 if [ "$pivoter" != "" ]; then
  pivot $i;
 fi
#classer
 if [ "$classer" != "" ]; then
  reptri="$repbase"/$(echo "$Class" | sed s/"%a"/"$a"/ | sed s/"%A"/"$A"/ | sed s/"%b"/"$b"/ | sed s/"%B"/"$B"/ | sed s/"%d"/"$d"/ | sed s/"%H"/"$H"/ | sed s/"%m"/"$m"/ | sed s/"%y"/"$y"/ | sed s/"%Y"/"$Y"/ | sed s/"%P"/"$P"/)
  if test ! -e $reptri; then
   mkdir -p $reptri
  fi
  mv $i $reptri
 else reptri="$repbase"
 fi
#cataloguer
 if [ "$(echo $imagescat | grep "$i")" != "" ]; then
  ln -s "$reptri""$i" "$repcat"/
 fi
ajpg=$[$ajpg + 1]
echo $[100*$ajpg/$njpg]
done | zenity --progress --text="Пожалуйста, подождите\nВыполнение действий над jpeg..." --auto-close

acr2=0
for i in *.cr2 *.CR2; do
#variables contenant les exifs
 exiftime=$(exiftool -CreateDate -d "%a %A %b %B %d %H %m %y %Y %M" $i)
 a="$(echo $exiftime | cut -d " " -f4)"
 A="$(echo $exiftime | cut -d " " -f5)"
 b="$(echo $exiftime | cut -d " " -f6)"
 B="$(echo $exiftime | cut -d " " -f7)"
 d="$(echo $exiftime | cut -d " " -f8)"
 H="$(echo $exiftime | cut -d " " -f9)"
 m="$(echo $exiftime | cut -d " " -f10)"
 y="$(echo $exiftime | cut -d " " -f11)"
 Y="$(echo $exiftime | cut -d " " -f12)"
 M="$(echo $exiftime | cut -d " " -f13)"
 P="$( exiftool -Model $i | cut -d " " -f21)"
#modifier le lenstype
 if [ "$modifltype" != "" ]; then
  LType $i;
 fi
#renommage
 if [ "$renommer" != "" ]; then
  nom=$(echo "$renom" | sed s/"%a"/"$a"/ | sed s/"%A"/"$A"/ | sed s/"%b"/"$b"/ | sed s/"%B"/"$B"/ | sed s/"%d"/"$d"/ | sed s/"%H"/"$H"/ | sed s/"%m"/"$m"/ | sed s/"%y"/"$y"/ | sed s/"%Y"/"$Y"/ | sed s/"%M"/"$M"/ | sed s/"%P"/"$P"/)-$(echo "$i" | cut -d "_" -f2)
  mv $i $nom
  i="$nom"
 fi
#classer
 if [ "$classer" != "" ]; then
reptri="$repbase"/$(echo "$Class" | sed s/"%a"/"$a"/ | sed s/"%A"/"$A"/ | sed s/"%b"/"$b"/ | sed s/"%B"/"$B"/ | sed s/"%d"/"$d"/ | sed s/"%H"/"$H"/ | sed s/"%m"/"$m"/ | sed s/"%y"/"$y"/ | sed s/"%Y"/"$Y"/ | sed s/"%P"/"$P"/)
 if test ! -e $reptri; then
  mkdir -p $reptri
 fi
 mv $i $reptri
 else reptri="$repbase"
 fi
#cataloguer
 if [ "$(echo $imagescat | grep "$i")" != "" ]; then
  ln -s "$reptri""$i" "$repcat"/
 fi
acr2=$[$acr2 + 1]
echo $[100*$acr2/$ncr2]
done | zenity --progress --text="Пожалуйста, подождите\nВыполнение действий над cr2..." --auto-close

#Fin du programme
zenity --info --text="Импорт окончен !"
exit

Однако многое лично меня смутило… Для начала я хотел чтобы все zenity
отображающие процессы показывали не бездумно

zenity --progress --auto-close --pulsate

а реально отображали бы состояние процесса.
Ну и опять же даже не сильно вникая можно очень многое сделать гораздо проще.
В общем немного подаставав обитателей канала #linux сети RusNet IRC Network а главное получив неоценимую помощь и подсказки от ramok в конце концов дошел вот до такого.

#!/bin/bash

#import-photos

#################################################################################
#Copyright (C) 2007 Free Software Foundation.

#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.

##################################################################################

################################################
#Purpose: Automate import photos from digital camera using gphoto2 through PTP and /bin/bash
#Based on http://forum.ubuntu-fr.org/viewtopic.php?id=146629&p=1
#Date: Пятница, 31 Июль 2009
#Authors: init_6, ramok 
#Improvements, Feedback, comments: Please go to http://sudormrf.wordpress.com/2009/07/31/импорт-фотографий-из-цифровых-камер/
#Notes: To use script first install media-gfx/gphoto2, media-libs/exiftool
#Version: 1.?
################################################

#ВАЖНО! - ДЕЛИТЕСЬ УСОВЕРШЕНСТВОВАНИЯМИ СКРИПТА С ОБЩЕСТВЕННОСТЬЮ

function config {
    cd `dirname $0`;

    rep=$HOME"/Photos";

    if [ "$(gphoto2 --auto-detect | wc -l)" -ge 3 ]; then
    zenity --question --text="Камера обнаружена ? \n\n$(gphoto2 --auto-detect)" --title="Автоматическое обнаружение";
    ok_gphoto=$?;
    else
    ok_gphoto=1;
    fi
}

function num_files {
    if [ ${ok_gphoto} = 0 ]; then
    num_files=$(gphoto2 --list-files | grep -ve '^There' | wc -l);
    fi
}

function copy_pictures {
    if [ ${ok_gphoto} = 0 ]; then
    (for ((file=1;file/dev/null; echo $(($file*100/$num_files)); done) | zenity --progress --auto-close --text="Пожалуйста подождите,\nИмпорт текущих фото...";
    if [ $? != 0 ]; then
        zenity --error --text="Ошибка импорта фотографий";
        cancel;
    fi
    fi
}

function delete_pictures {
    if [ ${ok_gphoto} = 0 ]; then
    (for ((file=1;file/dev/null; echo $(($file*100/$num_files)); done) | zenity --progress --auto-close --text="Пожалуйста подождите,\nУдаление фотографий...";
    if [ $? != 0 ]; then
        zenity --error --text="Ошибка удаления фотографий";
        cancel;
    fi
    fi
}

function move_pictures {
    copy_pictures;
    delete_pictures;
}

function extract {
    if [ ${num_files} = 0 ]; then
    zenity --error --text="Нет фотографий" --title="Ошибка";
    cancel;
    fi

    cd "$rep";

    echo "$ACTION" | grep "Сохранить файлы на устройстве" >/dev/null;
    if [ "$?" = 0 ]; then
    copy_pictures;
    else
    move_pictures;
    fi
    if [ "${PIPESTATUS[0]}" != 0 ]; then
    zenity --error --text="Произошла ошибка при импорте камеры" --title="Ошибка";
    cancel;
    fi

    zenity --info --text="В следующем окне выберите как классифицировать каталог. Эти данные (год, месяц, день, ...), взяты из информации exifs каждой фотографии.\n\nВарианты :\n%a : Аббревиатура дней (например Пн)\n%A : День (например Понедельник)\n%b : Абберевиатура месяца (например Ян)\n%B : Месяц\n%d : День месяца (например 01)\n%H : Часы\n%M : Минуты\n%m : Месяц по счету\n%y : Последние две цифры года (например 90)'\n%Y : Год (например 2600)\n%P : Модель камеры \n\nНапример : %Y/%B/%d/ для имен типа : путь/к/базе/год/месяц/день/"
    Class=$(zenity --entry \
     --title="Классификация" \
     --text="Укажите как организовать базу (например %Y/%B/%d/) :"\
     --entry-text "%Y/%B/%d/")

    ajpg=0
    for i in *.jpg *.JPG; do
    eval $(exiftool -CreateDate -d "a=%a A=%A b=%b B=%B d=%d h=%H m=%m y=%y Y=%Y M=%M" $i | sed -e 's/.*: //')
    repcible="$rep"/$(echo "$Class" | sed s/"%a"/"$a"/ | sed s/"%A"/"$A"/ | sed s/"%b"/"$b"/ | sed s/"%B"/"$B"/ | sed s/"%d"/"$d"/ | sed s/"%H"/"$H"/ | sed s/"%m"/"$m"/ | sed s/"%y"/"$y"/ | sed s/"%Y"/"$Y"/ | sed s/"%P"/"$P"/)
    if test ! -e $repcible; then
        mkdir -p $repcible
    fi
    mv $i $repcible
    ajpg=$[$ajpg + 1]
    echo $[100*$ajpg/$num_files]
    done | zenity --progress --text="Пожалуйста, подождите\nВыполнение действий над jpeg..." --auto-close

    zenity --info --text="Фотографии были успешно импортированы" --title="Информация";

}

function cancel {
    if [ "${PIPESTATUS[0]}" != 0 ]; then
    exit
    fi
}

function actions {
    extract;
}

config;

num_files;

ACTION=$(zenity --list --checklist --width=390 --height=290\
        --title="Выбор операций для выполнения"\
        --text="Нажмите кнопку ОК, чтобы начать импортирующими фотографии.\nВыберите для выполнения операций : "\
        --column=" " --column="Описание"\
        TRUE    "Сохранить файлы на устройстве" );

cancel;

actions;

Собственно основные моменты база фотографий располагается в $HOME”/Photos”. Далее происходит импорт фотографий в каталог база/год/месяц/день/ создания фотографии.

Использование вообще банально сохраняете скрипт к примеру в /usr/local/bin/import-photos делаете его исполнимым

chmod +x /usr/local/bin/import-photos

Далее для gnome в gnome-volume-properties “Сменные устройства и носители” для цифровых камер просто устанавливаете команду /usr local/bin/import-photos Вот приблизительно так

gnome-volume-properties

Далее при появлении цифровых камер происходит следующее в начале появляется пара диалоговых окон гнома

В первом надо поставить галочку напротив “Всегда выполнять это действие” и нажать Ок. Иначе это окно будет появляться постоянно при вставке носителя.

gnome-dialog-1

И вот такое окно

gnome-dialog-2

Во втором окне необходимо нажать на “Импортировать фотографии” тогда начинает работать скрипт

import-photos-1

Собственно скрипт автоматически обнаружил носитель с фотографиями. Далее диалог о сохранении файлов на обнаруженном носителе.

import-photos-2

Сам процесс копирования…

import-photos-3

Окно с напоминанием форматов времени.

import-photos-4

И диалог задания формата сортировки базы данных картинок.

import-photos-5

Ну и собственно

import-photos-6

На этом все. :)

Comments