3

通常のRGBカラーのPDFのセットがあります。ファイルサイズを小さくするために8ビットに変換することでメリットが得られます。PDFにラスター以外の要素を保持しながらこれを実行できるAPIまたはツールはありますか?

4

1 に答える 1

3

これは楽しいものです。PDFラスタライザーとdotPdfを備えたAtalasoftdotImageはこれを行うことができます(免責事項:私は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はすべての画像をドキュメント内のリソースとして管理し、それらのリソースを完全に置き換えることができます。そのため、作業を楽にするために、AtalaImageオブジェクトを処理するImageリソースコレクションにImageCompressorを追加し、既存の画像リソースを削除して新しいものに置き換えます。

今度は、ベンダーが自社製品について話すときにおそらく見られないようなことをします。私は、さまざまなレベルでそれを批判します。まず、それは超安くはありません。ごめん。価格を見るとステッカーショックを受けるかもしれませんが、価格には正直誰にも負けないスタッフからの技術サポートが含まれています。

これは、iTextPdf Sharp、BitMiracleのDocoticPDFライブラリ、またはTallComponentsPDFライブラリを使用して行うことができます。後者の2つもお金がかかります。ビットミラクルのエンジニアは非常に役立つことが証明されており、ここで彼らに会う可能性があります(HI!)。多分彼らもあなたを助けることができます。iTextPdfSharpは、正しいことを行うためにPDF仕様を本当に理解する必要があるという点で問題があります。そうしないと、ガベージPDFが出力される可能性があります。この実験を自分のライブラリとiTextPdfSharpと並べて行ったところ、修正するためにPDF仕様の深い知識を必要とする一般的なタスクの問題点。私は、PDFの仕様を知る必要がなく、悪いPDFの作成について心配する必要もないように、高レベルのツールで決定を下そうとしました。

私たちのコードベースには、似たようなことをする明らかに異なるツールがいくつかあるという事実は特に好きではありません。PageCollectionは、歴史的な理由からPDFラスタライザーの一部です。PdfDocumentは、ページを操作するためだけに作成されており、軽量でメモリを節約しようとします。PdfGeneratedDocumentは、ページコンテンツを操作/作成するために作成されています。PdfDecoderは、既存のPDFからラスター画像を生成するためのものです。PdfEncoderは、画像から画像のみのPDFを生成するためのものです。これらすべての明らかに重複するニッチツールを使用するのは困難な場合がありますが、それらには論理があり、相互の関係もあります。

于 2013-01-14T19:11:52.540 に答える