#!/usr/bin/php
<?php
$TMP_DIR = '.';
$DST_DIR = 'icones';
if(count($argv) <= 1) die("usage : ". $argv[0]. " file.app \n");
$file_app = $argv[1];
$info_plist = "$file_app/Contents/Info.plist";
if(!is_file($info_plist)) die("Invalid .app file\n");
echo "$file_app \n";
$xml_file = "$TMP_DIR/info.xml";
if(!is_dir($TMP_DIR)) `mkdir -p "$TMP_DIR"`;
if(!is_dir($DST_DIR)) `mkdir -p "$DST_DIR"`;
// on le convertit directement en XML
`/usr/bin/plutil -convert xml1 -o "$xml_file" "$info_plist"`;
$xml = simplexml_load_file($xml_file);
unlink($xml_file);
$loc_types = FALSE;
$document_types = FALSE;
$xml = $xml->children();
foreach($xml->children() as $child) {
if(($child->getName() == 'key') && ((string) $child == 'CFBundleDocumentTypes')) {
$loc_types = TRUE;
}
elseif(($loc_types) && ($child->getName() == 'array')) {
$document_types = $child;
break;
}
else
$loc_types = FALSE;
}
if($document_types === FALSE) die();// pas d'association de fichiers
foreach($document_types->children() as $child) {
if($child->getName() != 'dict') continue;
$loc_extensions = FALSE;
$loc_iconfile = FALSE;
$loc_typefile = FALSE;
$loc_mimes = FALSE;
$extensions = FALSE;
$mimes = FALSE;
$iconefile = FALSE;
$typefile = "";
foreach($child->children() as $subchild) {
if(($subchild->getName() == 'key') && ((string) $subchild == 'CFBundleTypeExtensions')) {
$loc_extensions = TRUE;
$loc_iconfile = FALSE;
$loc_typefile = FALSE;
$loc_mimes = FALSE;
}
elseif(($subchild->getName() == 'key') && ((string) $subchild == 'CFBundleTypeIconFile')) {
$loc_extensions = FALSE;
$loc_typefile = FALSE;
$loc_iconfile = TRUE;
$loc_mimes = FALSE;
}
elseif(($subchild->getName() == 'key') && ((string) $subchild == 'CFBundleTypeMIMETypes')) {
$loc_extensions = FALSE;
$loc_mimes = TRUE;
$loc_typefile = FALSE;
$loc_iconfile = TRUE;
}
elseif(($subchild->getName() == 'key') && ((string) $subchild == 'CFBundleTypeName')) {
$loc_extensions = FALSE;
$loc_iconfile = FALSE;
$loc_typefile = TRUE;
$loc_mimes = FALSE;
}
elseif(($subchild->getName() == 'array') && ($loc_mimes)) {
$mimes = $subchild;
$loc_extensions = FALSE; $loc_iconfile = FALSE; $loc_typefile = FALSE; $loc_mimes = FALSE;
}
elseif(($subchild->getName() == 'array') && ($loc_extensions)) {
$extensions = $subchild;
$loc_extensions = FALSE; $loc_iconfile = FALSE; $loc_typefile = FALSE; $loc_mimes = FALSE;
}
elseif(($subchild->getName() == 'string') && ($loc_iconfile)) {
$iconefile = 'Resources/' . (string) $subchild ;
if((substr($iconefile, -5) != '.icns')&&(substr($iconefile, -5) != '.tiff'))
$iconefile .= '.icns';
$loc_extensions = FALSE; $loc_iconfile = FALSE; $loc_typefile = FALSE; $loc_mimes = FALSE;
}
elseif(($subchild->getName() == 'string') && ($loc_typefile)) {
$typefile = (string) $subchild;
$loc_extensions = FALSE; $loc_iconfile = FALSE; $loc_typefile = FALSE; $loc_mimes = FALSE;
}
}
if(($iconefile === FALSE) || ($extensions === FALSE)) continue;
$fileextensions = array();
foreach($extensions->children() as $subchild) {
if($subchild->getName() != 'string') continue;
$fileextension = (string) $subchild;
$fileextensions[] = $fileextension;
echo "$fileextension ";
}
echo " : $iconefile \n";
//pour chacune des extensions, on va créer un dossier contenant toutes les informations
foreach($fileextensions as $ext) {
$ext = strtolower($ext);
if($ext == '*') continue;
$src_file = "$file_app/Contents/$iconefile";
if(!is_file($src_file)) continue;
$dst = "$DST_DIR/$ext";
$b = basename($src_file);
$t = strrpos($b, '.');
if(($t = strrpos($b, '.')) !== FALSE) { $pic_base = substr($b, 0, $t); $pic_ext = substr($b, $t + 1); }
else { $pic_base = $b; $pic_ext = ''; }
if($pic_ext !== 'icns') continue;// ce n'est pas un fichier icns, on zappe
if(!is_dir($dst)) mkdir($dst);// on crée un dossier qui va bien
// maintenant, on calcule le nom du fichier icns
$md5 = FALSE;//pour éviter les fichiers en double !
$c = FALSE;
while(is_file("$dst/$pic_base.icns")) {
if($md5 === FALSE) $md5 = md5_file($src_file);
if(md5_file("$dst/$pic_base.icns") == $md5) { $c = TRUE; break; }// le fichier existe déjà, on zappe
if(($t = strrpos($pic_base, '-')) !== FALSE) {
$i = (int) substr($pic_base, $t + 1);
if($i > 0) { $i++; $pic_base = substr($pic_base, 0, $t) . "- $i"; }
else $pic_base .= " - 1";
}
else $pic_base .= " - 1";
}
if($c) continue;// le fichier existe déjà, on zappe
//on a le nom du fichier ICNS
//on peut copier le fichier dans la destination
copy("$file_app/Contents/$iconefile", "$dst/$pic_base.icns");
`icns2png -x -s 16 -d 32 -o "$dst" "$dst/$pic_base.icns" 2> /dev/null`;
`icns2png -x -s 32 -d 32 -o "$dst" "$dst/$pic_base.icns" 2> /dev/null`;
`icns2png -x -s 128 -d 32 -o "$dst" "$dst/$pic_base.icns" 2> /dev/null`;
$infos = "<icns>${pic_base}.icns</icns>";
`echo "$infos" >> "$dst/infos.xml"`;
if(is_file("$dst/${pic_base}_16x16x32.png")) {
`convert "$dst/${pic_base}_16x16x32.png" "$dst/${pic_base}_16x16x32.gif" 2> /dev/null`;
$infos = "<png16>${pic_base}_16x16x32.png</png16>\n<gif16>${pic_base}_16x16x32.gif</gif16>";
`echo "$infos" >> "$dst/infos.xml"`;
}
if(is_file("$dst/${pic_base}_32x32x32.png")) {
`convert "$dst/${pic_base}_32x32x32.png" "$dst/${pic_base}_32x32x32.gif" 2> /dev/null`;
$infos = "<png32>${pic_base}_32x32x32.png</png32>\n<gif32>${pic_base}_32x32x32.gif</gif32>";
`echo "$infos" >> "$dst/infos.xml"`;
}
if(is_file("$dst/${pic_base}_128x128x32.png")) {
`convert "$dst/${pic_base}_128x128x32.png" "$dst/${pic_base}_128x128x32.gif" 2> /dev/null`;
$infos = "<png128>${pic_base}_128x128x32.png</png128>\n<gif128>${pic_base}_128x128x32.gif</gif128>";
`echo "$infos" >> "$dst/infos.xml"`;
}
//maintenant, on va chercher des informations
if(!is_file("$dst/filext.html")) {
`curl -o $dst/filext.html http://filext.com/file-extension/$ext 2> /dev/null`;
$filext = file_get_contents("$dst/filext.html");
$mimes = array();
if(strpos($filext, "<h3>Ooops </h3>") === FALSE) {//le type existe bel et bien
$t = strpos($filext, '<h3>');
$filext = substr($filext, 0, $t);
$next = 0;
while(($next = strpos($filext, '<table width="100%" border="1" align="center" cellpadding="3" cellspacing="1" bordercolor="#0000CC">', $next + 1)) !== FALSE) {
$t1 = strpos($filext, '<strong>MIME Type</strong>', $next);
$t1 = strpos($filext, '<tr>', $t1);
$t1 = strpos($filext, '<td>', $t1);
$t2 = strpos($filext, '</td>', $t1);
$t = trim(substr($filext, $t1 + 4, $t2 - $t1 - 4));
if((strpos($t, 'spacer.gif') === FALSE) && ($t !== '')) {
$t = explode(' <br> ', $t);
foreach($t as $u) {
if(strpos($u, '/') !== FALSE) $mimes[] = $u;
$infos = "<mime>$u</mime>";
`echo "$infos" >> "$dst/infos.xml"`;
}
}
}
}
}
# `curl -o http://www.fileinfo.net/extension/$ext $TMP_DIR/$ext`;
$infos = "<short_desc>$typefile</short_desc>";
`echo "$infos" >> "$dst/infos.xml"`;
}
}
?>
Et je me suis dit que ça pourrait en intéresser d'autresCe qu'il fait :
- il prend en argument un dossier .app,
- va lire le Info.plist (préalablement converti en XML),
- extrait les différents extension de fichier reconnus par cette application et les icônes qui lui sont associées.
- Chaque extension va avoir droit à son dossier personnel.
- Ensuite, il recopie pour chaque extension l'icône .ICNS kivabien
- extrait les images du .ICNS au format .PNG (en 16x16, 32x32 et 128x128) (demande icns2png),
- convertit les images PNG au format .GIF (demande convert)
- va chercher sur filext des informations
- finit par créer un fichier info.xml (toujours dans le même dossier), contenant les noms des icônes, les mime_type et une courte description.
Par exemple, si je lance ce script sur Safari.app, je vais avoir un dossier css, avec infos.xml contenant
<icns>document.icns</icns> <png16>document_16x16x32.png</png16> <gif16>document_16x16x32.gif</gif16> <png32>document_32x32x32.png</png32> <gif32>document_32x32x32.gif</gif32> <png128>document_128x128x32.png</png128> <gif128>document_128x128x32.gif</gif128> <mime>text/css</mime> <mime>application/css-stylesheet</mime> <short_desc>CSS style sheet</short_desc>
(bon, j'avais oublié que ce n'était pas du XML valide, mais c'est nettement plus chiant de faire du valide )
Du coup, comme toutes les informations sont dans le XML, c'est facile d'adapter le paquet d'icônes obtenues à un autre usage, et je me suis dit que ça pourrait en intéresser d'autres
Pour le lancer, je me suis fait un meta-script
for i in /Applications/*.app; do ./bin/app2icns.php "$i"; done; for i in /Applications/Utilities/*.app; do ./bin/app2icns.php "$i"; done; for i in /System/Library/CoreServices/*.app; do ./bin/app2icns.php "$i"; done; for i in /Developer/Applications/*.app; do ./bin/app2icns.php "$i"; done; for i in /Developer/Applications/Utilities/*.app; do ./bin/app2icns.php "$i"; done;
En revanche, je n'ai pas tellement d'idée pour régler les conflits (vu que plein d'applications redéfinissent des icônes pour les mêmes extensions)
(je ne distribue pas le résultat parce que les icônes ont sûrement des ©, mais on peut toujours me demander ^^)