IPB

Bienvenue invité ( Connexion | Inscription )

2 Pages V   1 2 >  
Reply to this topicStart new topic
> Modifier une donnée EXIF en applescript, La valeur à écrire est à lire dans un fichier excel
Options
Speed Moock
posté 27 Oct 2016, 18:04
Message #1


Adepte de Macbidouille
*

Groupe : Membres
Messages : 42
Inscrit : 30 Aug 2016
Membre no 199 619



Bonjour à tous,

Voici ce que je souhaite faire :
Je dispose de dossiers et sous dossiers contenant des images dont le nom est structuré ainsi :
racine fixe égale à G_
puis code produit en 6 caractères
séparateur fixe _
puis code couleur sur 2 à 4 caractères
séparateur fixe _ZP_
Index d'image valeur 1 à 10
séparateur fixe _
Code interne unique sur 6 caractères

Exemple G_12345_320_ZP_1_565656.jpg
est l'image numéro 1 du produit 12345

En parallèle je dispose d'un énorme listing excel composé en colonne A des codes produits et en colonne B de la taille de ces produit (champ texte)

Je cherche à réaliser un script qui pour chaque image va chercher si elle en trouve la taille dans le listing et si oui écrira dans une donnée EXIF la valeur du champ texte.
Si le code produit n'est pas dans le listing, ne rien écrire.

le script demande donc de la récursivité et l'utilisation de EXIFTOOL (que j'ai téléchargé et installé mais sans savoir faire mieux...)

Avez-vous des idées ?

Merci
Go to the top of the page
 
+Quote Post
Jaypee
posté 28 Oct 2016, 13:26
Message #2


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 346
Inscrit : 29 Aug 2002
Membre no 3 340



Speed Moock,

Au lieu d'empiler plusieurs outils, tu pourrais aussi en choisir un qui fait tout.

Et le langage Swift 3, te permet d'essayer interactivement (comme en Bash, en Perl, en Python ou Ruby) dans un playground créé dans XCode, ou dans un terminal. Ou sur le portaill d'IBM (qui a adopté Swift)
https://swiftlang.ng.bluemix.net/

Un gist (un snippet, un bout de code d'exemple) pour charger une image e tse préparer à lire ses propriétés :
https://gist.github.com/tsuyukimakoto/c7ef8ed096a3e22bda7d
Autre exemple:
http://erkkiahola3.blogspot.de/2015/11/exif-data.html

Par ailleurs, exporte le fichier Excel en csv qui est un simple fichier texte, plus facile à lire dans n'importe quel langage, sur n'importe quel OS.
Swift3 est open source et fonctionne très bien sur Linux aussi.

J-P

Ce message a été modifié par Jaypee - 28 Oct 2016, 13:33.
Go to the top of the page
 
+Quote Post
Speed Moock
posté 28 Oct 2016, 13:38
Message #3


Adepte de Macbidouille
*

Groupe : Membres
Messages : 42
Inscrit : 30 Aug 2016
Membre no 199 619



Bonjour Jaypee,

Merci pour la proposition mais déjà que je suis laborieux en applescript, je ne suis pas rendu sur d'autres langages...

Je vais déjà essayer en AS, je passerai ceinture noire plus tard !
Go to the top of the page
 
+Quote Post
Jaypee
posté 29 Oct 2016, 08:19
Message #4


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 346
Inscrit : 29 Aug 2002
Membre no 3 340



Pas de problème, Speed Moock. Si un outil est une solution, quel problème résoud-il que les autres outils ne savent pas mieux résoudre ?

Applescript demande une connaissance précise du modèle d'objets de macOS. Très facile à lire mais très difficile à écrire avec des nuances comme file, alias, POSIX file etc. Il n'est pas vraiment fait pour les apprentis programmeurs, et source de frustration. Facile pour des choses faciles. Mais quel autre langage ne l'est pas.

Avec la même énergie, on apprend un langage que beaucoup de gens maitrisent avec bien moins de frustrations durant le voyage.

J-P
Go to the top of the page
 
+Quote Post
hellomorld
posté 29 Oct 2016, 09:11
Message #5


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 5 571
Inscrit : 31 Oct 2003
Membre no 11 118



C'est assez simple à faire avec Livecode (http://www.livecode.com). La version Community est opensource et gratuite. C'est un successeur d'Hypercard qui en a conservé le langage (et dont l'Applescript s'est aussi grandement inspiré)
Comme le dit Jaypee, ce sera beaucoup plus simple de travailler sur un fichier texte issu d'excel (je conseille plutôt le format texte tabulé que le vrai csv).
Je te joins 2 fichiers ("piles") qui devraient te servir de base. Un pour lister les fichiers d'une arborescence, l'autre pour utiliser Exiftools (il permet de géotagger un fichier)

Fichier joint  livecode.zip ( 4.94 Ko ) Nombre de téléchargements : 4
.



--------------------
Go to the top of the page
 
+Quote Post
Jaypee
posté 29 Oct 2016, 13:02
Message #6


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 346
Inscrit : 29 Aug 2002
Membre no 3 340



A mon avis on peut se passer de EXIFtools

Il y a dans macOS un petit trésor caché, la commande sips. Essaie un man sips.
Par exemple: sips -g pixelHeight /chemin/de/mon/image.jpg

Et AppleScript a dans sa liste d'applications dont on peut ouvrir le dictionnaire "Image Events"
Il faut commencer par sélectionner une image dans le Finder puis:

Code
tell application "Finder"
    set selectedItem to (item 1 of (get selection))
    set filePath to POSIX path of (selectedItem as string)
    tell application "Image Events"
        set myImage to open (file filePath)
        set dims to (dimensions of myImage)
        close
    end tell
    display dialog ("Width: " & ((item 1 of dims) as string) & ", Height: " & ((item 2 of dims) as string))
end tell


Edit:
Pour l'EXIF, Il faut des outils vraiment spécifiques, et en voici un gratuit et orienté AppleScript, avec un exemple d'extraction de metadata EXIF, voilà ce qu'il produit:
Code
{{exif type:exif make, exif unicode:"Apple"}, {exif type:exif model, exif unicode:"iPhone 6"}, {exif type:software, exif unicode:"Adobe Photoshop Lightroom 5.7 (Macintosh)"}, {exif type:exif creation date, exif unicode:"2016:03:27 15:58:21"}, {exif type:exposure time in seconds, exif float:0.058823529631, exif unicode:"1/17"}, {exif type:aperture fNum, exif float:2.200000047684, exif unicode:"22/10"}, {exif type:exposure program, exif int:2, exif unicode:"2"}, {exif type:ISO film speed, exif int:400, exif unicode:"400"}, {exif type:capture date, exif unicode:"2016:03:27 14:54:43"}, {exif type:exposure bias EV, exif float:0.0, exif unicode:"0/1"}, {exif type:metering mode, exif int:5, exif unicode:"5"}, {exif type:flash, exif int:16, exif unicode:"16"}, {exif type:focal length mm, exif float:4.150000095367, exif unicode:"83/20"}, {exif type:captureDateSubSecondTime, exif unicode:"905"}}


Le soft gratuit est ici:
http://www.yvs.eu.com

J-P

Ce message a été modifié par Jaypee - 29 Oct 2016, 16:08.
Go to the top of the page
 
+Quote Post
Speed Moock
posté 29 Oct 2016, 18:05
Message #7


Adepte de Macbidouille
*

Groupe : Membres
Messages : 42
Inscrit : 30 Aug 2016
Membre no 199 619



Merci à tous !

Je vais profiter du long WE pour m'y pencher.

A bientôt
Go to the top of the page
 
+Quote Post
PBell
posté 29 Oct 2016, 18:53
Message #8


Adepte de Macbidouille
*

Groupe : Membres
Messages : 184
Inscrit : 7 Dec 2013
Lieu : Ile de France
Membre no 188 169



QUOTE (Speed Moock @ 27 Oct 2016, 19:04) *
pour chaque image va chercher si elle en trouve la taille dans le listing et si oui écrira dans une donnée EXIF la valeur du champ texte.


Bonsoir, en lisant cette demande, j'interprète que tu veux lire des dimensions sur Excel, et les écrire dans une sorte de commentaire dans le fichier image.
Mais je ne pense pas que tu veuilles changer la taille de l'image elle-même.

Dans ce cas, l'utilisation via "Image Events" ne peut être adéquates.

Il y a donc un premier groupe question à se poser, avant même de choisir le language:
- ces dimensions que tu veux mettre dans l'image, c'est dans quel but ?
- Est-ce juste un champ texte ?
- Quelle autre application va lire cette donnée ? sur Mac, sur PC ? (la réponse permettra de déterminer si la donnée peut être stockée dans les info file ou si elle doit être à l'intérieur de l'image).

Enfin, mon second groupe de questions est liée à la performance :
- un "énorme" listing Excel... c'est quoi ? 1000 lignes, 10 000 lignes ? 500 000 lignes ? (ce qui donnera aussi une idée du volume de fichier à traiter !)
- le dossier principal contient des sous dossiers : est-ce que tout le contenu n'est constitué que de fichier Image avec le même format de nom ? (ou d'autres fichier peuvent-ils exister ?)

Une fois répondu à ces questions, il sera plus facile de déterminer la méthode et donc le language approprié.
Bien sûr, comme l'indique Jaypee, le fichier Excel devra être traduit en texte (csv par exemple)

Cordialement


--------------------
iMac 27 i7 2,8GHz 8Go/1To 10.6.8 /10.10 / 10.11
iMac 20 C.Duo 2,6Ghz 8Go/350Go 10.6.8 / 10.11
Mini C.Duo 2,0Ghz 2Go/500Go 10.6.8
Go to the top of the page
 
+Quote Post
Jaypee
posté 29 Oct 2016, 19:47
Message #9


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 346
Inscrit : 29 Aug 2002
Membre no 3 340



L'un des scripts de la documentation de "Imagine Photo" fait le boulot, mais le seul champ susceptible de recevoir le texte libre est la champ "info".
CODE
tell application "iMagine Photo"
set thisFile to choose file with prompt "Image file with exif data: "
set savedFile to choose file name default name "NewImageFile.jpg"
set copyrightText to text returned of (display dialog "Enter the copyright text: " default answer "Copyright Jaypee 2016")
set artistText to text returned of (display dialog "Photographers name: " default answer "Jaypee")
set iMageInfo to text returned of (display dialog "Information about the image: " default answer "Product Info")
set thisImporter to import graphic thisFile
tell thisImporter to make exporter with properties {export file type:"JPEG"}
set the export file location of thisImporter to savedFile
set exifData to the exif data of thisImporter
set the export exif data of thisImporter to exifData
set the export exif data of thisImporter to {{exif type:copyright, exif unicode:copyrightText}, {exif type:artist, exif unicode:artistText}, {exif type:info, exif unicode:iMageInfo}}
export thisImporter
close thisImporter
set thisImporter2 to import graphic savedFile
set exifData2 to the exif data of thisImporter2
close thisImporter2
end tell
exifData2


Et la copie de la photo avec les nouveaux EXIFs a bien été créée.

J-P

Ce message a été modifié par Jaypee - 29 Oct 2016, 19:52.
Go to the top of the page
 
+Quote Post
Speed Moock
posté 30 Oct 2016, 00:23
Message #10


Adepte de Macbidouille
*

Groupe : Membres
Messages : 42
Inscrit : 30 Aug 2016
Membre no 199 619



Bonjour à tous

En lisant le post de Pbell je viens de me rendre compte d'un énorme quiproquo
La donnée taille dans mon fichier excel est la valeur en cm du produit photographié dans l'image, pas la taille en pixels de l'image 😜😜😜😜

Quant au listing excel il contient 30000 lignes...


Voilà je pense que cette précision de "taille" réorientera vos réflexions

Merci !!
Go to the top of the page
 
+Quote Post
PBell
posté 30 Oct 2016, 07:22
Message #11


Adepte de Macbidouille
*

Groupe : Membres
Messages : 184
Inscrit : 7 Dec 2013
Lieu : Ile de France
Membre no 188 169



Bonjour,
Merci pour la précision quant aux tailles en cm (je m'en doutais) et à la taille du fichier Excel.

Il reste à savoir ce que tu vas faire de ces dimensions produits (lecture dans d'autres applications,...) une fois mises "dans l'image" pour savoir quel est la meilleure place pour enregistrer cette donnée.
Il y a en effet beaucoup de champs Exif possibles

Cordialement


--------------------
iMac 27 i7 2,8GHz 8Go/1To 10.6.8 /10.10 / 10.11
iMac 20 C.Duo 2,6Ghz 8Go/350Go 10.6.8 / 10.11
Mini C.Duo 2,0Ghz 2Go/500Go 10.6.8
Go to the top of the page
 
+Quote Post
Jaypee
posté 30 Oct 2016, 10:08
Message #12


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 346
Inscrit : 29 Aug 2002
Membre no 3 340



Une recommandation de haut niveau.

Ce traitement est un cas d'école pour le "design pattern" appelé "Visiteur" qui sépare deux fonctions:
- Celle qui permet de parcourir complètement la structure à traiter, c'est le parcours récursif de liste ou d'arbre, à chaque point visité, on applique la deuxième fonction à tous les éléments intéressés à cette étape de la visite, puis on continue la visite.
- Celle dite fonction de visite qui fait le traitement désiré.

Dans le cas présent, la visite pourrait privilégier la liste Excel, et ce serait seulement un parcours de liste. Si on tient à récursiver, on applique la fonction de visite à la tête de liste, puis on parcourt le reste de la liste.
Soit on privilégie les images, et le parcours est un parcours d'arbre, la fonction de visite doit faire la recherche dans la liste Excel et l'écriture de l' EXIF. Dans ce cas, il peut être intéressant de trier au préalable cette liste selon la clé de recherche. On peut aussi envisager de charger la liste complètement en mémoire : Si la ligne fait 1Ko, on consommera 100 Mo de mémoire, une paille.
Comme il est plus commun de vouloir appliquer un certain traitement à tous les fichiers à partir d'une racine, cette approche est recommandée car plus générique et ré-utilisable

Pour l'adaptation en AppleScript:
- Les appels récursifs se signalent par le mot-clé "my"
on recFonction(x, y, z)
if test de fin then
finir
else
my recFonction(x', y', z')
end if
end recFonction

- Comment passer la fonction de visite, pour séparer le parcours du traitement?

Mon exemple simple
CODE
script mult2
on visite(n)
return n * 2
end visite
end script

script carre
on visite(n)
return n * n
end visite
end script

on parcours_liste(indice_depart, liste_num, fonc_visite)
local copie
copy liste_num to copie
if indice_depart > (the count of copie) then
return copie
else
set tete_de_liste to item indice_depart of copie
tell fonc_visite
set item indice_depart of copie to visite(tete_de_liste)
end tell
my parcours_liste(indice_depart + 1, copie, fonc_visite)
end if
end parcours_liste

set exemple to {1, 25, 7, 0, -2}

parcours_liste(1, exemple, mult2)
parcours_liste(1, exemple, carre)



Conclusion: Je ne recommande toujours pas AppleScript aux apprentis programmeurs car il est trop complexe... La preuve est dans mon dernier exemple
On y voit deux appels séparés, pas de réaffectation de variables.
Pourtant, si je n'avais pas explicitement déclaré une variable locale, le paramètre d'entrée "exemple" aurait implicitement "mué", il y aurait au final dans exemple la liste de carrés des doubles, alors qu'à aucun moment on n'a réaffecté la valeur de exemple dans un "set exemple to ...",
Pire encore, le piège est pressenti par un programmeur averti...
local copie
set copie to liste_num -- au lieu de copy liste_num to copie
Le "set" est une copie d'adresse, pas une copie de valeur, donc la déclaration de variable locale n' a aucun effet, à la fin la variable exemple est devenue discrètement {4, 2500, 196, 0, 16} "à l'insu de notre plein gré".

Au final, un effet de surprise, source de bugs difficiles à détecter. Bon courage à celles et ceux qui continuent dans cette voie dangereuse.

J-P

Ce message a été modifié par Jaypee - 30 Oct 2016, 10:17.
Go to the top of the page
 
+Quote Post
Speed Moock
posté 30 Oct 2016, 15:57
Message #13


Adepte de Macbidouille
*

Groupe : Membres
Messages : 42
Inscrit : 30 Aug 2016
Membre no 199 619



Bonjour,

Pour répondre à Pbell :
Le nombre d'images sera toujours inférieur au nombre de lignes du listing excel. Il y a donc une inclusion de l'un dans l'autre, et donc il faut parcourir les dossiers images et en chercher la présence dans le listing.

si trouve => écriture de la donnée dans le champ exif "info" (quitte à écraser un contenu déjà existant)
si non trouvé = > on ne fait rien

Pour information la métadonnée est ensuite reprise sur un site internet comme élément descriptif du produit. Il y a certainement plus simple pour afficher une taille produit sur un site mais on ne me laisse pas le choix et on me demande que l'information soit dans l'image en tant que métadonnée.

@Jaype : merci pour iMagine, je découvre au passage une appli sympa !

Merci
Go to the top of the page
 
+Quote Post
Jaypee
posté 30 Oct 2016, 17:21
Message #14


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 346
Inscrit : 29 Aug 2002
Membre no 3 340



Je complète mon exemple avec un parcours d'arbre. Vraiment c'est tout dans la subtilité, et ça demande énormément d'attention.
CODE
script mult2
on visite(n)
return n * 2
end visite
end script

script carre
on visite(n)
return n * n
end visite
end script

on parcours_liste(liste_num, fonc_visite)
local nums
copy {} to nums
if (the count of liste_num) > 0 then
repeat with num in liste_num
tell fonc_visite
copy visite(num) to end of nums
end tell
end repeat
return nums
else
return {}
end if
end parcours_liste

-- Un niveau a une liste de valeurs et une liste de sous-niveaux

set niveau2 to {valeurs:{200, 201}, sous_niveaux:{}}
set niveau1_2 to {valeurs:{120, 121}, sous_niveaux:{niveau2}}
set niveau1_1 to {valeurs:{110, 111}, sous_niveaux:{}}
set racine to {valeurs:{}, sous_niveaux:{niveau1_1, niveau1_2}}

on parcours_niveau(top, fonc_visite)
local sous_niv
if (count of (sous_niveaux of top)) > 0 then
copy {} to sous_niv
repeat with niv in (sous_niveaux of top)
copy my parcours_niveau(niv, fonc_visite) to end of sous_niv
end repeat
return {valeurs:parcours_liste(valeurs of top, fonc_visite), sous_niveaux:sous_niv}
else
return {valeurs:parcours_liste(valeurs of top, fonc_visite), sous_niveaux:{}}
end if
end parcours_niveau

parcours_niveau(racine, mult2)


La valeur de départ:
{valeurs:{}, sous_niveaux:{{valeurs:{110, 111}, sous_niveaux:{}}, {valeurs:{120, 121}, sous_niveaux:{{valeurs:{200, 201}, sous_niveaux:{}}}}}}
Le résultat:
{valeurs:{}, sous_niveaux:{{valeurs:{220, 222}, sous_niveaux:{}}, {valeurs:{240, 242}, sous_niveaux:{{valeurs:{400, 402}, sous_niveaux:{}}}}}}

Ce message a été modifié par Jaypee - 30 Oct 2016, 17:45.
Go to the top of the page
 
+Quote Post
Zeltron54
posté 30 Oct 2016, 20:14
Message #15


Adepte de Macbidouille
*

Groupe : Membres
Messages : 115
Inscrit : 15 Mar 2008
Lieu : Lorraine
Membre no 110 156



Bonsoir,

Tu peux aussi mettre ton information dans le champs "commentaires" que l'on vois avec un cmd+i .

Ce champs est facilement accessible en applescript avec un script genre : set comment of "chemin du fichier" to "taille du produit" .
Dans ce cas pas besoin d'exiftool.

Exemple avec un fichier texte:

00001 commentaire taille
00002 le com 2
00003 le com 3
00004 le com 4
00005 le com 5
00006 le com 6
00007 le com 7
00008 le com 8
00009 le com 9
00010 le com 10
00011

et un script style:

set CheminTXT to choose file with prompt "Sélectionnez le fichier texte" --Choix du fichier texte

my inspecter(cheminIMG, CheminTXT)
end tell

on inspecter(un_dossier, CheminTXT)

tell application "Finder"
-- traitement des fichiers image:
set les_fichiers to files of un_dossier
repeat with chaque_fichier in les_fichiers
-- traitement d'un fichier image

set nom to name of chaque_fichier --obtient la nom du fichier image
set code_produit to (items 3 thru 7 of nom) as string -- du troisième caractère au septième

-- traitement du fichier texte
open for access CheminTXT
read CheminTXT
set le_texte to the result -- récupère le fichier dans la variable
close access CheminTXT

set AppleScript's text item delimiters to (ASCII character 13)
set toutes_les_lignes to (every text item of le_texte) as list -- récupère les lignes du fichier
set AppleScript's text item delimiters to ""

repeat with i from 1 to count of toutes_les_lignes
set la_ligne to item i of toutes_les_lignes as string -- chaque ligne

set long to length of la_ligne -- si la ligne fait plus de 6 caractères(5 code produit+1tab)
if long > 6 then

set code_prod_list to items 1 thru 5 of la_ligne as string -- recupère la code produit

if code_produit = code_prod_list then -- compare

set lecom to items 7 thru -1 of la_ligne as string --si code produit = alors récupère la suite de la ligne

set comment of chaque_fichier to lecom -- écrit le commentaire

end if
end if
end repeat

end repeat
-- traitement des dossiers images:
set les_dossiers to folders of un_dossier
repeat with chaque_dossier in les_dossiers
-- traitement du dossier
my inspecter(chaque_dossier, CheminTXT)
end repeat
end tell
end inspecter

tell application "Finder"
display dialog "Ok j'ai terminé"
end tell


Ce message a été modifié par Zeltron54 - 30 Oct 2016, 20:59.


--------------------
Imac 27 I7 Fusion drive fin 2013 Ram 8Go Mac OS X (10.13.6)
MacBook Pro 15 pouces mi-2012 8Go Ram Mac OS X (10.13.6)
Go to the top of the page
 
+Quote Post
Jaypee
posté 30 Oct 2016, 21:45
Message #16


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 346
Inscrit : 29 Aug 2002
Membre no 3 340



@Zeltron54,

Le champ Commentaires ne semble pas interrogeable par la commande sips, ni par la lecture des données EXIF.
Si la description L x H x P doit être exploitable par une application web, elle doit être accessible par une interface standard.

Il y a un module Node.js qui lit les données EXIF
https://github.com/RodrigoEspinosa/exif-cli

En revanche le champ Description est le champ EXIF imageInfo, et extractible par sips -g description photo.jpg
D'ailleurs, sachant cela, sips -s description "texte de la description" /chemin/vers/la/phooto.jpg est une interface d'écriture simplifiée:
un "do shell script" pourrait suffire.

J-P

Ce message a été modifié par Jaypee - 31 Oct 2016, 06:56.
Go to the top of the page
 
+Quote Post
Speed Moock
posté 30 Oct 2016, 21:46
Message #17


Adepte de Macbidouille
*

Groupe : Membres
Messages : 42
Inscrit : 30 Aug 2016
Membre no 199 619



Merci Zeltron pour cette proposition, mais je l'avais écartée dès le départ car les personnes qui récupèrent mes images sont sur windows et disent ne pas savoir récupérer les commentaires finder.

A+
Go to the top of the page
 
+Quote Post
PBell
posté 31 Oct 2016, 08:18
Message #18


Adepte de Macbidouille
*

Groupe : Membres
Messages : 184
Inscrit : 7 Dec 2013
Lieu : Ile de France
Membre no 188 169



Bonjour,
Effectivement les seuls champs qui peuvent être utilisé avec des images, tant sur Mac que sur Windows doivent être des champs EXIF ou IPTC.
Les autres champs ne seront pas transférés d'un OS à l'autre (dommage que Microsoft n'ai pas aussi copié cette partie lorsqu'il a crée Windows).

Commençons par le language : nous avons jusqu'à 30 000 lignes dans le fichier Excel et sans doute autant de fichiers image. Donc la meilleure solution semble être un script shell Unix en terme de vitesse.
Cependant, j'ai préféré un script Applescript avec des appels Unix pour 2 raisons:
1) il faut commencer par demander à l'utilisateur le nom du dossier racine et du fichier Excel : c'est facile en AS. mais je ne pense pas que cela soit possible en shell Unix
2) J'ai des lacunes en shell qui ne me permettent pas d'assurer un script qui fonctionne. Mais les autres contributeurs pourront aussi traduire en shell

La demande pose 3 problèmes:
- récursivité dans l'arborescence des dossier et sous dossiers
- recherche rapide, à partir du produit, dans le fichier Excel, pour trouver la colonne B content un texte
- ajout de ce texte dans l'image elle-même (EXIF)


Récursivité:
La solution que j'ai retenue fonctionne, mais sera sans doute longue (peut être trop longue) sur 30000 fichier. Inutile de dire que je n'ai pas tester sur ce nombre, mais sur environ 200 images. C'est le point critique de performance. Je me suis basé sur la fonction "entire content" qui extrait tous les fichiers situés dans une arborescence. Si elle a le mérite d'être simple, ce n'est pas performant et j'ai de grands doutes sur 30 000 fichiers. Il sera sans doute utile de lancer le script plusieurs fois sur des dossiers de niveaux inférieurs pour se limiter à environ 1000 à 2000 images à chaque fois.
Si cela pose un problème, dis le, et je ré-écrirai cette partie en vrai récursivité. Il reste que 30 000 en un seul coup risque d'être très long.

Recherche rapide du produit dans le liste Excel:
Là, je me suis dis "facile !", mais c'est en fait là où j'ai passé le plus de temps. La fonction la plus rapide est une commande shell Unix 'grep'. 'Grep xxx yyy' est capable de trouver la ligne contenant xxx dans le fichier yay... Oui, mais qu'est-ce qu'une ligne ?
En fait, grep considère, comme beaucoup de logiciels, qu'un ligne est un ensemble de caractères se terminant par le caractère spécial linefeed (LF ascii=10). Oui mais... Excel en text tabdelimiter, en cdv, en UTF text,... ne mets pas ces fameux linefeed, mais des Carriage Return (CR ascii=13) ! donc pour grep, tout le fichier n'est qu'une ligne !!!
En analysant les différents format de sortie Excel, la solution est de sauvegarder ton fichier Excel en format "Windows fomatted text": là les fin de lignes sont faites avec le CR et le LF ! Du coup le grep fonctionne parfaitement.
Dans ce format de sortie Excel, la séparation entre les colonne se fait par une tabulation (ascii=9).
Pour les curieux, j'ai ajouté un '^' qui signifie que ce que je cherche doit être en début de ligne (au cas où la colonne B contienne des chiffres comme un code produit !)

Ajout du texte dans l'image:
Pas de doute ici, l'instruction à utiliser est le exiftool. Reste à savoir quel tag doit être utilisé. J'ai choisi 'imageDescription' car c'est une partie de l'EXIF standard et donc cela aura plus de chance d'être lu par de nombreux logiciels.

Voici le script résultant : (testé bien sûr)

CODE
set DosParent to choose folder "Sélectionner le dossier parent contenant les images à traiter"

set WFormatted to choose file "Sélectionner le fichier Windows formated contenant les dimensions"
set WPath to quoted form of (POSIX path of WFormatted)
set AppleScript's text item delimiters to {"_"}
set tab to ASCII character 9

tell application "Finder" to set MesImages to every file in entire contents of DosParent whose name starts with "G_"

repeat with uneImage in MesImages
    tell application "Finder" to set Produit to text item 2 of ((name of uneImage) as string)
    set R to ""
    try
        set R to do shell script "grep ^" & Produit & " " & WPath
    on error
        set R to ""
    end try
    if R is not "" then
        set DimText to text ((offset of tab in R) + 1) thru -1 of R
        set UnixPath to POSIX path of (uneImage as string)
        do shell script "/usr/local/bin/exiftool -ImageDescription='" & DimText & "' -Overwrite_Original " & quoted form of (UnixPath)
    end if
end repeat


Après traitement, tu pourra vérifier dans Aperçu, sur une image traitée, dans la fenêtre inspecteur, onglet IPTC, l'image description contenant ta colonne B.
Cordialement


--------------------
iMac 27 i7 2,8GHz 8Go/1To 10.6.8 /10.10 / 10.11
iMac 20 C.Duo 2,6Ghz 8Go/350Go 10.6.8 / 10.11
Mini C.Duo 2,0Ghz 2Go/500Go 10.6.8
Go to the top of the page
 
+Quote Post
Speed Moock
posté 31 Oct 2016, 08:51
Message #19


Adepte de Macbidouille
*

Groupe : Membres
Messages : 42
Inscrit : 30 Aug 2016
Membre no 199 619



Salut

Merci Pbell
Toujours clair et concis merci !!
Je teste mercredi sur un vrai dossier et un vrai listing de plusieurs milliers d'éléments

Merci
Go to the top of the page
 
+Quote Post
Jaypee
posté 31 Oct 2016, 09:53
Message #20


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 346
Inscrit : 29 Aug 2002
Membre no 3 340



Juste une petite remarque à propos d'EXIFtools, il n'est pas indispensable, car l'appli gratuite "iMagine Photo" est 100% orientée Applescipt, offrant le dictionnaire qui va bien.

Ensuite, je poursuis mon idée d'avoir tout le fichier Excel chargé en mémoire, qui est peut-être réaliste, ou pas...

CODE
set csv to {"p123,10x20x30", "p124,5x75x20", "p346,60x45x15", "p254,80x120x60", "p654,10x10x10"}
set memdb to {}
set text item delimiters to {","}
repeat with ligne in csv
copy {codeProduit:text item 1 of ligne, dimensions:text item 2 of ligne} to end of memdb
end repeat
set text item delimiters to {""}

script codeProduit
on trouve(val, liste)
repeat with e in liste
if (codeProduit of e) is val then
return e
end if
end repeat
end trouve
end script

tell codeProduit to set dims to dimensions of trouve("p346", memdb)
dims

Résultat: "60x45x15"
Note: On balaye séquentiellement la liste, il y a certainement un optimisation possible comme une recherche dichotomique.
CODE
set csv to {"p123,10x20x30", "p124,5x75x20", "p246,60x45x15", "p254,80x120x60", "p654,10x10x10", "p1123,10x20x30", "p1124,5x75x20", "p1246,60x45x15", "p1254,80x120x60", "p1654,10x10x10", "p2123,10x20x30", "p2124,5x75x20", "p2246,60x45x15", "p2254,80x120x60", "p2654,10x10x10"}
set memdb to {}
set text item delimiters to {","}
repeat with ligne in csv
copy {codeProduit:text item 1 of ligne, dimensions:text item 2 of ligne} to end of memdb
end repeat
set text item delimiters to {""}

script codeProduit
on trouve(val, liste)
repeat with e in liste
if (codeProduit of e) is val then
return e
end if
end repeat
end trouve
-- Prérequis, la liste est triée par code produit
-- A faire dans Excel avant exportation
on trouveDicho(val, liste)
return dicho(1, count of liste, val, liste)
end trouveDicho
-- fonction interne récursive
on dicho(debut, fin, val, liste)
local milieu
copy (debut + fin) div 2 to milieu
if liste is {} then
return {}
else if (val < codeProduit of item debut of liste) or (val > codeProduit of item fin of liste) then
return {}
else
-- cas chanceux
if val is codeProduit of item debut of liste then
return item debut of liste
else if val is codeProduit of item fin of liste then
return item fin of liste
-- cas général
else if val < codeProduit of item milieu of liste then
-- chercher de nouveau avant le milieu
return my dicho(debut, miliieu - 1, val, liste)
else
-- chercher de nouveau depuis milieu jusqu'à la fin
return my dicho(milieu, fin, val, liste)
end if
end if
end dicho
end script

tell codeProduit to set x to trouveDicho("p1246", memdb)
if x is not {} then
dimensions of x
end if


PS: Sur un exemple aussi trivial, la même dichotomie répétée 100 000 fois est plus longue de quelques secondes 19.0 contre 15.0 pour la recherche séquentielle. Sur 30 000 éléments, elle fait sûrement un meilleur score.
J-P

Ce message a été modifié par Jaypee - 31 Oct 2016, 10:36.
Go to the top of the page
 
+Quote Post
PBell
posté 31 Oct 2016, 19:09
Message #21


Adepte de Macbidouille
*

Groupe : Membres
Messages : 184
Inscrit : 7 Dec 2013
Lieu : Ile de France
Membre no 188 169



Bonsoir Jaypee,
Je ne connaissais pas l'application iMagine Photo que je viens de télécharger sur ton conseil. Merci
Effectivement, le dictionnaire des commandes Applescript est assez complet quant à la manipulation des images.
Cela en fait un outil très intéressant.

Par contre, en terme de données EXIF seules, le type de données gérées est beaucoup plus limité que Exiftool: le dictionnaire 'Exif type' liste environ 26 types.
Exiftool ne traite que les données exif, ce qui est bien plus limité que iMagine Photo, mais il le fait bien mieux avec des centaines de tag possibles.
Je ne les ai jamais compté, mais si tu fais "exiftool -list -EXIF:All" sur le Terminal tu auras la liste. De plus Exiftool ne gère pas que les données purement Exif, mais aussi d'autres tags: "exiftool -list" te donnera les tag Exif et les autres (environ 39 pages de liste de tags sur mon moniteur 27' !!)
J'ajouterai que Exiftool dispose aussi de fonctions de traitement en masse directement au niveau Unix, comme par exemple traiter tous les fichiers d'un dossier en une seule instruction.

En résumé, pour traiter l'image elle-même (dimensions, échelle, rotation), la modifier (ajouter des formes/shapes,...) iMagine Photo est parfait. Merci encore pour l'information.
Pour traiter uniquement les tag exils ou autres, je préfère rester à exiftool, qui est aussi gratuit.

Cordialement


--------------------
iMac 27 i7 2,8GHz 8Go/1To 10.6.8 /10.10 / 10.11
iMac 20 C.Duo 2,6Ghz 8Go/350Go 10.6.8 / 10.11
Mini C.Duo 2,0Ghz 2Go/500Go 10.6.8
Go to the top of the page
 
+Quote Post
Jaypee
posté 1 Nov 2016, 09:09
Message #22


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 346
Inscrit : 29 Aug 2002
Membre no 3 340



Merci à tous également... Un simple sujet comme celui-ci peut être l'occasion de recherche, et d'acquisition d'expérience.
Je m'intéresse en ce moment aux les performances et au comportement général d'AppleScript

La gestion de mémoire semble le point faible, dans ce sens que les performances baissent fortement lorsque une mémoire importante est requise. J'inclurai mon programme de test pour simuler une "base de données", un tableau de 20000 produits + dimensions, comme ceux que Speed Moock utilise.
La seule génération des produits (boucle et formatage de texte) ralentit significativement au delà de 8500 à 9000 articles.

Ensuite des recherches aléatoires de produits donne des résultats assez médiocres, de l'ordre de 3 à 4 secondes pour 10000 articles.

Comme je pressens la dégradation non-linéaire des performances (données x 3 n'impliquent pas performances x 3, mais plus) ma conclusion serait que:
- Si la communication inter applis fonctionne bien, il faut privilégier la délégation des fonctions complexes aux applis qui savent bien le faire, comme la recherche du produit dans la base. Ou alors prévoir une petite base de données SQL (SQLite est en standard, utilisé par le système lui-même)
- Si cette communication est pareillement médiocre, je crains qu'AppleScript soit limité par ses performances, il faut s'intéresser à des solutions de programmation plus classiques comme Python, Ruby pour les langages de script, et à Swift puisqu'il est promu par Apple (et par IBM maintenant. Une digression sur IBM: Sur un parc de 35000 Macs et autant de PC Windows,les Macs ont coûté 500$ de moins de support par leur service informatique que les PC par an)

Et pendant que j'écrivais les résultats sont tombés:
- 3000 articles: Recherche < 1 s
- 10000 articles: Recherche autour de 3 ou 4 s
- 20000 articles: Recherche autour de 15 à 20 s
Ma méthode de recherche dans le tableau:
- Dichotomie jusqu'à tomber en dessous d'une limite de 100, où la recherche devient séquentielle
- Pour éviter les re-copies de mémoire, la recherche séquentielle est faite entre deux indices départ et fin, sans changer le grand tableau de départ. Normalement, comme il a été observé plus tôt, AppelScript passe ses arguments systématiquement par adresse, dont passer la liste, ne consiste qu'à passer l'adresse, sans recopie.

Conclusion: Non, avec AppleScript on ne doit pas tout charger en mémoire. Même si en quantité, elle ne manque pas, sa gestion par AppleScript est extrêmement peu performante.

J-P
PS: Le code. Pour voir les messages défiler, cliquer sur le 3e l'icone (i) <flèche retour> <document avec des lignes> pour faire apparaître la console, puis choisir l'onglet "messages" ou "événements"
CODE
global CAPACITE
copy 3000 to CAPACITE

set memdb to {}

global FMT
copy 5 to FMT
on format(n, f)
copy "00000" & n to padded
copy (count of padded) to l
return text (1 + l - f) thru l of padded
end format

set startTime to do shell script "date +%s"
repeat with i from 1 to CAPACITE
copy {codeProduit:"p" & format(i, FMT), dimensions:"" & 10 * (1 + i mod 5) & "x" & 20 * (1 + i mod 3) & "x" & 50 * (1 + i mod 2)} to end of memdb
if (0 is i mod 500) then
log "==> " & i
end if
end repeat
set finishTime to do shell script "date +%s"
set creation_bd to finishTime - startTime

script codeProduit
on trouve(val, liste)
copy 100 to LIMITE
-- log val
local l
copy (count of liste) to l
if l is 0 then
return {codeProduit:"liste vide", dimensions:"n/a"}
else if val is "" then
return {codeProduit:"numéro produit vide", dimensions:"n/a"}
else if l < LIMITE then
return seq(1, count of liste, val, liste)
else
return dicho(1, count of liste, val, liste, LIMITE)
end if
end trouve

-- Recherche séquentielle
on seq(debut, fin, val, liste)
log "seq " & debut & " " & fin & " " & val
if (val < (codeProduit of (item debut of liste))) or (val > (codeProduit of (item fin of liste))) then
return {codeProduit:"hors limites", dimensions:"n/a"}
else
repeat with i from debut to fin
if (codeProduit of item i of liste) is val then
-- log "Trouvé séquentiellement"
return item i of liste
end if
end repeat
end if
end seq


-- Recherche dichotomique récursive
-- Prérequis, la liste est triée par code produit
-- A faire dans Excel avant exportation

on dicho(debut, fin, val, liste, LIMITE)
-- log "dicho " & debut & " " & fin & " " & val
local milieu, taille
copy fin - debut to taille
if taille ≤ LIMITE then
-- log "Redirigé vers seq"
return my seq(debut, fin, val, liste)
else if (val < (codeProduit of (item debut of liste))) or (val > (codeProduit of (item fin of liste))) then
return {codeProduit:"hors limites", dimensions:"n/a"}
else
set milieu to (debut + fin) div 2
-- cas chanceux
if val is codeProduit of item debut of liste then
return item debut of liste
else if val is codeProduit of item fin of liste then
return item fin of liste
-- cas général
else if val < codeProduit of (item milieu of liste) then
-- chercher de nouveau avant le milieu
return my dicho(debut, milieu - 1, val, liste, LIMITE)
else if val ≥ codeProduit of (item milieu of liste) then
-- chercher de nouveau depuis milieu jusqu'à la fin
return my dicho(milieu, fin, val, liste, LIMITE)
else
return {codeProduit:"bizarre", dimensions:"spéciales"}
end if
end if
end dicho
end script

set bench to {}
set ECHANTILLON to (CAPACITE div 5)
set testStartTime to do shell script "date +%s"
repeat with n from 1 to ECHANTILLON
set prod to "p" & format(random number from 1 to CAPACITE, FMT)
set startTime to do shell script "date +%s"
tell codeProduit to set x to trouve(prod, memdb)
if x is not {} then
set y to {produit:codeProduit of x, dimensions:dimensions of x}
else
set y to {}
end if
set finishTime to do shell script "date +%s"
set timeItTook to finishTime - startTime
copy {recherche:prod, trouve:y, execution:timeItTook} to end of bench
log "" & n & " " & timeItTook
end repeat
set testFinishTime to do shell script "date +%s"

log "Base de données de " & CAPACITE & " articles générée en " & creation_bd & " s"
log "Temps total écoulé pour les " & ECHANTILLON & " tests " & (testFinishTime - testStartTime) & " s"

set total to 0.0
repeat with resultat in bench
copy total + (execution of resultat) to total
end repeat
-- bench
log "Temps moyen, hors génération aléatoire " & (total / ECHANTILLON) & " s"


Ce message a été modifié par Jaypee - 1 Nov 2016, 10:07.
Go to the top of the page
 
+Quote Post
Speed Moock
posté 1 Nov 2016, 10:10
Message #23


Adepte de Macbidouille
*

Groupe : Membres
Messages : 42
Inscrit : 30 Aug 2016
Membre no 199 619



Bonjour à tous,

J'ai testé sur un dossier contenant 291 images (sans sous dossiers) et un listing d'autant de ligne correspondant pile poile au contenu du dossier.
Résultat : 3 minutes de travail (je suis sur un McBook pro 2.2 Ghz Intel Core i7 et avec 4Go de mémoire DDR3 à 1333 Mhz).... donc oui ça sera trés (trop) long sur mes dossiers de travail.

A+
Go to the top of the page
 
+Quote Post
Jaypee
posté 1 Nov 2016, 16:43
Message #24


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 346
Inscrit : 29 Aug 2002
Membre no 3 340



Je recommande très vivement de créer une petite base de données sqlite3. Même depuis AppleScript, le temps de recherche est virtuellement nul avec une base de 32000 articles !

Etape 1: Générer le csv en Ruby. OK. C'est un one-liner, un peu chevelu... Durée pour 32000 articles: instantané. Dans un terminal taper irb (Interactive RuBy) c'est déjà installé en standard sur tous les Macs.
Code
File.open '/Users/jaypee/workspaces/Ruby/bdproduits.csv', 'w' do |f| (1..32000).each  {|i| f.write "p#{i.to_s.rjust(5,"0")},#{10*(1 + i % 5)}x#{20 * (1 + i % 3)}x#{5 * (1 + i % 2)}\n"}  end


Etape 2: Générer la bd SQLite3. Durée: Moins qu'il n'en faut pour le documenter ici.
Code
cd /Users/jaypee/workspaces/Ruby
sqlite3 produits.db
create table produits(code, dimensions);
.mode csv
.import '/Users/jaypee/workspaces/Ruby/bdproduits.csv' produits
.exit

La syntaxe en ligne de commande est: sqlite3 <base.bd> <requête SQL>

Etape 3: Bench en AppleScript
CODE
global CAPACITE
copy 3000 to CAPACITE

global FMT
copy 5 to FMT
on format(n, f)
copy "00000" & n to padded
copy (count of padded) to l
return text (1 + l - f) thru l of padded
end format

set bench to {}
set ECHANTILLON to (CAPACITE div 5)
set testStartTime to do shell script "date +%s"
repeat with n from 1 to ECHANTILLON
set prod to "p" & format(random number from 1 to CAPACITE, FMT)
set startTime to do shell script "date +%s"
copy "/usr/bin/sqlite3 /Users/jaypee/workspaces/Ruby/produits.db \"select dimensions from produits where code = '" & prod & "'\"" to cmd
-- log cmd
set dims to do shell script cmd
set y to {produit:prod, dimensions:dims}
set finishTime to do shell script "date +%s"
set timeItTook to finishTime - startTime
copy {recherche:prod, trouve:y, execution:timeItTook} to end of bench
log "" & n & " " & timeItTook
end repeat
set testFinishTime to do shell script "date +%s"

log "Temps total écoulé pour les " & ECHANTILLON & " tests " & (testFinishTime - testStartTime) & " s"

set total to 0.0
repeat with resultat in bench
copy total + (execution of resultat) to total
end repeat
log "Temps moyen, hors génération aléatoire " & (total / ECHANTILLON) & " s"
bench


Résultats
(*Temps total écoulé pour les 600 tests 94,0 s*)
(*Temps moyen, hors génération aléatoire 0,116666666667 s*)

(*Temps total écoulé pour les 2000 tests 362,0 s*)
(*Temps moyen, hors génération aléatoire 0,119 s*)

Les perfs sont stables, quel que soit le nombre d'articles.

Comparaison avec recherche en AppleScript de mon précédent script
(*Base de données de 3000 articles générée en 6,0 s*)
(*Temps total écoulé pour les 600 tests 322,0 s*)
(*Temps moyen, hors génération aléatoire 0,476666666667 s*)

(*Base de données de 10000 articles générée en 171,0 s*)
(*Temps total écoulé pour les 2000 tests 9685,0 s*)
(*Temps moyen, hors génération aléatoire 4,808 s*)

Conclusion: Avec 10000 articles, des perfs moyennes améliorées 40.4 fois, 26 fois en temps écoulé, de plus de deux heures à 6 minutes

J-P

Ce message a été modifié par Jaypee - 1 Nov 2016, 17:05.
Go to the top of the page
 
+Quote Post
Speed Moock
posté 1 Nov 2016, 21:49
Message #25


Adepte de Macbidouille
*

Groupe : Membres
Messages : 42
Inscrit : 30 Aug 2016
Membre no 199 619



Ah oui quand même...

Bon je vais me creuser la tête pour adapter ce code à mon besoin...

Merci Jaypee !
Go to the top of the page
 
+Quote Post
PBell
posté 1 Nov 2016, 23:24
Message #26


Adepte de Macbidouille
*

Groupe : Membres
Messages : 184
Inscrit : 7 Dec 2013
Lieu : Ile de France
Membre no 188 169



Bonsoir,
Comme l'a justement indiqué Jaypee, ce type de demande est intéressant car il force à se poser d'autres questions et donc améliore la compréhension.

Je me suis donc penché sur la question de la vitesse.
Sur le grep, je n'avais aucun doute que cela soit la plus rapide. Je confirme grep est au niveau bas shell donc pas mieux.

Sur l'Exiftool, c'est affectivement assez rapide mais il ne faut pas oublier qu'une écriture de donnée EXIF implique en fait une ré-ecriture complète du fichier image; en effet la structure de données Exif implique l'insertion de la donnée (elle ne peut être ajoutée à la fin) et donc la ré-écriture de l'image.
La vitesse dépend des accès disque : disque dur/mémoire flash, accès serveur/carte disque, type de connexion (SATA, USB,...).
Elle dépend aussi de la taille de l'image traitée : je doute que des images pour un site web fassent 10Mb chacune, mais tout de même, ce sera plus long de ré-écrire 300Ko par image que 30Ko !

Il reste, comme l'a parfaitement décrit Jaypee, la question de l'utilisation de la mémoire par AS.
J'ai commencé par revoir le script pour utiliser la récursivité avec des listes de folder et de fichiers. Beaucoup mieux, mais pas encore assez.
J'ai donc mixé un script de base avec un appel de récursivité, pour réduire l'utilisation de la mémoire au maximum. Elle est maintenant dépendante, essentiellement du nombre niveau de sous dossiers.

Une fois la mise au point faite, et comme il me semblait que la performance était là, j'ai décidé de tester à plus grande échelle.
J'ai crée un fichier Excel avec 30 000 lignes de 2 colonnes:
1) code produit = nombre sur 6 chiffres,
2) texte de dimension = ("Dimension " & code produit & "cm") .. qui me permet de vérifier que le grep à partir du code produit est correct
Comme expliqué précédemment, j'ai enregistré cette liste de 30 000 produits/dimension sur un fichier Window Formatted text.

J'ai ensuite écrit un petit script qui me génère des images Jpg avec un nom du type G_xxxxxx_21_ZP_1_test.jpg.
Le script a fait varier xxxxxx de 120 000 à 131 200, donc 11200 images, que j'ai éclatées en 4 sous dossiers, regroupées dans un dossier parent.

Voilà pour l'environnement de test ! Je pense ainsi me rapprocher du besoin en terme de volume. Non ?

Lors de mes tests, je me suis aussi aperçu que les "log" que je mettais ralentissaient. Surtout, j'ai découvert que lancer le script à partir de l'éditeur est bien plus lent que de le sauver en tant qu'application puis de lancer l'application. Le moniteur d'activité confirme une plus faible utilisation de mémoire. Je pense que c'est en partie du à la notion d'historique de l'éditeur, qui n'existe plus en mode "application".
J'ai fait une première série de tests avec toutes les fonctions (boucle, récursivité, recherche produit, conversion de posix,...), sauf l'écriture Exif elle-même.
Par exemple, un premier test sur 200 images avec le nouveau script tourne en 23 secondes dans l'éditeur et seulement en 11 secondes en mode application !
Pour 1000 images, je passe de 2minutes 49 secondes à 1 minute seulement en mode application.
J'ai enfin supprimé les log directs pour passer à l'écriture d'un fichier log .txt, mais en passant via du shell ce qui ne ralenti pas (ou si peu !).

Comme vous pouvez le voir, j'ai limité les appels au Finder au maximum (le Finder est connu pour sa lenteur).

Une fois tous ces tests positifs, j'ai remis l'écriture des Exif. p
Désormais, pour 200 images, cela passe de 11 secondes à 62 secondes. Et encore, mes images sont petites (40Ko) !!
In finé, après quelques ajustements sur le script, j'ai lancé le script avec les 11200 images réparties en 4 sous dossiers, le fichier produits/dimensions de 30 000 lignes: temps de traitement total 49 minutes, tout compris !!
Je crois que je ne peux faire mieux !
...sauf à passer via un script shell direct.

Voici le script dernière version. Il faut l'enregistrer sous forme d'application et lancer l'application (ne pas lancer via l'éditeur !)
CODE
-- balayge recursif des dossiers / sous dossiers
global C
global WPath
global Fichier_Log

set DosParent to choose folder with prompt "Sélectionner le dossier parent"
set Fichier_Log to (((path to desktop) as text) & "mon_journal.txt")


set WFormatted to choose file with prompt "Sélectionner le fichier Windows formated contenant les dimensions"
set WPath to quoted form of (POSIX path of WFormatted)
set AppleScript's text item delimiters to {"_"}
set tab to ASCII character 9

set C to 0
set T1 to (current date)

LitDossier(DosParent)
set T2 to (current date)
Slog((C & return & (T1 as string) & return & (T2 as string)), Fichier_Log)
display dialog (C & return & T1 as string) & return & T2 as string

-- sous routine pour la récursivité
on LitDossier(Doss)
    tell application "Finder" to set Liste_item to (every item of Doss) -- lit tous les items du dossier
    repeat with Un_item in Liste_item
        tell application "Finder" to set SK to kind of Un_item
        if SK is "Dossier" then -- c'est un dossier, donc appel récursif
            LitDossier(Un_item)
        else -- c'est une image à traiter
            tell application "Finder" to set N to (name of Un_item) as string
            if N starts with "G_" then
                set Produit to text item 2 of N
                set R to ""
                try
                    set R to do shell script "grep ^" & Produit & " " & WPath
                on error
                    set R to ""
                end try
                if R is not "" then
                    set DimText to text ((offset of tab in R) + 1) thru -1 of R
                    set UnixPath to POSIX path of (Un_item as string)
                    Slog(Produit & "//" & DimText, Fichier_Log)
                    do shell script "/usr/local/bin/exiftool -ImageDescription='" & DimText & "' -Overwrite_Original " & quoted form of (UnixPath)
                end if
                set C to C + 1
            end if -- starts with "G_"
        end if -- dossier ou file
    end repeat
end LitDossier

on Slog(msg, MFichier) -- Fichier log via Shell *****************************************
    --    set the UnixPath to POSIX path of MFichier
    try
        -- Créer si besoin
        do shell script "touch " & (quoted form of (POSIX path of MFichier))
        -- Ajouter le message en fin de fichier
        do shell script "echo " & (quoted form of msg) & " >> " & (quoted form of (POSIX path of MFichier))
    end try
end Slog


Pour savoir où en est le script, il suffit de voir sur le bureau le fichier "mon_journal.txt", de le sélectionner et "barre d'espace" pour afficher le contenu via la fonction Coup d'Oeil. Dans mes tests, je savais à combien d'images j'en était car elles sont numérotées à partir de 120000.

Plus tes images sont grandes, plus le temps de traitement sera long.
Plus la vitesse d'écriture de tes images sur le support est élevée, plus rapide sera le script.
Il peut être judicieux de copier le dossier parent en local au lieu de le laisser sur le serveur.

Cordialement

PS : toutes ces mesures ont été faites sur un imac27, processeur Intel core i7 2,8GHz , ram 8Go et ElCapitain.


--------------------
iMac 27 i7 2,8GHz 8Go/1To 10.6.8 /10.10 / 10.11
iMac 20 C.Duo 2,6Ghz 8Go/350Go 10.6.8 / 10.11
Mini C.Duo 2,0Ghz 2Go/500Go 10.6.8
Go to the top of the page
 
+Quote Post
Speed Moock
posté 1 Nov 2016, 23:43
Message #27


Adepte de Macbidouille
*

Groupe : Membres
Messages : 42
Inscrit : 30 Aug 2016
Membre no 199 619



Merci Pbell !
Je teste ceci demain en environnement pro
Sur le nombre de niveaux d'arboresence tu as vu juste
Je peux faciliter le traitement en listant dans un excel le listing de mes images et en restreignant le fichier contenant les tailles à ces seules images

Par contre mes images font 5 Mo...


Bref je reviens vers vous avec des nouvelles sous peu
Go to the top of the page
 
+Quote Post
Jaypee
posté 2 Nov 2016, 07:15
Message #28


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 346
Inscrit : 29 Aug 2002
Membre no 3 340



Speed Moock,
Vu la tournure que prend les choses, je crois que tu as intérêt à faire tout en shell script.
A la base fais juste un script "de visite" pour une image
- parsing du nom => produit
- dims=`sqlite3 db sql` # apostrophe inversées pour exécuter la commande, ajouter un dollar devant $dims pour lire la valeur de dims
- exiftools pour écrire l'info dans l'image


Puis le parcours... il existe en standard avec la commande shell find, exemple:

find . : liste tous les fichiers sous le répertoire courant (= le point)

find racine/ -name "*jpg" -exec mon_script.sh {} \; # Trouver tous les jpeg sous la racine et leur appliquer mon script

Conseil d'ami, AppleScript n'apporte plus rien à ce stade, hormis compliquer la tâche

J-P
Go to the top of the page
 
+Quote Post
PBell
posté 2 Nov 2016, 08:21
Message #29


Adepte de Macbidouille
*

Groupe : Membres
Messages : 184
Inscrit : 7 Dec 2013
Lieu : Ile de France
Membre no 188 169



Merci Jaypee,
Je suis assez d'accord avec toi. J'avais indiqué au départ que le language qui me semblait le plus approprié était le shell script.
Mais je ne suis que très novice en shell script, c'est pourquoi j'ai "habillé" le grep et le exiftool avec de l'Applescript.

Par exemple, lister les fichiers dont le titre commence par "G_" et se termine par ".jpg" avec récursivité sur les sous dossiers ne me pose pas de problème en shell, pas plus que le grep. Je devrais même pouvoir adapter le grep avec un pipe pour ne prendre que la partie après la tabulation.

Par contre, je ne maîtrise pas le traitement au milieu.
J'ai vu qu'il y a des boucles "for" en shell, mais aussi que certains exemples font des pipes "|" en lieu de place de cette boucle pour appliquer une instruction à chaque fichier.
J'ai plein de questions...et pas de réponses !

Il me semble que le pipe est OK à condition que chaque fichier trouvé avec le find ne nécessite qu'une seule instruction. Est-ce exact ?
si plusieurs instructions, il faut utiliser le "for"...?
Dans ce cas, quelle est la syntaxe pour avoir plusieurs instructions dans la boucle et surtout dans quelle variable est le fichier en cours ? Bref quel est l'équivalent des classique repeat/end repeat ou encore for/next (VBA)
Pour le parsing du nom, je devrais pouvoir trouver tout seul, mais pour ces points, tes commentaires, voire un exemple m'aiderait à mieux comprendre.

Merci d'avance.

@SpeedMock, si tes fichiers font 5Mo, de toute façon tu verra que l'essentiel du temps de traitement est l'insertion de la donnée Exif qui nécessite la recopie de l'image: soit, pour 30 000 images, une recopie de 150Go !! d'où l'intérêt de vérifier ta vitesse d'accès disque

Cordialement


--------------------
iMac 27 i7 2,8GHz 8Go/1To 10.6.8 /10.10 / 10.11
iMac 20 C.Duo 2,6Ghz 8Go/350Go 10.6.8 / 10.11
Mini C.Duo 2,0Ghz 2Go/500Go 10.6.8
Go to the top of the page
 
+Quote Post
yponomeute
posté 2 Nov 2016, 08:38
Message #30


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 4 812
Inscrit : 26 Jan 2011
Lieu : Pollachius virens
Membre no 164 083



Citation (PBell @ 31 Oct 2016, 08:18) *
1) il faut commencer par demander à l'utilisateur le nom du dossier racine et du fichier Excel : c'est facile en AS. mais je ne pense pas que cela soit possible en shell Unix

Il me semble qu'avec platypus c'est possible (à confirmer, cela fait longtemps que je ne l'ai pas utilisé) : http://sveinbjorn.org/platypus


D'autre part j'ai déjà eu des traitements sur des dizaines de milliers de fichiers en script shell. J'avais adopté une solution en plusieurs étapes qui fonctionnait bien : au lieu de faire le traitement dans une boucle j'écrivais la ligne de commande à exécuter dans un fichier, et ensuite j'exécutais les lignes du fichier.
Par exemple :

Code
echo "ma ligne de commande shell;" >> liste_commandes.sh


et ensuite

Code
bash  liste_commandes.sh


En fait j'utilise systématiquement cette technique lorsque je développe un script, cela me permet de ne pas exécuter les commandes en phase de développement et de pouvoir facilement vérifier que script produit bien la bonne commande.



--------------------
MBP 2017 15" avec clavier pourri et touchbar inutile
Go to the top of the page
 
+Quote Post

2 Pages V   1 2 >
Reply to this topicStart new topic
1 utilisateur(s) sur ce sujet (1 invité(s) et 0 utilisateur(s) anonyme(s))
0 membre(s) :

 



Nous sommes le : 22nd October 2018 - 18:16