[]
ドキュメントを最適化することで、ドキュメントのサイズを大幅に縮小し、ロード、読み込み、共有を高速化することができます。DioDocs for Pdf では、PDF 文書の品質や完全性を損なうことなく、さまざまなオプションで最適化することができます。ドキュメントの最適化オプションの詳細については、以下のセクションを参照してください。
DioDocs for Pdf では、GcPdfDocument クラスのRemoveDuplicateImages メソッドを使用することで、ドキュメントのサイズを効率的に縮小できます。このメソッドは、ドキュメント内にある同一画像の重複インスタンスを排除し、1つのインスタンスのみを複数の場所で保持します。これにより、ドキュメントのサイズが縮小されます。
次のサンプルコードは、RemoveDuplicateImages メソッドを使用してドキュメントのファイルサイズを最適化する方法を示します。
// 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メソッドの動作を制御することができます.
MergeSubsets: 同じフォントのサブセットを単一のサブセットにマージするかどうかを示します。デフォルトは true です。
RemoveUnusedGlyphs: 未使用のグリフをフォントから削除するかどうかを示す。デフォルトは true です。
フォント最適化の方法については、次のサンプルコードを参照してください。
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;
} DioDocs for PDFはTrueTypeフォントのみをサポートしています
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以下)。
エンコーディング形式を設定する方法については、以下のサンプルコードを参照してください。
// フォントファイルをロードします
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 列挙型を用いて、文書が保存されるときに既存の PDF ストリームがどのように扱われるかを設定します。 PdfStreamHandling 列挙型の定義は、以下の通りです。
| |
SaveMode 列挙型を用いて、PDFの保存モードを設定します。 SaveMode 列挙型の定義は、以下の通りです。
| |
UseObjectStreams 列挙型を用いて、PDFを保存するときにオブジェクトストリームを使うかどうかを設定します。 UseObjectStreams 列挙型の定義は、以下の通りです。
|
複数のオブジェクトストリームを使用して、PDFのドキュメントサイズを抑制する方法については、以下のサンプルコードを参照してください。
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"です。
Copy" オプションは、ドキュメント内の既存の PDFストリームをそのまま保存します。
"UseCompressionLevel "オプションは、 PDF のサイズが減少することを保証するものではありません。
これは、元のストリームが DioDocs for PDF よりも高い圧縮率で圧縮されている可能性があるためです。
"MinimizeSize"オプションは、基本的に出力される PDF のサイズが増加することはなく、多くの場合でサイズが小さくなることを保証します。
DioDocs for PDF は、既存の各ストリームを(すでに圧縮されている場合は一度解凍し、)GcPdfDocumentクラスの CompressionLevelプロパティを使用して再圧縮します。
その上で、圧縮後のデータサイズと元のサイズを比較し、圧縮後の方が小さい場合にのみ、その圧縮結果を使用します。(元の方が小さい場合は、元のストリームをそのまま使用します。)
このオプションを使用することで、最小サイズの PDF を出力できますが、その分、ドキュメントの保存にかかる時間は長くなります。
制限事項
DioDocs for PDF では、以下の場合、オブジェクトストリームを使用してドキュメントを保存することはできません。
ドキュメントをリニアライズして保存している場合。
ドキュメントを StartDoc / EndDoc メソッドを使用して生成している場合。
ドキュメントを増分更新モードで保存していて、相互参照インデックスとしてテーブルを使用している場合。これはPDF仕様自体の制限によるものです。
このト ピックのサンプルコードは、Util.cs と い う ヘルパークラスを使っ て PDF ドキュメントを更新しています。実際の動作をローカルで確認したい場合には、オンラインデモからプロジェクトをダウンロードしてください。
DioDocs for PDF は、ファイルサイズ最適化機能をまとめて設定できる Optimize メソッドを提供しています。このメソッドにより、PDF ドキュメントへの最適化機能の適用から保存までが1回の呼び出しで行えます。第1引数には、最適化の結果を出力するPDFのストリーム、またはファイルパスを渡します。第2引数には、OptimizeDocumentOptionsクラスを指定します。このクラスのメンバを利用すると、最適化機能の制御ができます。
メモ: 一部のオプションはドキュメントの保存方法に影響するため、保存操作が必要です。
OptimizeDocumentOptionsクラスのメンバは以下の通りです。
これらは Optimize メソッドで使用可能な最適化処理を表します。
オプション | 説明 |
|---|---|
CompressionLevel | 圧縮レベルを取得または設定します。 |
DiscardEmbeddedFiles | 埋め込みファイル、EmbeddedFiles をドキュメントから削除するかどうかを示す値を取得または設定します。 |
DiscardEmbeddedPageThumbnails | 埋め込みページ サムネイルをドキュメントから削除するかどうかを示す値を取得または設定します。 |
DiscardJavaScriptActions | ActionJavaScript をドキュメントから削除するかどうかを示す値を取得または設定します。 |
DiscardOutlines | アウトラインをドキュメントから削除するかどうかを示す値を取得または設定します。 |
DiscardSubmitImportResetActions | ActionSubmitForm、ActionImportData、および ActionResetForm 型のアクションをドキュメントから削除するかどうかを示す値を取得または設定します。 |
OptimizeFontsOptions | ドキュメント内のフォントを最適化するために使用するオプションを取得または設定します。 |
PdfStreamHandling | ドキュメントの保存時に既存の PDF ストリームをどのように処理するかを制御する値を取得または設定します。 |
RemoveDuplicateImages | 同じ内容の画像をドキュメントから削除するかどうかを示す値を取得または設定します。 |
RemoveEmbeddedFonts | 埋め込みフォントをドキュメントから削除するかどうかを示す値を取得または設定します。 |
UseObjectStreams | PDF の保存時にオブジェクト ストリームを使用するかどうかを示す値を取得または設定します。 |
メモ:OptimizeDocumentOptionsクラスには、すべての最適化を最大限に行うSetForMinimumSizeメソッドも用意されています。ただし、このメソッドを使用する際は注意が必要です。推奨されないデータ、例えば埋め込みフォントなどが削除される可能性があるためです。
Optimizeメソッドを使用してドキュメントを最適化する方法については、以下のサンプルコードを参照してください。
//最適化前のPDFのストリームを取得します。
var doc = new GcPdfDocument();
using var fs = new FileStream(@"..\..\..\doc.pdf", FileMode.Open);
doc.Load(fs);
//OptimizeDocumentOptionsクラス。
OptimizeDocumentOptions options = new OptimizeDocumentOptions();
//アウトラインを削除するDiscardOutlinesをtrueにします。
options.DiscardOutlines = true;
//Optimizeメソッドで、最適化処理の実装し、PDFを保存します。
doc.Optimize("optimized.pdf", options);