O'Reilly Hacks
oreilly.comO'Reilly NetworkSafari BookshelfConferences Sign In/My Account | View Cart   
Book List Learning Lab PDFs O'Reilly Gear Newsletters Press Room Jobs  


 
Buy the book!
PDF Hacks
By Sid Steward
August 2004
More Info

HACK
#84
Tailor PDF Text at Serve-Time
Create a PDF template that you can populate as it is served
The Code
[Discuss (1) | Link to this hack]

The Code

This example PHP script, alter_pdf_text_example.php, opens a pdfsrc file, reads the offset data we added, and then serves the PDF. As it serves the PDF, it replaces the placeholders with the given text. Note how the replacement text is escaped using escape_pdf_string.

<?php
// alter_pdf_text_example.php, version 1.0
// http://www.pdfhacks.com/dynamic_text/

// the filename of the source PDF file, which 
// contains placeholders for our dynamic text
$pdfsrc_fn= './cover.pdfsrc';

// the data we will place into the PDF text;
$customer_text= "Mary Jane Doe";
$date_text= "March 15, 2004";

function escape_pdf_string( $ss )
{
  $ss_esc= '';
  $ss_len= strlen( $ss );
  for( $ii= 0; $ii< $ss_len; ++$ii ) {
    if( ord($ss{$ii})== 0x28 ||  // open paren
        ord($ss{$ii})== 0x29 ||  // close paren
        ord($ss{$ii})== 0x5c )   // backslash
      {
        $ss_esc.= chr(0x5c).$ss{$ii}; // escape the character w/ backslash
      }
    else if( ord($ss{$ii}) < 32 || 126 < ord($ss{$ii}) ) {
      $ss_esc.= sprintf( "\\%03o", ord($ss{$ii}) ); // use an octal code
    }
    else {
      $ss_esc.= $ss{$ii};
    }
  }
  return $ss_esc;
}

// open the source PDF file, which contains placeholders
$fp= @fopen( $pdfsrc_fn, 'r' );
if( $fp ) {

  if( $_GET['debug'] ) {
    header("Content-Type: text/plain"); // debug
  }
  else {
    header('Content-Type: application/pdf');
  }

  $pdf_offset= 0;
  $text_offsets= array( );

  // iterate over first lines of pdfsrc file to load $text_offsets;
  while( $cc= fgets($fp, 1024) ) {
    if( $cc{0}== '#' ) { // one of our comments
      list($comment, $name, $offset)= explode( '-', $cc );

      if( $name== 'customer' ) {
        $text_offsets[(int)$offset]= 
          escape_pdf_string( $customer_text );
      }
      else if( $name== 'date' ) {
        $text_offsets[(int)$offset]= 
          escape_pdf_string( $date_text );
      }
      else { // default
        $text_offsets[(int)$offset]= 
          escape_pdf_string( '[ERROR]' );
      }
    }
    else { // finished with our comments
      echo $cc;
      $pdf_offset= strlen($cc)+ 1;

      break;
    }
  }

  // sort by increasing offsets
  ksort( $text_offsets, SORT_NUMERIC );
  reset( $text_offsets );

  $output_text_line_b= false;
  $output_text_b= false;
  $closed_string_b= false;

  list( $offset, $text )= each( $text_offsets );
  $text_ii= 0;
  $text_len= strlen($text);

  // iterate over rest of file
  while( ($cc= fgetc($fp))!= "" ) {

    if( $output_text_line_b && $cc== '(' ) {
      // we have reached the beginning of our TEXT
      $output_text_line_b= false;
      $output_text_b= true;

      echo '(';
    }
    else if( $output_text_b ) {
      if( $cc== ')' ) { // finished with this TEXT
        if( $closed_string_b ) {
          // string has already been capped; pad
          echo ' ';
        }
        else {
          echo ')';
        }

        // get next offset/TEXT pair
        list( $offset, $text )= each( $text_offsets );
        $text_ii= 0;
        $text_len= strlen($text);

        // reset
        $output_text_b= false;
        $closed_string_b= false;
      }
      else if( $text_ii< $text_len ) {
        // output one character of $text
        echo $text{$text_ii++};
      }
      else if( $text_ii== $text_len ) {
        // done with $text, so cap this string
        echo ')';
        $closed_string_b= true;
        $text_ii++;
      }
      else {
        echo ' '; // replace padding with space
      }
    }
    else {
      // output this character
      echo $cc;

      if( $offset== $pdf_offset ) {
        // we have reached a line in pdfsrc where
        // our TEXT should be; begin a lookout for '('
        $output_text_line_b= true;
      }
    }

    ++$pdf_offset;
  }

  fclose( $fp );
}
else { // file open failure
  echo 'Error: failed to open: '.$pdfsrc_fn;
}
?>


O'Reilly Home | Privacy Policy

© 2007 O'Reilly Media, Inc.
Website: | Customer Service: | Book issues:

All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.