FPDI/FPDF: Watermark and Print Multiple Pages
Solution 1
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.
Solution 2
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:
- No errors when setting angles
- Having ability to set transparency
- Custom fonts
- Updated Feature: Updating the text
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!
Mr A
Updated on March 31, 2020Comments
-
Mr A about 4 years
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 fix it, it wasn't elaborate enough.
Here is the code:
require_once('fpdf/fpdf.php'); require_once('fpdi/fpdi.php'); class WaterMark { public $pdf, $file, $newFile, $wmText = "STACKOVERFLOW"; /** $file and $newFile have to include the full path. */ public function __construct($file, $newFile) { $this->pdf = new FPDI(); $this->file = $file; $this->newFile = $newFile; } /** $file and $newFile have to include the full path. */ public static function applyAndSpit($file, $newFile) { $wm = new WaterMark($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; $this->pdf->addPage(); $pagecount = $this->pdf->setSourceFile($currentFile); for($i = 1; $i <= $pagecount; $i++){ $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->pdf->Output($newFile, 'F'); } public function isWaterMarked() { return (file_exists($this->newFile)); } public function spitWaterMarked() { 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)); } } } header('Content-type: application/pdf'); //header('Content-Disposition: attachment; filename="downloaded.pdf"'); WaterMark::applyAndSpit('C:\xampp\htdocs\tst\test0.pdf','C:\xampp\htdocs\tst\output0.pdf');
When I load a pdf that has more than 2 all of the pages merges in one page. I attached the image in this post.
Thanks.
-
Mr A about 12 yearsAny idea on how to set the transparency? I got changed the values that is similar to this but didn't got any result. fpdf.org/en/script/script9.php
-
vascowhite about 12 yearsThat's not transparent, just a pale colour and they've cheated by putting in the watermark first, then putting the page text on top of that. fpdf.org/en/script/watermark.pdf
-
Steve Smith over 11 yearsHas anyone not noticed that on acrobat reader for PC if the text is at an angle then the whole pdf bugs out. Does anyone have a workaround for this?See my question stackoverflow.com/questions/13069104/…
-
Iman over 9 yearsHelped me. You are a life saver!
-
Elton da Costa over 9 yearsHelped me. You are a life saver! ² =)
-
Aaron Marton about 6 yearsGreat help! Although I needed to modify the fontFamily usage, had to remove SetPrintHeader() and SetPrintFooter() because they are no longer included in TCPDF.
-
Aaron Marton about 6 years@yogibear, useTemplate($tplidx, null, null, 0, 0, true); doesn't work with 0 values for width and height, so I had to pass the dynamically obtained width and height values, with "false" as the last argument to the useTemplate() method. The way it worked for me was: $this->pdf->useTemplate($tplidx, null, null, $specs['width'], $specs['height'], false);
-
Russell Mazonde over 5 yearsNot sure if anyone is still interested but I achieved the transparency effect i wanted using the following approach:
$this->pdf->SetAlpha(0.1);
$this->pdf->StartTransform();
$this->pdf->Rotate(45, $watermarkXCord, $watermarkYCord);
$this->pdf->SetFont("", "", 120);
$this->pdf->Text($watermarkXCord, $watermarkYCord, $this->watermarkAttribute);
$this->pdf->StopTransform();
$this->pdf->SetAlpha(1);