I'm converting PDFs to JPEGs and I can't get setImageScene to work.
I've tried calling it before readImage and after readImage. It has no effect on the numbering of the files.
Can someone provide a working example?
Thanks
It doesn't look setImageScene works. It's really easy to number files yourself though.
$imagick = new Imagick("./LayerTest.psd");
$pageNumber = 200;
foreach ($imagick as $subImage) {
$filename = "./output_$pageNumber.png";
$subImage->setImageFormat('png');
$subImage->writeImage($filename);
$pageNumber++;
}
Related
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.
First of all I would like to mention that I'm a complete noob in php and since I'm playing around with wordpress based websites I started fiddling with PHP code. I have absolutely no background in php and most of my knowledge comes from reading code and using php.net reference to undestand the causal relationships and generally what is happening.
I have come up with a solution for a problem that I have, however I feel that solution is ugly and could be optimized to be more readable and more efficient. I'm asking this question primarily as mean to learn from the answers, so if you honor me with a reply it will be greatly appreciated if you throw in a few lines of argumentation as to why this optimization is viable.
The goal of the code is to take the contents of $image_path which is just a filename of an image that has either jpg, jpeg or png file extension and rewrite that filename by adding -200x100 just before the extension(foo.jpg turns into foo-200x100.jpg). Here is the code I came up with:
if (strpos($image_path, '.jpeg')) {
$image_thumb = substr_replace($image_path, '-200x100.jpeg', strpos($image_path, '.jpeg'));
}
elseif (strpos($image_path, '.jpg')) {
$image_thumb = substr_replace($image_path, '-200x100.jpg', strpos($image_path, '.jpg'));
}
elseif (strpos($image_path, '.png')) {
$image_thumb = substr_replace($image_path, '-200x100.png', strpos($image_path, '.png'));
}
else {
$image_thumb = 'No image';
}
Your solution matches the extension in any part of the path, which is probably not what you want:
$image_path = '/some/path/images.jpeg/this-is-an-image.jpeg';
Result:
/some/path/images-200x100.jpeg
You can use pathinfo() to parse $image_path into its components and then put them back together with modifications:
$pathinfo = pathinfo($image_path);
if (isset($pathinfo['extension']) && in_array($pathinfo['extension'], array('jpeg', 'jpg', 'png'), true)) {
$image_thumb = sprintf('%s/%s-200x100.%s', $pathinfo['dirname'], $pathinfo['filename'], $pathinfo['extension']);
} else {
$image_thumb = 'No image';
}
Result for the previous example:
/some/path/images.jpeg/this-is-an-image-200x100.jpeg
I want download an image from AWS S3 and process it with php. I am using "imagecreatefromjpeg" and "getimagesize" to process my image but it seem that
Storage::disk('s3')->get(imageUrlonS3);
retrieve the image in binary and is giving me errors. This is my code:
function createSlices($imagePath) {
//create transform driver object
$im = imagecreatefromjpeg($imagePath);
$sizeArray = getimagesize($imagePath);
//Set the Image dimensions
$imageWidth = $sizeArray[0];
$imageHeight = $sizeArray[1];
//See how many zoom levels are required for the width and height
$widthLog = ceil(log($imageWidth/256,2));
$heightLog = ceil(log($imageHeight/256,2));
//more code here to slice the image
.
.
.
.
}
// ex: https://s3-us-west-2.amazonaws.com/bucketname/image.jpg
$content = Storage::disk('s3')->get(imageUrlonS3);
createSlices($content);
What am I missing here ?
Thanks
I think you are right in your question what the problem is - the get method returns the source of the image of itself, not the location of the image. When you pass that to createSlices, you're passing the binary data, not its file path. Inside of createSlices you call imagecreatefromjpeg, which expects a file path, not the image itself.
If this indeed the case, you should be able to use createimagefromstring instead of createimagefromjpeg and getimagesizefromstring instead of getimagesize. The functions createimagefromstring and getimagesizefromstring each expects the binary string of the image, which I believe is what you have.
Here's the relevant documentation:
createimagefromstring - http://php.net/manual/en/function.imagecreatefromstring.php
getimagesizefromstring - http://php.net/manual/en/function.getimagesizefromstring.php
Resulting code might look something like this:
function createSlices($imageData) {
$im = imagecreatefromstring($imageData);
$sizeArray = getimagesizefromstring($imageData);
//Everything else can probably be the same
.
.
.
.
}
$contents = Storage::disk('s3')->get($imageUrlOnS3);
createSlices($contents);
Please note I haven't tested this, but I believe from what I can see in your question and what I read in the documentation that this might just do it.
Loads of answers on how to do it for a command line
convert /path/to/file/file.pdf[3] output.jpg
great... but what if I am using in memory processing, I am generating PDF with PDFlib and then output its buffer to a function that I want to generate jpg preview of selected page. How? My code :
[...]
$buf = $pdf->get_buffer();
//$buff is just a PDF stored in a string now.
$im = new Imagick();
$im->readimageblob($buf);
$im->setImageFormat("jpg");
$im->setimagecompressionquality(60);
$len = strlen($im);
header("Content-type: image/jpeg");
header("Content-Length: $len");
header("Content-Disposition: inline; filename=test.jpg");
echo $im;
This creates a jpeg but always returns last page of the PDF. I want to be able to choose which one will be converted. Is it doable without saving temporary files and using command line (exec('convert /path/to/file/file.pdf[3] output.jpg')) syntax?
Let me add that I tried
$im->readimageblob($buf[2]);
and it did not work :)
For the ones who is still searching for solution of reading specific page number from blob, please check this question Creating array populated by images from a PDF using PHP and ImageMagick
$img_array = array();
$im = new imagick();
$im->setResolution(150,150);
$im->readImageBlob($pdf_in);
$num_pages = $im->getNumberImages();
for($i = 0;$i < $num_pages; $i++)
{
$im->setIteratorIndex($i);
$im->setImageFormat('jpeg');
$img_array[$i] = $im->getImageBlob();
}
$im->destroy();
I'm loading the PDF binary into memory from Amazon S3 and then selecting the specific page I want using setIteratorIndex() followed by getImage()
function get_image_from_pdf($pdf_bytes, $page_num){
$im = new \Imagick();
$im->setResolution(150, 150);
$im->readImageBlob($pdf_bytes);
$im->setIteratorIndex($page_num);
$im = $im->getImage();
$im->setImageFormat('png');
return $im->getImageBlob();
}
version 3.0.1
being on the last image or first image in imagic object
$image_obj = new Imagick("test.pdf"); then you on last image in $image_obj
if you use
fp_pdf = fopen("test.pdf", 'rb');
$image_obj = new Imagick();
$image_obj -> readImageFile($fp_pdf);
then you on the first image in $image_obj
In second case to switch to last image you can do
fp_pdf = fopen("test.pdf", 'rb');
$image_obj = new Imagick();
$image_obj -> readImageFile($fp_pdf,2); // 2 can be any positive number?
then you on the last image in $image_obj
echo $image_obj->getNumberImages() // Returns the number of images in the object
then
if ($image_obj->hadPreviousImage)
$image_obj->previousImage() //Switch to the previous image in the object
}
or
if ($image_obj->hasNextImage()) {
$image_obj->nextImage()) //Switch to the next image in the object
}
e.g. if you have 6 images total and you need 4th then do from the end
$image_obj->previousImage()
$image_obj->previousImage()
$image_obj->setImageFormat("png");
header("Content-Type: image/png");
echo $image_obj;
EDIT: Another find is that you can
foreach($image_obj as $slides) {
echo "<br>".$Obj_img->getImageWidth();
//or wehatever you need to do.
}
EDIT 2: Very simple solution would be to use this function $image_obj->setIteratorIndex(4) count starts with zero.
It's not good news unfortunately, but I can definitively say that, as of time of writing, the ImageMagick (and PHP libraries) don't support the page notation that you're trying to use. (For people from the future finding this: I'm checking php-imagick-3.0.1 and imagemagick-6.6.0.4).
I'm trying to do the exact same thing as you, and I've just spent the last few hours trawling through the source, trying to figure out what it does and how it gets the pages, and it looks like it simply won't use it when reading from a stream (ie. the readBlob() call).
As such, I'm just going to be putting it in a temporary file and reading it from there instead. Not as elegant, but it'll work.
I'm trying to convert PDF to IMG (JPG) with help PHP.
I'm using imagick extension.
this is my code
$fp_pdf = fopen($pdf, 'rb');
$img = new imagick(); // [0] can be used to set page number
$img->readImageFile($fp_pdf);
$img->setImageFormat( "jpg" );
$img->setImageCompression(imagick::COMPRESSION_JPEG);
$img->setImageCompressionQuality(90);
$img->setResolution(300,300);
$img->setImageUnits(imagick::RESOLUTION_PIXELSPERINCH);
$data = $img->getImageBlob();
my source pdf file has right dimension (210x297 mm, like A4 has). And everything looks good.
But my jpg has page dimension as 842x595 px, and DPI is 72.
and img file much more smaller on paper then pdf, when i had print it.
what is a proper way to make image file from pdf and make it so big as pdf (on paper)
You could use imagemagick through exec() or similar, the shell arguments are much less verbose than the PHP extension.
$pdf_file = escapeshellarg( "mysafepdf.pdf" );
$jpg_file = escapeshellarg( "output.jpg" );
$result = 0;
exec( "convert -density 300 {$pdf_file} {$jpg_file}", null, $result );
// at this point $result should == 0 if the conversion was successful
It's the "-density" (which sets the DPI to read the source file as) option that specifically fixes your problem.
Also imagemagick by default uses a -quality setting of 92 for JPEG writing in most cases - so you probably don't need to explicitly declare it.
It looks like you missed two setters:
Imagick::setImagePage() http://www.php.net/manual/en/function.imagick-setimagepage.php
And:
Imagick::setImageExtent() http://www.php.net/manual/en/function.imagick-setimageextent.php
In order to get the correct parameters for these functions, you may try the following:
$fp_pdf = fopen($pdf, 'rb');
$params=array();
$img = new imagick();
$img->readImageFile($fp_pdf);
/*my modification: */$img->setImageUnits(imagick::RESOLUTION_PIXELSPERINCH);
/*my modification: */$params=$img->identifyImage();
$img->setImageFormat( "jpg" );
$img->setImageCompression(imagick::COMPRESSION_JPEG);
$img->setImageCompressionQuality(90);
/*my modification: */$img->setPage($params['geometry']['width'], $params['geometry']['height'], 0, 0)
/*my modification: */$img->setResolution($params['resolution']['x'], $params['resolution']['y']);
$img->setImageUnits(imagick::RESOLUTION_PIXELSPERINCH);
$data = $img->getImageBlob();
If you find that some others attributes should be set, then let me show you the information that $params is holding. It may proof useful for you:
$params=array(
[imageName],
[format],
[geometry] => Array
(
[width]
[height]
)
[type],
[colorSpace],
[resolution],
(
[x]
[y]
)
[units],
[fileSize],
[compression],
[signature],
)
To be honest, I'm not completely sure if this will work. Is just a try in order to help you. I sincerely hope it does.
ImageMagick uses GhostScript to process JPEGs, so you'd do better to exec GhostScript directly, which would be much more efficient and give you more control. It would also be only 1 exec statement, instead of playing around with the IMagick functions.
As mentioned before, setting the resolution before reading the file does the trick:
$fp_pdf = fopen($pdf, 'rb');
$img = new imagick(); // [0] can be used to set page number
$img->setResolution(300,300);
$img->readImageFile($fp_pdf);
$img->setImageFormat( "jpg" );
$img->setImageCompression(imagick::COMPRESSION_JPEG);
$img->setImageCompressionQuality(90);
$img->setImageUnits(imagick::RESOLUTION_PIXELSPERINCH);
$data = $img->getImageBlob();
You have to call setResolution before reading the image. Otherwise imagemagick will use the default system dpi.