Fit Pages
This demo shows how to adjust the format of all pages in a document.
Thereby the original page is going to get scaled and centered, so that it fits into the new format.
For demonstration purpose the original document is created from scratch to show or test the behavior.
PHP
<?php // load and register the autoload function require_once __DIR__ . '/../../../../../bootstrap.php'; // create a string writer for a temporary result $writer = new \SetaPDF_Core_Writer_String(); // create a document $document = new \SetaPDF_Core_Document($writer); // the wanted format $wantedFormat = [200, 100]; // get the pages helper $pages = $document->getCatalog()->getPages(); // create a new font $font = \SetaPDF_Core_Font_Standard_Courier::create($document); // create an array with different formats $formats = [ [ // 1 \SetaPDF_Core_PageFormats::A4, "A4\n" . \SetaPDF_Core_PageFormats::A4, 0, 70, ], [ // 2 [100, 100, 0, 0], "100x100\n100,100,0,0", 90, 10, ], [ // 3 [0, 0, 200, 200], "200x200\n0,0,200,200", 90, 10, ], [ // 4 [-200, -700, 200, 700], "400x1400\n-200,-700,200,700", 90, 30, ], [ // 5 [10, 50, 210, 550], "200x500\n10,50,210,550", 90, 20, ], [ // 6 [-210, -550, -10, -50], "200x500\n-210,-550,-10,-50", -90, 15, ], [ // 7 [-10, -50, -210, -550], "200x500\n-10,-50,-210,-550", 270, 15, ], [ // 8 [-100, 100, -200, -100], "100x200\n-100,100,-200,-100", 360, 7, ], [ // 9 [2000, 5000, 4000, 2000], "2000x3000\n2000,5000,4000,2000", 180, 150, ], [ // 10 [50, 10, 550, 210], "500x200\n50,10,550,210", 0, 50, ], [ // 11 [2000, -3900, 2500, -3000], "500x900\n2000,-3900,2500,-3000", 0, 30, ] ]; // create the pages foreach ($formats as $formatArray) { list($format, $formatName, $rotation, $fontSize) = $formatArray; // create a new page with the given format $page = $pages->create($format); // set the rotation $page->setRotation($rotation); // get the canvas $canvas = $page->getCanvas(); // set the line width $canvas->path()->setLineWidth(10); // draw a rectangle around the page $canvas->draw()->rect( $page->getCropBox()->llx + 5, $page->getCropBox()->lly + 5, $page->getCropBox()->urx - $page->getCropBox()->llx - 10, $page->getCropBox()->ury - $page->getCropBox()->lly - 10 ); // create a new text block $text = new \SetaPDF_Core_Text_Block($font, $fontSize); // set the align $text->setAlign(\SetaPDF_Core_Text::ALIGN_CENTER); // set the text of the text block $text->setText($formatName); // draw the text in the center $x = ($page->getCropBox()->getUrx() - $page->getCropBox()->getWidth() / 2) - $text->getWidth() / 2; $y = ($page->getCropBox()->getUry() - $page->getCropBox()->getHeight() / 2) - $text->getHeight() / 2; $text->draw($canvas, $x, $y); // create an annotation for demonstration purpose $annotation = new \SetaPDF_Core_Document_Page_Annotation_Square( [$x, $y, $x + $text->getWidth(), $y + $text->getHeight()] ); // set the color of the annotation $annotation->setColor([0, 1, .2]); // add the annotation to the page $page->getAnnotations()->add($annotation); } // save and finish the temporary document $document->save()->finish(); // transfer the document into a new instance $fittedDocument = \SetaPDF_Core_Document::load( new \SetaPDF_Core_Reader_String($writer), new \SetaPDF_Core_Writer_Http('fit.pdf', true) ); // get the pages object $pages = $fittedDocument->getCatalog()->getPages(); // get the page count $pageCount = $pages->count(); // iterate through all pages for ($pageNumber = 1; $pageNumber <= $pageCount; $pageNumber++) { // get the page object $page = $pages->getPage($pageNumber); // sanitize the current page format $format = \SetaPDF_Core_PageFormats::getFormat($page->getWidthAndHeight(), \SetaPDF_Core_PageFormats::ORIENTATION_AUTO); // check if the format of the current page is the desired format if (\SetaPDF_Core_PageFormats::is($wantedFormat, $format)) { continue; } // determine the orientation of the page $orientation = $page->getOrientation(); // align the wanted format to the page orientation $wantedFormatArray = \SetaPDF_Core_PageFormats::getFormat($wantedFormat, $orientation); // check if the page is rotated $rotated = ($page->getRotation() / 90) % 2; // calculate the scale factors $scaleX = $wantedFormatArray['width'] / $format['width']; $scaleY = $wantedFormatArray['height'] / $format['height']; // switch scale values if the page is rotated if ($rotated) { list($scaleX, $scaleY) = [$scaleY, $scaleX]; } // take the smaller value as the scaling factor $scale = min($scaleX, $scaleY); // let's scale the page content $canvas = $page->getCanvas(); $contents = $page->getContents(); // we add a separate content stream before the existing stream $stream = $contents->prependStream(true); // save the graphic state $canvas->saveGraphicState(); // get the old boundary $cropBox = $page->getBoundary(); // calculate the scaling $rect = new \SetaPDF_Core_Geometry_Rectangle( $cropBox->getLlx() * $scale, $cropBox->getLly() * $scale, $cropBox->getUrx() * $scale, $cropBox->getUry() * $scale ); // calculate the values for centering $centerX = ($wantedFormatArray['width'] - (!$rotated ? $rect->getWidth() : $rect->getHeight())) / 2; $centerY = ($wantedFormatArray['height'] - (!$rotated ? $rect->getHeight() : $rect->getWidth())) / 2; // switch scale values if page is rotated if ($rotated) { list($centerX, $centerY) = [$centerY, $centerX]; } // calculate the shift that is caused by the scale and add the centering value $translateX = $cropBox->getLlx() - $rect->getLl()->getX() + $centerX; $translateY = $cropBox->getLly() - $rect->getLl()->getY() + $centerY; // let's translate the canvas $canvas->translate($translateX, $translateY); // let's scale $canvas->scale($scale, $scale); // append a closing content stream $stream = $contents->pushStream(true); // and restore the opened graphic state $canvas->restoreGraphicState(); // let's adjust the boundary boxes $boxes = \SetaPDF_Core_PageBoundaries::$all; // reverse the boxes order to pass valid boxes to the page if ($scale < 1) { $boxes = array_reverse($boxes); } // iterate through all possible boundaries foreach ($boxes AS $boxName) { $_box = $page->getBoundary($boxName, false, true); if ($_box === false) { continue; } // create a new boundary box $box = \SetaPDF_Core_DataStructure_Rectangle::byArray( [ $_box->getLlx(), $_box->getLly(), $_box->getUrx() * $scaleX + ($_box->getLlx() - ($_box->getLlx() * $scaleX )), $_box->getUry() * $scaleY + ($_box->getLly() - ($_box->getLly() * $scaleY )) ] ); // reset the boundary box $page->setBoundary($box, $boxName, false); } // now we adjust the coords of all annotation objects $annotations = $page->getAnnotations(); $all = $annotations->getAll(); foreach ($all AS $annotation) { $dict = $annotation->getDictionary(); // the size of a popup annotation has to be handled individually // we just use the scale and translate values which were calculated before if ($annotation instanceof \SetaPDF_Core_Document_Page_Annotation_Popup) { $_rect = $annotation->getRect(); $rect = \SetaPDF_Core_DataStructure_Rectangle::byArray([ $_rect->getLlx() * $scale + $translateX, $_rect->getLly() * $scale + $translateY + $_rect->getHeight(), $_rect->getLlx() * $scale + $translateX + $_rect->getWidth(), $_rect->getUry() * $scale + $translateY ]); $dict['Rect'] = $rect->getValue(); continue; } $_rect = $annotation->getRect(); $rect = \SetaPDF_Core_DataStructure_Rectangle::byArray([ $_rect->getLlx() * $scale + $translateX, $_rect->getLly() * $scale + $translateY, $_rect->getUrx() * $scale + $translateX, $_rect->getUry() * $scale + $translateY ]); $dict['Rect'] = $rect->getValue(); } } // save the document $fittedDocument->save()->finish();