I modified this stack question: Applying watermarks on pdf files when users try to download the files but I encountered an error, though there was a comment that says on how to
In case anyone wants to use FPDF AND create the pdf on the fly without having to load it from a file here's how I did it. You will instantiate your PDF object with this class instead of the FPDF class. This should be run AFTER the pdf is created in memory but BEFORE it is output:
<?php
include_once('fpdf.php');
class PDF_Rotate extends FPDF
{
var $angle=0;
public function ApplyWaterMarkToAllPages() {
for($i = 0; $i < count($this->pages); $i++) {
$this->page = $i;
$this->ApplyWaterMark();
}
}
private function ApplyWaterMark()
{
//Put the watermark
$this->SetFont('Arial','B',60);
$this->SetTextColor(255,192,203);
$this->RotatedText(15,280,'D O N O T F I L E - S A M P L E ',50);
$this->SetTextColor(0,0,0);
}
private function RotatedText($x, $y, $txt, $angle)
{
//Text rotated around its origin
$this->rotate($angle,$x,$y);
$this->Text($x,$y,$txt);
$this->Rotate(0);
}
private function Rotate($angle,$x=-1,$y=-1)
{
if($x==-1)
$x=$this->x;
if($y==-1)
$y=$this->y;
if($this->angle!=0)
$this->_out('Q');
$this->angle=$angle;
if($angle!=0)
{
$angle*=M_PI/180;
$c=cos($angle);
$s=sin($angle);
$cx=$x*$this->k;
$cy=($this->h-$y)*$this->k;
$this->_out(sprintf('q %.5F %.5F %.5F %.5F %.2F %.2F cm 1 0 0 1 %.2F %.2F cm',$c,$s,-$s,$c,$cx,$cy,-$cx,-$cy));
}
}
function _endpage()
{
if($this->angle!=0)
{
$this->angle=0;
$this->_out('Q');
}
parent::_endpage();
}
}
?>
I had a class called Document that I put everything in for abstraction. Here is the output function from it. I created a class level variable called "applyWaterMark" to control whether or not the watermark is applied to the document.
protected function OutputDocument() {
if($this->applyWaterMark) {
$this->pdf->ApplyWaterMarkToAllPages();
}
$this->pdf->Output();
}
This post was a great help to me in getting things started. But I quickly found that FPDF had some pitfalls a few people here have been experiencing. For me, I also noticed that the watermark only displays on the first page in some browser instances as well as opening it up through adobe acrobat (Acrobat X Pro).
Instead, I switched to using TCPDF, which solved a variety of problems including:
To use the custom fonts, just uncomment the custom font block below (http://www.tcpdf.org/fonts.php).
Also, final note, the standard FPDI package only supports PDF version 1.4. So if your importing any PDF's that are above that, the import will not work and blow up. You will need to buy a commercial version (https://www.setasign.com/products/fpdi-pdf-parser/details/), or just save your PDFs at version 1.4, thats what we did.
Here's my updated code:
require_once(APPPATH . 'third_party/tcpdf/tcpdf.php');
require_once(APPPATH . 'third_party/fpdi/fpdi.php');
class WatermarkerTCPDF extends FPDI {
public $pdf, $file, $newFile,
$wmText = "STACKOVERFLOW",
$fontsize = 24,
$fontfamily = 'ptsansnarrow400';
/** $file and $newFile have to include the full path. */
public function __construct($file = null, $newFile = null) {
$this->pdf = new FPDI();
//custom fonts
//$this->fontfamily = $this->pdf->addTTFfont(APPPATH . 'third_party/tcpdf/ttf/ptsansnarrow400.ttf', 'TrueTypeUnicode', '');
if (!empty($file)) {
$this->file = $file;
}
if (!empty($newFile)) {
$this->newFile = $newFile;
}
}
/** $file and $newFile have to include the full path. */
public static function applyAndSpit($file, $newFile = null) {
$wm = new Watermarker($file, $newFile);
if ($wm->isWaterMarked())
return $wm->spitWaterMarked();
else {
$wm->doWaterMark();
return $wm->spitWaterMarked();
}
}
/** @todo Make the text nicer and add to all pages */
public function doWaterMark() {
$currentFile = $this->file;
$newFile = $this->newFile;
$pagecount = $this->pdf->setSourceFile($currentFile);
for ($i = 1; $i <= $pagecount; $i++) {
$tplidx = $this->pdf->importPage($i);
$specs = $this->pdf->getTemplateSize($tplidx);
$this->pdf->SetPrintHeader(false);
$this->pdf->SetPrintFooter(false);
$this->pdf->addPage($specs['h'] > $specs['w'] ? 'P' : 'L');
$this->pdf->useTemplate($tplidx, null, null, 0, 0, true);
// now write some text above the imported page
$this->pdf->SetFont($this->fontfamily, '', $this->fontsize);
$this->pdf->SetTextColor(204, 204, 204);
//$this->pdf->SetXY($specs['w']/2, $specs['h']/2);
$_x = ($specs['w']/2) - ($this->pdf->GetStringWidth($this->wmText, $this->fontfamily, '', $this->fontsize)/2.8);
$_y = $specs['h']/2;
$this->pdf->SetXY($_x, $_y);
//$this->pdf->SetXY(0, 0);
$this->pdf->setAlpha(0.3);
$this->_rotate(45, 100, 100);
$this->pdf->Write(0, $this->wmText);
//$this->pdf->writeHTMLCell($w=0, $h=0, $x='', $y='', $this->wmText, $border=0, $ln=1, $fill=0, $reseth=true, $align='', $autopadding=true);
}
if (empty($newFile)) {
header('Content-Type: application/pdf');
$this->pdf->Output();
} else {
$this->pdf->Output($newFile, 'F');
}
}
public function isWaterMarked() {
//return (file_exists($this->newFile));
$_file = $this->newFile;
$file = file_get_contents($_file);
force_download($file);
}
public function spitWaterMarked() {
$_file = $this->newFile;
$file = file_get_contents($_file);
force_download($file);
//return readfile($this->newFile);
}
protected function _rotate($angle, $x = -1, $y = -1) {
if ($x == -1)
$x = $this->pdf->x;
if ($y == -1)
$y = $this->pdf->y;
//if ($this->pdf->angle != 0)
//$this->pdf->_out('Q');
$this->pdf->angle = $angle;
if ($angle != 0) {
$angle*=M_PI / 180;
$c = cos($angle);
$s = sin($angle);
$cx = $x * $this->pdf->k;
$cy = ($this->pdf->h - $y) * $this->pdf->k;
$this->pdf->_out(sprintf(
'q %.5f %.5f %.5f %.5f %.2f %.2f cm 1 0 0 1 %.2f %.2f cm', $c, $s, -$s, $c, $cx, $cy, -$cx, -$cy));
}
}
public function wmText($text = null)
{
$total = 20;
if (!empty($text)) {
$this->wmText = '';
for ($i = 0; $i < $total; $i++) {
$this->wmText .= ' ' . $text;
}
}
return $this;
}
}
To use this, just:
try {
//this is for CodeIgniter
$this->load->library('WatermarkerTCPDF');
//if your using it as a standard class in vanilla PHP just do:
//require_once('PATH_TO_LIBRARY/WatermarkerPDF.php');
//If you want to output the PDF to another file, you can supply
//a second parameter: new WatermarkerTCPDF($file_path, $new_file_path);
//just remember, the full path is required
$watermark = new WatermarkerTCPDF($file_path);
$watermark->wmText($this->session->userdata('email'));
$watermark->doWaterMark();
} catch (Exception $e) {
exit($e->getMessage());
}
Anyway, hope this will help someone someday!
I have found a couple of things wrong with that script. To get it working change the doWatermark()
method to this:-
public function doWaterMark()
{
$currentFile = $this->file;
$newFile = $this->newFile;
$pagecount = $this->pdf->setSourceFile($currentFile);
for($i = 1; $i <= $pagecount; $i++){
$this->pdf->addPage();//<- moved from outside loop
$tplidx = $this->pdf->importPage($i);
$this->pdf->useTemplate($tplidx, 10, 10, 100);
// now write some text above the imported page
$this->pdf->SetFont('Arial', 'I', 40);
$this->pdf->SetTextColor(255,0,0);
$this->pdf->SetXY(25, 135);
$this->_rotate(55);
$this->pdf->Write(0, $this->wmText);
$this->_rotate(0);//<-added
}
$this->pdf->Output($newFile, 'F');
}
I moved the line $this->pdf->addPage();
into the loop, as otherwise everything is output onto one page. I also added $this->_rotate(0);
to bring the document back upright before saving it out. Pretty simple really. I have commented the changed lines for you.
I tested it on a 32 page pdf and it seemed to work fine.