I installed composer require spatie/image-optimizer, but when I run the example below the I had two problems:
1- The class could not be found by calling it by using (use). So I solved it by using include.
2- After solving the first problem, the code works fine but the resultant image is the same image with no optimization.
include 'Spatie/Imageoptimizer/src/OptimizerChainFactory.php';
require __DIR__.'/autoload.php';
$pathToImage = "D:/xampp/htdocs/images/vendor/uploads/2.png";
//use Spatie\ImageOptimizer\OptimizerChainFactory;
// Get the image and store the original size
$image = $pathToImage;
$originalSize = filesize($image);
// Optimize updates the existing image
$optimizerChain = OptimizerChainFactory::create();
$optimizerChain->optimize($image);
// Clear stat cache to get the optimized size
clearstatcache();
// Check the optimized size
$optimizedSize = filesize($image);
$percentChange = (1 - $optimizedSize / $originalSize) * 100;
echo sprintf("The image is now %.2f%% smaller\n", $percentChange);
exit(0);
Could you please suggest me any solutions!
I found the cause of the problem, which is the jpg and Optipng tools are not installed in the windows. Is there any way to install the tools in windows and link them to the plugin.
Related
I have a site with about 1500 JPEG images, and I want to compress them all. Going through the directories is not a problem, but I cannot seem to find a function that compresses a JPEG that is already on the server (I don't want to upload a new one), and replaces the old one.
Does PHP have a built in function for this? If not, how do I read the JPEG from the folder into the script?
Thanks.
you're not telling if you're using GD, so i assume this.
$img = imagecreatefromjpeg("myimage.jpg"); // load the image-to-be-saved
// 50 is quality; change from 0 (worst quality,smaller file) - 100 (best quality)
imagejpeg($img,"myimage_new.jpg",50);
unlink("myimage.jpg"); // remove the old image
I prefer using the IMagick extension for working with images. GD uses too much memory, especially for larger files. Here's a code snippet by Charles Hall in the PHP manual:
$img = new Imagick();
$img->readImage($src);
$img->setImageCompression(Imagick::COMPRESSION_JPEG);
$img->setImageCompressionQuality(90);
$img->stripImage();
$img->writeImage($dest);
$img->clean();
You will need to use the php gd library for that... Most servers have it installed by default. There are a lot of examples out there if you search for 'resize image php gd'.
For instance have a look at this page http://911-need-code-help.blogspot.nl/2008/10/resize-images-using-phpgd-library.html
The solution provided by vlzvl works well. However, using this solution, you can also overwrite an image by changing the order of the code.
$image = imagecreatefromjpeg("image.jpg");
unlink("image.jpg");
imagejpeg($image,"image.jpg",50);
This allows you to compress a pre-existing image and store it in the same location with the same filename.
Is there a way in PHP given a video file (.mov, .mp4) to generate a thumbnail image preview?
Solution #1 (Older) (not recommended)
Firstly install ffmpeg-php project (http://ffmpeg-php.sourceforge.net/)
And then you can use of this simple code:
<?php
$frame = 10;
$movie = 'test.mp4';
$thumbnail = 'thumbnail.png';
$mov = new ffmpeg_movie($movie);
$frame = $mov->getFrame($frame);
if ($frame) {
$gd_image = $frame->toGDImage();
if ($gd_image) {
imagepng($gd_image, $thumbnail);
imagedestroy($gd_image);
echo '<img src="'.$thumbnail.'">';
}
}
?>
Description: This project use binary extension .so file, It's very old and last update was for 2008. So, maybe don't works with newer version of FFMpeg or PHP.
Solution #2 (Update 2018) (recommended)
Firstly install PHP-FFMpeg project (https://github.com/PHP-FFMpeg/PHP-FFMpeg)
(just run for install: composer require php-ffmpeg/php-ffmpeg)
And then you can use of this simple code:
<?php
require 'vendor/autoload.php';
$sec = 10;
$movie = 'test.mp4';
$thumbnail = 'thumbnail.png';
$ffmpeg = FFMpeg\FFMpeg::create();
$video = $ffmpeg->open($movie);
$frame = $video->frame(FFMpeg\Coordinate\TimeCode::fromSeconds($sec));
$frame->save($thumbnail);
echo '<img src="'.$thumbnail.'">';
Description: It's newer and more modern project and works with latest version of FFMpeg and PHP. Note that it's required to proc_open() PHP function.
Two ways come to mind:
Using a command-line tool like the popular ffmpeg, however you will almost always need an own server (or a very nice server administrator / hosting company) to get that
Using the "screenshoot" plugin for the LongTail Video player that allows the creation of manual screenshots that are then sent to a server-side script.
I recommend php-ffmpeg library.
Extracting image
You can extract a frame at any timecode using the
FFMpeg\Media\Video::frame method.
This code returns a FFMpeg\Media\Frame instance corresponding to the
second 42. You can pass any FFMpeg\Coordinate\TimeCode as argument,
see dedicated documentation below for more information.
$frame = $video->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(42));
$frame->save('image.jpg');
If you want to extract multiple images from the video, you can use the following filter:
$video
->filters()
->extractMultipleFrames(FFMpeg\Filters\Video\ExtractMultipleFramesFilter::FRAMERATE_EVERY_10SEC, '/path/to/destination/folder/')
->synchronize();
$video
->save(new FFMpeg\Format\Video\X264(), '/path/to/new/file');
By default, this will save the frames as jpg images.
You are able to override this using setFrameFileType to save the frames in another format:
$frameFileType = 'jpg'; // either 'jpg', 'jpeg' or 'png'
$filter = new ExtractMultipleFramesFilter($frameRate, $destinationFolder);
$filter->setFrameFileType($frameFileType);
$video->addFilter($filter);
I'm trying to finish up my image uploader that utilizes imagick for the handling of various image types. One thing specifically that I'm trying to get working is the conversion of jpeg files to progressive jpeg. I've tried the following code below, but when I view the images that get output in irfranview, the jpeg are not progressive. Any ideas? This literally must work by Monday.. Please help
foreach ($thumbnailScaleWidths as $thumbnailScaleWidth) {
$thumbnail = new imagick($uploadedFile['tmp_name']);
$thumbnailDimensions = $thumbnail->getImageGeometry();
$thumbnailWidth = $thumbnailDimensions['width'];
$thumbnailHeight = $thumbnailDimensions['height'];
$thumbnailScaleHeight = ($thumbnailScaleWidth / $thumbnailWidth) * $thumbnailHeight;
$thumbnail->thumbnailImage($thumbnailScaleWidth, $thumbnailScaleHeight);
$thumbnail->setImageInterlaceScheme(Imagick::INTERLACE_PLANE);
$thumbnail->writeImages($_SERVER['DOCUMENT_ROOT'] . "/Resources/Media/$userId/$internalName-$thumbnailScaleWidth.$fileType", true);
}
Any ideas as to why this isn't outputting progressive jpegs?
I know this thread is old but here is an answer that might save time to others in the future.
So since you are reading an image from file, you should use the following method instead:
Imagick::setInterlaceScheme
It seems that Imagick::setImageInterlaceScheme will work only when Imagick is used to generate an image by itself...
I having some problems with an image that has EXIF/IPTC data stored in it.
When I use imageCreateFromJpeg (to rotate/crop or etc) the newly stored file doesn't preserve the EXIF/IPTC data.
My current code looks like this:
<?php
// Before executing - EXIF/IPTC data is there (checked)
$image = "/path/to/my/image.jpg";
$source = imagecreatefromjpeg($image);
$rotate = imagerotate($source,90,0);
imageJPEG($rotate,$image);
// After executing - EXIF/IPTC data doesn't exist anymore.
?>
Am I doing something wrong?
You aren't doing anything wrong, but GD doesn't deal with Exif of IPTC data at all as its beyond the scope of what GD does.
You will have to use a 3rd party library or other PHP extension to read the data from the source image and re-insert it to the output image created by imagejpeg.
Here are some libraries of interest: pel (php exif library), an example on php.net showing how to use pel to do what you want, php metadata toolkit, iptcembed() function.
Here is an example of image scaling using gd, and copying Exif and ICC color profile using PEL:
function scaleImage($inputPath, $outputPath, $scale) {
$inputImage = imagecreatefromjpeg($inputPath);
list($width, $height) = getimagesize($inputPath);
$outputImage = imagecreatetruecolor($width * $scale, $height * $scale);
imagecopyresampled($outputImage, $inputImage, 0, 0, 0, 0, $width * $scale, $height * $scale, $width, $height);
imagejpeg($outputImage, $outputPath, 100);
}
function copyMeta($inputPath, $outputPath) {
$inputPel = new \lsolesen\pel\PelJpeg($inputPath);
$outputPel = new \lsolesen\pel\PelJpeg($outputPath);
if ($exif = $inputPel->getExif()) {
$outputPel->setExif($exif);
}
if ($icc = $inputPel->getIcc()) {
$outputPel->setIcc($icc);
}
$outputPel->saveFile($outputPath);
}
copy('https://i.stack.imgur.com/p42W6.jpg', 'input.jpg');
scaleImage('input.jpg', 'without_icc.jpg', 0.2);
scaleImage('input.jpg', 'with_icc.jpg', 0.2);
copyMeta('input.jpg', 'with_icc.jpg');
Output images:
Input image:
The answer by #drew010 is correct in that this cannot be done without an external library or other program. However, that answer is quite old and there are now at least two good ways of doing it. #Thiago Barcala gave one answer, using PEL.
Here is a completely different one using a different one, the PERL-script exiftool by Paul Harvey. I prefer this solution because exiftool has a longer history of development and use, is better documented, and seems more stable and reliable to me. PEL is newer by nearly 10 years, has an unstable API, a history of the project changing hands, and has yet to reach version 1.0. I tried setting it up and ran into some roadblocks, and found no documentation for overcoming them, whereas setting up exiftool worked out-of-the-box.
Install exiftool, then, after saving the old image to a new path run:
exec('exiftool -TagsFromFile /full/path/to/original_image.jpg /full/path/to/newly_saved_image.jpg');
You must leave both files in existence for this to work; if you overwrite the file as your original code does, the EXIF data will be lost.
Make sure your php.ini allows for the exec() call; sometimes it is disallowed for security reasons. Also, take great care that you do not allow any user-generated input in any parameters you pass to that call because it could allow an attacker to execute an arbitrary command under the privileges of the web server. The exec call is most secure if your script generates the filenames according to some formula, such as alphanumeric characters only, with a fixed directory path, and then feed them into the exec call.
If you don't want to install exiftool globally, you can just replace exiftool by the full path to it. If you are using SELinux, make sure to set the context on the file for the exiftool script to httpd_exec_t to allow it to be executed by the web server, and make sure the directory the whole script is in has context httpd_sys_content_t or some other context that allows access by the webserver.
After searching Google and SO, I found this little bit of code for creating thumbnails of PDF documents using ImageMagick.
The trouble for me is in implementing it into my WordPress theme. I think that I'm getting stuck on the path to cache that the script needs for temporary files.
I'm using it as described in the article:
<img src="http://localhost/multi/wp-content/themes/WPalchemy-theme/thumbPdf.php?pdf=http://localhost/multi/wp-content/uploads/2012/03/sample.pdf&size=200 />
which must be right (maybe... but I assume i am correct to use full URL to the actual file), because when I click on that URL I am taken to a page that reads the following error:
Unable to read the file: tmp/http://localhost/multi/wp-content/uploads/2012/03/sample.pdf.png
Now tmp is defined in the thumbPdf.php script, but I am confused as to what it's value should be. Is it a url or a path? Like timthumb.php, can i make it be relative to the thumbPdf.php script? (I tried ./cache which is the setting in timthumb -and was sure to have a /cache folder in my theme root, to no avail). also, fyi I put a /tmp folder in my root and still get the same error.
So how do I configure tmp to make this work?
http://stormwarestudios.com/articles/leverage-php-imagemagick-create-pdf-thumbnails/
function thumbPdf($pdf, $width)
{
try
{
$tmp = 'tmp';
$format = "png";
$source = $pdf.'[0]';
$dest = "$tmp/$pdf.$format";
if (!file_exists($dest))
{
$exec = "convert -scale $width $source $dest";
exec($exec);
}
$im = new Imagick($dest);
header("Content-Type:".$im->getFormat());
echo $im;
}
catch(Exception $e)
{
echo $e->getMessage();
}
}
$file = $_GET['pdf'];
$size = $_GET['size'];
if ($file && $size)
{
thumbPdf($file, $size);
}
I have seen this answer:
How do I convert a PDF document to a preview image in PHP?
and am about to go try it next
The error tells everything you need.
Unable to read the file: tmp/http://localhost/multi/wp-content/uploads/2012/03/sample.pdf.png
Script currently tries to read file from servers tmp/ folder.
$tmp = 'tmp';
$format = "png";
$source = $pdf.'[0]';
//$dest = "$tmp/$pdf.$format";
$dest = "$pdf.$format";
Remember securitywise this doesn't really look so good, someone could exploit ImageMagic bug to achieve very nasty things by giving your script malformed external source pdf. You should at least check if the image is from allowed source like request originates from the same host.
Best way to work with ImageMagic is to always save the generated image and only generate a new image if generated image doesn't exist. Some ImageMagic operations are quite heavy on large files so you don't want to burden your server.