5

我修改了这个堆栈问题:当用户尝试下载文件时在 pdf 文件上应用水印但我遇到了一个错误,尽管有评论说明如何修复它,但不够详细。

这是代码:

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');

当我加载一个超过 2 个的 pdf 时,所有页面都合并在一页中。我在这篇文章中附上了图片。在此处输入图像描述

谢谢。

4

3 回答 3

8

我发现该脚本有一些问题。要使其正常工作,请将doWatermark()方法更改为:-

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');
}

我将该行$this->pdf->addPage();移到循环中,否则所有内容都会输出到一页上。我还添加$this->_rotate(0);了在保存之前将文档恢复原状。真的很简单。我已经为您评论了更改后的行。

我在 32 页的 pdf 上对其进行了测试,它似乎工作正常。

于 2012-05-06T12:40:29.420 回答
2

这篇文章对我开始工作很有帮助。但我很快发现 FPDF 有一些这里的一些人一直在经历的陷阱。对我来说,我还注意到水印仅显示在某些浏览器实例的第一页上,以及通过 adobe acrobat (Acrobat X Pro) 打开它。

相反,我转而使用 TCPDF,它解决了各种问题,包括:

  • 设置角度时没有错误
  • 具有设置透明度的能力
  • 自定义字体
  • 更新功能:更新文本

要使用自定义字体,只需取消注释下面的自定义字体块 ( http://www.tcpdf.org/fonts.php )。

另外,最后要注意的是,标准 FPDI 包仅支持 PDF 版本 1.4。因此,如果您导入任何高于此值的 PDF,导入将无法正常工作并崩溃。您将需要购买商业版本 ( https://www.setasign.com/products/fpdi-pdf-parser/details/ ),或者只是将您的 PDF 保存在 1.4 版,这就是我们所做的。

这是我更新的代码:

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;
    }
}

要使用它,只需:

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());
}

无论如何,希望有一天这会对某人有所帮助!

于 2014-09-07T01:09:55.163 回答
0

如果有人想使用 FPDF 并即时创建 pdf 而不必从文件中加载它,我就是这样做的。您将使用此类而不是 FPDF 类来实例化您的 PDF 对象。这应该在 pdf 在内存中创建之后但在输出之前运行:

<?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();
    }
}
?>

我有一个名为 Document 的类,我将所有内容都放入其中以进行抽象。这是它的输出函数。我创建了一个名为“applyWaterMark”的类级别变量来控制水印是否应用于文档。

  protected function OutputDocument() {
    if($this->applyWaterMark) {
      $this->pdf->ApplyWaterMarkToAllPages();
    }    
    $this->pdf->Output();
  }
于 2020-03-31T00:23:19.633 回答