Printing a QR Code on a PDF

WaterWoo and EDDiMark can add QR codes to PDFs dynamically upon download request via WooCommerce. This is because both plugins use TCPDF to write PDF content, and TCPDF allows for barcode creation. Though this blog post might also be helpful for someone just trying to figure out how to write a barcode with TCPDF and PHP, these instructions are more geared toward a Wordpress developer wishing to add 1D or 2D barcodes to existing PDF files.

For WaterWoo, use the ‘wwpdf_add_barcode’ filter hook in the plugin (located in classes/wwpdf-watermark.php). For EDDiMark, use the ‘eddimark_add_barcode’ filter hook (located in classes/eddimark-watermark.php).

Your hooked function should simply create and return an array of arguments to pass to the open source TCPDF barcoding methods (1D or 2D). The array has ten arguments, the first of which decides whether you want a 1D or 2D QR code. The rest of the arguments are specific to either TCPDF write1DBarcode() or TCPDF write2DBarcode(), which take slightly different arguments.

What’s the difference between a 1D and a 2D barcode?

1D and 2D barcode difference

On the left, a 1D barcode. Data is read horizontally via bars of differing width. On the right, a 2D barcode; data is read horizontally and vertically. You may be familiar with the 2D barcode, as QR codes have become a popular means of distributing branding and marketing via smartphones and other readers.

Write a 1D Barcode with TCPDF

For a 1D barcode, TCPDF uses a method called write1DBarcode() and 9 arguments:

write1DBarcode( $code, $type, $x='', $y='', $w='', $h='', $xres='', $style=array(), $align='' )

9 Arguments

  • parameter $code (string) code to print
  • parameter $type (string) type of barcode. Type will be one of the following: ‘C39’, ‘C39+’, ‘C39E’, ‘C39E+’, ‘C93’, ‘S25’, ‘S25+’, ‘I25’, ‘I25+’, ‘C128’, ‘C128A’, ‘C128B’, ‘C128C’, ‘EAN2’, ‘EAN5’, ‘EAN8’, ‘EAN13’, ‘UPCA’, ‘UPCE’, ‘MSI’, ‘MSI+’, ‘POSTNET’, ‘PLANET’, ‘RMS4CC’, ‘KIX’, ‘IMB’, ‘IMBPRE’, ‘CODABAR’, ‘CODE11’, ‘PHARMA’, ‘PHARMA2T’ (see inc/tcpdf/tcpdf_barcodes_1d.php for more detail).
  • parameter $x (int) x position in user units (empty string = current x position)
  • parameter $y (int) y position in user units (empty string = current y position)
  • parameter $w (int) width in user units (empty string = remaining page width)
  • parameter $h (int) height in user units (empty string = remaining page height)
  • parameter $xres (float) width of the smallest bar in user units (empty string = default value = 0.4mm)
  • parameter $style (array) array of options:
    • boolean $style[‘border’] if true prints a border
    • int $style[‘padding’] padding to leave around the barcode in user units (set to ‘auto’ for automatic padding)
    • int $style[‘hpadding’] horizontal padding in user units (set to ‘auto’ for automatic padding)
    • int $style[‘vpadding’] vertical padding in user units (set to ‘auto’ for automatic padding)
    • array $style[‘fgcolor’] color array for bars and text
    • mixed $style[‘bgcolor’] color array for background (set to false for transparent)
    • boolean $style[‘text’] if true prints text below the barcode
    • string $style[‘label’] override default label
    • string $style[‘font’] font name for text
    • int $style[‘fontsize’] font size for text
    • int $style[‘stretchtext’]: 0 = disabled; 1 = horizontal scaling only if necessary; 2 = forced horizontal scaling; 3 = character spacing only if necessary; 4 = forced character spacing.
    • string $style[‘position’] horizontal position of the containing barcode cell on the page: L = left margin; C = center; R = right margin.
    • string $style[‘align’] horizontal position of the barcode on the containing rectangle: L = left; C = center; R = right.
    • string $style[‘stretch’] if true stretch the barcode to best fit the available width, otherwise uses $xres resolution for a single bar.
    • string $style[‘fitwidth’] if true reduce the width to fit the barcode width + padding. When this option is enabled the ‘stretch’ option is automatically disabled.
    • string $style[‘cellfitalign’] this option works only when ‘fitwidth’ is true and ‘position’ is unset or empty. Set the horizontal position of the containing barcode cell inside the specified rectangle: L = left; C = center; R = right.
  • parameter $align (string) Indicates the alignment of the pointer next to barcode insertion relative to barcode height. The value can be:
    • T: top-right for LTR or top-left for RTL
    • M: middle-right for LTR or middle-left for RTL
    • B: bottom-right for LTR or bottom-left for RTL
    • N: next line

 
You don’t need to pass ALL the arguments, but you can if you need to. Remember, the first argument for your hooked function return array is just ‘1D’ or ‘2D’, then the remaining 5-9 arguments should follow. A sample PHP hooked function might look like this:

function my_1D_barcode_function( $barcode_array, $identifier ) {

    $barcode_array = array( '1D', 'My barcode alphanumeric content', '100', '200', '100', '30'  );
    return $barcode_array;

}
add_filter( 'wwpdf_add_barcode', 'my_1D_barcode_function', 10, 2 );

That will add a 10x3cm barcode 10cm across and 20cm down the page, which says “My barcode alphanumeric content.” Of course edit it to make sure the arguments create the barcode you want, where you want it. You could add this code to your (child) theme functions.php file, or by using the Code Snippets plugin if you’re unfamiliar with how to edit theme files.

Note: The code in this post applies to WaterWoo version 3.0+ and EDDiMark version 2.2+. It will be similar for older/other Little Package plugins. Sample code is not guaranteed to work.

Here’s where it gets fun for WooCommerce users (if it’s not fun and you have no idea what any of this means, please consider hiring a developer)! Since the WooCommerce order ID is included as an argument in the ‘wwpdf_add_barcode’ filter hook, you are able to add email, address, full name, etc., to the barcode (assuming you collected those details from your customer during WooCommerce checkout). You might try something like:

function phone_1D_barcode_function( $barcode_array, $order_id ) {

    $order = wc_get_order( $order_id );
    $order_data = $order->get_data();
    $phone = $order_data['billing']['phone'];

    if ( ! isset( $phone ) || $phone == '' ) { 
	// no phone number yet, try seeing if user is logged in and has a saved phone number:
        if ( is_user_logged_in() ) {
            $user = wp_get_current_user();
            $phone = get_user_meta( $user->ID, 'billing_phone', true ) == '' ? '' : get_user_meta( $user->ID, 'billing_phone', true );
        }
    }

    if ( ! isset( $phone ) || $phone == '' ) { 
        $code = 'fallback barcode content';
    } else {
        // you might want to manipulate the phone number to remove +-_( first, like this:
        // $phone = preg_replace( '/\D+/', '', $phone ); // uncomment to clean up and only use the digits
        $code = $phone;
    }
    $barcode_array = array( '1D', $code, '100', '200', '100', '30'  );
    return $barcode_array;

}
add_filter( 'wwpdf_add_barcode', 'phone_1D_barcode_function', 10, 2 );

Write a 2D Barcode with TCPDF

Create a 2D barcode with TCPDF very much how you create a 1D barcode, but by passing some slightly different parameters. For one, the $type of barcodes will obviously be different, because now we are 2D.

For a 2D barcode, TCPDF uses a method called write2DBarcode() and 9 arguments:

write2DBarcode($code, $type, $x='', $y='', $w='', $h='', $style=array(), $align='', $distort=false)

9 Arguments

  • parameter $code (string) code to print
  • parameter $type (string) type of barcode: DATAMATRIX; PDF417; PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6; QRCODE; QRCODE,L; QRCODE,M; QRCODE,Q; QRCODE,H; RAW; RAW2; TEST (see tcpdf_barcodes_2d.php for supported formats).
  • parameter $x (int) x position in user units
  • parameter $y (int) y position in user units
  • parameter $w (int) width in user units
  • parameter $h (int) height in user units
  • parameter $style (array) array of options:
    • boolean $style[‘border’] if true prints a border around the barcode
    • int $style[‘padding’] padding to leave around the barcode in barcode units (set to ‘auto’ for automatic padding)
    • int $style[‘hpadding’] horizontal padding in barcode units (set to ‘auto’ for automatic padding)
    • int $style[‘vpadding’] vertical padding in barcode units (set to ‘auto’ for automatic padding)
    • int $style[‘module_width’] width of a single module in points
    • int $style[‘module_height’] height of a single module in points
    • array $style[‘fgcolor’] color array for bars and text
    • mixed $style[‘bgcolor’] color array for background or false for transparent
    • string $style[‘position’] barcode position on the page: L = left margin; C = center; R = right margin; S = stretch
  • parameter $align (string) Indicates the alignment of the pointer next to barcode insertion relative to barcode height. The value can be:
    • T: top-right for LTR or top-left for RTL
    • M: middle-right for LTR or middle-left for RTL
    • B: bottom-right for LTR or bottom-left for RTL
    • N: next line
  • parameter $distort (boolean) if true distort the barcode to fit width and height, otherwise preserve aspect ratio

 
You don’t need to pass ALL the arguments, but you can if you need to. Remember, the first argument for your hooked function return array is just ‘1D’ or ‘2D’, then the remaining 5-9 arguments should follow. A sample PHP hooked function might look like this:

function my_2D_barcode_function( $barcode_array, $identifier ) {

    $barcode_array = array( '2D', 'My 2d barcode says HI', '100', '200', '100', '30'  );
    return $barcode_array;

}
add_filter( 'wwpdf_add_barcode', 'my_2D_barcode_function', 10, 2 );

Caveat

The ‘wwpdf_add_barcode’ and ‘eddimark_add_barcode’ filters were placed as a convenience for Wordpress users who want to extend watermarking with barcodes. You’ll see it is not “plug and play” on the plugin backend; there are no “settings panels” where you can create barcodes. But it’s not much work for someone who is familiar with PHP/Wordpress, either. Hopefully you can understand this was not a “feature” built into WaterWoo or EDDiMark because TCPDF may offer unpredictable results and we do not support TCPDF — it is 3rd party code. So please experiment with it, have fun, and if you have comments or suggestions, contact us.