DioDocs for PDF
最適化
機能 > 最適化

ドキュメントを最適化することで、ドキュメントのサイズを大幅に縮小し、ロード、読み込み、共有を高速化することができます。DioDocs for Pdf では、PDF 文書の品質や完全性を損なうことなく、さまざまなオプションで最適化することができます。ドキュメントの最適化オプションの詳細については、以下のセクションを参照してください。

重複イメージの削除

DioDocs for Pdf では、GcPdfDocument クラスのRemoveDuplicateImages メソッドを使用することで、ドキュメントのサイズを効率的に縮小できます。このメソッドは、ドキュメント内にある同一画像の重複インスタンスを排除し、1つのインスタンスのみを複数の場所で保持します。これにより、ドキュメントのサイズが縮小されます。

次のサンプルコードは、RemoveDuplicateImages メソッドを使用してドキュメントのファイルサイズを最適化する方法を示します。

C#
コードのコピー
// GcPDFDocumentを初期化します
GcPdfDocument doc = new GcPdfDocument();

// ファイル ストリームで PDF ドキュメントを開きます
FileStream fs = File.OpenRead("Invoice.pdf");

// ドキュメントをロードします
doc.Load(fs);

// 重複画像を削除します
doc.RemoveDuplicateImages();

// PDF ドキュメントを保存します
doc.Save("RemovedDuplicateImages.pdf");
メモ: 結合された PDF ドキュメントのファイルサイズを最適化することもできます。詳細については、 「結合されたドキュメントから重複画像を削除する」を参照してください。

フォントに関する最適化

フォントの最適化

DioDocs for PDFでは、 GcPdfDocumentクラスのOptimizeFonts メソッドを使用することで、同じフォントのサブセットをマージしたり、重複フォントや未使用フォントを削除するなどのフォントに関する最適化ができます。また、OptimizeFontsOptions クラスで提供される以下のプロパティを使用することで、OptimizeFontsメソッドの動作を制御することができます.

フォント最適化の方法については、次のサンプルコードを参照してください。

C#
コードのコピー
static void Main(string[] args)
{
    // 最適化されていないPDFファイルを生成します
    var tmpInput = MakeInputFile("CompleteJavaScriptBook.pdf");
    var fiInput = new FileInfo(tmpInput);

    // 生成したPDFを最適化します
    var tmpOutput = Path.GetTempFileName();
    var tmpDoc = new GcPdfDocument();
    using (var fs = File.OpenRead(tmpInput))
    {
        tmpDoc.Load(fs);

        // PDFを保存する時、GcPdfDocumentクラスの CompressionLevel のデフォルト値は"Fastest"です
        // CompressionLevelプロパティを"Optimal"に設定して、PDFのサイズを小さくします。
        tmpDoc.CompressionLevel = CompressionLevel.Optimal;

        // フォント情報を最適化します
        tmpDoc.OptimizeFonts();
        tmpDoc.Save(tmpOutput);
    }
    var fiOutput = new FileInfo(tmpOutput);

    // 元ファイルと生成されたファイルのファイルサイズ情報を、生成されたドキュメントに追記します
    var doc = new GcPdfDocument();
    Common.Util.AddNote(String.Format(
        "GcPdfDocumentクラスの OptimizeFontsメソッドを使用することで、重複するフォントデータをマージし、未使用のフォントデータを削除します。" +
        "その結果、5ページのPDFのサイズを{0:N0}から{1:N0}バイトに縮小しました。", fiInput.Length, fiOutput.Length),
        doc.NewPage());
    doc.Save("OptimizeFonts.Pdf");

    // 一時ファイルを削除します
    File.Delete(tmpInput);
    File.Delete(tmpOutput);
}

// 元ファイル(最適化されていないファイル)の生成
static string MakeInputFile(string inFn)
{
    // GcPdfDocumentクラスのインスタンスを生成します
    var indoc = new GcPdfDocument();

    // PDFドキュメント(元ファイル)をロードします
    using var fs = File.OpenRead(inFn);
    indoc.Load(fs);

    // 元ファイルの先頭5ページから1ページずつの5つのドキュメントを生成します
    var pageCount = 5;
    var docs = new List<GcPdfDocument>(pageCount);
    for (int i = 0; i < pageCount; ++i)
    {
        var outdoc = new GcPdfDocument();
        outdoc.MergeWithDocument(indoc, new MergeDocumentOptions() { PagesRange = new OutputRange(i + 1, i + 1) });
        docs.Add(outdoc);
    }

    // 生成した5つのドキュメントを1つに結合する
    var doc = new GcPdfDocument();
    foreach (var d in docs)
        doc.MergeWithDocument(d);

    // 生成されたPDFを一時ファイルとして保存します
    var outFn = Path.GetTempFileName();
    doc.Save(outFn);
    return outFn;
}
Note: DsPdf only supports TrueType fonts.

フォントフォーマットの最適化

PDFドキュメントは、フォントのエンコーディング方法によって、サイズを小さくすることが可能です。

DioDocs for PDFでは、GcPdfDocument および FontHandler クラスのPdfFontFormat  プロパティを使用することで、PDF ドキュメント内のフォントのエンコーディング形式を設定できます。このプロパティは PdfFontFormat 列挙型で設定します。

PdfFontFormat 列挙型で定義されているエンコーディング形式は、以下の通りです。

形式 説明
Type0AutoOneByteEncoding フォントを、1個ない し複数の Type0 PDF フ ォ ン トとして保存 します。(デフォルト)
Type0IdentityEncoding フォントを、各キャラクタが2バイトでエンコードされた、Identity エンコーディングの単一の Type0 フォントとして保存します。

デフォルトでは Type0AutoOneByteEncoding (1バイトエンコーディング形式)が使用され、この場合、Type0IdentityEncoding(Identityエンコーディング形式)を使用する場合よりも小さなPDFコンテンツを生成します。ただし、Type0AutoOneByteEncoding を使用するフォントでレンダリングされるテキストの量が少ない場合(目安:1000シンボル未満)、Type0IdentityEncoding を使用する場合より、結果として得られるPDFコンテンツのサイズが大きくなる場合があります。これは、Type0AutoOneByteEncoding を使用する場合、エンコーディングに関する追加情報が必要となるためです。必要なサイズは、テキストで使用される一意な文字の数に応じて 変わります(通常l1KB以下)。

エンコーディング形式を設定する方法については、以下のサンプルコードを参照してください。

C#
コードのコピー
// フォントファイルをロードします
var gabriola = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "Gabriola.ttf"));
if (gabriola == null)
    throw new Exception("Could not load font Gabriola");

// GcPdfDocumentのインスタンスを生成します
var doc = new GcPdfDocument();
var g = doc.NewPage().Graphics;

// PDFフォントフォーマットを"Type0IdentityEncoding"に設定します
doc.PdfFontFormat = PdfFontFormat.Type0IdentityEncoding;

// ロードしたフォントを使用して、文字を描画します
var tf = new TextFormat() { Font = gabriola, FontSize = 16 };
g.DrawString($"Sample text drawn with font {gabriola.FontFamilyName}.", tf, new PointF(72, 72));
            
// フォントサイズを変更します
tf.FontSize += 4;
            
// 文字を描画します
g.DrawString("The quick brown fox jumps over the lazy dog.", tf, new PointF(72, 72 * 2));

// 非太字フォントで太字スタイルをエミュレートします
tf.FontStyle = GCTEXT.FontStyle.Bold;

// 文字列を描画します
g.DrawString("This line prints with the same font, using emulated bold style.", tf, new PointF(72, 72 * 3));

// 太字の斜体フォントをロードし、TextFormatインスタンスに適用します
var timesbi = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "timesbi.ttf"));
tf.Font = timesbi ?? throw new Exception("Could not load font timesbi");
tf.FontStyle = GCTEXT.FontStyle.Regular;

// 文字を描画します
g.DrawString($"This line prints with {timesbi.FullFontName}.", tf, new PointF(72, 72 * 4));
            
// PDFドキュメントを保存します
doc.Save("OptimizeFontFormat.pdf");
メモ: ドキュメントにテキストを追加する前に PdfFontFormat プロパティを設定しないと例外が発生する場合があります。この例外は、ドキュメント内にフォントが埋め込まれていないにもかかわらず、フォントが埋め込みモードに設定されている場合です。
メモ: PdfFontFormat プロパティは、PDF標準フォントには影響しません。PDF仕様上、これらのフォントは PDF Type 1フォントとして保存されなければいけないためです。

制限事項

DioDocs for PDFでは、フォントが埋め込まれていない場合、ユーザーの選択に関係なくType0IdentityEncodingを使用します。

オブジェクトストリームによる最適化

DioDocs for Pdf では、SavePdfOptions クラスの UseObjectStreams プロパティを使用することで、PDF文書を保存する際にオブジェクトストリームを使用することができます。このプロパティは、UseObjectStreams 列挙型を使用して、オブジェクトストリームを使用するかどうかを指定、使用する場合は、適用するオブジェクトストリームのタイプを決定します。

オブジェクトストリームは、間接オブジェクトのシーケンスを、ファイルの一番外側のレベルに格納するのではなく、CompressionLevel プロパティを使用してよりコンパクトに格納できるストリームオブジェクトです。オブジェクトストリームはPDF文書のサイズを大幅に縮小します。

SavePdfOptions クラスは、PDFドキュメントを保存する際の設定内容を実装しやすくするものであり、Save メソッドや Sign メソッド、TimeStamp メソッドなどで使用することができます。SavePdfOptionsクラスでは以下のようなプロパティを提供します。

プロパティ 説明
PdfStreamHandling

PdfStreamHandling 列挙型を用いて、文書が保存されるときに既存の PDF ストリームがどのように扱われるかを設定します。

PdfStreamHandling 列挙型の定義は、以下の通りです。

  • Copy: 元のストリームの内容を変更せずにそのまま出力します。(デフォルト)
  • UseCompressionLevel: 既存のPDFストリームを解凍し、CompressionLevelプロパティの値にあわせて再圧縮します。
  • MinimizeSize: 既存のストリームをそのままコピーするか、再圧縮して、可能な限り小さなサイズにします。
Mode

SaveMode 列挙型を用いて、PDFの保存モードを設定します。

SaveMode 列挙型の定義は、以下の通りです。

  • Default: このモードでは、リニアライズも増分更新も行いません。
  • Linearized: ドキュメントをリニアライズ(Webに最適化)して保存します。
  • IncrementalUpdate: ドキュメントを増分更新モードで保存します。
UseObjectStreams

UseObjectStreams 列挙型を用いて、PDFを保存するときにオブジェクトストリームを使うかどうかを設定します。

UseObjectStreams 列挙型の定義は、以下の通りです。

  • None: オブジェクトストリームを使用しません。
  • Single: 文書全体に対して単一のオブジェクトストリームを使用します。このオプションは、PDFファイルサイズを大幅に削減できますが、ビューアでPDFを開くときに遅延が発生する可能性があります。
  • Multiple: 複数のオブジェクトストリームを使用します。Singleに比べてファイルサイズが若干大きくなりますが、PDFはビューアで遅延なく開きます。

複数のオブジェクトストリームを使用して、PDFのドキュメントサイズを抑制する方法については、以下のサンプルコードを参照してください。

C#
コードのコピー
static void Main(string[] args)
{
    // 最適化されていないPDFを生成します。
    var tmpInput = MakeInputFile();
    var fiInput = new FileInfo(tmpInput);

    // 生成したPDFを最適化します
    var tmpOutput = Path.GetTempFileName();
    var tmpDoc = new GcPdfDocument();
    using (var fs = File.OpenRead(tmpInput))
    {
        tmpDoc.Load(fs);

        // PDFを保存する時、GcPdfDocumentクラスの CompressionLevel のデフォルト値は"Fastest"です
        // CompressionLevelプロパティを"Optimal"に設定して、PDFのサイズを小さくします。
        tmpDoc.CompressionLevel = CompressionLevel.Optimal;

        // オブジェクトストリームを使用してストリームを最小化します。
        tmpDoc.Save(tmpOutput, new SavePdfOptions(SaveMode.Default, PdfStreamHandling.MinimizeSize, UseObjectStreams.Multiple));
    }
    var fiOutput = new FileInfo(tmpOutput);

    // 元ファイルと生成されたファイルのファイルサイズ情報を、生成されたドキュメントに追記します
    var doc = new GcPdfDocument();
    Common.Util.AddNote(String.Format(
        "PDF保存時にUseObjectStreams.Multipleオプションを使用すると、ほとんどの場合、ファイルサイズが小さくなります。" +
        "今回の場合、PDFとしての表現性もPDFを開く速度も失うことなく、{0:N0}から{1:N0}バイトに減少しました。 \n" +
        "UseObjectStreams.Singleオプションを使用すると、PDFビューアで開くのが遅くなりますが、PDFサイズはさらに小さくなります。", fiInput.Length, fiOutput.Length),
        doc.NewPage());

    // 生成結果を保存します
    doc.Save("ObjectStreams.pdf");

    // 一時ファイルを削除します
    File.Delete(tmpInput);
    File.Delete(tmpOutput);
}

// 元ファイル(最適化されていないファイル)の生成
static string MakeInputFile()
{
    // 生成するページ数:1000ページ
    const int N = Common.Util.LargeDocumentIterations;
    var start = Common.Util.TimeNow();
    var doc = new GcPdfDocument();

    // テキストフォーマットを設定します
    var tl = new TextLayout(72)
    {
        MaxWidth = doc.PageSize.Width,
        MaxHeight = doc.PageSize.Height,
        MarginAll = 72,
        FirstLineIndent = 36,
    };
    tl.DefaultFormat.Font = StandardFonts.Times;
    tl.DefaultFormat.FontSize = 12;

    // PDFドキュメントを生成します
    for (int pageIdx = 0; pageIdx < N; ++pageIdx)
    {
        tl.Append(Common.Util.LoremIpsum(1));
        tl.PerformLayout(true);
        doc.NewPage().Graphics.DrawTextLayout(tl, PointF.Empty);
        tl.Clear();
    }

    // タイトルページを挿入します
    tl.FirstLineIndent = 0;
    var fnt = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "yumin.ttf"));
    var tf0 = new TextFormat() { Font = fnt, FontSize = 24, FontBold = true };
    tl.Append(string.Format("Large Document\n{0} Pages of Lorem Ipsum\n\n", N), tf0);
    var tf1 = new TextFormat(tf0) { FontSize = 14, FontItalic = true };
    tl.Append(string.Format("Generated on {0} in {1:m\\m\\ s\\s\\ fff\\m\\s}.", Common.Util.TimeNow().ToString("R"), Common.Util.TimeNow() - start), tf1);
    tl.TextAlignment = TextAlignment.Center;
    tl.PerformLayout(true);
    doc.Pages.Insert(0).Graphics.DrawTextLayout(tl, PointF.Empty);

    // UseObjectStreams.None(デフォルト)設定で生成されたPDFドキュメントを一時ファイルとして保存します
    var outFn = Path.GetTempFileName();
    doc.Save(outFn, new SavePdfOptions(SaveMode.Default, PdfStreamHandling.Copy, UseObjectStreams.None));
    return outFn;
}

メモ: PdfStreamHandlingプロパティのデフォルト値は"Copy"です。


制限事項

DioDocs for PDF では、以下の場合、オブジェクトストリームを使用してドキュメントを保存することはできません。

メモ: このト ピックのサンプルコードは、Util.cs と い う ヘルパークラスを使っ て PDF ドキュメントを更新しています。実際の動作をローカルで確認したい場合には、オンラインデモからプロジェクトをダウンロードしてください。