Volume Counter FAQs

FAQs and information about the counting mechanism for volume licenses used by iText 7.

3rd January 2018
iText PDF

How do I enable volume counting?

You don't need to enable anything. If you have a valid volume license file and if you have loaded the iText license key volume dependency, then iText will have automatically enabled this for you. Both the license key library and volume license key library are required, see the Volume Counter installation guide for details on installation

How do I get a volume license key file?

If you are an existing customer, you should contact your sales rep. Otherwise, you will need to contact our sales department. You can fill out a form here and one of our sales representatives will contact you

What if my Internet connection fails?

Don't worry, your code or program will not be affected if iText cannot connect to our server.

If your internet connection fails, then iText will cache all failed requests during its runtime and will try to send them with the next event. For the requests to be sent you will need to have a connection during the current runtime of your application. Statistics won't be carried over if the application shuts down.

Is the volume counting interface safe to use in a fully closed environment?

For volume counting to work you will need to allow access on port 443 to the volume counting server at kinesis.us-east-1.amazonaws.com. However, access is only required “one-way” as information is only sent, not received.

For iText DITO, access is also required for ob0bbfpvm5.execute-api.us-east-1.amazonaws.com if you want to query your volume quota.

If you want to know details of the information that we collect, refer to your Software License Agreement (SLA).

Can I use my volume license keys with iText 5?

You can use your volume license keys with iText 5, but you won't be able to use the automated mechanism. To keep track of your statistics, you'll need to implement the Counter interface and register it to the CounterFactory. You can see an example implementation detailed here.

How can I use volume counting with my AGPL project?

Non-paying users can use a barebones counter for their projects. It doesn't involve our server but is a custom implementation of the Counter interface provided by iText. You can set your implementation by calling the following code:

Java

IEventCounterFactory counterFactory = new SimpleEventCounterFactory(new CustomEventCounter()); EventCounterHandler.getInstance().register(counterFactory);

.NET

IEventCounterFactory counterFactory = new SimpleEventCounterFactory(new CustomEventCounter()); EventCounterHandler.GetInstance().Register(counterFactory);

Can I see a code example for custom volume counting?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void testCoreEvent() {
    // Use com.itextpdf.kernel.counter.IEventCounterFactory implementation.
    // SimpleEventCounterFactory is the most basic one, simply yielding an instance which is passed to the constructor.
    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) {
        // This implementation is not thread safe!
        System.out.println("Process event: " + event.getEventType());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void TestCoreEvent()
        {
            // Use iText.Kernel.Counter.IEventCounterFactory implementation.
            // SimpleEventCounterFactory is the most basic one, simply yielding an instance which is passed to the constructor.
            IEventCounterFactory counterFactory = new SimpleEventCounterFactory(new CustomEventCounter());
            EventCounterHandler.GetInstance().Register(counterFactory);
            LicenseKey.LoadLicenseFile(license);
            PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new MemoryStream()));
            pdfDocument.AddNewPage();
            pdfDocument.Close();
 
        }
 
        public class CustomEventCounter : EventCounter
        {
            protected override void OnEvent(IEvent @event, IMetaInfo metaInfo)
            {
                Console.WriteLine("Process event: " + @event.GetEventType());
            }
        }

How can I count the number of PDF reads and writes in iText 7?

The DefaultEventCounter class in iText 7.1.4 and later is used by iText and its add-ons to send statistics. It is based on an event system rather than by file reads and writes, so iText 7 Core operations, will only get a Core event. This makes it easier for volume counting purposes. 

However, if you want to implement a custom solution for counting the number of PDF reads and writes in iText 7, the following example demonstrates a method for telling iText to output a log file that lists all read and write events:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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);
            }
            // ... any other required constructors matching PdfDocument
            @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 {
            // register event-counter factory
            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();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class CustomEvent : IGenericEvent
        {
            public static CustomEvent READ = new CustomEvent("read");
            public static CustomEvent WRITE = new CustomEvent("write");
            private string subtype;
            public CustomEvent(string subtype)
            {
                this.subtype = subtype;
            }
            public string GetEventType()
            {
                return "custom-" + subtype;
            }
            public string GetOriginId()
            {
                return NamespaceConstant.ITEXT;
            }
        }
        class ReadingWritingEventsAwarePdfDocument : PdfDocument
        {
            protected internal ReadingWritingEventsAwarePdfDocument(PdfReader reader) : base(reader)
            {
            }
            protected internal ReadingWritingEventsAwarePdfDocument(PdfWriter writer) : base(writer)
            {
            }
            protected internal ReadingWritingEventsAwarePdfDocument(PdfReader reader, PdfWriter writer) : base(reader, writer)
            {
            }
            protected override void Open(PdfVersion NewPdfVersion)
            {
                if (this.reader != null)
                {
                    EventCounterHandler.GetInstance().OnEvent(CustomEvent.READ, null, this.GetType());
                }
                if (this.writer != null)
                {
                    EventCounterHandler.GetInstance().OnEvent(CustomEvent.WRITE, null, this.GetType());
                }
                base.Open(NewPdfVersion);
            }
        }
        private static void Test()
        {
            EventCounterHandler.GetInstance().Register(new SystemOutEventCounterFactory());
            PdfDocument writingDoc = new ReadingWritingEventsAwarePdfDocument(new PdfWriter(DEST));
            Document document = new Document(writingDoc);
            document.Add(new Paragraph("Hello world"));
            document.Close();
            Console.WriteLine("--- Document processing separator ---");
            PdfDocument readingDoc = new ReadingWritingEventsAwarePdfDocument(new PdfReader(SRC));
            readingDoc.GetPage(1).GetPageSize();
            readingDoc.Close();
            Console.WriteLine("--- Document processing separator ---");
            PdfDocument stampingDoc = new ReadingWritingEventsAwarePdfDocument(new PdfReader(SRC), new PdfWriter(DEST));
            new PdfCanvas(stampingDoc.GetPage(1)).Rectangle(100, 100, 300, 500).Fill();
            stampingDoc.Close();
        }

This will produce a log file containing the following information:

[core.clean.CustomCounter$ReadingWritingEventsAwarePdfDocument]custom-write event

[core.clean.CustomCounter$ReadingWritingEventsAwarePdfDocument]core-process event

Can I use a custom counter in addition to volume counting?

Yes, the volume counting implementation can be used concurrently with a custom counter.

How does volume counting work?

iText 7 Core

The volume counting system used in iText Core is based on “events”, which are distinct PdfDocument instances. An event is recorded when a document is read, written, or stamped, as these operations all include a PdfDocument instance. An event is also counted when PdfDocument is called in the background by PdfMerger or PdfSplitter.

Therefore, any operation that involves reading, writing or otherwise modifying a PDF will contribute towards volume counting. For example, merging two separate documents would be counted as two distinct events (as there are separate PdfDocument instances for each of the two documents you merge).

Only one event will be counted per document. So, opening a PDF, editing it and then closing it will be counted as one event. Similarly, opening a PDF, editing it and then saving as a separate document is also counted as one event, as you can read one PDF and write a different one with the same PdfDocument instance.

In the following examples we show various iText operations that cause events to be added to the volume counter.

Example 1 – Reading a PDF document (forms)

1
2
3
4
5
6
7
8
9
10
11
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();
1
2
3
4
5
6
7
8
9
10
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();
            }
}

This is counted as 1 event.

Example 2 – Writing a PDF document

1
2
3
4
5
6
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!"));
}
1
2
3
4
5
PdfWriter pdfWriter = new PdfWriter(DEST);
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
using (Document document = new Document(pdfDocument)) {
            document.Add(new Paragraph("Hello World!"));
}

This is also counted as 1 event.

Example 3 – Splitting a PDF document

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void splitPDF(final String SRC) throws IOException {
        final int maxPageCount = 2; // create a new PDF per 2 pages from the original file
        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();
            }
        });
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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();
                }
            }
        }

Splitting uses PdfSplitter which calls a PdfDocument instance. Therefore, splitting a 2-page document counts as 3 events, as you read a file in one instance and then write 2 split files, each in a separate instance.

Example 4 – Merging two PDF documents

1
2
PdfMerger merge = new PdfMerger(new PdfDocument(new PdfReader(DEST)));
merge.merge(new PdfDocument(new PdfWriter(DEST)), 1, 2);
1
2
PdfMerger merge = new PdfMerger(new PdfDocument(new PdfReader(DEST)));
merge.Merge(new PdfDocument(new PdfWriter(DEST)), 1, 2);

Likewise, merging is done with PdfMerger calling PdfDocument, and so this also counts as 2 events, as you are reading two files in one instance and then writing the merged file.

pdfHTML

For pdfHTML each event in PdfDefaultProcessor#processElements and PdfDefaultProcessor#processDocument is counted and added to the volume counter.

Example 5 – HTML conversion to PDF

1
HtmlConverter.convertToPdf(new FileInputStream(ORIG), new FileOutputStream(DEST));
1
2
HtmlConverter.ConvertToPdf(new FileStream(SRC, FileMode.Open), new FileStream(DEST, FileMode
    .Create, FileAccess.Write));

This HTML conversion is counted as 1 event.

pdfSweep

For pdfSweep each PdfCleanUpTool instance is counted. 

Example 6 – PDF redaction

1
2
3
4
5
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);
}
1
2
3
4
5
6
7
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);
}

This redaction example creates 2 events, 1x core-process and 1xsweep-cleanup.



Contact

Still have questions? 

We're happy to answer your questions. Reach out to us and we'll get back to you shortly.

Contact us
Stay updated

Join 11,000+ subscribers and become an iText PDF expert by staying up to date with our new products, updates, tips, technical solutions and happenings.

Subscribe Now