Moyen rapide d'obtenir les dimensions de l'image (pas la taille du fichier)

138

Je recherche un moyen rapide d'obtenir la hauteur et la largeur d'une image en pixels. Il doit gérer au moins JPG, PNG et TIFF, mais plus il y en a, mieux c'est. J'insiste vite car mes images sont assez grandes (jusqu'à 250 Mo) et il faut tellement de temps pour obtenir la taille avec ImageMagick identifycar il lit évidemment les images dans leur ensemble en premier.

De préférence, je cherche un moyen qui fonctionne bien dans Ruby, ou même dans Rails 3.

Je connais la théorie (différents formats d'image, leurs en-têtes et leurs différences, etc.). En effet, je demande une sorte de bibliothèque qui puisse résoudre mon problème de manière assez générique.

Je viens de trouver une taille d'image qui semble prometteuse bien que le développement semble être mort.

d'Anjou
la source
8
Cela ne semble pas être le cas pour les nouvelles versions d'ImageMagick. En utilisant ImageMagick 6.5.4-7, j'ai confirmé qu'identifier (au moins pour TIF et PNG) ne lit que l'en-tête (jusqu'à 60 Ko) et fonctionne très rapidement, même pour les images de 335 Mo.
coderforlife

Réponses:

195
  • La filecommande imprime les dimensions de plusieurs formats d'image (par exemple PNG, GIF, JPEG; versions récentes également PPM, WEBP) et ne lit que l'en-tête.

  • La identifycommande (d'ImageMagick) imprime beaucoup d'informations d'image pour une grande variété d'images. Il semble se limiter à la lecture de la partie d'en-tête (voir les commentaires). Il a également une sortie unifiée qui filemanque malheureusement.

  • exiv2vous donne des dimensions pour de nombreux formats, y compris JPEG, TIFF, PNG, GIF, WEBP, même si aucun en-tête EXIF ​​n'est présent. On ne sait pas s'il lit toutes les données pour cela. Consultez la page de manuel d'exiv2 pour tous les formats d'image pris en charge.

  • head -n1 vous donnera les dimensions pour les formats PPM, PGM.

Pour les formats populaires sur le web, à la fois exiv2et identifyfera le travail. Selon le cas d'utilisation, vous devrez peut-être écrire votre propre script qui combine / analyse les sorties de plusieurs outils.

ypnos
la source
3
J'ai fait quelques tests avec la commande Identifier ImageMagick, en utilisant strace pour enregistrer les appels open / read / mmap / close pour voir combien de données ont été lues à partir de l'image identifiée. Cela dépend légèrement du type de fichier et de la taille du fichier, mais j'obtenais 20 à 60 Ko de lecture par «identifier» pour des images de 5 à 335 Mo (j'ai également testé contre «convertir» qui montrait tous les octets en cours de lecture). Il semble donc que "identifier" soit un bon choix ici (car il prend en charge tous les formats courants et ne lit que l'en-tête).
coderforlife
1
Je pense qu'exiv2 fait aussi du PNG.
chx
Existe-t-il des moyens d'analyser facilement la sortie des commandes de fichier? Identifier est génial mais cela ne fonctionne malheureusement pas avec les fichiers WebP
Brian Leishman
Identifier le fait le travail avec WebP, et ImageMagick a un support pour WebP depuis des années. Peut-être pourriez-vous obtenir une mise à jour?
ypnos
32

Je ne suis pas sûr que php soit installé, mais cette fonction PHP est assez pratique

 php -r "print_r(getimagesize('http://www.google.com/images/logos/ps_logo2.png'));"
ajreal
la source
1
C'est beaucoup plus rapide que "identifier". Bonne approche. Merci.
souravb
19

Vous pouvez utiliser la fonction d' identification d'ImageMagick . Voici comment procéder dans bash (notez que $ 0 est le chemin de l'image):

width=$(identify -format "%w" "$0")> /dev/null
height=$(identify -format "%h" "$0")> /dev/null

Et cela masque également tous les messages d'erreur potentiels. Les implémentations modernes identifyne lisent que l'en-tête, pas l'image entière, donc c'est rapide. Je ne sais pas comment cela se compare aux autres méthodes.

James L.
la source
2
Je pense que c'est beaucoup plus efficace de cette façon:read width height < <(identify -format "%w %h" "${1}")
Cromax
5

https://joseluisbz.wordpress.com/2013/08/06/obtaining-size-or-dimension-of-images/ (BMP, PNG, GIF, JPG, TIF ou WMF)

Ici pour deux formats PNG et JPG.

Mon code est issu d'une classe conçue pour mon usage, vous pouvez le modifier selon vos besoins.

Veuillez vérifier ces fonctions / méthodes en utilisant PHP :

  public function ByteStreamImageString($ByteStream,&$Formato,&$Alto,&$Ancho) {
    $Alto = 0;
    $Ancho = 0;
    $Formato = -1;
    $this->HexImageString = "Error";
    if (ord($ByteStream[0])==137 && ord($ByteStream[1])==80 && ord($ByteStream[2])==78){
      $Formato = 1; //PNG
      $Alto = $this->Byte2PosInt($ByteStream[22],$ByteStream[23]);
      $Ancho = $this->Byte2PosInt($ByteStream[18],$ByteStream[19]);
    }
    if (ord($ByteStream[0])==255 && ord($ByteStream[1])==216
        && ord($ByteStream[2])==255 && ord($ByteStream[3])==224){
      $Formato = 2; //JPG
      $PosJPG = 2;
      while ($PosJPG<strlen($ByteStream)){
        if (sprintf("%02X%02X", ord($ByteStream[$PosJPG+0]),ord($ByteStream[$PosJPG+1]))=="FFC0"){
          $Alto = $this->Byte2PosInt($ByteStream[$PosJPG+5],$ByteStream[$PosJPG+6]);
          $Ancho = $this->Byte2PosInt($ByteStream[$PosJPG+7],$ByteStream[$PosJPG+8]);
        }
        $PosJPG = $PosJPG+2+$this->Byte2PosInt($ByteStream[$PosJPG+2],$ByteStream[$PosJPG+3]);
      }
    }
    if ($Formato > 0){
      $this->HexImageString = "";
      $Salto = 0;
      for ($i=0;$i < strlen($ByteStream); $i++){
        $Salto++;
        $this->HexImageString .= sprintf("%02x", ord($ByteStream[$i]));
        if ($Salto==64){
          $this->HexImageString .= "\n";
          $Salto = 0;
        }
      }
    }
  }


  private function Byte2PosInt($Byte08,$Byte00) {
    return ((ord($Byte08) & 0xFF) << 8)|((ord($Byte00) & 0xFF) << 0);
  }

Utilisation du code PHP:

      $iFormato = NULL;//Format PNG or JPG
      $iAlto = NULL; //High
      $iAncho = NULL;//Wide
      ByteStreamImageString($ImageJPG,$iFormato,$iAlto,$iAncho);//The Dimensions will stored in  iFormato,iAlto,iAncho

Maintenant, ces fonctions / méthode utilisant JAVA :

  private void ByteStreamImageString(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) {
    High[0] = 0;
    Wide[0] = 0;
    Frmt[0] = -1;
    this.HexImageString = "Error";
    if ((int)(ByteStream[0]&0xFF)==137 && (int)(ByteStream[1]&0xFF)==80 &&(int)(ByteStream[2]&0xFF)==78){
      Frmt[0] = 1; //PNG
      High[0] = this.Byte2PosInt(ByteStream[22],ByteStream[23]);
      Wide[0] = this.Byte2PosInt(ByteStream[18],ByteStream[19]);
    }
    if ((int)(ByteStream[0]&0xFF)==255 && (int)(ByteStream[1]&0xFF)==216
        &&(int)(ByteStream[2]&0xFF)==255 && (int)(ByteStream[3]&0xFF)==224){
      Frmt[0] = 2; //JPG
      int PosJPG = 2;
      while (PosJPG<ByteStream.length){
        if (String.format("%02X%02X", ByteStream[PosJPG+0],ByteStream[PosJPG+1]).equals("FFC0")){
          High[0] = this.Byte2PosInt(ByteStream[PosJPG+5],ByteStream[PosJPG+6]);
          Wide[0] = this.Byte2PosInt(ByteStream[PosJPG+7],ByteStream[PosJPG+8]);
        }
        PosJPG = PosJPG+2+this.Byte2PosInt(ByteStream[PosJPG+2],ByteStream[PosJPG+3]);
      }
    }
    if (Frmt[0] > 0){
      this.HexImageString = "";
      int Salto = 0;
      for (int i=0;i < ByteStream.length; i++){
        Salto++;
        this.HexImageString += String.format("%02x", ByteStream[i]);
        if (Salto==64){
          this.HexImageString += "\n";
          Salto = 0;
        }
      }
    }
  }


  private Integer Byte2PosInt(byte Byte08, byte Byte00) {
    return new Integer (((Byte08 & 0xFF) << 8)|((Byte00 & 0xFF) << 0));
  }

Utilisation du code Java:

        int[] iFormato = new int[1]; //Format PNG or JPG
        int[] iAlto = new int[1]; //High
        int[] iAncho = new int[1]; //Wide
        ByteStreamImageString(ImageJPG,iFormato,iAlto,iAncho); //The Dimensions will stored in  iFormato[0],iAlto[0],iAncho[0]
Joseluisbz
la source
Je vois que vous utilisez des tableaux pour les arguments comme un hack pour obtenir ref/ outparameters en Java - est-ce considéré comme une meilleure pratique?
Dai
Cette réponse est très ancienne, maintenant je ne veux pas mettre à jour (j'oublie beaucoup de choses et je n'ai pas le temps), mais vous pouvez vérifier le code et le modifier.
joseluisbz
joseluisbz.wordpress.com/2013/07/26/… (explication pour WMF)
joseluisbz
Pour cet exemple, je recommande d'implémenter une nouvelle classe avec 3 champs, Format, Haut et Largeur, renvoyant une instance de cette classe.
joseluisbz
1

Ce sont les dimensions en pixels que vous voulez (largeur et hauteur), je suppose?

Je pense que la plupart des formats de fichiers ont des informations d'en-tête définissant les dimensions, de sorte que le logiciel qui lit le fichier puisse savoir combien d'espace il doit réserver avant de commencer à lire le fichier. Certains formats de fichiers de type "brut" peuvent simplement être un flux d'octets avec un octet "fin de ligne" à la fin de chaque ligne horizontale de pixels (auquel cas le logiciel doit lire la première ligne et diviser la taille du flux d'octets par la longueur de la ligne pour obtenir la hauteur).

Je ne pense pas que vous puissiez faire cela de manière "générique", car vous devez comprendre le format du fichier (ou utiliser une bibliothèque bien sûr) pour savoir comment le lire. Vous pouvez probablement trouver du code qui, dans la plupart des cas, donnera une estimation approximative des dimensions sans lire le fichier entier, mais je pense que certains types de fichiers peuvent vous obliger à lire le fichier entier pour être sûr de ses dimensions réelles. Je m'attends à ce que la plupart des formats d'image centrés sur le Web aient un en-tête avec de telles informations afin que le navigateur puisse créer les dimensions de la boîte avant que l'image entière ne soit chargée.

Je suppose qu'une bonne bibliothèque aurait des méthodes pour obtenir les dimensions des fichiers qu'elle gère, et que ces méthodes seraient implémentées aussi efficacement que possible.

Mise à jour : imageinfo semble faire ce que vous voulez. (Je ne l'ai pas testé)

Stein G. Strindhaug
la source
Cet outil fonctionne aussi vite que j'en ai besoin;). Je vais voir si je peux l'utiliser correctement.
dAnjou
0

Si vous avez des informations EXIF ​​dans les images, vous pouvez simplement lire l'en-tête EXIF.

Georgi
la source
Malheureusement, je ne sais pas quel genre d'images il y aura et si elles contiennent des données EXIF.
dAnjou
3
Combien de vos images N'avoir cette information? Peut-être que si 90% d'entre eux ont des données EXIF, la lenteur de l'utilisation d'ImageMagick sur les 10% restants sera acceptable.
Andy Lester
Pourquoi cette réponse a-t-elle des votes négatifs? C'est une réponse valable à la question et peut bien être exactement ce que le PO ou quelqu'un d'autre recherche.
Will Sheppard
0

-ping est une option qui semble avoir été introduite à cet effet.

Cependant, à partir d'ImageMagick 6.7.7, je n'observe pas de ralentissement même pour tous les gros fichiers, par exemple:

head -c 100000000 /dev/urandom > f.gray
# I don't recommend that you run this command as it eats a lot of memory.
convert -depth 8 -size 20000x10000 f.gray f.png
identify f.png

Pouvez-vous produire un exemple d'image d'entrée pour lequel il est encore lent?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
0

tldr: le fichier "imagename" fera l'affaire

fonctionne avec webp, tous les formats jpg (jpeg, jpg200, ..),

Exemple de sortie ressemble à

Données d'image JPEG, norme JFIF 1.02, rapport hauteur / largeur, densité 1x1, longueur de segment 16, ligne de base, précision 8, 650x400, images 3

chargez la sortie du fichier dans une liste python et utilisez le 4ème champ de la liste.

FYI, a optimisé plus de 18000 images pour réduire le trafic réseau.

mj-ek
la source