IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Pascal Discussion :

Extraire les propriétés d'un *.ico


Sujet :

Pascal

  1. #1
    Membre éclairé

    Inscrit en
    Avril 2003
    Messages
    284
    Détails du profil
    Informations forums :
    Inscription : Avril 2003
    Messages : 284
    Points : 773
    Points
    773
    Par défaut Extraire les propriétés d'un *.ico
    Bonjour,

    Je suis en train d''écrire, pendant mes moments de libre, un programme pour gérer les icones pour accompagner Lazarus...

    Je suis confronté chaque jours à de petits poblèmes que je résouds un à un, ceci dans le but de vous présenter bientot dans la section source, un editeur d'icone écrit en pascal pour linux et windows...

    J'ai commencé par me documenter sur le format des ficiers *ico, et fait le tour de ce que Lazarus propose déjà comme objets, procedures et fonctions...
    J'ai bien entendu téléchargé un programme d'edition d'icone assez complet, pour faire différents tests en étudiants les différents fichiers créés dans différents formats et vérifier ce que les documentations sur ce format indiquent...

    Je me rends compte que de nombreux icones ne suivent pas 100% des regles stipulées par le format, et cependant, les icones fonctionnent correctement, et le programme téléchargé corrige de lui-meme les renseignements non fournis dans le header...

    Bref, si celà intéresse certains d'entre vous, je vous propose :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    {"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    Coder une fonction capable de donner pour un fichier icone donné :
    le nombre d'icones dans le fichier et pour chacun d'eux :
    largeur, hauteur, nombre réel de couleurs de la palette, bits/pixels
    Le code doit etre portable, donc pas d'API windows SVP...
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""}
    Non parce que je n'y arrive pas, mais pour pouvoir discuter des différentes solutions trouvées par les uns et les autres pour générer les renseignements non stipulées dans les headers, ou non conformes...
    Je ne suis pas très heureux des solutions que j'envisage de mettre en oeuvre...

    En effet, si vous faites des tests sur différents icones, vous verrez bien vite que l'extraction du nombre de couleurs ou du nombre de bpp utilisé ne peut souvent pas etre fait par une simple lecture du header, les membres de ce dernier n'étant pas renseignés...
    me voici donc en train d'étudier la taille de l'image en cours (dans le fichier) par rapport à ses dimensions (hauteur / largeur) pour en deduire les bpp...

    Les choses se corsent avec le format png récemment accepté au sein d'une icone de 256*256 dans vista (d'ailleurs si vous avez de la doc la dessus...)


    Bref si ce genre de petits soucis vous interresse n'hésitez pas à me répondre, j'entrerai plus dans le détail et je serai heureux d'échanger des idées avec vous...

    Clandestino

  2. #2
    Membre éclairé

    Inscrit en
    Avril 2003
    Messages
    284
    Détails du profil
    Informations forums :
    Inscription : Avril 2003
    Messages : 284
    Points : 773
    Points
    773
    Par défaut
    Little screenshot of what it looks like
    Images attachées Images attachées  

  3. #3
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    J'ai moi-même développé un petit utilitaire qui extrait carrément les icônes au format BMP, et qui n'attend que la gestion des icônes Vista et l'exportation PNG pour être publié, quand j'aurai un peu plus de temps. Mais c'est sous Delphi.

    Et j'ai aussi constaté quelques - hum - irrégularités dans les formats. Mais celà reste assez rare, non ?

  4. #4
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 943
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 943
    Points : 5 655
    Points
    5 655
    Par défaut
    Jao,

    Dans le temps, j'ai bricolé un peu là-dedans, et j'avais arrêté, assez effaré par ce qui se passait.

    En effet, on a défini un format, et il ne sert quasiment à rien, puisqu'on peut parfaitement s'en foutre, à pied, à cheval ou en voiture.
    Si les cons volaient, il ferait nuit à midi.

  5. #5
    Membre éclairé

    Inscrit en
    Avril 2003
    Messages
    284
    Détails du profil
    Informations forums :
    Inscription : Avril 2003
    Messages : 284
    Points : 773
    Points
    773
    Par défaut
    Bon, pas beaucoup de volontaires...
    Voici un mini tut pour récapituler ce que j'ai appris....

    Les irrégularités concernent surtout des champs non remplis dans l'entete...

    Pour le format des icones Vista, j'en ai saisi le fonctionnement et on peut très facilement extraire le PNG correspondant...

    C'est d'ailleurs ce que je fais (dans un stream) pour pouvoir le visualiser...

    Voici la methode à suivre:
    (ce poste a etre un peu long mais je suis obligé de détailler sous peine d'ecrire quelque chose d'incompréhensible)...

    Un fichier *.ico peut contenir plusieurs images dans un meme fichier...
    les images sont traditionnellement carrées, de mesure 16x16, (24x24 rare), 32x32, 48x48, 64x64, 128x128 et depuis vista 256x256
    il est fabriqué suivant un modele bien défini :

    1)une première entete de 6 Bytes (ICONDIR)
    les deux premiers bytes sont toujours nuls,
    le WORD suivant est égal à 1 (pour dire que c'est une icone),
    le WORD suivant indique le nombre d'images dans l'icone....

    Ainsi l'ICONDIR dans un editeur hexadecimal de l'icon Blonote attachée donne :

    00 00 01 00 0D 00
    $000D en hexadecimal bien sûr, donc il y a treize icones...

    2)Une entete pour chaque image (ici treize entetes d'affilée)(ICONDIRENTRY)

    Dump Hexadécimal du premier ICONDIRENTRY:
    30 30 10 00 01 00 04 00 68 00 00 00 D6 00 00 00

    Le premier Byte donne la largeur de l'image $30 = 48
    Le deuxieme byte donne la hauteur de l'image $30 = 48
    le byte suivant donne le nombre de couleurs... $10 = 16 Attention cette valeur est nulle pour des images de plus de 8bits par pixels
    Le byte suivant, réservé est toujours nul
    Le WORD qui suit est sensé représenter les 'color planes' selon la documentation officielle, qui n'en dit pas plus sur le sujet. Tous les icones que j'ai croisés ont cette valeur égale à $0001...
    Le WORD suivant représente le nombre de bits par pixel $0004 = 4bpp
    L'avant dernier DWORD représente l'offset de debut du Data de l'icone $00000068 = au 104 ème byte
    Le dernier DWORD indique la taille de ces Datas $000000D6 = 214 octets

    3) Les datas de chaques images : ici treize images à la suite...
    La lecture des entètes de chaque image nous donnant les offsets de chacune d'elle dans l'avant dernier DWORD



    COMMENT EXTRAIRE UNE ICONE D'UN FICHIER MULTI-ICONES?

    Il est donc très facile d'extraire d'un icone contenant plusieurs images, chacune de ces images, puis de les enregistrer en tant qu'icones individuels :

    Il suffit de lire les headers et de trouver combien il y a d'image, puis pour chaque image créer un fichier ou on ecrit :
    -1 entète de 6 bytes donc le WORD indiquant le nombre d'image a été corrigé pour indiquer $0001
    -1 header d'image, qui est une copie du header de l'image en cours, corrigé au niveau de l'adresse de départ de l'image : pour un fichier à image unique cette adresse est toujours égale à $00000016 (somme de la taille des deux entètes)
    -les Datas de l'image exactement comme dans le fichier multiicones...
    On peut mettre le tout dans une boucle pour extraire toutes les icones...

    voici un code source pour freepascal sous windows :
    Il devrait fonctionner sous linux pour peu qu'on lui indique un path d'enregistrement correct pour les fichiers...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    {-----------------------------------------------------------------------------
       ICON EXTRACTOR
       
       Petit extracteur d'icones
       Ce programme attend en paramètre un nom de fichier d'icones valide, et
       extrait vers le répertoire c:\ des icones simples contenant chacune des
       images contenues dans le fichier de départ
       
       Clandestino
    -----------------------------------------------------------------------------}
    Program IconExtractor;
     
    {$Mode Delphi}
     
    uses classes, sysutils;
     
    type
    // les icones commencent par 3 WORDS définis ainsi
      TlazIconHeader = packed record
        IdReserved    : WORD;       // fixe, toujours 0
        IdType        : WORD;       // type de ressource pour un icone = 1
        IdCount       : WORD;       // Nombre d'images
        end;
    // Puis suivent les definitions des images
    // ceci étant répété le nombre de fois defini au dessus par idCount
      TlazImageHeader = packed record
        bWidth        : BYTE;       // Largeur, en pixels, de l'image
        bHeight       : BYTE;       // Hauteur, en pixels, de l'image
        bColorCont    : BYTE;       // Nombre de couleurs: =0 si >=8bpp
        bReserved     : BYTE;       // fixe, toujours 0
        wPlanes       : WORD;       // Nombre de 'colors planes' << pas compris,
                                    // semble toujours égal à 1
        wBitCounts    : WORD;       // bits per pixels
        dwBytesInRes  : DWORD;      // Taille de l'image dans le fichier
        dwImageOffset : DWORD;      // Offset de debut de l'image dans le fichier
        end;
    // Puis suivent, aux adresses indiquées par dwimageoffset
    // sur une taille de dwimageOffset
    // les données des images
     
     
    var
    ImageHeader : TlazImageHeader ;
    LIH : TlazIconHeader;
    tfs : Tfilestream;
    tms : TmemoryStream;
    i:WORD;
    begin
    if paramcount >0 then begin
      if fileexists(paramstr(1)) then begin
        tfs:= tfilestream.Create(paramstr(1),fmopenread);
        tms := tmemorystream.Create;
        // on lit l'entete de fichier
        tfs.Read(LIH, sizeof(LIH));
        // Si c'est un icone
        if LIH.IdType = 1 then begin
            // une boucle pour toutes les images
            for i:= 1 to LIH.IdCount do begin
                tms.clear;
                // on se place au début de l'entete de l'image i
                tfs.Seek ((i-1)*sizeof(ImageHeader)+sizeof(LIH),sofrombeginning);
                // on charge l'entete de l'image i
                tfs.Read(ImageHeader, sizeof(ImageHeader));
                // on se replace au début dans les deux streams
                tms.Seek(0,sofrombeginning);
                tfs.seek(0,sofrombeginning);
                // on copie l'entete de fichier dans le stream temp
                tms.CopyFrom(tfs,sizeof(LIH));
                // on se place au debut de l'entete de l'image i
                tfs.Seek ((i-1)*sizeof(ImageHeader),sofromcurrent);
                // on copie cette entète dans le stream temp
                tms.copyfrom(tfs,sizeof(ImageHeader));
                // on se place à l'adresse du debut du data de l'image i
                tfs.Seek(ImageHeader.dwImageOffset, sofrombeginning);
                // on copie le data dans le stream temp
                tms.CopyFrom(tfs,ImageHeader.dwBytesInRes);
                tms.Seek($04,Sofrombeginning); // adresse du WORD nombre d'images
                tms.WriteByte($01);            // Patch = 1 image
                tms.Seek($12,Sofrombeginning); // adresse du dword offset debut Data
                tms.WriteDWord($00000016);     // Patch = bonne adresse
                tms.Seek(0,Sofrombeginning);
     
                // il ne reste plus qu'à copier le resultat dans un fichier
                // sur le disque
                tms.SaveToFile('c:\'+inttostr(I)+'.ico');
            end;
        end else writeln('Ce fichier n''est pas un fichier icone valide');
     
        tms.Free;
        tfs.Free;
       end;
      end;
      writeln(inttostr(I)+' fichiers crees dans c:\');
    readln;
    End.

    FORMAT DES FICHIER ICONES DE VISTA

    Après avoir étudié de près quelques icones fournies avec Vista (voir icone de notepad jointe), j'en suis arrivé aux conclusions suivantes...

    Microsoft a introduit des icones de dimension 256*256.
    pour en reduire la taille sur le disque dur, les datas de l'icone sont enregistrés sous forme d'une image au format png...

    Le format du fichier est donc sensiblement le meme que pour une icone Classique :
    l'entete de 6 bytes est la meme.
    Dans l'entète de l'image, les bytes donnant la largeur et la hauteur sont à zéro (on pourrait difficilement indiquer une valeur de 256 dans un seul byte )
    La partie Data contient une image png classique...


    COMMENT EXTRAIRE UN PNG D'UNE ICONE VISTA ?

    Il suffit de lire l'entete des image et en trouver une dont les largeurs et auteurs sont à $00, puis d'extraire les datas : le debut et la taille étant donnés dans l'entète...
    Une vérification de la "signature" d'une image png peut être faite en lisant les 4 premiers bytes des Datas qui sont toujours pour un png :
    $89 $50 $4E $47


    COMMENT CREER UNE ICONE POUR VISTA?

    Utilisez un logiciel de dessin pour créer un PNG 8bits 256*256 (je vais de mon coté tenter de le faire avec Lazarus directement) et ajoutez y une entête d'icone comme expliqué ci-dessus... rien de bien compliqué...



    Dans l'espoir que ces recherches seront utiles à quelques-uns...

    Clandestino

    Modification : ajout d'un fichier multi icones vista en PJ
    Fichiers attachés Fichiers attachés

  6. #6
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut


    En fait, mon utilitaire à moi est conçu pour extraire les différentes icônes d'un fichier .ico (et bientôt .ddl et .exe) sous forme d'icônes corrigées, et de bitmaps. C'est un outil pour développeur, je m'en sers pour créer des boutons.

    La plupart des observations que tu as faites ici recoupent les miennes, sauf sur un point : moi, j'ai un certain nombre d'icônes dont le champ Planes vaut zéro, et j'ai eu l'occasion de tester mes routines sur plusieurs centaines d'icônes.

    J'ai constaté que souvent, avec une valeur Planes de 1, la valeur ColorCount (celle qui précède Planes) n'est parfois pas viable car égale à zéro, même pour des icônes de moins de 256 couleurs. Donc, il vaut mieux tester la valeur Bitcount (celle qui suit Planes).

    Par contre, quand Planes est égal à zéro, c'est BitCount qui n'est pas viable, et il vaut mieux tester ColorCount.

    A titre d'information, voilà ce que j'utilise comme structures, entre autres (réf. msdn, attention ! sous Delphi, Cardinal est 32 bits) : elles sont très semblables aux tiennes, juste d'un style un peu moins "C" et un peu plus "pascalien"...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    type TIconHeader =
           Record
            Reserved : Word;
            FileType : Word;
            ImgCount : Word;
           end;
     
         TIconEntry =
           Record
            Width       : Byte;
            Height      : Byte;
            ColorCount  : Byte;
            Reserved    : Byte;
            Planes      : Word;
            BitCount    : Word;
            SizeInBytes : Cardinal;
            FileOffset  : Cardinal;
           End;
     
        TIconContent =
           Record
            FName   : String;
            Header  : TIconHeader;
            Entries : array[0..65535 div SizeOf(TIconEntry)] of TIconEntry;
           End;
    Et voilà ma fonction qui détermine le format de bitmap le plus adapté à la conversion. Cette routine est le fruit d'un grand nombre d'expérimentations. Il existe certainement encore des cas rares où elle ne fonctionnera pas, auquel cas je compte sur Canvas.Draw pour résoudre le problème, et si elle n'y arrive pas, alors c'est vraiment que l'icône est zarbi.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function EntryDelphiPixelFormat(var IconContent:TIconContent;const N:Integer):TPixelFormat;
     begin
      Result := pfCustom;
      if (N < 0) or (N >= IconContent.Header.ImgCount) then exit;
      with IconContent.Entries[N] do
        if Planes = 1
           then begin
                 case BitCount of
                  1      : Result := pf1bit;
                  2..4   : Result := pf4bit;
                  0,5..8 : Result := pf8bit;
                  9..15  : Result := pf15bit;
                  16     : Result := pf16bit;
                  17..24 : Result := pf24bit;
                  25..32 : Result := pf32bit;
                  else Result := pf24bit;
                 end;
                end
           else begin
                 if ColorCount =  0  then Result := pf8bit else
                 if ColorCount <= 2  then Result := pf1bit else
                 if ColorCount <= 16 then Result := pf4bit else
                 Result := pf8bit;
                end;
     end;
    Pour les icônes Vista, tu confirmes donc l'hypothèse que j'avais déjà faite, et ça me fera gagner du temps. Merci.

  7. #7
    Membre du Club

    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 8
    Points : 53
    Points
    53
    Par défaut
    Salut Clandestino,

    Il y a aussi un éditeur d'icône en cours ici http://wiki.lazarus.freepascal.org/Icon_Editor_Roadmap

    Ton projet est intéressant...

    Il n'y a pas de pub, juste un forum français ???

  8. #8
    Inactif Avatar de Hibou57
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    852
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 852
    Points : 493
    Points
    493
    Par défaut
    Juste en passant trés vite : il y a longtemps j'ai constaté des irrégularités assez fréquente également même avec les fichiers bitmap, qui sont pourtant simple. Et quand on pense qu'il s'agissait de bitmap (et d'icône aussi), issu d'applications professionnelles, alors on se dit que les standard sont difficilement appliqués.

    Je ne pense pas qu'il y ait une solution unique à ces problème. Cela ressemble un peu au problème de CSS que l'on peut avoir avec les navigateur, ce problème du respect de spefications est universel. Le mieux que l'on puisse faire, c'est de respecter scrupuleusement les specifications de formats de fichier, pour donner le bon exemple, et ne pas produire soi-même de mauvais fichier.
    ------------------------------------------------------------
    Sur le web, c'est la liberté qui est gratuite, mais bien évidement pas la consomation ... et encore moins la consomation à outrance
    ------------------------------------------------------------
    Language shapes the way we think, and determines what we can think about [ B. Lee Whorf ] ... mais ce n'est pas tout à fait vrai à 100%...
    ------------------------------------------------------------
    Pascal (FreePascal?) - Ada (Gnat-3.15p)
    XSLT (XSLTProc) - CGI binaires (Ada/C) [ Clavier Arabe ]
    ------------------------------------------------------------

Discussions similaires

  1. [Jena] Comment extraire les propriétés et les relations d'une ontologie ?
    Par Nawel_Hafsa dans le forum Frameworks
    Réponses: 4
    Dernier message: 08/08/2012, 11h27
  2. Informations sur un exe (dans les propriétés windows)
    Par SteelBox dans le forum Windows
    Réponses: 6
    Dernier message: 06/07/2004, 18h20
  3. [VBA] Les propriétés de cellule dans Excel
    Par Kylen dans le forum API, COM et SDKs
    Réponses: 6
    Dernier message: 05/07/2004, 23h02
  4. Extraire les infos d'un tag ID3
    Par patkiller dans le forum Langages de programmation
    Réponses: 11
    Dernier message: 30/05/2003, 14h35
  5. Extraire les icônes d'une DLL
    Par Globus dans le forum MFC
    Réponses: 6
    Dernier message: 13/09/2002, 13h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo