Обработка на големи изображения с Delphi за запазване като .jpeg

В Delphi 7 имам библиотека, която използва компонента TCanvas за извеждане на информация. Полученото изображение е около 4800*6000 пиксела и бих искал да го отпечатам и запазя като .jpeg.

За да постигна това, създадох TBitmap и дадох неговия Canvas като параметър на библиотеката и след това присвоих растерното изображение на jpeg. Очевидно това отнема твърде много памет, защото получавам изключение, когато се опитвам да задам ширината и височината на растерното изображение, казвайки „Няма достатъчно място за съхранение за обработка на тази команда.“

// output to printer
Printer.BeginDoc();
doPrint(Printer.Canvas);
Printer.EndDoc();

// output in bmp.Canvas
bmp := TBitmap.Create;
bmp.Width := Printer.PageWidth;
bmp.Height := Printer.PageHeight; // <- BAM! Exception!
doPrint(bmp.Canvas);

// save as jpeg
jpg := TJPEGImage.Create;
jpg.Assign(bmp);
jpg.SaveToFile('...');

// free
bmp.Free();
jpg.Free();

какво правя грешно Мога ли да запазя Printer.Canvas директно като .jpeg файл?

Редактиране: Актуализиран приблизителен размер на изображението от 2000*2000 на 4800*6000


person Tom    schedule 28.10.2009    source източник
comment
Каква библиотека е това, принудени ли сте да GETMEM или нещо подобно? Причината да питам е, че ако това беше TBitmap, ще се оправиш. RE   -  person Reallyethical    schedule 28.10.2009
comment
Не използвам нищо специално и библиотеката е просто нещо, което използва Canvas за извеждане на някаква информация, също е написана на Delphi и целият изходен код е пълен с нищо повече от var s:TStringList и cnv.TextOut(..) така че може лесно да се прекомпилира и трябва да е наред.   -  person Tom    schedule 28.10.2009


Отговори (10)


трябва да можете да обработвате големи растерни изображения с помощта на TBitmap32 от Graphic32 (http://www.graphics32.org/wiki/)

person glob    schedule 29.10.2009

Трябва да зададете пикселния формат за bmp на нещо, преди да оразмерите bmp, както предлага Бен Зиглер. Това прави цялата разлика.

person Niels Thomsen    schedule 29.10.2009
comment
Ще пробвам и това, така или иначе е черно-бяло изображение. - person Tom; 30.10.2009

Тази грешка възниква, ако зададете размера на растерното изображение на нещо по-голямо от размера на вашия работен плот. За да избегнете тази грешка, можете да създадете независимо от устройството растерно изображение по следния начин:

bmp := TBitmap.Create;
bmp.HandleType := bmDIB;
bmp.Width := Printer.PageWidth;
bmp.Height := Printer.PageHeight; 

Дали имате нужда от това решение зависи от възможностите на вашата видеокарта. Имахме тази грешка често в ситуации на терминален сървър, където не беше разпределено много видео RAM за една сесия. Използвайки това решение, вие принуждавате Delphi да използва нормална RAM за вашето растерно изображение вместо памет на вашата видеокарта.

person GHN    schedule 25.09.2012

Класът TBitmap на Delphi има проблеми с обработката на толкова големи растерни изображения. И не, не можете да запазите TCanvas директно в .jpg файл.

person Remy Lebeau    schedule 28.10.2009
comment
Ако никой не излезе с идеи/заобиколни решения в скоро време, ще приема отговора ви. - person Tom; 29.10.2009
comment
Самият клас TBitmap няма никакви проблеми, той е просто обвивка около функциите на Windows API. В зависимост от версията на Windows и графичната карта (драйвер) може да има проблеми или не, просто така, но Delphi всъщност не влиза в това. Мога да създам растерно изображение с размери 10 000 на 10 000 пиксела без проблеми в моята система. Просто отнема известно време, за да го запълните с цвят или да го запишете във файл (размер 380 MB). - person mghie; 29.10.2009

Опитах следния код на моята машина (Windows XP, Delphi 2006) и не получих никакви изключения. Каква ОС използвате?

  procedure TForm3.Button3Click(Sender: TObject);
  var
     bmp : TBitmap;
  begin
     bmp := TBitmap.Create;
     bmp.PixelFormat := pf32bit;
     bmp.Width := 6000;
     bmp.Height := 4800;
     bmp.Free;
  end;
person Ben Ziegler    schedule 28.10.2009
comment
Windows XP SP1 с 1GB RAM. Приложението се използва на Windows 7 с 2 GB RAM без никакви проблеми, но бих искал да се уверя, че работи добре на моята система (поне за отстраняване на грешки) - person Tom; 30.10.2009

Както mghie каза: Зависи много от вашата система, вижте Компютърна лаборатория на EFG за големи растерни изображения

person Jan Oosting    schedule 29.10.2009

Опитайте да зададете PixelFormat на pf32bit или pf24bit (както в примера от Ben Ziegler), в повечето случаи този PixelFormat върши работа (доколкото си спомням, беше главно на XP). Можете да намерите повече информация тук.

person Krystian Bigaj    schedule 29.10.2009

Това не е JPEG формат: спецификацията позволява растерни изображения с големина до 32767x32767 пиксела.

Проблемът е огромното потребление на mem от големи растерни изображения и ограниченията на TCanvas, които в крайна сметка могат да бъдат проследени до платформата Windows.

Моята библиотека NativeJpg декодира обработката на JPEG отделно от визуализацията и можете напр. запазете такъв JPEG, като използвате "лента по лента", с по-управляеми растерни плочки като резултат.

NativeJpg е с отворен код и можете да изтеглите тази библиотека тук: http://www.simdesign.nl/forum/viewforum.php?f=16

Погледнете tiledemo, за да видите как да създавате и запазвате огромни изкуствени JPEG изображения.

С уважение, Нилс

person Nils Haeck    schedule 09.07.2011

За да консумирате по-малко памет, винаги можете да опитате да създадете по-малки растерни изображения. да кажем, че разделяте височината на принтера на 10 или задавате максимална височина на 1000. Само предложение, не съм сигурен дали е приложимо във вашия случай. Резултатът е повече от едно изображение на страница.

person Darkerstar    schedule 25.09.2012

Не съм сигурен дали това ще работи или ще помогне. Но създадохме функция, която ще запише компонент в jpeg:

    function SaveComponentToJPeg(mControl: TWinControl): TJpegImage;
    var
      bmp: TPicture;
      jpg : TJpegImage;
      dc: HDC;
      wnd: HWND;
      Params: array[0..255] of Char;

    begin
      bmp:=TPicture.Create;
      jpg := TJpegImage.create;
      try
        bmp.Bitmap.Width  := mControl.Width  - 05;  // Deduct for border.
        bmp.Bitmap.Height := mControl.Height -05;  // Deduct for border.
        wnd               := mControl.Handle;  //ctiveWindow;
        dc                := GetDc(wnd);
        BitBlt(bmp.Bitmap.Canvas.Handle,0,0,bmp.Width,bmp.Height,dc,0,0,SrcCopy);
        ReleaseDc(wnd, dc);
        jpg.assign(bmp.bitmap);
        result := jpg
      finally
        bmp.Free;
      end;
    end;
person M Schenkel    schedule 30.10.2009