2013-01-14 19 views
3

我有一組正常RGB顏色的PDF。他們將從轉換到8位以減少文件大小中受益。是否有任何API或工具允許我在保留PDF中的非柵格元素的同時執行此操作?將PDF圖像實際轉換爲8位

回答

2

這是一個有趣的。使用PDF Rasterizer和dotPdf的Atalasoft dotImage可以做到這一點(免責聲明:我爲Atalasoft工作並編寫了大部分PDF工具)。我想通過發現候選第一頁開始:

List<int> GetCandidatePages(Stream pdf, string password) 
{ 
    List<int> retVal = new List<int>(); 
    using (PageCollection pages = new PageCollection(pdf, password)) { 
     for (int i=0; i < pages.Count; i++) { 
      if (pages[i].SingleImageOnly()) 
       retVal.Add(i); 
     } 
    } 
    pdf.Seek(0, SeekOrigin.Begin); // restore file pointer 
    return retVal; 
} 

接下來,我柵格化只是那些頁面,把它們變成8位圖像,但讓事情變得高效,我會使用它管理的的ImageSource內存得好:

public class SelectPageImageSource : RandomAccessImageSource { 
    private List<int> _pages; 
    private Stream _stm; 

    public SelectPageImageSource(Stream stm, List<int> pages) 
    { 
     _stm = stm; 
     _pages = pages; 
    } 

    protected override ImageSourceNode LowLevelAcquire(int index) 
    { 
     PdfDecoder decoder = new PdfDecoder(); 
     _stm.Seek(0, SeekOrigin.Begin); 
     AtalaImage image = PdfDecoder.Read(_stm, _pages[index], null); 
     // change to 8 bit 
     if (image.PixelFormat != PixelFormat.Pixel8bppIndexed) { 
      AtalaImage changed = image.GetChangedPixelFormat(PixelFormat.Pixel8bppIndexed); 
      image.Dispose(); 
      image = changed; 
     } 
     return new FileReloader(image, new PngEncoder()); 
    } 
    protected override int LowLevelTotalImages() { return _pages.Count; } 

} 

接下來,你需要從這個創建一個新的PDF:

public void Make8BitImagePdf(Stream pdf, Stream outPdf, List<int> pages) 
{ 
    PdfEncoder encoder = new PdfEncoder(); 
    SelectPageImageSource source = new SelectPageImageSource(pdf, pages); 
    encoder.Save(outPdf, source, null); 
} 

接下來,你需要用新的替換原來的網頁:

public void ReplaceOriginalPages(Stream pdf, Stream image8Bit, Stream outPdf, List<int> pages) 
{ 
    PdfDocument docOrig = new PdfDocument(pdf); 
    PdfDocument doc8Bit = new PdfDocument(image8Bit); 
    for (int i=0; i < pages.Count; i++) { 
     docOrig.Pages[pages[i]] = doc8Bit[i]; 
    } 
    docOrig.Save(outPdf); // this is your final 
} 

這將做你想要的,或多或少。不太理想的是,圖像頁面已被光柵化,這可能不是你想要的。好的是,通過光柵化,生成輸出很容易,但它可能不是原始圖像的分辨率。這可以完成,但它需要更多的工作,因爲您需要從SingleImageOnly頁面提取圖像,然後更改它們的像素格式。這個問題是SingleImageOnly並不意味着圖像適合整個頁面,也不意味着圖像被放置在任何特定的位置。除了PixelFormat更改(實際上是在更改之前)之外,還需要將用於將圖像放在頁面上的矩陣應用到圖像本身,並使用帶有適當邊距和原始頁面大小的PdfEncoder以獲得應該在哪裏的形象。這是全部切割和乾燥,但它是一個相當數量的代碼。

還有另一種方法可能也可以使用我們的PDF生成API。它涉及到打開文檔並將文檔的圖像資源替換爲8位圖像資源。這也是可行的,但並非完全無關緊要。你會做這樣的事情:

public void ReplaceImageResources(Stream pdf, Stream outPdf, List<int> pages) 
{ 
    PdfGeneratedDocument doc = new PdfGeneratedDocument(pdf); 
    doc.Resources.Images.Compressors.Insert(0, new AtalaImageCompressor()); 

    foreach (int page in pages) { 
     // GetSinglePageImage uses PageCollection, as above, to 
     // pull a single image from the page (no need to use the matrix) 
     // then converts it to 8 bpp indexed and returns it or null if it 
     // is already 8 bpp indexed (or 4bpp or 1bpp). 
     using (AtalaImage image = GetSinglePageImage(pdf, page)) { 
      if (image == null) continue; 
      foreach (string resName in doc.Pages[page].ImportedImages) { 
       doc.Resources.Images.Remove(resName); 
       doc.Resources.Images.Add(resName, image); 
       break; 
      } 
     } 
    } 
    doc.Save(outPdf); 
} 

正如我所說的,這是有難度的 - 生成PDF套件是從全棉布製作新的PDF文件或添加新的頁面到現有的PDF(將來做,我們要添加完整編輯)。但PDF在文檔中管理其所有圖像爲資源,我們有能力完全替換這些資源。爲了使生活更輕鬆,我們將ImageCompressor添加到處理AtalaImage對象的Image資源集合中,並刪除現有的圖像資源並將其替換爲新的。

現在我要做一些你可能不會看到任何供應商在談論他們自己的產品時做的事情 - 我會在很多層面上批評它。首先,它不是很便宜。抱歉。當您看到價格時,您可能會感到不安,但價格包含誠實無瑕的員工的技術支持。

您可以使用iTextPdf Sharp或Bit Miracle的Docotic PDF庫或高級組件PDF庫做很多工作。後兩者也花錢。 Bit Miracle的工程師已被證明是非常有用的,你很可能會在這裏看到他們(你好!)。也許他們也可以幫助你。iTextPdfSharp存在問題,因爲您確實需要理解PDF規範才能做正確的事情,否則您可能會輸出垃圾PDF - 我已經使用iTextPdfSharp並行處理了自己的庫,並發現了一些要求深入瞭解要修復的PDF規範的常見任務的痛點。我試圖在我的高級工具中做出決定,以至於您不需要知道PDF規範,也不需要擔心創建不好的PDF。

我不特別喜歡這樣的事實,即我們的代碼庫中有幾個顯然不同的工具可以做類似的事情。由於歷史原因,PageCollection是我們的PDF光柵化器的一部分。 PdfDocument嚴格用於處理頁面,並嘗試使用內存輕量級和小氣。 PdfGeneratedDocument用於操作/創建頁面內容。 PdfDecoder用於從現有PDF生成光柵圖像。 PdfEncoder用於從圖像生成僅限圖像的PDF。讓所有這些看起來重疊的利基工具都可能令人望而生畏,但是對於他們以及他們彼此的關係來說,這是一種邏輯。