Как написать огромный JPEG, который превышает физическую память с помощью Delphi?

Вот проблема. У меня есть большой набор пикселов JPEG размером 512x512 пикселей в качестве обычных файлов jpg.

Я написал часть программного обеспечения, которое делает кучу вещей, и вам нужно сшить все эти файлы в один огромный JPEG в конце.

Прежде всего, я НЕ хочу использовать ImageMagick для этого, но выполняю его внутри своего программного обеспечения!

В Delphi невозможно скопировать файл JPG на другой холст JPG, поэтому сначала необходимо создать TBitmap, затем фрагменты будут скопированы на холст TBitmap, а затем TBitmap будет преобразован в jpeg-изображение и сохранен в файл.

Проблема возникает, когда результирующие размеры файла слишком велики (например, 20 000 x 20 000 пикселей). Когда я вызываю TBitmap.SetSize, я, естественно, получаю ошибку (вне памяти или что-то вроде этого).

Я сделал несколько тестов с помощью Photoshop на той же машине и смог создать сложный (не пустой) файл размером 30 000 x 30 000 и сохранить его в формате JPEG.

Итак, вопрос в том, как я могу выполнить одно и то же? Fing какой-то способ сшить все эти JPEGS, написав результат непосредственно на диск или использовать какой-то другой трюк?...

Несмотря на то, что 20k x 20k пикселей кажутся достаточно большими, это значение применимо только к моей машине (4 ГБ оперативной памяти), поэтому меньшее количество RAM будет еще более ограничено программным обеспечением!

Спасибо

Изменить: уточнить:

Я бы хотел найти способ сшивания этих маленьких изображений JPG и написать большой, не сохраняя большое изображение в ОЗУ. По-видимому, чтение/запись потока битмапа возможно непосредственно на диске (не уверен), но это приведет к ОЧЕНЬ большому файлу. Таким образом, если формат JPG не позволяет этого делать, любой другой сжатый формат, такой как TIFF или PNG, будет делать. Я также хотел бы избежать слишком много рекомпрессии, чтобы не потерять (уже сжатое) начальное качество JPG.

Следовательно, идеальным решением было бы прямое чтение небольших файлов и запись в большой. Размеры плиток - 256x256 или 512x512, если это поможет в некоторых настройках сжатия JPEG.

Ответ 1

Спасибо всем!

На самом деле, ответ и возможное решение - это продолжить работу с Photoshop, то есть записать поток растровых изображений из фрагментов в большой файл BMP на диске (например, файл размером 20 000 x 30 000 будет равен 2,4 Гб) и затем используйте библиотеку NativeJpg для преобразования этого большого растрового изображения в jpg путем подачи полосы данных растровых изображений по полосе, каждая из которых имеет высоту 8 пикселей.

Также можно было бы сшить одну строку плиток (максимум 512 пикселей), а затем отправить ее в библиотеку NativeJpg 8 на 8, а затем перейти к следующей строке плиток!

Пример кода Эрика Тернера:

procedure GetBitmapTile(BM: TBitmap; Y, X: Integer);
var JpegImage: TJpegImage;
begin
  JpegImage := NIL; // Replace with tile lookup //
  BM.PixelFormat := pf32bit;
  BM.Width := JpegImage.Width;
  BM.Height := JpegImage.Height;
  BM.Canvas.Draw(0, 0, JpegImage);
end;

procedure WriteBitmapFile(TileCountY, TileCountX: Integer; BM_Stm: TStream);
var
  BM: TBitmap;
  TileY: Integer;
  TileX: Integer;
  PixelY: Integer;
begin
  BM := TBitmap.Create;
  for TileY := 0 to TileCountY-1 do
    for TileX := 0 to TileCountX-1 do
    begin
      GetBitmapTile(BM, TileY, TileX);
      for PixelY := 0 to 511 do
        BM_Stm.Write(BM.ScanLine[PixelY]^, 512 * SizeOf(TRGBQuad));
    end;
    BM.Free;
end;

Библиотека NativeJpg: http://www.simdesign.nl/nativejpg.html

Ответ 2

Photoshop, как и многие другие медиа-ориентированные программы, долгое время имел дело с проблемой работы с файлами, большими, чем основная память. Для больших фотографий одна из технологий заключается в том, что она обрабатывает только часть изображения.

На практике это более запутанно (каламбур), чем просто вырезать и вставлять.

Я не программист Delphi, но меня беспокоит то, что, когда у вас заканчивается память, создающая изображение, не произойдет ли это, когда вы попытаетесь использовать это изображение?

Ответ 3

Это довольно сложное поле, и, как уже говорит @Peter, люди Photoshop были в этом с 1990 года. Вероятно, вы не сможете работать со своими языками программирования, встроенными в JPG, поскольку они, скорее всего, загрузят (и распакуют) все изображение в ОЗУ.

Я бы порекомендовал искать внешние библиотеки, которые справляются с этим - есть ли доступные бесплатно, я не знаю, но это может быть так.

Ответ 4

Максимальный размер изображений в Delphi (по крайней мере в предыдущих версиях) в большей степени зависит от графических драйверов окон, чем от объема системной памяти

Некоторые эксперименты по этому поводу: Компьютерная лаборатория EFG

Ответ 5

Вам может потребоваться реализовать пользовательский класс для обработки этого.

В видеопамяти изображение (или буфер экрана) представляет собой линейный массив. Горизонтальные строки сохраняются последовательно, и каждый пиксель соответствует смещению массива в (y * width + x) -1.

Таким образом, в изображении 320x200 пиксель в 5,2 будет иметь индекс массива 5 * 320 + 2-1 или 1601. За несколько секунд до аппаратного ускорения вы должны были бы malloc() буфер размером вашего экрана и математически выполнять операции, такие как рисование текстур, фигур, эффектов освещения и т.д., затем BLT буфер для видеопамяти.

В вашем случае вы можете использовать встроенные растровые и графические классы для работы с меньшими изображениями, которые вписываются в память, а затем копировать их пиксельные данные в большой массив или ряд массивов (я забываю, если виртуальная память позволит вы создаете буферы > размер физической памяти). Затем, используя библиотеку JPEG, которая работает непосредственно с этим массивом (который не зависит от размера ОЗУ, установленного на компьютере), вы должны иметь возможность подавать массив в библиотеку и сохранять содержимое на диск. Сжатие LZW довольно простое, и я бы ожидал, что их будет много материала для ручного сжатия JPEG в Интернете.

Остерегайтесь этого: если вы используете 32-разрядную ОС, ваше адресное пространство должно быть ограничено 4 ГБ. Единственный способ, с помощью которого я могу думать о том, чтобы скрыть это, - создать меньшие буферы (скажем, по одной строке за раз), забросить данные частью данных пикселя, соответствующей строке ваши готовые изображения, сохраните их и зациклируйте до тех пор, пока вы не охватите всю область изображения.

Я надеюсь, что это ясно. Удачи!

Ответ 6

Для работы с большими нагрузками, я прибегаю к http://www.graphicsmagick.org/

Здесь также есть набор блоков Pascal http://graphics32.org/, но они довольно математичны и сложны (и, следовательно, t заставил их работать), но также и для тяжелой работы.

Ответ 7

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

То, что вы также можете сделать, это посмотреть, как это делает кто-то другой. Я отмечаю, что группа разработки PixeLook их библиотека PixeLook, которые являются компонентами для Delphi 6 для создания приложений для обработки изображений и обработки данных.

Они утверждают, что большие изображения и матрицы данных легко обрабатываются и на странице их скриншотов, они показывают изображение 5200 x 5200 (26 МБ), и они говорят, что их тесты также выполнялись с размером изображения до 220 МБ.

Если вам действительно нужна большая обработка изображений непосредственно в вашем приложении, этот пакет может работать для вас за 50 долларов. Если он закрывается, но не совсем правильно (я не знаю, присоединится ли он к jpegs), тогда вы можете подумать о покупке источника за 299 долларов, посмотреть, что он делает, и расширить его.

Отказ от ответственности: у меня нет связи с этой компанией.

Ответ 8

Как насчет частичного внешнего программного обеспечения/внутреннего решения? IJG (независимая группа JPEG) имеет превосходный инструмент командной строки jpegtran, который я использовал в своем средстве просмотра без потерь. Нет проблем с тем, чтобы использовать CreateProcess, WaitForsingleObject внутри вашего собственного кода, чтобы выглядеть похожим на ваш собственный код. Вы даже можете упаковать исполняемые файлы внутри своего ресурса и извлечь его временно

Таким образом, у них также есть утилита jpegjoin (найти ее в http://jpegclub.org/jpegtran/), которая может использоваться одинаково. UPDATE: эта утилита предназначена для соединения без потерь, поэтому требуется значительно меньший объем памяти/диска