Closed JanSlabon closed 6 years ago
I'm adding this to make the issue more verbose. From the tFPDF documentation:
This class is a modified version of FPDF that adds UTF-8 support. Moreover, it embeds only the necessary parts of the fonts that are used in the document, making the file size much smaller than if the whole fonts were embedded. These features were originally developed for the mPDF project.
I would argue that UTF-8 support is an essential feature for a modern PDF library, so I hope that FPDI adds this feature.
The latest version of tFPDF is 1.25 and is based on FPDF 1.7. FPDF's latest version is 1.81. The changes made by tFPDF are substantial, so adding compatability is most likely not as simple as applying the diff between tFPDF and FPDF 1.7 to FPDF 1.81. (I'd be happy to try, but I have no knowledge of pdf / ttf, nor are there any unit tests to guide me.)
@drjayvee thanks for triggering this issue!
After all this is not a big deal but for an official implementation we need to offer a sync repository of tFPDF through packagist. I will see if we are going to set this up in the near future.
Until that: Use this simple class which brings back FPDI functionalities (not FpdfTpl) to tFPDF 1.25. Feedback is welcome!
I was looking at the 2.0 version because we want to be ready for PHP 7.2 in the near future. We're currently using FPDI v1.4, which works fine with PHP <= 7.1, but breaks in 7.2*. Under the hood though, (t)FPDF
is in dire need of modernization.
Actually, I was secretly hoping that Setasign was working towards unifying all the different PDF libs to create the one true PHP PDF library. Currently, we've got FPDI extends FPDF_TPL extends tFPDF
, which is a fork of an older version of FPDF... it's a mess! One fork supports UTF-8, another one supports templates, yet another implements rounded corners, sub/sup text, etc.
From what you're saying about offering a sync repo of tFPDF
, it sounds like you wish to keep FPDF_TPL
/ tFPDF
under the hood. Is that correct? Are there plans to refactor, modernize and combine the base libraries?
I'd be happy to help, but like I said, I'm not at all familiar with the internals.
* I got an error about use of each
, but now that I've looked at the code, there's only one call in FPDI v1.4. I'll take a look at newer versions.
hoping that Setasign was working towards [...] to create the one true PHP PDF library.
That's really in our minds and on our roadmap. Last puzzles are licensing, financing and man power/time.
From what you're saying about offering a sync repo of tFPDF
We simply need this to have it in our development process via composer (require-dev).
[...]it sounds like you wish to keep FPDF_TPL / tFPDF under the hood. Is that correct?
The features of FpdfTpl are still available in FPDI 2. But not in the given class of my previous reply for tFPDF. I omit this due to the class structure which collides here again.
Are there plans to refactor, modernize and combine the base libraries?
No. We would create a complete new state of the art library.
Currently my collegue is working on a kind of proxy class which is compatible to the interface of FPDF/FPDI but uses SetaPDF in the back, which comes with font subsetting (simliar to tFPDF but much faster and more stable/tested). If you're a SetaPDF customer this thing could be a temporary solution for you, too.
Great to hear you're working on a completely modernized library! Hals- & Beinbruch ;p
I guess we'll just wait until FPDI includes templating and UTF-8 before we upgrade to FPDI 2.x.
Thanks a lot for taking the time to reply.
This version does not work for you because of the missing features of FPDF_TPL/FpdfTpl?
We're actually not working on it but have it in mind or on our roadmap.
We do need template support added by FPDF_TPL
(importPage
, useTemplate
), so Tfpdi
won't work for us.
If you could bump up priority for template support, I'd be very grateful. I'd be happy to (beta) test once you have something working which supports templates and UTF-8.
Jeroen, if you are only using importPage()
and useTemplate()
you're ready to go! The methods beginTemplate()
and endTemplate()
of FpdfTpl
are missing. The main functionalities of FPDI are available! It's only the manual creation of templates which is actually missing.
Jan, thanks for pointing that out! This combination works fine for our requirements.
For reference, I'm now using
composer require setasign/fpdi
)class PDF extends Tfpdi {
public function getAsString () {
return $this->buffer;
}
/**
* Draw rectangle with rouded corners
*
* @author Christophe Prugnaud
* @link http://www.fpdf.org/en/script/script35.php
*
* @param int $x x
* @param int $y y
* @param int $w width
* @param int $h height
* @param int $r radius
* @param string $style
* @param string $corners numbers of the corners to be rounded: 1, 2, 3, 4 or any combination (1=top left, 2=top right, 3=bottom right, 4=bottom left).
*/
public function RoundedRect ($x, $y, $w, $h, $r, $style = '', $corners = '1234') {
$k = $this->k;
$hp = $this->h;
if ($style == 'F')
$op = 'f';
elseif ($style == 'FD' || $style == 'DF')
$op = 'B';
else
$op = 'S';
$MyArc = 4 / 3 * (sqrt(2) - 1);
$this->_out(sprintf('%.2F %.2F m', ($x + $r) * $k, ($hp - $y) * $k));
$xc = $x + $w - $r;
$yc = $y + $r;
$this->_out(sprintf('%.2F %.2F l', $xc * $k, ($hp - $y) * $k));
if (strpos($corners, '2') === false)
$this->_out(sprintf('%.2F %.2F l', ($x + $w) * $k, ($hp - $y) * $k));
else
$this->_Arc($xc + $r * $MyArc, $yc - $r, $xc + $r, $yc - $r * $MyArc, $xc + $r, $yc);
$xc = $x + $w - $r;
$yc = $y + $h - $r;
$this->_out(sprintf('%.2F %.2F l', ($x + $w) * $k, ($hp - $yc) * $k));
if (strpos($corners, '3') === false)
$this->_out(sprintf('%.2F %.2F l', ($x + $w) * $k, ($hp - ($y + $h)) * $k));
else
$this->_Arc($xc + $r, $yc + $r * $MyArc, $xc + $r * $MyArc, $yc + $r, $xc, $yc + $r);
$xc = $x + $r;
$yc = $y + $h - $r;
$this->_out(sprintf('%.2F %.2F l', $xc * $k, ($hp - ($y + $h)) * $k));
if (strpos($corners, '4') === false)
$this->_out(sprintf('%.2F %.2F l', ($x) * $k, ($hp - ($y + $h)) * $k));
else
$this->_Arc($xc - $r * $MyArc, $yc + $r, $xc - $r, $yc + $r * $MyArc, $xc - $r, $yc);
$xc = $x + $r;
$yc = $y + $r;
$this->_out(sprintf('%.2F %.2F l', ($x) * $k, ($hp - $yc) * $k));
if (strpos($corners, '1') === false) {
$this->_out(sprintf('%.2F %.2F l', ($x) * $k, ($hp - $y) * $k));
$this->_out(sprintf('%.2F %.2F l', ($x + $r) * $k, ($hp - $y) * $k));
} else
$this->_Arc($xc - $r, $yc - $r * $MyArc, $xc - $r * $MyArc, $yc - $r, $xc, $yc - $r);
$this->_out($op);
}
protected function _Arc ($x1, $y1, $x2, $y2, $x3, $y3) {
$h = $this->h;
$this->_out(sprintf('%.2F %.2F %.2F %.2F %.2F %.2F c ', $x1 * $this->k, ($h - $y1) * $this->k,
$x2 * $this->k, ($h - $y2) * $this->k, $x3 * $this->k, ($h - $y3) * $this->k));
}
/**
* This function properly handles <sub>, <sup> tags in strings.
* And prints the string on current x,y coordinates on this pdf.
*
* @param string $string might contain sub/sup tags
*/
public function printSubSupString ( $string ) {
if ( strstr($string, '<sup>') || strstr($string, '<sub>') ) {
for( $i=0; $i<strlen($string); $i++ ) {
if ( $string[$i] === '<' ) {
if ( substr($string, $i, 5) === '<sub>' ) {
$textPart = substr($string, $i+5, strpos($string, '</su', $i)-($i+5) );
$this->subSupWrite(5, $textPart, '', 7, -4 );
$i = strpos($string, '</su', $i)+5;
} elseif ( substr($string, $i, 5) === '<sup>' ) {
$textPart = substr($string, $i+5, (strpos($string, '</su', $i)-($i+5)) );
$this->subSupWrite(5, $textPart, '', 7, 4 );
$i = strpos($string, '</su', $i)+5;
}
} else {
$char = mb_substr( $string, $i, 1 ); // ensure $char can contain multibyte chars
$this->Write(5, $char );
}
}
} else {
$this->Write(5, $string );
}
}
/**
* Output sub or sup text
*
* @link http://www.fpdf.org/en/script/script61.php
* @author Wirus
*
* @param int $h height
* @param string $txt text
* @param string $link link
* @param int $subFontSize fontSize
* @param int $subOffset offset, >0 for sup, <0 for sub.
* (4 is suggested as default offset)
*/
public function subSupWrite ( $h, $txt, $link='', $subFontSize=12, $subOffset=0 ) {
// resize font
$subFontSizeold = $this->FontSizePt;
$this->SetFontSize($subFontSize);
// reposition y
$subOffset = ((($subFontSize - $subFontSizeold) / $this->k) * 0.3) + ($subOffset / $this->k);
$subX = $this->x;
$subY = $this->y;
$this->SetXY( $subX, ($subY - $subOffset) );
//Output text
$this->Write( $h, $txt, $link );
// restore y position
$subX = $this->x;
$subY = $this->y;
$this->SetXY( $subX, ($subY + $subOffset) );
// restore font size
$this->SetFontSize( $subFontSizeold );
}
/*
* ensure $txt is string
*/
public function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='') {
parent::Cell($w, $h, (string)$txt, $border, $ln, $align, $fill, $link);
}
function Error($msg) {
throw new \Exception($msg);
}
}
I'd love to add these to Fpdi through a PR. Interested?
Thanks for the PR offer but these this has nothing to do with FPDI and should be implemented individually in an extending class. We leave this issue open until tFPDF support is available by default.
Very well!
I'll give the new version FPDI a spin once tFPDF support is available.
Thanks so much for your time and advice!
On Fri, Jun 8, 2018 at 3:33 PM, Jan Slabon notifications@github.com wrote:
Thanks for the PR offer but these this has nothing to do with FPDI and should be implemented individually in an extending class. We leave this issue open until tFPDF support is available by default.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/Setasign/FPDI/issues/27#issuecomment-395762040, or mute the thread https://github.com/notifications/unsubscribe-auth/AC7-yyDTMlwN7e5rZr3x4N_YcIf1Y4eMks5t6n0rgaJpZM4P8Sry .
There is an unofficial composer package of tFPDF.
@JanSlabon I only use importPage()
and useTemplate()
. So I will try updating to the new version of FPDI using your workaround. Thanks.
Worth mentioning. There seems to be an alternative to tFPDF called TCPDF, which is supported by FPDI by using the class \setasign\Fpdi\TcpdfFpdi
. Feature-wise, I don't know the difference between tFPDF and TCPDF, but they both seem to support UTF-8 and font subsetting.
This unofficial repo is far away from the official release. Feel free to use the POC I mentioned some posts above. There will be a simliar official solution as we have for TCPDF.
@JanSlabon thank you for the workaround. But how do you actually include the tFPDF package? As you already mentioned, there exists no repository of tFPDF through packagist. I have problems with the unoffical tFPDF package mentioned from MartinMa, because for some reason all function names have been renamed, so this won't work with old scripts.
Your class starts with class Tfpdi extends \tFPDF
so I assume you include it with composer autoload? I tried that too, but its not working, see https://stackoverflow.com/questions/51388856/adding-tfpdf-class-with-composer
Looking forward to a solution since I need UTF-8 and I need to import a PDF. Thanks for your help !
You shall never add any foreign package to the vendor folder!
Just create your own library folder and place tFPDF in there and require it when you need it. You may call it "legacy style" but it works, too ;-)
@JanSlabon okay I managed to include the tFPDF package with composer as explained here.
I added your workaround package in the folder vendor/setasign/fpdi/src/
. Then I tried to import with that class only one template like this:
$pdf->AddPage('L');
$pdf->setSourceFile(storage_path('app/templates/plain_certificate_sh_v12.pdf'));
$templateId = $pdf->importPage(1);
$pdf->useTemplate($templateId, ['adjustPageSize' => true]);
But I get the error
Call to undefined method setasign\Fpdi\Tfpdi::setPageFormat()
Am I doing anything wrong here?
Edit: Whoups didn't see you answer! Thank you for the quick response! I will put it the folder outside vendor then.
Ok, the POC has some missing features :-)
Change your code to:
$pdf->setSourceFile(storage_path('app/templates/plain_certificate_sh_v12.pdf'));
$templateId = $pdf->importPage(1);
$size = $pdf->getTemplateSize($templateId);
$pdf->AddPage($size['orientation'], $size);
$pdf->useTemplate($templateId);
@JanSlabon Thank you! That worked :)!!!
We just added a clone repository of tFPDF and added support for it in FPDIs "dev-master"-branch. Could you please test it?
We also created a metadata package. So installing it via composer this way:
"require": {
"setasign/fpdi": "dev-master as 2.1",
"setasign/fpdi-tfpdf": "^2.1"
}
Feedback is welcome!
Implemented and new release 2.1 will support tFPDF by default.
Thanks a lot! Didn't had the time to test yet. Will try this weekend. The workaround, however, worked perfectly. So I guess this will be just fine, too.
Great, this (setasign\Fpdi\Tfpdf\Fpdi
) works out of the box for us!
Does "2.1 will support tFPDF by default" mean users won't have to add an additional dependency (setasign/fpdi-tfpdf
)? I would very much encourage that, for reasons that I've outlined above. :)
Does "2.1 will support tFPDF by default" mean users won't have to add an additional dependency (setasign/fpdi-tfpdf)?
No. It's the other way round: Remove the dependency setasign/fpdi
but use setasign/fpdi-tfpdf
directly to evaluate the dependencies between tFPDF and FPDI. FPDI itself can be used with 3 different things now (FPDF, TCPDF, tFPDF). It wouldn't make sense to setup the dependency in FPDI then.
Oh, I see now.
The problem I see is that many new users may assume FPDI supports UTF-8 by default and won't know they need tFPDF until they run into problems. Therefore, I would propose to make that functionality built-in by default.
Anyway, the new setup is already a lot more user-friendly, for which I'm grateful!
On Wed, Sep 19, 2018 at 4:11 PM Jan Slabon notifications@github.com wrote:
Does "2.1 will support tFPDF by default" mean users won't have to add an additional dependency (setasign/fpdi-tfpdf)?
No. It's the other way round: Remove the dependency setasign/fpdi but use setasign/fpdi-tfpdf directly to evaluate the dependencies between tFPDF and FPDI. FPDI itself can be used with 3 different things now (FPDF, TCPDF, tFPDF). It wouldn't make sense to setup the dependency in FPDI then.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/Setasign/FPDI/issues/27#issuecomment-422819076, or mute the thread https://github.com/notifications/unsubscribe-auth/AC7-y-eFprCdow3oKRviikLd04V5azruks5uclCCgaJpZM4P8Sry .
FPDI comes not with a single method which would allow you to write text. Why should anybody think that it supports UTF-8 by default then?
Oh really! :D I guess I'm confused then, sorry about that!
Between tFPDF
, FPDI
, FPDF_TPL
, TCPDF
, there are so many names (classes/packages/extensions/???) that I don't know which does what.
I would hope that one day there's a PDF library that has all the functionality (templates, UTF-8 support with font subsetting, etc) incorporated. Maybe that's a pipe dream.
For now, fpdi-tfpdf
is exactly what we need, so thanks again for that.
@iwasherefirst2 Feel free to open a new issue and provide all required details so that we are able to reproduce your issue and please do not highjack already closed issues. "setasign/fpdi-tfpdf" is a dependency in your composer.json and for sure not a class name!
Currently FPDI v2 cannot be used with tFPDF.
Also overwrite the Output() method to be compatible with FPDF 1.81.