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);
Related
I'm working with the PHP ImageMagick Library to convert uploaded pdf files to single png files so I can display the pdf as a single image on my Laravel webpage. So far I'm able to convert an entire pdf to a single image with this code:
<?php
$imagick = new Imagick();
$file = new File;
// other lines of code
// ...
$imgPath = Storage::path($file->file_path);
$imgSavePath = Storage::path('uploads/buffer/'.Str::beforeLast($file->name, '.').'.png');
$imagick->readImage($imgPath);
$imagick->resetIterator();
$imagick = $imagick->appendImages(true);
$imagick->writeImages($imgSavePath, true);
This works by producing a single png image. However, I find this to be resource intensive (storage wise) and time consuming because I'm delivering the functionality through an ajax call.
I want my web application to convert only the first n pages of the pdf (say first 5 pages) into a single image to act as a preview on the site - thereafter the user can download the entire pdf to view on their local system. The function should work regardless of the number of pages in an uploaded pdf document.
So far, I only find in the documentation where I can read a page at a particular index from the Imagick object and convert to an image using:
...
$imgPath = Storage::path($file->file_path);
$index = 5;
$imagick->readImage($imgPath. '[' . $index . ']');
However, I'm finding it difficult to refactor this so that the application can read the first n pages.
Intuitively, the readImage() function seems to work in a similar way as the command line syntax. Thanks to the hint from #MarkSetchell in the comments:
<?php
$imagick = new Imagick();
$file = new File;
// other lines of code
// ...
$imgPath = Storage::path($file->file_path);
$imgSavePath = Storage::path('uploads/buffer/'.Str::beforeLast($file->name, '.').'.png');
$imagick->readImage($imgPath.'[0-4]'); // read only the first 5 pages
$imagick->resetIterator();
$imagick = $imagick->appendImages(true);
$imagick->writeImages($imgSavePath, true);
I'm using ImageMagick 6.9.10-68 and PHP 8.1.12
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.
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);
Having installed the PEAR GraphViz package I'm trying to follow the second answer on this page to create a JPEG of a graph. As test code, I have the following:
<?php
require_once 'Image/GraphViz.php';
$graph = new Image_GraphViz();
$graph->addNode('A');
$img = $graph->fetch('jpeg', 'dot');
print "IMG: " . $img;
I've also tried it using the $graph->image('jpeg', 'dot'); method. Both ways, it returns an empty string. When I change the format to something like SVG, it works, which makes me think that certain image generation libraries just aren't installed. But I have the regular (commandline) Graphviz tools installed and they generate images fine. What do I need to install to make this work so PHP can generate images itself?
Currently i can create PDF files from images in Imagick with this function
$im->setImageFormat("pdf");
$im->writeImage("file.pdf");
And it's possible to fetch multiple pages with imagick like this
$im = new imagick("file.pdf[0]");
$im2 = new imagick("file.pdf[1]");
But is it possible to save two image objects to two pages?
(example of what i am thinking, its not possible like this)
$im->setImageFormat("pdf");
$im->writeImage("file.pdf[0]");
$im2->setImageFormat("pdf");
$im2->writeImage("file.pdf[1]");
I know this is long past due, but this result came up when I was trying to do the same thing. Here is how you create a multi-page PDF file in PHP and Imagick.
$images = array(
'page_1.png',
'page_2.png'
);
$pdf = new Imagick($images);
$pdf->setImageFormat('pdf');
if (!$pdf->writeImages('combined.pdf', true)) {
die('Could not write!');
}
Accepted answer wasn't working for me, as a result, it always generated one page pdf (last image from constructor), to make this work I had to get file descriptor first, like this:
$images = array(
'img1.png', 'img2.png'
);
$fp = fopen('combined.pdf', 'w');
$pdf = new Imagick($images);
$pdf->resetiterator();
$pdf->setimageformat('pdf');
$pdf->writeimagesfile($fp);
fclose($fp);
Is this working?
$im->setImageFormat("pdf");
$im->writeImage("file1.pdf");
$im2->setImageFormat("pdf");
$im2->writeImage("file2.pdf");
exec("convert file*.pdf all.pdf");
CAM::PDF is a pure-Perl solution for low-level PDF manipulation like this. You can either use the appendpdf.pl command-line tool, or do it programmatically like this:
use CAM::PDF;
my $doc1 = CAM::PDF->new('file1.pdf');
my $doc2 = CAM::PDF->new('file2.pdf');
$doc1->appendPDF($doc2);
$doc1->cleanoutput('out.pdf');
If you can figure out how to make ImageMagick write to a string instead of to a file (I'm not an ImageMagick expert...) then you save some performance overhead by keeping it all in Perl.
(I'm the author of CAM::PDF. It's free software: GPL+Artistic dual-licensed).
I do not know php or this Imagick library, but if calling an external program is acceptable I can recommend the program pdfjoin to merge pdf files.
It does have an dependency to pdflatex, so if this is something you intend to run on a server you might have to install extra latex stuff, but the end result from pdfjoin is very good, so I think it will be worth it.