跳到主要內容

GDI+處理Tiff

鳥毅公司的文件管理系統採用tiff檔案,由於某案子需要把某些檔案裏的幾篇抽出來轉成pdf,想一想用GDI+和.Net寫比較簡單。

先參考A simple TIFF management class,用他的TiffManager在JoinTiffImages這個method結合tiff檔時出現 "無效參數" (或Invalid Parameter )的錯誤訊息,是在 Image.SaveAdd 裏的 EncoderParameters 出錯。

查MSDN討論區有人問但都沒有解,最後查到Save images into a multi-page TIFF file or add images to an existing TIFF file,這位bijulsoni老大說:
The most probable reason for this error is that the image on which you are trying to apply CCITT4 compression is not a bi-tonal image. The CCITT4 compression is applicable to bi-tonal images only. So I have given code for converting an image to a bi-tonal image. The code given in the sample application uses .NET GDI+ classes for storing images.
用人話說:Tiff的CCITT4 壓縮只能用在雙色影像檔(就是黑白啦),所以必須用bijulsoni寫的method轉成雙色。由於鳥毅還得做浮水印,所以只好用LZW壓成灰階(大約3~5倍大)

另外在轉檔的過程中,遇到記憶體不足。是因為Image物件的記憶體不會自動釋放,原因我不知 :P 我在不使用物件後加上 Bitmap.Dispose()就搞定。
所以TiffManager裏JoinTiffImages有些小地方要改:

 public void JoinTiffImages (string[] imageFiles, string outFile, EncoderValue compressEncoder)
 {
  //If only one page in the collection, copy it directly to the target file.
  if (imageFiles.Length == 1) {
   File.Copy (imageFiles [0], outFile, true);
   return;
  }
  //use the save encoder
  Encoder enc = Encoder.SaveFlag;
  EncoderParameters ep = new EncoderParameters (2);
  ep.Param [0] = new EncoderParameter (enc, (long)EncoderValue.MultiFrame);
  ep.Param [1] = new EncoderParameter (Encoder.Compression, (long)compressEncoder);

  Bitmap bitmaps = null;
  int frame = 0;
  ImageCodecInfo info = GetEncoderInfo ("image/tiff");

  foreach (string strImageFile in imageFiles) {
   if (frame == 0) {
    bitmaps = (Bitmap)Image.FromFile (strImageFile);
    bitmaps.Save (outFile, info, ep);
   } else {
    //save the intermediate frames
    ep.Param [0] = new EncoderParameter (enc, (long)EncoderValue.FrameDimensionPage);

    Bitmap bm = (Bitmap)Image.FromFile (strImageFile);
    bitmaps.SaveAdd (bm, ep);
    bm.Dispose ();
   }
   if (frame == imageFiles.Length - 1) {
    //flush and close.
    ep.Param [0] = new EncoderParameter (enc, (long)EncoderValue.Flush);
    bitmaps.SaveAdd (ep);
   }
   frame++;
  }
  bitmaps.Dispose ();
  return;
 }
浮水印是參下以下兩篇:
Creating a Watermarked Photograph with GDI+ for .NET
Watermark Maker Source: Watermark Project
不過我最後用ImageMagick效果比較好,檔案也小一點。原來TiffManager拆圖存成tiff格式太大,後來我改用png格式儲存比jpeg還小,執行速度也快,供各位參考。

Tiff轉PDF不用考慮,還是ImageMagick,還會把檔案壓小一點,只要一行指令搞定
convert xx.tif xx.pdf
結論:
GDI+雖然方便,但陷阱不少,使用時要小心。另一點是GDI+效率不高,中小企業內部用還不錯,若放在online高流量web或是寫影像處理軟體,還是用3rd party的API 吧!

後記:
本來要把意見貼到Code Project原篇,結果出現以下錯誤:(asp... 唉)

留言

匿名表示…
為了這問題找了好久..看到您的文章,終於解決了~太感謝了^^

這個網誌中的熱門文章

DBeaver 介面語言

DBeaver是我個人頗常用的一套跨平台Database管理工具,最近升級後發現Windows版本居然變成簡體中文,而且無法切換為英文。

自然人憑證讀卡機驅動程式

鳥毅用的是第一代的自然人憑證讀卡機,EZ100PU(後來有同事買EZmini可以讀SIM卡似乎更好),每年報稅時用一次。 本來只是要申請些政府業務,一時之間找不到光碟,沒想到在 驅動程式下載 居然看到Linux和Mac的驅動程式,剩下的就是政府單位的網頁和程式應該改版了吧!!!

如何將較高版本SQL Server複製到低版本SQL Server (降級為舊版)並保留權限及資料庫圖表

一般若是要將SQL Server裡的Database轉往其他Server時,最簡單的方式就是備份(Backup)後再還原(Restore),或者是䣃離(detach)後附加(attach)。 但是很不幸地,若是由較低版本(e.g. 2008)到較高版本(e.g. 2012)要怎麼辦呢?