2010-03-15 75 views
13

我正在開發一個silverlight項目,用戶可以在其中創建自己的Collages。如何在不佔用大量內存的情況下顯示圖像

問題

當使用的BitmapImage類加載大量的圖片,Silverlight的豬了龐大的不合理數量的RAM。 150張照片,其中單張最多可容納4,5mb,佔用大約1,6GB內存 - 因此最終導致內存異常。

我正在通過流加載它們,因爲用戶選擇了自己的照片。

我正在尋找

類,方法或一些過程,以消除RAM的大量被吸起來。速度是一個問題,所以我不想在圖像格式或類似的東西之間進行轉換。快速調整大小的解決方案可能工作。

我試過使用一個WriteableBitmap來渲染圖像,但我發現這種方法迫使我重新發明輪子,當涉及到拖放和其他事情我希望用戶能夠處理圖像。

+0

所以......你需要一個有效的解決方案,但是你不想使用提高效率的方法,即在較低的層次上處理圖像?爲什麼不?我不知道Silverlight,希望你找到一個解決方案,但有時你實際上不得不捲起袖子做一些工作。 – 2010-03-15 23:58:53

+0

問題只在於內存效率。我不需要快速渲染或快速修改圖像數據本身 - 我只需要使用不超過內存中的實際JPEG數據來表示它,並在稍後將它合併到PDF中。我使用的PDF框架需要我輸入JPEG數據流,但我沒有看到將BitmapImage轉換爲JPEG流的好方法。 – 2010-03-16 00:14:43

+1

您可以包含一些關於程序如何工作的代碼,以及圖像的一般大小是什麼?您一次顯示多少個? – 2010-04-06 14:31:08

回答

6

我會嘗試的是在加載下一個流之前將每個流加載並將其大小調整爲縮略圖(例如,640x480)。然後讓用戶使用較小的圖像。一旦準備好生成PDF,請一次從原始流中重新加載JPEG,然後在加載下一個位圖之前處理每個位圖。

+0

這會將您的4.5兆字節圖像變成〜.9兆字節的圖像。你可以通過16位顏色將它降低到0.6兆字節。現在你的150張圖片大約需要60兆字節。還有很多,但更合理。再次,只要你使用原始圖像進行最終渲染,你會沒事的。 – 2010-04-06 14:36:03

+0

我已經試過這樣做了,它真的讓處理能力陷入沉寂。 我認爲Silverlight在某種程度上已經在做這件事情,當它呈現圖片時。難以強制bitmapimages拋出資源,同時將最終渲染圖像保存在內存中嗎? – 2010-04-07 08:22:56

+0

至少,WPF將這作爲合成過程的一部分。縮放因此由圖形硬件實時完成。我懷疑silverlight會做類似的事情。在這種情況下,答案是否定的,它不是已經這樣做了,至少不是以您可以訪問的方式。 – 2010-04-12 00:33:50

1

可能發生在你身上的是一個關於垃圾收集的小知名事實,這也讓我感覺良好。如果一個對象足夠大(我不記得該行的確切位置),垃圾收集將決定即使當前沒有作用域中的任何內容都與該對象相關聯(在您和我的對象中都是圖像),它會保留圖像在內存中,因爲它已經決定,如果你再次想要這個圖像,保留它而不是刪除它並稍後重新加載會更便宜。

+0

是的,我在探聽答案時發現了這個問題。 現在還沒有解決方法,或者是什麼? – 2010-04-07 08:20:17

+0

System.GC.Collect()和System.GC.WaitForPendingFinalizers()是我似乎是如何幫助它的,但可能有更好的方法。 – Alex 2010-04-07 12:22:56

1

這不是一個完整的解決方案,但是如果要在位圖和JPEG之間轉換(反之亦然),則需要查看FJCore image library。它使用起來相當簡單,並允許您執行重新調整JPEG圖像或將它們移動到不同質量的操作。如果你使用Silverlight進行客戶端圖像處理,這個庫可能不夠用,但這當然是必要的。

您還應該瞭解如何將圖像呈現給用戶。如果您正在使用Silverlight進行拼貼,估計您將無法使用虛擬化控件,因爲用戶將一次處理150張圖片。但正如其他人所說的,您還應該確保您不會呈現基於全尺寸JPEG文件的位圖。 1MB壓縮的JPEG可能會擴展到10MB的位圖,這可能是您的許多麻煩來自的地方。確保您以更小(低質量和調整大小)的JPEG文件爲基礎向用戶呈現圖像。

+0

感謝您的回答,我已經偶然發現了FJCore - 存在大量問題,例如,與通過BitmapImage加載它們時相比,解碼時JPEG實際上會變得更大。 上面討論了答案的底部。 – 2010-04-07 08:24:26

3

我猜你正在做的事情liek這樣的:

Bitmap bitmap = new Bitmap (filename of jpeg); 

,然後做:

OnPaint (...) 
{ 
    Graphics g = ....; 
    g.DrawImage (bitmap, ...); 
} 

這將是調整的巨大JPEG圖像上每一次屏幕上顯示的尺寸你畫它。我猜你的JPEG大小約爲2500x2000像素。當您將JPEG加載到位圖中時,位圖加載代碼解壓縮數據並將其存儲爲可容易呈現的格式(即以與顯示器相同的像素格式)的RGB數據或作爲被稱爲設備獨立位圖(又名DIBitmap)。這些位圖需要比壓縮的JPEG存儲更多的RAM。

你目前的實現已經在做格式轉換和調整大小,但是以一種不合理的方式進行,即每次渲染時調整一個巨大的圖像到屏幕大小。

理想情況下,您想要加載圖像並將其縮小。 .Net有一個系統來執行此操作:

Bitmap bitmap = new Bitmap (filename of JPEG); 
Bitmap thumbnail = bitmap.GetThumbnailImage (width, height, ....); 
bitmap.Dispose(); // this releases all the unmanged resources and makes the bitmap unusable - you may have been missing this step 
bitmap = null; // let the GC know the object is no longer needed 

其中寬度和高度是所需縮略圖的大小。現在,這可能會產生看起來不夠好的圖像(但它會使用任何嵌入的縮略圖數據(如果存在的話會更快),在這種情況下,請執行位圖 - >位圖調整大小。

當您創建PDF文件時,您需要重新加載JPEG數據,但從用戶的角度來看,沒關係。我相信,只要您有一些反饋意見讓用戶知道正在處理數據,用戶不會介意等一會兒將數據導出爲PDF。您也可以在後臺線程中執行此操作,並讓用戶在另一個拼貼畫上工作。

+1

你是對的,但是在Silverlight中,我使用了派生自這些類的類。我需要使用BitmapImage,因爲沒有其他的等價物。 這意味着我沒有直接控制格式轉換,並且我沒有任何方法從jpeg獲取縮略圖。 所以我唯一的選擇是從原始圖像製作一個bitmapimage,並使用它來創建縮略圖 - 然而,然後我遇到了上面Alex指出的問題。 謝謝你的回覆。 – 2010-04-07 10:11:28

+0

@Sheeo:我認爲Image.Dispose將解決Alex提出的問題,因爲您告訴系統您不再需要這些資源 - 文檔聲明Dispose方法釋放所有無法使用的資源(並且大部分資源將不受管理 - DIBitmap) – Skizz 2010-04-07 10:21:40

0

終於爲我工作用WriteableBitmapEX做以下解決方案:

當然如果圖像是不是已經足夠小,存儲在內存中,我只用縮略圖。

gotch'a我有一個事實,即WriteableBitmap沒有無參數的構造函數,但初始化爲0,0作爲大小,然後加載源自動設置這些。這對我來說並不自然。

感謝大家的幫助!

private WriteableBitmap getThumbnailFromBitmapStream(Stream bitmapStream, PhotoFrame photoFrame) 
    { 
     WriteableBitmap inputBitmap = new WriteableBitmap(0,0); 
     inputBitmap.SetSource(bitmapStream); 

     Size thumbnailSize = getThumbnailSizeFromWriteableBitmap(inputBitmap, photoFrame.size); 

     WriteableBitmap thumbnail = new WriteableBitmap(0,0); 
     thumbnail = inputBitmap.Resize((int)thumbnailSize.Width, (int)thumbnailSize.Height, WriteableBitmapExtensions.Interpolation.NearestNeighbor); 

     return thumbnail; 
    } 
0

一個額外的變種,以減少RAM使用: 不要加載圖像,此時AR無形的,而用戶滾動頁面加載它們。此方法由網頁開發人員使用,以提高網頁加載速度。對你來說,它不會在RAM中存儲圖像的孔數量。

我認爲最好的方法是不要在運行時製作縮略圖,但將它們存儲在全尺寸圖片附近並且只爲它們獲取鏈接。當它需要時,你一直可以獲得全尺寸圖片的鏈接並加載它。

相關問題