Как написать огромный JPEG, который превышает физическую память, используя Delphi? - PullRequest
11 голосов
/ 27 июня 2010

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

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

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

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

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

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

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

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

Спасибо

Редактировать: Чтобы уточнить:

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

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

Ответы [ 8 ]

8 голосов
/ 27 июня 2010

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

На самом деле, ответ и возможное решение состоит в том, чтобы действовать так же, как это делает 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

1 голос
/ 28 июня 2010

Для такой тяжелой работы, как это, я прибегаю к http://www.graphicsmagick.org/

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

1 голос
/ 27 июня 2010

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

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

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

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

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

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

1 голос
/ 27 июня 2010

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

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

1 голос
/ 27 июня 2010

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

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

1 голос
/ 27 июня 2010

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

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

0 голосов
/ 08 июля 2010

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

Так что у них также есть утилита jpegjoin (найдите ее по адресу http://jpegclub.org/jpegtran/), которую можно использовать таким же образом. ОБНОВЛЕНИЕ: эта утилита предназначена для объединения без потерь, поэтому требует гораздо меньшего объема памяти / дискового пространства

0 голосов
/ 27 июня 2010

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

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

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

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

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

...