2010-06-27 70 views
11

這是問題所在。我有一大套512x512像素的JPEG圖塊作爲普通的jpg文件。如何使用Delphi編寫超過物理RAM的巨大JPEG?

我已經寫了一段軟件來完成一堆事情,並且最後需要將所有這些文件拼接成一個巨大的JPEG文件。

首先,我不希望使用ImageMagick來做到這一點,而是在我的軟件中執行它!

在Delphi中,不可能將JPG文件複製到另一個JPG畫布上,因此必須先創建TBitmap,然後將圖塊複製到TBitmap畫布上,然後將TBitmap轉換爲JPEG圖片並保存到一份文件。

如果生成的文件尺寸過大(如20 000 x 20 000像素),則會出現此問題。當我調用TBitmap.SetSize時,我自然會得到一個錯誤(內存不足或類似的東西)。

我在同一臺機器上使用Photoshop進行了一些測試,並能夠創建一個複雜的(非空白)30 000 x 30 000文件並將其保存爲JPEG。

所以問題是,我怎麼能做同樣的事情呢?通過將結果直接寫入磁盤或使用其他一些技巧來拼接所有這些JPEGS的方法?...

即使20k x 20k像素看起來足夠大,但此值僅適用於我的機器(4 GB ram),所以少量的內存將更加限制軟件!

感謝

編輯:爲了澄清:

我想什麼是找到那些拼接小JPG圖片的方式,寫大一個沒有保持大的圖像在RAM中。顯然,可以直接在磁盤上讀取/寫入位圖流(不確定),但這會導致非常大的文件。所以,如果JPG格式不允許這樣做,任何其他壓縮格式如TIFF或PNG都可以。我也想避免過多的重新壓縮,不要失去(已經壓縮的)最初的JPG質量。

因此,完美的解決方案將是一種直接讀取小文件並以某種方式寫入大文件的方式。瓷磚的尺寸是256x256或512x512,以防止JPEG壓縮材料上的某些對齊情況。

回答

8

感謝大家!

實際上,答案和可能的解決方案是按照Photoshop所做的那樣進行操作,即將瓦片中的位圖流寫入磁盤上的大型bmp文件(例如,20 000 x 30 000的文件爲2。4 Gb),然後使用NativeJpg庫將此大位圖轉換爲jpg,方法是通過條帶提供條帶化位圖數據,每個位圖數據高度爲8個像素。

也可以將一行瓷磚(512個像素高)拼接起來,然後將其送入NativeJpg庫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

像很多其他面向媒體的程序一樣,Photoshop必須處理長時間處理大於主內存的文件問題。對於大型照片來說,一種技術是平鋪只能處理圖像的一部分。

實際上這比簡單的剪切和粘貼更復雜(雙關語意圖)。

我不是Delphi程序員,但是令我擔心的是,當您創建映像的內存不足時,當您嘗試使用該映像時會發生同樣的情況嗎?

+0

我知道這會出現,但如前所述我不能打開一個更大的圖像的方式,並在Photoshop中工作;) – Alexander 2010-06-27 11:07:54

1

這是一個非常艱難的領域,正如@Peter已經說過的,Photoshop人員一直在這個since 1990。您可能無法使用您的編程語言的內置JPG解碼庫,因爲它們可能會將整個圖像加載(並解包)到RAM中。

我建議尋找處理此問題的外部庫 - 是否有體面的免費可用我不知道,但它可能是這種情況。

+0

謝謝Pekka。我不必打開大圖片,閱讀部分很簡單。問題在於寫作! ;) – Alexander 2010-06-27 11:08:45

+0

@Alexander由於JPG格式的性質,它仍然很複雜:您不能只將字節流拼接在一起,因爲它可能會使用不使用壓縮的原始格式。除非你是爲了學習效果,否則我建議使用一個外部庫:) – 2010-06-27 11:20:45

+0

那麼,我現在所做的是將圖像分成兩部分,然後編寫兩個單獨的文件,然後不得不重新縫合它們Photoshop,但我肯定會因爲這是一個個人項目而獲得學習效果;)否則,我認爲我根本不會問這個問題! 如果有另一種格式適合這個像PNG或其他原始bmp(這會導致一個可笑的大文件)... – Alexander 2010-06-27 11:42:24

1

圖像在Delphi(至少在以前的版本)的最大尺寸是更依賴於Windows的圖形驅動程序比對系統內存量

一些這方面的實驗: EFG's computer lab

+0

謝謝1月,我已經讀過這個網站,但我其實在想更多的技術可以讀取和寫入JPEG數據,而不必將完整的圖像存儲在內存中。我知道netpbm軟件包以它們的原始格式執行它,甚至可以在一些格式之間進行轉換,而不需要將整個數據加載到RAM中... – Alexander 2010-06-27 11:39:41

0

你的問題也讓我想到電子表格。這當然只是人口稀少。您可以嘗試查看一些可能會給您一些想法的圖像壓縮庫。

你也可以做的是看別人是怎麼做的。我注意到,PixeLook開發組有their PixeLook library這是Delphi 6的組件,用於創建圖像和數據處理應用程序。

他們聲稱大圖像和數據矩陣很容易處理,它們顯示5200 x 5200圖像(26 MB)的顯示,他們說他們的測試也是在圖像大小高達220 MB的情況下執行的。

如果您真的需要在您的應用程序中直接使用大型圖像處理軟件,該軟件包可能會爲您工作50美元。如果它接近但不完全正確(我不知道它是否會加入jpegs),那麼你可以考慮購買299美元的源代碼,看看它做了什麼,並擴展它。

聲明:我與這家公司無任何聯繫。

+0

220 MB圖像(<2 Gb)和2.4 Gb圖像(> 2 Gb)是完全不同的聯賽。 您可以將第一張圖像加載到內存中。好吧,它很大,但不是很大,所以這是可能的。但是你不能爲第二張圖片做這件事。由於它的大小比你的地址空間大。 – Alex 2010-06-28 09:15:19

1

您可能需要實現一個自定義類來處理這個問題。

在視頻內存中,圖像(或屏幕緩衝區)是一個線性陣列。水平行按順序存儲,每個像素對應於(y * width + x)-1處的數組偏移量。因此,在一張320x200的圖像中,5,2的像素將位於數組索引5 * 320 + 2-1或1601處。在硬件加速之前的幾天,您會將malloc()緩衝區屏幕大小,並在數學上執行繪製紋理,形狀,光照效果等操作,然後將緩衝區BLT輸出到視頻RAM。

就你而言,你可以使用內置的位圖和圖像類來處理適合內存的較小圖像,然後將它們的像素數據複製到一個大陣列或一系列陣列中(我忘記了虛擬內存是否會允許您創建緩衝區>物理RAM的大小)。然後,使用直接在該陣列上工作的JPEG庫(與機器上安裝的RAM的大小無關),您應該能夠將該陣列饋送到庫中,並將其保存到磁盤中。 LZW壓縮非常簡單,我希望他們能夠在網上手動實現JPEG壓縮。

一個警告:如果您使用的是32位操作系統,則您的地址空間應限制爲4GB。爲了解決這個問題,我能想到的唯一辦法就是創建更小的緩衝區(比如說,一次一行),用行對應的部分像素數據填充數據您需要的圖像,保存並循環,直到覆蓋整個圖像區域。

我希望這很清楚。祝你好運!

+0

我只是喜歡在回答發佈六個月後出現的降價。 – 2010-11-10 16:07:24

1

富勒重型工作就是這樣,我求助於http://www.graphicsmagick.org/

有是還包括一整套的帕斯卡單位在這裏http://graphics32.org/,但他們是非常數學和複雜(我爲此沒有得到他們的工作),但也建立了艱苦的工作。

+0

感謝但對於graphicsmagick,請閱讀我的問題: 「首先,我不希望使用ImageMagick來做到這一點,而是在我的軟件中執行它!」 – Alexander 2010-06-29 17:24:16

+1

GraphicsMagick有一個C++庫,您可以在構建時使用,並且有一個OLE接口:http://www.graphicsmagick.org/programming.html(然後,我必須承認,從Delphi中使用C++庫是另一回事) – 2010-06-30 20:58:39

0

部分外部軟件/內部通話解決方案如何? IJG(Independent JPEG Group)擁有一個非常出色的命令行工具jpegtran,我在查看器中使用它進行無損旋轉。在你自己的代碼中使用CreateProcess,WaitForsingleObject來使你看起來像你自己的代碼沒有問題。你甚至可以將可執行文件打包到你的資源中並且臨時解壓縮它

因此,它們也有jpegjoin實用程序(可在http://jpegclub.org/jpegtran/上找到),可以使用相同的方式。更新:此實用程序是用於無損加入,所以需要更小的內存/磁盤佔用空間