FPDI Output File Size - php

I am using FPDF and FPDI to extract 2 pages from a pdf document that is generally about 28 pages long. The pdf files are basically a page with an image filling each page entirely and are around 35-40mb.
When using FPDI to extract the last 2 pages from the full document and create a new file, the file size of the new 2 page file remains almost the same. Any ideas why this might be?
Here is the basic code used to do the extracting:
public function extractPagesFromFile($file, $outputFileName, $numPages = 2) {
$pageCount = $this->_fpdf->setSourceFile($file);
if ($numPages < 0 || $numPages > $pageCount) {
return false;
}
for ($pageNo = $pageCount - $numPages + 1; $pageNo < $pageCount + 1; $pageNo++) {
$tplIdx = $this->_fpdf->ImportPage($pageNo);
if (!isset($s)) {
$s = $this->_fpdf->getTemplatesize($tplIdx);
}
$this->_fpdf->AddPage($s['w'] > $s['h'] ? 'L' : 'P', array($s['w'], $s['h']));
$this->_fpdf->useTemplate($tplIdx);
}
$this->_fpdf->Output('F', $outputFileName);
$this->_fpdf->cleanUp();
}

FPDI copies all resources of a page. I guess that all images in your file are located in a single resource dictionary. Because of this all of them will be copied. This is a common issue when extracting pages from existing PDF documents. Without parsing and interpreting the pages content stream it is impossible to know which resources should be copied or not. There's no solution with/for FPDI atm.
Anyhow we (Setasign) offer other non-free PHP components, such as the SetaPDF-Merger, that work on a lower level and for which we'd build a demo that fixes this behaviour.

Related

Style & layout is not copied while creating new pptx from pptx in PHPPresentation

I want to split slides of one pptx file into seperated pptx files, containing one slide each. The content/text is copied but the layout & styling is not copied. Here is the code.
Can anyone please help ?
<?php
use PhpOffice\PhpPresentation\PhpPresentation;
use PhpOffice\PhpPresentation\IOFactory;
use PhpOffice\PhpPresentation\Style\Color;
use PhpOffice\PhpPresentation\Style\Alignment;
use PhpOffice\PhpPresentation\Slide\SlideLayout;
$objReader = \PhpOffice\PhpPresentation\IOFactory::createReader('PowerPoint2007');
$objPHPPowerPoint = $objReader->load('a.pptx');
$totalSlides = $objPHPPowerPoint->getSlideCount();
$oMasterSlide = $objPHPPowerPoint->getAllMasterSlides()[0];
$documentProperties = $objPHPPowerPoint->getDocumentProperties();
for ( $count = 0; $count < $totalSlides; $count++ ) {
$objPHPPresentation = new PhpPresentation();
$slide = $objPHPPowerPoint->getSlide( $count );
$background = $slide->getBackground();
$newSlide = $objPHPPresentation->addSlide( $slide );
$newSlide->setBackground ( $background );
$objPHPPresentation->setAllMasterSlides( $oMasterSlide );
$objPHPPresentation->removeSlideByIndex(0);
$oWriterPPTX = \PhpOffice\PhpPresentation\IOFactory::createWriter($objPHPPresentation, 'PowerPoint2007');
$oWriterPPTX->save($count.'.pptx');
}
I don't think it's an issue with your code - more an issue with the underlying libraries - as mentioned here: PhpPresentation imagecreatefromstring(): Data is not in a recognized format - PHP7.2
It ran a test to see if it was something I could replicate - and I was able to. The key difference in my test was in one presentation I had a simple background, and in the other it was a gradient.
This slide caused problems:
But this one was copied over fine:
With the more complex background I got errors like:
PHP Warning: imagecreatefromstring(): Data is not in a recognized format
My code is even less complicated than yours, I just clone the original slideshow and remove all except a single slide before saving it:
for ( $count = 0; $count < $totalSlides; $count++ ) {
$copyVersion = clone $objPHPPowerPoint;
foreach ($copyVersion->getAllSlides() as $index => $slide) {
if ($index !== $count) {
$copyVersion->removeSlideByIndex($index);
}
}
$oWriterPPTX = \PhpOffice\PhpPresentation\IOFactory::createWriter($copyVersion, 'PowerPoint2007');
$oWriterPPTX->save($count.'.pptx');
}
Sorry if this doesn't exactly solve your problem, but hopefully it can help identify why it's happening. The other answer I linked to has more information about finding unsupported images types in your slides.
You can try using Aspose.Slides Cloud SDK for PHP to split a presentation into separate slides and save them to many formats. You can evaluate this REST-based API making 150 free API calls per month for API learning and presentation processing. The following code example shows you how to split a presentation and save slides to PPTX format using Aspose.Slides Cloud:
use Aspose\Slides\Cloud\Sdk\Api\Configuration;
use Aspose\Slides\Cloud\Sdk\Api\SlidesApi;
use Aspose\Slides\Cloud\Sdk\Model;
$configuration = new Configuration();
$configuration->setAppSid("my_client_id");
$configuration->setAppKey("my_client_key");
$slidesApi = new SlidesApi(null, $configuration);
$filePath = "example.pptx";
// Upload the file to the default storage.
$fileStream = fopen($filePath, 'r');
$slidesApi->uploadFile($filePath, $fileStream);
// Split the file and save the slides in PPTX format in the same folder.
$response = $slidesApi->split($filePath, null, Model\SlideExportFormat::PPTX);
// Download files of the slides.
foreach($response->getSlides() as $slide) {
$slideFilePath = pathinfo($slide->getHref())["basename"];
$slideFile = $slidesApi->downloadFile($slideFilePath);
echo $slideFile->getRealPath(), "\r\n";
}
Sometimes it is necessary to split a presentation without using any code. In this case, you can use Online PowerPoint Splitter.
I work as a Support Developer at Aspose.

Insert stored PDF files from database (MySQL) into MPDF Output

Is there a way to import pdf files which stored in database into mpdf class instance?
As for now i can use import for certain page from file only like shown below.
$mpdf->SetImportUse();
$pagecount = $mpdf->SetSourceFile('testfile.pdf');
$tplId = $mpdf->ImportPage($pagecount, 50, 50, 100, 100);
$mpdf->UseTemplate($tplId, '', '', 100, 100);
$mpdf->Output();
But what if I want to import from pdf which saved in database?
Thanks for helping.
Reading large files from a database is a bad idea, you'll find storing them somewhere on the file-system to be much faster. But, any file stored in the database should be stored in its' original form (possibly base64 encoded). Pretend the value you get from the database is the return from fread() and it should work fine.
Little bit later, but maybe this help somebody else.
With MPDF 8 and later:
Method SetSourceFile accept string (filename) OR StreamReader. The StreamReader can be created from file OR from string.
So your code will looks like:
// $mpdf->SetImportUse(); is not supported in MPDF 8
$data = ''; // your data, NOT base64
$pagecount = $mpdf->SetSourceFile(\setasign\Fpdi\PdfParser\StreamReader::createByString($data));
for ($i=1; $i<=$pagecount; $i++) {
$import_page = $mpdf->ImportPage($i, 50, 50, 100, 100); // OR just: $import_page = $mpdf->ImportPage($i);
$mpdf->UseTemplate($import_page);
if ($i < $pagecount) {
$mpdf->AddPage();
}
}
$mpdf->Output();
Note:
You can always call WriteHTML before or after or inside for cycle.

PHP - FPDI - Can't Write to more than One Page

The problem is, I need to write data to several copies of the same imported pdf file, and save it as one pdf. I can write data to one page just fine, but when I try to write to more than one, or even continue text (using SetAutoPageBreak()), it simply stops writing once it hits the next page. Although, if I add an arbitrary loop to write more data, the resulting pdf's number of pages is increased to accommodate the added data, but the pages beyond the first are still blank. I have simplified what I'm trying to do into a smaller example to illustrate the issue:
public function actionSample() {
$pdf = new FPDI();
$pdf->AcceptPageBreak();
$pdf->SetAutoPageBreak(true, 30);
$pagecount = $pdf->setSourceFile('images/sample.pdf');
for ($i = 1; $i <= $pagecount; $i++) {
$pdf->AddPage();
$tplidx = $pdf->ImportPage($i);
$pdf->useTemplate($tplidx, 10, 10, 200);
$s = $pdf->getTemplatesize($tplidx);
$pdf->SetTextColor(32,32,32);
$pdf->SetFontSize(10);
$pdf->SetXY($pdf->getX(), $pdf->getY()+10);
$pdf->Write(2, 'This is not!');
}
$pdf->Output('Sample.pdf', 'D');
}
The sample document has 3 blank pages initially. (I did this to make it easier to see what was being written)
$pdf->AddPage();
you have to just put this piece of code inside for loop near closing braces.
All the best..!!

Using FPDI and FDP to generate slightly different pdf files

i first import a pdf using fpdi to make a fpdf object, i then perform several changes on that pdf. I clone it to make a custom pdf just adding some texts. Then i output the two files to disk but just one is created and i got a fatal error for the second output :
Fatal error: Call to undefined method stdClass::closeFile() in C:\Program Files\EasyPHP 3.0\www\oursin\oursin\public\scripts\FPDI\fpdi.php on line 534
pieces of my code:
$pdf = new FPDI('L','mm',array(291.6,456));
$fichier=$repertoireGrilles.'GR_IFR.pdf';
$pdf->setSourceFile($fichier);
// add a page
$tplIdx = $pdf->importPage(1);
$pdf->AddPage();
$pdf->useTemplate($tplIdx,0,0,0);
..
...
methods on $pdf
..
..
..
$pdfCopie=clone $pdf;
methods on $pdfCopie
$pdfCopie-> Output($repertoireGrilles.'grillesQuotidiennes/'.$date.'/Grille_'.$date.'_'.$ou.'_copie.pdf','F');
$pdf-> Output($repertoireGrilles.'grillesQuotidiennes/'.$date.'/Grille_'.$date.'_'.$ou.'.pdf','F');
Anybody to help me to tackle this issue that keeps my brain under high pressure for hours (days) :) ?
Cloning, forking, copying, any of that is really dirty. You will have a very hard time with outputs if you take that route. Instead, consider this approach:
Make multiple AJAX calls to a single PHP file, pass a pid value to it so as to differentiate between them.
Go through the exact same document setup for FPDI. This is far more consistent than cloning, forking, copying, etc.
Check pid and do different things to different documents after all the setup is done.
Output the documents.
Here is my jQuery:
$(document).ready(function(){
var i;
for( i=0; i<=1; i++ )
{
$.ajax({
url: 'pdfpid.php',
data: {
pid: i,
pdf: 'document.pdf'
},
type: 'post'
});
}
});
As you can see, it's pretty simple. pdfpid.php is the name of the file that will generate and process the documents. In this case, I want the document with a pid of 0 to be my "original" and the one with a pid of 1 to be the "cloned" document.
// Ensure that POST came in correctly
if( !array_key_exists('pid',$_POST) || !array_key_exists('pdf',$_POST) )
exit();
// Populate necessary variables from $_POST
$pid = intval($_POST['pid']);
$src = $_POST['pdf'];
// Setup the PDF document
$pdf = new FPDI();
$pdf->setSourceFile($src);
$templateID = $pdf->importPage(1);
$pdf->addPage();
$pdf->useTemplate($templateID);
$pdf->SetFont('Arial','B',24);
switch( $pid )
{
default:
break;
case 0:
// "Parent" document
$pdf->Text(10,10,"ORIGINAL");
$filename = "original.pdf";
break;
case 1:
// "Child" document
$pdf->Text(10,10,"CLONED");
$filename = "cloned.pdf";
break;
}
$pdf->Output($filename,'F');
I got both documents as an output, with the unique modifications between the "parent" and the "child" all in place.

VIew files in directory with pagination - php

I want to display files in my directory in browser. I know that this is possible using #opendir and readdir .. But what I want is to limit the number of files in the list to a specific number and display next using pagination.
You could use scandir to read all the contents of the directory into an array. Then output the contents of the array based on the pagination value.
$offset = 10; //get this as input from the user, probably as a GET from a link
$quantity = 10; //number of items to display
$filelist = scandir('/mydir');
//get subset of file array
$selectedFiles = array_slice($filelist, $offset-1, $quantity);
//output appropriate items
foreach($selectedFiles as $file)
{
echo '<div class="file">'.$file.'</div>';
}
Cross-posting an example (also in this question) --
DirectoryIterator and LimitIterator are my new best friends, although glob seems to prefilter more easily. You could also write a custom FilterIterator. Needs PHP > 5.1, I think.
No prefilter:
$dir_iterator = new DirectoryIterator($dir);
$paginated = new LimitIterator($dir_iterator, $page * $perpage, $perpage);
Glob prefilter:
$dir_glob = $dir . '/*.{jpg,gif,png}';
$dir_iterator = new ArrayObject(glob($dir_glob, GLOB_BRACE));
$dir_iterator = $dir_iterator->getIterator();
$paginated = new LimitIterator($dir_iterator, $page * $perpage, $perpage);
Then, do your thing:
foreach ($paginated as $file) { ... }
Note that in the case of the DirectoryIterator example, $file will be an instance of SplFileInfo, whereas glob example is just the disk path.
Depends on how you want to go about it. There are a ton of javascript/jquery pagination libraries out there .. just google "Javascript pagination."
If javascript is not an option or if you would prefer to just use php, then it should be relatively simple.
Use opendir/readdir to get a list of all the files. Set up however many you want for display. Divide the remainder by this number to get the number of pages. Then take a slice from the array of the (page - 1) * (number to list) up to (number to list). These are the files you will show. Pass the page number through get/post. If it's too high, then use the last page, too low or non-numeric, use the first page.
For pagination, you can use Zend_Paginator.
Once you get list of files in the directory, you only configure the paginator and it will take care of the rest.
Maybe something like this?
$page = 1;
$resultsPerPage = 10;
$files = array();
while(($obj = readdir($dir))) {
$files[] = $obj;
}
$limit = $page * $resultsPerPage;
($limit > count($files)) ? $limit = count($files) : $limit = $limit;
for($i = ($limit - $resultsPerPage); $i < $limit; $i++) {
echo($files[$i];
}
And then have your nav buttons modify the page number.
you should try YUI 2 pagination and maybe if you want to display the file in a table use the datatable there are a very usefull components from yahoo user interface
greetings

Categories