33 votes

la taille d'une image jpeg (jfif)

J'ai besoin de trouver la taille d'un fichier jpeg (jfif) de l'image. L'image n'est pas enregistrée en tant que fichier autonome, donc je ne peux pas utiliser GetFileSize ou toute autre API tels celui-ci (l'image est placée dans un cours d'eau et pas d'autres en-tête est présent, à l'exception de l'habituel jpeg/jfif en-tête(s).

J'ai fait quelques recherches et découvert que les images JPEG sont composés de différentes parties, chaque partie commençant avec un cadre marqueur (0xFF; XX), et la taille de cette image. En utilisant cette information, j'ai été en mesure d'analyser beaucoup d'informations à partir du fichier.

Le problème est que je ne trouve pas la taille des données compressées, comme il semble, il n'y a pas de cadre de marqueur pour les données compressées. Aussi, il semble que les données compressées suit le SOS (FF;DA) marqueur et l'image se termine avec la Fin De l'Image (MI) (FF; D9) marqueur.

Une façon d'y parvenir serait de rechercher la MI marqueur à partir de l'octet pour octet, mais je pense que la compression de données peut contenir cette combinaison d'octets, non?

Savez-vous facilement et de façon correcte à trouver la taille totale de l'image? (Je préfère un peu de code/idée sans aucune bibliothèque externe s'il vous plaît :) ) ?

En gros, j'ai besoin de la distance (en octets) entre le Début de l'Image(SOI-FFE0) et à la Fin de l'Image (de MI-FFD9).

39voto

Adam Goode Points 4114

Les données compressées ne comprendra pas de SOI ou de MI octets, de sorte que vous êtes en sécurité là-bas. Mais le commentaire, les données d'application, ou d'autres têtes pourraient. Heureusement, vous pouvez identifier et d'ignorer ces sections, la longueur est donnée.

La spécification du format JPEG vous indique ce dont vous avez besoin:
http://www.w3.org/Graphics/JPEG/itu-t81.pdf

Regardez le Tableau B. 1, à la page 32. Les symboles qui ont une * ne pas avoir un champ de longueur suivant (TVD, DI, DI, TEM). Les autres le font.

Vous aurez besoin de sauter par-dessus les divers domaines, mais il n'est pas trop mauvais.

Comment aller de travers:

  1. Commencer à lire SOI (FFD8). C'est le début. Elle devrait être la première chose dans le flux.

  2. Ensuite, les progrès dans le fichier, trouver plus d'marqueurs et sautant sur les en-têtes:

    • SOI marqueur (FFD8): image Endommagée. Vous devriez avoir trouvé une manifestation d'intérêt déjà!

    • TEM (FF01): autonome marqueur, continuer.

    • En premier (FFD0 par FFD7): autonome marqueur, continuer. Vous pourriez valider que le redémarrage des marqueurs de compter à partir de FFD0 par FFD7 et le répète, mais ce n'est pas nécessaire pour la mesure de la longueur.

    • MI marqueur (FFD9): Vous avez terminé!

    • Un marqueur qui n'est pas PREMIER, DI, DI, TEM (FF01 par FFFE, moins les exceptions ci-dessus): Après le marqueur, de lire le 2 octets, c'est la 16-bits de big-endian longueur de l'en-tête de trame (non compris les 2 octets de marqueur, mais dont le champ de longueur). Sautez la quantité donnée (généralement la longueur de moins de 2, puisque vous avez déjà obtenu ces octets).

    • Si vous obtenez une fin-de-fichier avant de l'EOI, alors vous avez une image endommagée.

  3. Une fois que vous avez un appel à candidature, vous avez obtenu à travers le format JPEG et la longueur. Vous pouvez commencer à nouveau par la lecture d'un autre SOI si vous vous attendez à plus d'un JPEG dans votre flux.

3voto

user243783 Points 11

Peut-être quelque chose comme ça

 int GetJpgSize(unsigned char *pData, DWORD FileSizeLow, unsigned short *pWidth, unsigned short *pHeight)
{
  unsigned int i = 0;


  if ((pData[i] == 0xFF) && (pData[i + 1] == 0xD8) && (pData[i + 2] == 0xFF) && (pData[i + 3] == 0xE0)) {
    i += 4;

    // Check for valid JPEG header (null terminated JFIF)
    if ((pData[i + 2] == 'J') && (pData[i + 3] == 'F') && (pData[i + 4] == 'I') && (pData[i + 5] == 'F')
        && (pData[i + 6] == 0x00)) {

      //Retrieve the block length of the first block since the first block will not contain the size of file
      unsigned short block_length = pData[i] * 256 + pData[i + 1];

      while (i < FileSizeLow) {
        //Increase the file index to get to the next block
        i += block_length; 

        if (i >= FileSizeLow) {
          //Check to protect against segmentation faults
          return -1;
        }

        if (pData[i] != 0xFF) {
          return -2;
        } 

        if (pData[i + 1] == 0xC0) {
          //0xFFC0 is the "Start of frame" marker which contains the file size
          //The structure of the 0xFFC0 block is quite simple [0xFFC0][ushort length][uchar precision][ushort x][ushort y]
          *pHeight = pData[i + 5] * 256 + pData[i + 6];
          *pWidth = pData[i + 7] * 256 + pData[i + 8];

          return 0;
        }
        else {
          i += 2; //Skip the block marker

          //Go to the next block
          block_length = pData[i] * 256 + pData[i + 1];
        }
      }

      //If this point is reached then no size was found
      return -3;
    }
    else {
      return -4;
    } //Not a valid JFIF string
  }
  else {
    return -5;
  } //Not a valid SOI header

  return -6;
}  // GetJpgSize
 

2voto

John Gietzen Points 23645

Puisque vous n'avez pas de n'importe quelle langue posté, je ne suis pas sûr que cela fonctionne, mais:

Pouvez-vous Stream.Seek(0, StreamOffset.End); , puis prendre le flux de position?

Veuillez être précis sur ce framework que vous utilisez.

Le réel fait de la question est, si le fichier d'en-tête ne spécifie pas la taille attendue, vous devez chercher (ou de lire) à la fin de l'image.

MODIFIER

Puisque vous essayez de flux multiples de fichiers, vous souhaitez utiliser un streaming amical format de conteneur.

OGG devrait être un bon ajustement pour cela.

JPEG est en fait déjà le streaming amical, mais vous devez vous assurer que chaque fichier est valide terminator avant de l'envoyer vers le bas le cours d'eau ou d'autre, vous courez le risque de plantage de votre application avec inattendus de saisie.

0voto

Chinmay Kanchi Points 16353

En python, vous pouvez simplement lire le fichier entier dans un objet chaîne et trouver la première occurrence de FF E0 et la dernière occurrence de FF D9. Vraisemblablement, ce sont le début et la fin que vous recherchez?

 f = open("filename.jpg", "r")
s = f.read()
start = s.find("\xff\xe0")
end = s.rfind("\xff\xd9")
imagesize = end - start
 

-3voto

girishvora12 Points 5

Ce code permet de prendre moins de 500 Ko et le format .jpg avant de télécharger l'image

 protected void btnOk_Click(object sender, EventArgs e)
{
    long maxsize = 512000;
    string str = Path.GetFileName(FileUpload1.FileName);
    int filesize = FileUpload1.PostedFile.ContentLength;
    string fileexe = Path.GetExtension(FileUpload1.FileName);
    if (filesize <= maxsize )
    {
        if (fileexe == ".jpg" || fileexe == ".jpeg")
        {
            FileUpload1.SaveAs(Server.MapPath("~/Image/" + str));
        }
        else
        {
            lblMsg.Text = "Image extension must be jpg or jpeg";
        }
    }
    else
    {
        lblMsg.Text = "File size is too large.";
    }

}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X