EDDiMark Documentation

More about EDDiMark PDF

EDDiMark does its magic using the open-source TCPDF and TCPDI libraries (not developed or maintained by EDDiMark dev). TCPDI parses the existing PDF (assuming it is unencrypted and uncorrupted), recreating it in memory, and TCPDF applies your watermark. Regretfully, TCPDI is unable to parse certain PDF elements into memory, such as internal links and forms. However, hopefully this feature will be more stable in a future TCPDI release. Understanding a little about how TCPDI and TCPDF come into play, using PHP memory, might help you to create the most effective and efficient watermarks.

View the EDDiMark PDF changelog here.


Make sure to test your watermarking thoroughly before going live! TCPDF is a fallible third-party library which does its best to parse/understand and re-write your PDF with your desired changes (watermarks/encryption/etc), but it cannot possibly work on all PDFs and on all servers 100% of the time. Stay realistic, think carefully through the process, plan, and do your testing.

PHP Version

You should be running at least PHP version 5.6 for all features of EDDiMark PDF to work, but higher that for it to work WELL. WordPress recommends you run PHP version 7.2 or higher. EddiMark is PHP version 7.3 compatible, so don’t hesitate to upgrade after making backups. PHP 7.0 is twice as fast for WordPress as PHP 5.6, and processes EDDiMark demands much more efficiently! This is the first thing you should try if you’re running out of memory while processing PDFs.

Increase Memory

Increase your PHP memory allotment to at least 64MB. We recommend a 128MB, 256MB or maybe even 512MB setting. If your host does not allow more than 16 or 32, it might be a good time to switch hosts or servers. If you expect your PDF to take more than 30 seconds to parse (gasp!), you may also need to increase your PHP max_execution_time.

Large PDFs?

If you are having trouble sharing large PDF files, keep in mind that your hosting plan needs to be robust enough to support the memory and bandwidth necessary to fulfill these requests. Try these suggestions to tune your setup for performance. Keep your watermarks simple (avoid HTML and images if possible) and use non-Unicode fonts if possible (Helvetica, Times, Courier).

Maybe it’s time for a server upgrade? Easy Digital Downloads has written a valuable article about how to keep your digital goods website up and cranking along.


EDDiMark default top/bottom and left/right margins are set to zero, meaning your default watermark will appear in the top left corner, without spacing. You can use margins to move your watermark stays away from the page edges. You can also use X and Y fine tuners to move the watermark across (X) and down (Y) the page. Remember, measurements are in millimeters.

Usually, you’d use the Y tuner to move your watermark DOWN from the TOP of the page, millimeter by millimeter. If you have PDFs with varying heights and want better control of where the watermark sits, you can move the footer watermark UP from the BOTTOM of the page by using a negative integer (e.g. -10, which would be 10mm) in the Y fine tuner setting. Just make sure to keep your watermark within the page boundaries — if it goes off the page, EDDiMark will create a new (unwanted) blank page with the orphaned watermark.

As far as watermark positioning goes, the X-axis and Y-axis tuners work across and down the page in MILLIMETERS. If you’ve moved your watermark too far down the page, it will create a blank page. Reduce your Y-axis number and/or your font size to get the watermark back on the page.

It’s very important to test your watermark settings until you are sure the watermark will fit inside the margins you have set, otherwise you will see problems.

Simple Shortcodes

Simple shortcodes available are [FIRSTNAME] [LASTNAME] [EMAIL] [DATE] [PAYMENTID]. Using one of these in your overlay or footer text will cause the shortcode to be replaced by the customer data during watermarking.

[DATE] Shortcodes

[DATE] can be used as-is, and will insert the order date.

Future [DATE] Shortcodes

To add a future date marked from the date of purchase, you can use the [DATE-#YRS] [DATE-#MOS] [DATE-#WKS] [DATE-#DAYS] shortcode, where # is replaced with the number of days/months/weeks/years desired. This shortcode is based on 30-day months, and 365-day years, so it might be best to use days if you need precision.


[DATE-365DAYS] would be 365 days from the checkout date.

[DATE-2YRS] would be 730 days from the checkout date, but does not take into account a leap year.

Opacity Shortcodes

The {OPAC} shortcode — and watermarking with opacity — is totally unique to this plugin is very helpful for people not wanting to obscure their PDF content, since the watermark sits on top. Some people use this shortcode to create an invisible — or nearly invisible — text watermark.

The {OPAC} shortcode doesn’t always play nice with HTML in your watermark, so sometimes some rearranging will need to be done. Consider wrapping your HTML inside {OPAC} tags if trying to get opacity, if the inverse isn’t working.


{OPAC-0.5}This is sample text{/OPAC}

This is sample text” will be at 50% transparency. The tag needs a dash, then a number representing the fraction of 100% opacity.

{OPAC-0.1}This is very transparent text{/OPAC}

This is very transparent text” will be at 10% transparency.

Note there is an open tag and a close tag around the text. If text does not wrap when using this tag, you may have to use HTML <br> tags. {OPAC} tag is still beta.

Text alignment

To style a link <a> or tag when using HTML, the following inline CSS options are available: font-style:italic, font-weight:bold, and text-align:center and text-align:right. This feature allows you to center text – yay!

Here’s an example of the code used to center some text.

<span style="text-align: center; font-weight: bold;">center some bold text</span>

This might also work:

<span style="text-align: center"><strong>center some bold text</strong></span>

Manual / Test Watermarking

Settings for testing PDF watermarks

Added in v2.0, the “test kitchen” allows you to preview your watermarks before going live with them. The test watermark will observe all of the EDDiMark general settings, but also allow you to enter any customer (or mock customer) details to flesh out any shortcodes you may have used ([FIRSTNAME], [LASTNAME], etc.). Have fun with it!

File Management & Cleanup

There are a few new settings in version 2.0 to allow you to serve watermarked PDFs efficiently, and erase them more easily. First of all in version 2.0, the file name no longer changes — your customer sees what you want them to see, out-the-box. After watermarking, watermarked files are moved to folders made unique by the customers’ payment IDs. If these files are not immediately deleted, they will sit forever… unless you turn on the “Delete files weekly” EDDiMark setting.

EDDiMark PDF management settings

This will add watermarked files to a weekly cron and they will be deleted for you. If you have the “recycle” option selected, files still inside the EDD “Download Link Expiration” window will be kept on the server. Why recycle? Because PDF watermarking can be memory-intensive, and delivering a customer’s already-watermarked file you have stored puts less pressure on the server. Want your files to be deleted on a different schedule?

Hooks (actions/filters)

Hooks were included to make it possible to adjust EDDiMark to carry out some of your specific needs. The hooks are no supported by EDDiMark staff unless you find a bug or need arguments added. We will not be able to write actions and filter code for you. The hooks were placed for your developer’s convenience.

‘ eddimark_add_custom_font ‘ and ‘ eddimark_font_decode ‘, and ‘ eddimark_out_charset ‘ filters, more here (Also note that as of version 1.5, the plugin comes with an automatic font uploader; you can upload your own TTF font to the watermarker, leaving these hooks a lot less necessary for custom font work.)

‘ eddimark_add_barcode ‘ filter for maybe adding barcodes

‘ eddimark_settings_array ‘ filter to allow for manipulation of main watermarking settings (possibly to add settings).

‘ eddimark_set_zoom_mode ‘ and ‘ eddimark_set_viewer_preferences ‘ filters for setting PDF viewing preferences via TCPDF. Examples of SetDisplayMode() in use. More on TCPDF setViewerPreferences() here.

Immediate deletion. If you are using “Forced” downloads (vs. “Redirect,” an EDD Settings->Misc->File Downloads setting), you can clean watermarked files off the server immediately using the ‘ eddimark_do_cleanup ‘ filter hook, with something like the following code in your theme or in a plugin:

add_filter( 'eddimark_do_cleanup', '__return_true' );

The ‘ eddimark_dont_cleanup ‘ hook was deprecated in version 2.0, because it was a bit confusing with double-negatives, and do to the fact there is no immediate cleanup available for “Redirect” file download types.

Also in version 2.0, your original file names are preserved despite watermarking. This is done by moving the file either into:

  • a) (Most likely) a folder named after the EDD Payment ID in the wp-content/uploads/eddimark-pdf/ folder. For example, a PDF downloaded for Payment ID 3589 would move to the wp-content/uploads/eddimark-pdf/3589 folder.
  • b) a folder inside your /tmp directory. (Doesn’t work with NGINX) The temp directory is found out using the WP get_temp_dir() function, so from here it’s hard to tell you where those files end up. But inside that directory, your files will be in folders named like this: “eddimark_paymentID” where paymentID is a number equal to the customer’s payment ID.

Need to change the way your files are named? As of version 2.0, this is no longer likely, but if so, you can use the ‘ eddimark_file_name ‘ hook. The new file name is also delivered to customers. Here’s an example of adding the download key to the file name:

add_filter( 'eddimark_file_name', 'eddimark_alter_file_name', 10, 2 );
eddimark_alter_file_name( $file_name, $key, $args ) {

    // replaces the timestamp in the filename with the unique download key
    $file_name = $file_name . '_' . $key . '.pdf';
    return $file_name;


Barcodes (maybe adding)

To add a barcode somewhere on your page, you can use the ‘eddimark_add_barcode’ filter. An example goes like this:

add_filter( 'eddimark_add_barcode', 'eddimark_barcode_function', 10, 1 );
function eddimark_barcode_function( $barcode_array ) {
    return array( '2D', 'Test Barcode', 'QRCODE', 100, 230, 30, 30 );

This hooked function adds a QR code to your PDF, 100mm from the left, and 230 mm down the page, 30mm square size. This could be really cool for adding a QR code to your PDF file – a receipt, a ticket, or any other confirmation needing scanning.

The ‘my_barcode_function’ function returns an array used by EDDiMark to create a barcode.

  1. The first argument accepts either ‘1D’ or ‘2D’.
  2. The second argument will be your barcode contents.
  3. The third argument states the TYPE of barcode (please refer to TCPDF documentation for 1D vs 2D barcode setup and appropriate names for barcode types.)
  4. The fourth argument is X-axis placement. In the example, I have it set 10cm (100mm) over to the right.
  5. The fifth argument is Y-axis placement. In the example, I have it set 23cm (230mm) over to the right.
  6. The sixth argument is the width of the barcode in millimeters.
  7. The seventh argument is height of the barcode in millimeters.

Fonts (maybe adding)

To run watermarking with your custom font, you can run the filter “eddimark_add_custom_font”. Font must be added to TCPDF first using AddFont(). Please read TCPDF docs. Fonts which come with TCPDF can also be added back in to the fonts folder; they were removed to keep this plugin as lightweight as possible. This is in development and not a supported feature.

add_filter( 'eddimark_add_custom_font', ‘eddimark_custom_font_name’, 10, 1 );
function eddimark_custom_font_name() {
    $font = TCPDF_FONTS::addTTFfont( $font_file, $font_type, $enc, $flags, $outpath, $platid, $encid, $addcbbox, $linkbox );
    return $font;

Keep in mind the $font value you return will be run in SetFont() while EDDiMark does its magic.

addTTFfont() parameters:

$fontfile (string) Font file (full path).
$fonttype (string) Font type. Leave empty for autodetect mode. Valid values are: TrueTypeUnicode, TrueType, Type1, CID0JP = CID-0 Japanese, CID0KR = CID-0 Korean, CID0CS = CID-0 Chinese Simplified, CID0CT = CID-0 Chinese Traditional.
$enc (string) Name of the encoding table to use. Leave empty for default mode. Omit this parameter for TrueType Unicode and symbolic fonts like Symbol or ZapfDingBats.
$flags (int) Unsigned 32-bit integer containing flags specifying various characteristics of the font (PDF32000:2008 – 9.8.2 Font Descriptor Flags): +1 for fixed font; +4 for symbol or +32 for non-symbol; +64 for italic. Fixed and Italic mode are generally autodetected so you have to set it to 32 = non-symbolic font (default) or 4 = symbolic font.
$outpath (string) Output path for generated font files (must be writeable by the web server). Leave empty for default font folder.
$platid (int) Platform ID for CMAP table to extract (when building a Unicode font for Windows this value should be 3, for Macintosh should be 1).
$encid (int) Encoding ID for CMAP table to extract (when building a Unicode font for Windows this value should be 1, for Macintosh should be 0). When Platform ID is 3, legal values for Encoding ID are: 0=Symbol, 1=Unicode, 2=ShiftJIS, 3=PRC, 4=Big5, 5=Wansung, 6=Johab, 7=Reserved, 8=Reserved, 9=Reserved, 10=UCS-4.
$addcbbox (boolean) If true includes the character bounding box information on the php font file.
$link (boolean) If true link to system font instead of copying the font data (not transportable) – Note: do not work with Type1 fonts.

If your overlay or footer are not looking right after you’ve added a new font, the filter ‘eddimark_font_decode’ might need to be used to add html_entity_decode() around your overlay or footer input.

Passwords & Encryption

Be aware that protecting a PDF requires to encrypt it, which increases the processing time a lot. This can cause a PHP time-out in some cases, especially if the document contains images or fonts.

The file will be automatically encrypted if a password is set. If you don’t set any password, the document will open as usual. If you set a user password, the PDF viewer will ask for it before displaying the document (learn more about implications here). Typing the word “email” into the password field in EDDiMark settings will force the end user to open the PDF with the buyer’s email address.

The permission array is composed of values taken from the following ones (specify the ones you want to block):

  • The following are set together:
    • print : Print the document
    • print‑high : Print the document to a representation from which a faithful digital copy of the PDF content could be generated. When this is not set, printing is limited to a low-level representation of the appearance, possibly of degraded quality.
  • The following are set together:
    • modify : Modify the contents of the document by operations other than those controlled by ‘fill-forms’, ‘extract’ and ‘assemble’
    • assemble : Assemble the document (insert, rotate, or delete pages and create bookmarks or thumbnail images), even if ‘modify’ is not set
  • copy : Copy or otherwise extract text and graphics from the document
  • The following are set together:
    • annot‑forms : Add or modify text annotations, fill in interactive form fields, and, if ‘modify’ is also set, create or modify interactive form fields (including signature fields)
    • Fill‑forms : Fill in existing interactive form fields (including signature fields), even if ‘annot-forms’ is not specified

More information about SetProtection() here.

Recommended you allow:
  • Copy. If not allowed this document will not be readable by humans who rely on screen readers instead of their eyes to read. Keep it accessible!

Errors and Error Logging

If you are having troubles with EDDiMark (and maybe the libraries it uses, TCPDI/TCPDF), it’s often very helpful to know what’s going on “under the hood.” There are two ways to get more information, especially if you are not getting descriptive error messages printed to your screen. Here’s two places to look:

Especially if your site is in development, it’s great to leave WordPress debugging turned on. We usually turn it off for production sites unless there is a problem, and only then turn it on temporarily. Please read about how to turn on WordPress debugging. In the wp-config.php file, we use the following three lines so logs are saved to a file and not printed to the screen. It’s prettier that way.

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

Logs will be stored in your WordPress /wp-content/ folder.

Something Easier, Please?

You can also turn on Easy Digital Downloads debugging in the EDD settings. Go to Downloads->Settings->Misc and check Debug Mode to turn it on. This may provide some clues if you are having troubles. We recommend turning debugging off again when everything seems to be going OK.

Little Package Web