iText 7 で使用するボリューム ライセンスのカウントの仕組みに関するよく寄せられる質問と回答を掲載しています。
このページの掲載内容は、開発元である Apryse 社の公開する iText 製品に関する Volume Counter FAQs ページを基にしています。本ページの記載と開発元の公開する資料の内容に不一致がある場合は、開発元の掲載が正式なものとされます。
iText 7.2 のリリースより、従来のライセンス体系が新しい Unified Licensing Mechanism に置き換えられました。これにより、従来の itext-licensekey および itext-licensekey-volume 依存関係が licensing-base および licensing-remote 依存関係に置き換わり、ライセンス ライブラリのバージョン番号が 3.x から 4.x になりました。また、XML ライセンスファイルが JSON 形式の新しいファイルに置き換わりました。
ライセンス キー ファイルが XML 形式の場合はこのページの iText 7.1.x の説明に、JSON 形式の場合は iText 7.2.x の説明を参照してください。
特に何も有効にする必要はありません。有効なボリューム ライセンス ファイルがあり、iText ライセンス キーのボリューム依存性をロードしていれば、iText が自動的に有効にします。ライセンス キー ライブラリとボリューム ライセンス キー ライブラリの両方が必要です。インストールの詳細については、ボリューム カウンターのインストール ガイドを参照してください。
iText 7.1.15 と License Key および iText License Key Volume ライブラリのバージョン 3.1.4 のリリースでは、リモート レポートがデフォルトで有効になっており、使用量のレポートがより簡単になりました。
iText がサーバーに接続できなくても、コードやプログラムに影響を受けませんのでご安心ください。インターネット接続に失敗した場合、iText は実行中に失敗したリクエストをすべてキャッシュし、次のイベントで送信を試みます。アプリケーションがシャットダウンした場合、統計情報は引き継がれません。
ボリューム カウントを動作させるには、以下のサーバーの 443 ポートへのアクセスを許可する必要があります。
kinesis.us-east-1.amazonaws.comcognito-identity.eu-central-1.amazonaws.comsdk-requests.license.itextpdf.comsdk-login.licensing.itextpdf.comsdk-health.licensing.itextpdf.comただし、情報は送信されるだけで受信されないため、アクセスは「一方通行」であることが求められます。
iText のバージョンとその実行環境、ライセンスキー、イベントの種類 (どの製品のものか)、発生した時間などの情報を収集しています。これらの情報は、iText の開発、特定の機能の使用状況の把握、Java や .NET の対象バージョンの把握に役立ちます。iText が収集する情報の詳細は、お客様のソフトウェア ライセンス契約 (SLA) をご参照ください。
ボリューム ライセンス キーは iText 5 で使用できますが、自動的に行われる仕組みは使えません。統計情報を記録するためには、カウンター インターフェイスを実装し、それを CounterFactory に登録する必要があります。実装例の詳細はこちらをご覧ください。
AGPL ライセンスをお持ちのお客様は、自分のプロジェクトに最小限のカウンターを使うことができます。これは iText のサーバーを介さず、iText が提供するカウンター インターフェイスのカスタム実装です。以下のコードを呼び出すことで、実装を設定することができます。
Java
IEventCounterFactory counterFactory = new SimpleEventCounterFactory(new CustomEventCounter());
EventCounterHandler.getInstance().register(counterFactory);
.NET
IEventCounterFactory counterFactory = new SimpleEventCounterFactory(new CustomEventCounter());
EventCounterHandler.GetInstance().Register(counterFactory);
iText では、PdfDocument クラスのインスタンスを「イベント」としてカウントすることで、処理量のカウントを行っています。PDF の読み取り、書き込み、その他の変更を伴う操作はすべて、ボリューム カウントにカウントされます。
1 つのドキュメントにつき、1 つのイベントしかカウントされません。PDF を結合したり分割したりすると、複数のイベントが発生します。たとえば、2 つの別々のドキュメントをマージすると、2 つの異なるイベントとしてカウントされます (結合する 2 つのドキュメントそれぞれに別々の PdfDocument インスタンスが存在するため)。
Java
final PdfDocument pdfDocument = new PdfDocument(new PdfReader(SRC));
final PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDocument, false);
if (acroForm != null) {
Map fields = acroForm.getFormFields();
for (Map.Entry entry : fields.entrySet()) {
System.out.println(entry.getKey() + " is " + entry.getValue().getFormType());
}
}
pdfDocument.close();
C#
PdfDocument pdfDocument = new PdfDocument(new PdfReader(SRC));
PdfAcroForm acroForm = PdfAcroForm.GetAcroForm(pdfDocument, false);
if (acroForm != null)
{
foreach (KeyValuePair entry in acroForm.GetFormFields())
{
Console.WriteLine(entry.Key + " is " + entry.Value.GetFormType());
pdfDocument.Close();
}
}
Java
final PdfWriter pdfWriter = new PdfWriter(DEST);
final PdfDocument pdfDocument = new PdfDocument(pdfWriter);
try (final Document document = new Document(pdfDocument)) {
document.add(new Paragraph("Hello World!"));
}
C#
PdfWriter pdfWriter = new PdfWriter(DEST);
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
using (Document document = new Document(pdfDocument)) {
document.Add(new Paragraph("Hello World!"));
}
分割には PdfSplitter が PdfDocument を呼び出すため、1 つのインスタンスでファイルを読み、2 つの分割ファイルをそれぞれ別のインスタンスで書き込むため、3 イベントとしてカウントされます。
Java
private void splitPDF(final String SRC) throws IOException {
final int maxPageCount = 2;
new PdfSplitter(new PdfDocument(new PdfReader(new File(SRC)))) {
int partNumber = 1;
protected PdfWriter getNextPdfWriter(final PageRange documentPageRange) {
try {
return new PdfWriter("out/splitDocument_" + partNumber++ + ".pdf");
} catch (final FileNotFoundException ignored) {
throw new RuntimeException();
}
}
}.splitByPageCount(maxPageCount, new PdfSplitter.IDocumentReadyListener() {
@Override
public void documentReady(final PdfDocument pdfDocument, final PageRange pageRange) {
pdfDocument.close();
}
});
}
C#
class CustomSplitter : PdfSplitter
{
int PartNumber = 1;
public CustomSplitter(PdfDocument pdfDocument) : base(pdfDocument) { }
protected override PdfWriter GetNextPdfWriter(PageRange documentPageRange)
{
return new PdfWriter("out/splitDocument_" + PartNumber++ + ".pdf");
}
}
private static void Split()
{
int MaxPageCount = 2;
using (var pdfDoc = new PdfDocument(new PdfReader(SRC)))
{
var splitter = new CustomSplitter(pdfDoc);
var splittedDocs = splitter.SplitByPageCount(MaxPageCount);
foreach (var splittedDoc in splittedDocs)
{
splittedDoc.Close();
}
}
}
結合は PdfMerger が PdfDocument を呼び出すため、1 インスタンスで 2 つのファイルを読み、その後結合されたファイルを書き込むため、2 イベントとしてカウントされます。
Java
PdfMerger merge = new PdfMerger(new PdfDocument(new PdfReader(DEST)));
merge.merge(new PdfDocument(new PdfWriter(DEST)), 1, 2);
C#
PdfMerger merge = new PdfMerger(new PdfDocument(new PdfReader(DEST)));
merge.Merge(new PdfDocument(new PdfWriter(DEST)), 1, 2);
pdfHTML では、PdfDefaultProcessor#processElements と PdfDefaultProcessor#processDocument の各イベントがカウントされます。
Java
HtmlConverter.convertToPdf(new FileInputStream(ORIG), new FileOutputStream(DEST));
C#
HtmlConverter.ConvertToPdf(new FileStream(SRC, FileMode.Open), new FileStream(DEST, FileMode.Create, FileAccess.Write));
pdfSweep では、各 PdfCleanUpTool のインスタンスがカウントされます。
Java
try (PdfDocument pdf = new PdfDocument(new PdfReader(SRC), new PdfWriter(DEST))) {
final ICleanupStrategy cleanupStrategy = new RegexBasedCleanupStrategy("Creating").setRedactionColor(ColorConstants.PINK);
final PdfAutoSweep autoSweep = new PdfAutoSweep(cleanupStrategy);
autoSweep.cleanUp(pdf);
}
C#
using (var pdf = new PdfDocument(new PdfReader(SRC), new PdfWriter(DEST)))
{
ICleanupStrategy cleanupStrategy = new RegexBasedCleanupStrategy("Creating")
.SetRedactionColor(ColorConstants.PINK);
PdfAutoSweep autoSweep = new PdfAutoSweep(cleanupStrategy);
autoSweep.CleanUp(pdf);
}
pdf2Data では、Pdf2DataExtractor#recognize メソッドの各呼び出しが 1 pdf2Data イベントとしてカウントされます。
Java
Template template = Pdf2DataExtractor.parseTemplateFromPDF(pathToPdfTemplate);
Pdf2DataExtractor extractor = new Pdf2DataExtractor(template);
ParsingResult result = extractor.recognize(pathToFileToParse);
C#
Template template = Pdf2DataExtractor.ParseTemplateFromPDF(pathToPdfTemplate);
Pdf2DataExtractor extractor = new Pdf2DataExtractor(template);
ParsingResult result = extractor.Recognize(pathToFileToParse);
JSON ライセンス キー ファイルをお持ちで、iText Core 7.2.x またはそのアドオンをお使いの場合、現在の使用量を簡単に確認できます。
Java / C#
LicenseKey.loadLicenseFile(new File("license.json"));
for (LicenseInfo licenseInfo : LicenseKey.getLoadedLicensesInfo()) {
Map map = licenseInfo.getLimitsInfo().getEventsLimitInfo();
for (Map.Entry entry : map.entrySet()) {
logger.info("Remaining volume: " + entry.getValue().getRemainingVolume()
+ " out of " + entry.getValue().getTotalVolume());
}
}
iText 7.1.4 以降の DefaultEventCounter クラスは、iText とそのアドオンが統計情報を送信するために使用します。iText 7 で PDF の読み取りと書き込みの回数をカウントするカスタム ソリューションを実装したい場合、以下の例では、すべての読み取りと書き込みイベントをリストアップしたログファイルを出力するように iText に指示する方法を示しています。
static class CustomEvent implements IGenericEvent {
public static final CustomEvent READ = new CustomEvent("read");
public static final CustomEvent WRITE = new CustomEvent("write");
private final String subtype;
private CustomEvent(String subtype) {
this.subtype = subtype;
}
@Override
public String getEventType() {
return "custom-" + subtype;
}
@Override
public String getOriginId() {
return NamespaceConstant.ITEXT;
}
}
static class ReadingWritingEventsAwarePdfDocument extends PdfDocument {
public ReadingWritingEventsAwarePdfDocument(PdfReader reader) { super(reader); }
public ReadingWritingEventsAwarePdfDocument(PdfWriter writer) { super(writer); }
public ReadingWritingEventsAwarePdfDocument(PdfReader pdfReader, PdfWriter pdfWriter) {
super(pdfReader, pdfWriter);
}
@Override
protected void open(PdfVersion newPdfVersion) {
if (this.reader != null) {
EventCounterHandler.getInstance().onEvent(CustomEvent.READ, null, getClass());
}
if (this.writer != null) {
EventCounterHandler.getInstance().onEvent(CustomEvent.WRITE, null, getClass());
}
super.open(newPdfVersion);
}
}
public void test() throws IOException {
EventCounterHandler.getInstance().register(new SystemOutEventCounterFactory());
PdfDocument writingDoc = new ReadingWritingEventsAwarePdfDocument(new PdfWriter(DEST_PATH));
Document document = new Document(writingDoc);
document.add(new Paragraph("Hello world"));
document.close();
System.out.println("--- Document processing separator ---");
PdfDocument readingDoc = new ReadingWritingEventsAwarePdfDocument(new PdfReader(SOURCE_PATH));
readingDoc.getPage(1).getPageSize();
readingDoc.close();
System.out.println("--- Document processing separator ---");
PdfDocument stampingDoc = new ReadingWritingEventsAwarePdfDocument(
new PdfReader(SOURCE_PATH), new PdfWriter(DEST_PATH));
new PdfCanvas(stampingDoc.getPage(1)).rectangle(100, 100, 300, 500).fill();
stampingDoc.close();
}
これにより、以下の情報を含むログファイルが作成されます。
[core.clean.CustomCounter$ReadingWritingEventsAwarePdfDocument]custom-write event
[core.clean.CustomCounter$ReadingWritingEventsAwarePdfDocument]core-process event
はい、ボリューム カウントの実装は、カスタム カウンターと同時に使用することができます。
Java
public void testCoreEvent() {
IEventCounterFactory counterFactory = new SimpleEventCounterFactory(new CustomEventCounter());
EventCounterHandler.getInstance().register(counterFactory);
LicenseKey.loadLicenseFile(license);
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
pdfDocument.addNewPage();
pdfDocument.close();
EventCounterHandler.getInstance().unregister(counterFactory);
}
class CustomEventCounter extends EventCounter {
@Override
protected void onEvent(IEvent event, IMetaInfo metaInfo) {
System.out.println("Process event: " + event.getEventType());
}
}
C#
public void testCoreEvent()
{
IEventCounterFactory counterFactory = new SimpleEventCounterFactory(new CustomEventCounter());
EventCounterHandler.GetInstance().Register(counterFactory);
LicenseKey.LoadLicenseFile("license path");
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new iText.IO.Source.ByteArrayOutputStream()));
pdfDocument.AddNewPage();
pdfDocument.Close();
EventCounterHandler.GetInstance().Unregister(counterFactory);
}
class CustomEventCounter : EventCounter
{
protected override void OnEvent(IEvent @event, IMetaInfo metaInfo)
{
Console.WriteLine("Process Event: ");
}
}
Java
public class CountingHandler implements IEventHandler {
private static Logger logger = LoggerFactory.getLogger(CountingHandler.class);
@Override
public void onEvent(IEvent iEvent) {
if (iEvent instanceof ITextCoreProductEvent) {
ITextCoreProductEvent event = (ITextCoreProductEvent) iEvent;
logger.info(event.getEventType());
}
}
}
EventManager.getInstance().register(new CountingHandler());
C#
class CountingHandler : IEventHandler
{
public void OnEvent(IEvent @event)
{
if (@event is ITextCoreProductEvent)
{
Console.WriteLine(((ITextCoreProductEvent)@event).GetEventType());
}
}
}
EventManager.GetInstance().Register(new CountingHandler());