Imagick and jpeg image compression - no change? - php

So, I'm testing some of our images with the Imagick PHP library, to see what compression we want to use. But there doesn't seem to be any change to the output file, no matter what I do. This is my basic process:
$original_image = new \Imagick( $image_url );
foreach ( ['original', '92', '80', '60', '40'] as $compression_size )
{
$tester = clone $original_image;
// don't compress the original
if ( 'original' != $compression_size )
{
$tester->setImageCompression(Imagick::COMPRESSION_JPEG);
$tester->setCompressionQuality( (int) $compression_size);
}
$filename: <original base> . "-$compression_size.jpg";
file_put_contents($filename, $tester->getImageBlob() );
$tester = null;
}
The results show that the file sizes between the various compressions don't change, and visually, there is no difference between the original and even the compression = 40 version. What am I doing wrong here?

From the docs (http://php.net/manual/en/imagick.setcompressionquality.php):
This method only works for new images e.g. those created through Imagick::newPseudoImage. For existing images you should use Imagick::setImageCompressionQuality().
So, replace
$tester->setCompressionQuality( (int) $compression_size);
for
$tester->setImageCompressionQuality( (int) $compression_size);

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.

How to processing an image downloaded from AWS S3 with Laravel 5?

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.

Output each individual animated GIF frame as visually intended

With some animated GIFs, for subsequent frames, the only data that is stored, is the difference compared to an earlier frame. Now, I've only just touched the surface of the internal workings of the data structure of (animated) GIFs, but I believe this is done with what is either called compression, frame difference, or disposal (not entirely sure, actually).
With Gmagick, or Imagick, for PHP, how do I extract each frame (write them out) such that not just this minimal data is extracted, but the complete representation of that frame as it is visually intended?
I've tried the following with Gmagick so far, to no avail, unfortunately:
// as per this comment:
// http://php.net/manual/en/imagick.setimagedispose.php#95701
// I've tried values in the range 0-4 here:
$img->setImageDispose( 0 ); // $img is animated GIF instance of Gmagick
$frameIndex = 0;
do
{
$img->setImageIndex( $frameIndex );
$frame = $img->getImage();
$frameName = ++$frameIndex . '.gif';
$frame->writeImage( $frameName, false ); // or:
// $frame->write( $frameName );
}
while( $img->hasNextImage() );
I've tried a few other things as well, such as Gmagick::setImageScene(), etc. But nothing works. I am only able to save the frame difference data, not the data such as visually intended.
I found out on my own how to do it with Imagick:
$frameIndex = 0;
$img = $img->coalesceImages();
foreach( $img as $frame )
{
$frameName = ++$frameIndex . '.gif';
$frame->writeImage( $frameName );
}
In other words, Imagick::coalesceImages() did the trick.

PDF to JPG conversion using PHP

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.

How do I list imags from directory?

I'm trying to show all images within a specified directory.
The following code lists all allowed file names:
function getDirectoryList()
{
// create an array to hold directory list
$results = array();
// create a handler for the directory
$handler = opendir($this->currentDIR);
// open directory and walk through the filenames
while ($file = readdir($handler)) {
// Make sure we get allowed images types
if ($this->allowedFileType($file,$this->allowedImageTypes) )
{
$results[] = $file;
}
}
// tidy up: close the handler
closedir($handler);
// done!
return $results;
}
(...)
$images = getDirectoryList();
foreach($images as $img) {
echo "<li>".$img."</li>";
}
How can I get file size and MIME type?
I read that mime_content_typeis deprecated and I should use finfo_file istead. But I've not been very successfull with this.
Do I have to use /usr/share/misc/magic to get file information? Can't I use GD library?
I've looked at many examples, but they are old and don't work that well.
Any help appreciated.
to get the size and mime type of image its simple,
use function : getimagesize
uses like :
list($width, $height, $type, $attr) = getimagesize("img/myimg.jpg");
Returns an array with 7 elements.
Index 0 and 1 contains respectively the width and the height of the image.
Index 2 is one of the IMAGETYPE_XXX constants indicating the type of the image.
using filesize give the size in bytes
To expand on Haim Evgi's post, use getimagesize() to retrieve the dimensions and the image type in an array. Then, use image_type_to_mime_type() on the image type code to retrieve the MIME:
list ($fileWidth, $fileHeight, $fileType) = getimagesize($filename);
$fileMimeType = image_type_to_mime_type($fileType);

Categories