Подтвердить что ты не робот

Размер jpeg (jfif) изображения

Мне нужно найти размер jpeg (jfif) изображения. Изображение не сохраняется как отдельный файл, поэтому я не могу использовать GetFileSize или любой другой API, такой как этот (изображение помещается в поток, и никакой другой заголовок не присутствует, за исключением обычного заголовка jpeg/jfif (s).

Я провел некоторое исследование и выяснил, что изображения в формате JPEG состоят из разных частей, каждая часть начинается с маркера кадра (0xFF; XX) и размером этого кадра. Используя эту информацию, я смог разобрать много информации из файла.

Проблема заключается в том, что я не могу найти размер сжатых данных, поскольку, по-видимому, маркер рамки для сжатых данных отсутствует. Кроме того, кажется, что сжатые данные следуют маркеру SOS (FF; DA), и изображение заканчивается маркером конца изображения (EOI) (FF; D9).

Для этого можно было бы искать маркер EOI от байта до байта, но я думаю, что сжатые данные могут содержать эту комбинацию байтов, правильно?

Знаете ли вы простой и правильный способ найти общий размер изображения? (Я бы предпочел бы какой-нибудь код/​​идею без какой-либо внешней библиотеки, пожалуйста:))?

В принципе, мне нужно расстояние (в байтах) между началом изображения (SOI-FFE0) и концом изображения (EOI-FFD9).

4b9b3361

Ответ 1

Сжатые данные не будут содержать байты SOI или EOI, поэтому вы в безопасности. Но комментарий, данные приложения или другие заголовки могут. К счастью, вы можете идентифицировать и пропустить эти разделы по мере их длины.

Спецификация JPEG сообщает вам, что вам нужно:
http://www.w3.org/Graphics/JPEG/itu-t81.pdf

Посмотрите на таблицу B.1, на стр. 32. Символы, у которых есть *, не имеют после него поля длины (RST, SOI, EOI, TEM). Другие делают.

Вам нужно будет пропустить разные поля, но это не так уж плохо.

Как пройти:

  • Начните читать SOI (FFD8). Это начало. Это должно быть первым в потоке.

    • Затем пройдите через файл, найдите больше маркеров и пропустите заголовки:

    • Маркер SOI (FFD8): Поврежденное изображение. Вы должны были найти EOI уже!

    • TEM (FF01): автономный маркер, продолжайте движение.

    • RST (FFD0 через FFD7): автономный маркер, продолжайте движение. Вы можете подтвердить, что маркеры перезапуска подсчитываются от FFD0 до FFD7 и повторяются, но это необязательно для измерения длины.

    • Маркер EOI (FFD9): все готово!

    • Любой маркер, который не является RST, SOI, EOI, TEM (FF01 через FFFE, за вычетом исключений выше): после маркера, прочитайте следующие 2 байта, это 16-битный большой -endian длины заголовка этого кадра (не включая 2-байтовый маркер, но включая поле длины). Пропустите указанную сумму (обычно длина минус 2, так как вы уже получили эти байты).

    • Если вы получите конец файла перед EOI, у вас есть поврежденное изображение.

    • Как только у вас есть EOI, вы прошли через JPEG и должны иметь длину. Вы можете начать заново, прочитав другой SOI, если вы ожидаете более одного JPEG в своем потоке.

Ответ 2

Поскольку у вас нет какого-либо языка, я не уверен, что это сработает, но:

Можете ли вы Stream.Seek(0, StreamOffset.End);, а затем взять позицию потока?

Пожалуйста, укажите, какие рамки вы используете.

Реальный факт заключается в том, что если заголовок файла не указывает ожидаемый размер, вам нужно искать (или читать) до конца изображения.

ИЗМЕНИТЬ

Поскольку вы пытаетесь передать несколько файлов, вам понадобится использовать удобный для загрузки формат контейнера.

OGG должно быть хорошо подходит для этого.

JPEG на самом деле уже совместим с потоковой передачей, но вы должны гарантировать, что каждый файл имеет действительный терминатор перед отправкой его по потоку, иначе вы рискуете скомпрометировать свое приложение с неожиданным вводом.

Ответ 3

Может быть, что-то вроде этого

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

Ответ 4

В python вы можете просто прочитать весь файл в строковый объект и найти первое вхождение FF E0 и последнее вхождение FF D9. Предположительно, это начало и конец, которые вы ищете?

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

Ответ 5

Этот код предназначен для того, чтобы принять размер менее 500kb и формат .jpg перед загрузкой изображения

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.";
    }

}