I have been trying to extract images and charts from an Xlsx file using the phpspreadsheet libray; I have however been unsuccessful.
Indeed, the piece of code I wrote is unable to find any image or chart from my xlsx file.
However, when I convert the file from Xlsx to Xls using Excel, the same code works and manages to extract images and charts.
This is the code i use to load my spreadsheet :
$fileType = \PhpOffice\PhpSpreadsheet\IOFactory::identify($filePath);
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($fileType);
$spreadsheet = $reader->load($filePath);
And then I added the code provided by the official documentation :
$i = 0;
foreach ($spreadsheet->getActiveSheet()->getDrawingCollection() as $drawing) {
if ($drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing) {
ob_start();
call_user_func(
$drawing->getRenderingFunction(),
$drawing->getImageResource()
);
$imageContents = ob_get_contents();
ob_end_clean();
switch ($drawing->getMimeType()) {
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_PNG :
$extension = 'png';
break;
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_GIF:
$extension = 'gif';
break;
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_JPEG :
$extension = 'jpg';
break;
}
} else {
$zipReader = fopen($drawing->getPath(),'r');
$imageContents = '';
while (!feof($zipReader)) {
$imageContents .= fread($zipReader,1024);
}
fclose($zipReader);
$extension = $drawing->getExtension();
}
$myFileName = '00_Image_'.++$i.'.'.$extension;
file_put_contents($myFileName,$imageContents);
}
The above code works with an .xls file but not with an .xlsx : the getDrawingCollection and/or getChartCollection return an empty array with .xlsx files...
Do any of you guys know how to perform this?
I'm open to any solution... even if it means converting the file via another library...
Thanks in advance,
I found the solution... one line of code, to add after initializing the reader :
$reader->setIncludeCharts(true);
Related
I have a Excel file like this:
I wrote a code that allows me to extract all the photos from the xlsx file and insert them in a folder.
There are several merged cells in the file and before processing I would like to remove all the merged cells from the Excel file. I tried with $objPHPExcel->setActiveSheetIndex("0")->unmergeCells(); but it doesn't work.
How can I solve my problem?
<?php
//uploaded xlsx file recovery
$xlsx="C:/wamp64/www/Extract_pictures_Excel/xlsx_files/".date('Y_m_d H-i-s')."_file.xlsx";
move_uploaded_file($_FILES["mon_fichier"]["tmp_name"],$xlsx);
require_once 'PHPExcel/Classes/PHPExcel/IOFactory.php';
$objPHPExcel = PHPExcel_IOFactory::load($xlsx);
//Unique name folder for the pictures
$dirname = uniqid();
mkdir("C:/wamp64/www/Extract_pictures_Excel/pictures_folders/$dirname/");
$sheet = $objPHPExcel->getActiveSheet();
//Unmerge all cells
foreach($sheet->getMergeCells() as $cells)
{
$sheet->unmergeCells($cells);
// var_dump($cells);
}
$objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
$objWriter->save('./unmerged_files/unmerged.xlsx');
//reading the xlsx file
foreach ($sheet->getDrawingCollection() as $drawing ) {
if ($drawing instanceof PHPExcel_Worksheet_MemoryDrawing) {
ob_start();
call_user_func(
$drawing->getRenderingFunction(),
$drawing->getImageResource()
);
$imageContents = ob_get_contents();
ob_end_clean();
switch ($drawing->getMimeType()) {
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG :
$extension = 'png'; break;
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_GIF:
$extension = 'gif'; break;
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG :
$extension = 'jpg'; break;
}
} else {
$zipReader = fopen($drawing->getPath(),'r');
$imageContents = '';
while (!feof($zipReader)) {
$imageContents .= fread($zipReader,1024);
}
fclose($zipReader);
$extension = $drawing->getExtension();
$chemin = "C:/wamp64/www/Extract_pictures_Excel/pictures_folders/$dirname/";
}
//retrieving cell values for the images name
$row = (int) substr($drawing->getCoordinates(), 1);
//Condition to read merged cell
$stylecode = $sheet->getCell('H'.$row)->getValue();
$colorcode = $sheet->getCell('E'.$row)->getValue();
$finalname = $stylecode.'_'.$colorcode;
$myFileName = $chemin.$finalname.'.'.$extension;
file_put_contents($myFileName, $imageContents);
}
?>
I have changed the library to PhpOffice\PhpSpreadsheet because PHPExcel is outdated.
require_once './vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
$xlsx = './test/catalogmtnwr2021202009210323241.xlsx';
$spreadsheet = IOFactory::load($xlsx);
$sheet = $spreadsheet->getActiveSheet();
Now I am testing what is merged and unmerge it
echo 'before unmerge: ', count($sheet->getMergeCells()), PHP_EOL;
foreach($sheet->getMergeCells() as $cells)
$sheet->unmergeCells($cells);
echo 'after unmerge: ', count($sheet->getMergeCells()), PHP_EOL;
before unmerge: 678
after unmerge: 0
And at last write back into file
$writer = new Xlsx($spreadsheet);
$writer->save('./test/unmerged.xlsx');
This unmerged the cells as expected
I wrote a php script that allows me to read an uploaded excel file and insert all the images contained in a folder by renaming them with the cell values "style" and "color" to have style_color.jpg. The script works fine but if I upload an xlsx file containing merged cells like this:
images with the same "style" doesn't work.The tool will just put the style on the first image. I would like the first two images to be called :
SCJEG4_1041
SCJEG4_0049
How can I read these merged cells?
<?php
//uploaded xlsx file recovery
$xlsx="C:/wamp64/www/Extract_pictures_Excel/xlsx_files/".date('Y_m_d H-i-s')."_images.xlsx";
move_uploaded_file($_FILES["mon_fichier"]["tmp_name"],$xlsx);
require_once 'PHPExcel/Classes/PHPExcel/IOFactory.php';
$objPHPExcel = PHPExcel_IOFactory::load($xlsx);
//Unique name folder for the pictures
$dirname = uniqid();
mkdir("C:/wamp64/www/Extract_pictures_Excel/pictures_folders/$dirname/");
//reading the xlsx file
$sheet = $objPHPExcel->getActiveSheet();
foreach ($sheet->getDrawingCollection() as $drawing ) {
if ($drawing instanceof PHPExcel_Worksheet_MemoryDrawing) {
ob_start();
call_user_func(
$drawing->getRenderingFunction(),
$drawing->getImageResource()
);
$imageContents = ob_get_contents();
ob_end_clean();
switch ($drawing->getMimeType()) {
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG :
$extension = 'png'; break;
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_GIF:
$extension = 'gif'; break;
case PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG :
$extension = 'jpg'; break;
}
} else {
$zipReader = fopen($drawing->getPath(),'r');
$imageContents = '';
while (!feof($zipReader)) {
$imageContents .= fread($zipReader,1024);
}
fclose($zipReader);
$extension = $drawing->getExtension();
$chemin = "C:/wamp64/www/Extract_pictures_Excel/pictures_folders/$dirname/";
}
//retrieving cell values for the images name
$row = (int) substr($drawing->getCoordinates(), 1);
$stylecode = $sheet->getCell('H'.$row)->getValue();
$colorcode = $sheet->getCell('E'.$row)->getValue();
$finalname = $stylecode.'_'.$colorcode;
$myFileName = $chemin.$finalname.'.'.$extension;
file_put_contents($myFileName, $imageContents);
}
?>
If you can assume that you read the rows in sequence, you can get the cell value and if the cell is blank, use the previous value. This code use ?: to say if it's blank, use $stylecode ...
$stylecode = $sheet->getCell('H'.$row)->getValue() ?: $stylecode;
I am using PhpSpreedSheet to load an excel, update it and save it again ... The problem I find is that it does not save it well for the graphics, and when you open the excel it tells you the typical thing that there has been a problem and "Do you want that we try to recover as much content as possible? " and remove the graphics.
Excel has completed validation and repair at the file level. Some parts of this book may have been repaired or discarded. Part removed: Part Properties of the document. (Drawing form) Part removed: Drawing form. Removed part: Drawing form.
$reader = IOFactory::createReader('Xlsx');
$reader->setIncludeCharts(true);
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($this->spreadsheet);
$writer->setIncludeCharts(true);
To include a drawing you should use something like this:
$drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$drawing->setName('Logo');
$drawing->setDescription('Logo');
$drawing->setPath('./images/officelogo.jpg');
$drawing->setCoordinates('B15');
$drawing->setHeight(36);
$drawing->setWorksheet($spreadsheet->getActiveSheet());
For reading out of all images you should use the code from the documentation:
$i = 0;
foreach ($spreadsheet->getActiveSheet()->getDrawingCollection() as $drawing) {
if ($drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing) {
ob_start();
call_user_func(
$drawing->getRenderingFunction(),
$drawing->getImageResource()
);
$imageContents = ob_get_contents();
ob_end_clean();
switch ($drawing->getMimeType()) {
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_PNG :
$extension = 'png';
break;
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_GIF:
$extension = 'gif';
break;
case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_JPEG :
$extension = 'jpg';
break;
}
} else {
$zipReader = fopen($drawing->getPath(),'r');
$imageContents = '';
while (!feof($zipReader)) {
$imageContents .= fread($zipReader,1024);
}
fclose($zipReader);
$extension = $drawing->getExtension();
}
$myFileName = '00_Image_'.++$i.'.'.$extension;
file_put_contents($myFileName,$imageContents);
}
I use PHPExcel to import data from a .csv file which has the same rows and columns with a excel file. Basically I open them with LibreOffice and they look the same. However there are two result when calculating theirs worksheet dimensions.
csv: A1:A10
xlsx: A1: AMK10
I just want to ask that it is always like that due to the different formats or I do something wrong?
$pi = pathinfo($filePath);
switch ($pi['extension']) {
case 'xls':
$reader = PHPExcel_IOFactory::createReader('Excel5');
break;
case 'xlsx':
$reader = PHPExcel_IOFactory::createReader('Excel2007');
break;
case 'csv':
$reader = PHPExcel_IOFactory::createReader('CSV');
break;
default:
return array();
}
$phpexcel = $reader->load($filePath);
$sheet = $phpexcel->getActiveSheet();
$sheet->calculateWorksheetDimension();
When loading a CSV file, if the delimiter isn't a default comma (,) then you need to explicitly set the delimiter for the reader. e.g.
PHPExcel_IOFactory::createReader('CSV');
$reader->setDelimiter(';');
I currently have a .xlsx file with a workbook with multiple sheets with text and images.
I need to import this data into my MySQL database.
Does anyone know of any tutorials or just some code that can help me get all the sheet within the workbook and retrieve text and images, and insert them into the database.
Check out PHPExcel. Here's how you would loop through the sheets. I'm not sure how you can get images though.
$reader = new PHPExcel_Reader_Excel2007();
$excel = $reader->load($filename);
foreach ($excel->getWorksheetIterator() as $worksheet){
// Get the data from current worksheet
// and store in DB as you like
}
$reader = new PHPExcel_Reader_Excel2007();
$PHPExcel = $reader->load('test.xlsx');
$worksheet = $PHPExcel->getActiveSheet();
// extract images from worksheet and save files: 0.jpeg, 1.jpeg, 2.png, ...
foreach ($worksheet->getDrawingCollection() as $i => $drawing) {
$filename = $drawing->getPath();
$imagesize = getimagesize($filename);
switch ($imagesize[2]) {
case 1:
$image = imagecreatefromgif($filename);
imagegif($image, "$i.gif");
break;
case 2:
$image = imagecreatefromjpeg($filename);
imagejpeg($image, "$i.jpeg");
break;
case 3:
$image = imagecreatefrompng($filename);
imagepng($image, "$i.png");
break;
default:
continue 2;
}
}