Skip to content

Instantly share code, notes, and snippets.

@IacopoMelani
Created July 9, 2020 14:44
Show Gist options
  • Save IacopoMelani/df8c2c3ecc748bd0c9f478bd270dccf2 to your computer and use it in GitHub Desktop.
Save IacopoMelani/df8c2c3ecc748bd0c9f478bd270dccf2 to your computer and use it in GitHub Desktop.
Fix class xlsxwriterplus.class.php from https://github.com/mk-j/PHP_XLSXWriter/issues/88
<?php
class XLSWriterPlus extends XLSXWriter
{
/**
* @var array
*/
private $images = [];
/**
* @var array
*/
private $imageOptions = [];
/**
* @var array
*/
private $ignoredErrorsCells = [];
/**
* @return array
*/
public function getIgnoredErrorsCells()
{
return $this->ignoredErrorsCells;
}
/**
* @param array $ignoredErrorsCells
*/
public function setIgnoredErrorsCells($ignoredErrorsCells)
{
$this->ignoredErrorsCells = $ignoredErrorsCells;
}
/**
* @return array
*/
public function getSheets()
{
return $this->sheets;
}
/**
* @param string $imagePath
* @param string $imageName
* @param array $imageOptions
* @param int $imageId
* @throws Exception
*/
public function addImage($imagePath, $imageName, $imageId, $imageOptions = [])
{
if(!file_exists($imagePath)){
throw new Exception(sprintf('File %s not found.', $imagePath));
}
$this->images[$imageId] = array(
'path' => $imagePath,
'name' => $imageName
);
$this->imageOptions[$imageId] = array_merge([
'startColNum' => 0,
'endColNum' => 0,
'startRowNum' => 0,
'endRowNum' => 0,
], $imageOptions);
}
public function writeToString()
{
$temp_file = $this->tempFilename();
$this->writeToFile($temp_file);
$string = file_get_contents($temp_file);
return $string;
}
/**
* @param $filename
* @throws Exception
*/
public function writeToFile($filename)
{
$i = 1;
foreach ($this->sheets as $sheet_name => $sheet) {
$this->finalizeSheet($sheet_name, $i);
$i++;
}
if (file_exists($filename)) {
if (is_writable($filename)) {
@unlink($filename);
} else {
throw new \Exception("Error in " . __CLASS__ . "::" . __FUNCTION__ . ", file is not writeable.");
}
}
$zip = new \ZipArchive();
if (empty($this->sheets)) {
throw new \Exception("Error in " . __CLASS__ . "::" . __FUNCTION__ . ", no worksheets defined.");
}
if (!$zip->open($filename, \ZipArchive::CREATE)) {
throw new \Exception("Error in " . __CLASS__ . "::" . __FUNCTION__ . ", unable to create zip.");
}
$zip->addEmptyDir("docProps/");
$zip->addFromString("docProps/app.xml" , $this->buildAppXML() );
$zip->addFromString("docProps/core.xml", $this->buildCoreXML());
$zip->addEmptyDir("_rels/");
$zip->addFromString("_rels/.rels", $this->buildRelationshipsXML());
if (count($this->images) > 0) {
$zip->addEmptyDir("xl/media/");
$zip->addEmptyDir("xl/drawings");
$zip->addEmptyDir("xl/drawings/_rels");
foreach ($this->images as $imageId => $image) {
$zip->addFile($image['path'], 'xl/media/' . $image['name']);
}
$i = 1;
foreach ($this->sheets as $sheet) {
$zip->addFromString("xl/drawings/drawing" . $i . ".xml", $this->buildDrawingXML());
$zip->addFromString("xl/drawings/_rels/drawing" . $i . ".xml.rels", $this->buildDrawingRelationshipXML());
$i++;
}
}
$zip->addEmptyDir("xl/worksheets/");
$zip->addEmptyDir("xl/worksheets/_rels/");
$i = 1;
foreach ($this->sheets as $sheet) {
$zip->addFile($sheet->filename, "xl/worksheets/" . $sheet->xmlname);
$zip->addFromString("xl/worksheets/_rels/" . $sheet->xmlname . '.rels', $this->buildSheetRelationshipXML($i++));
}
$zip->addFromString("xl/workbook.xml", $this->buildWorkbookXML());
$zip->addFile($this->writeStylesXML(), "xl/styles.xml");
$zip->addFromString("[Content_Types].xml", $this->buildContentTypesXML());
$zip->addEmptyDir("xl/_rels/");
$zip->addFromString("xl/_rels/workbook.xml.rels", $this->buildWorkbookRelsXML());
$zip->close();
}
/**
* @param string $imagePath
* @param int $imageId
* @return string
*/
public function buildDrawingXML()
{
$imageRelationshipXML = '';
if(count($this->images) > 0) {
$imageRelationshipXML = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<xdr:wsDr xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">';
}
foreach($this->images as $imageId => $image) {
$imageOptions = $this->imageOptions[$imageId];
list($width, $height) = getimagesize($image['path']);
if($imageOptions['endColNum'] == 0 && $imageOptions['endRowNum'] == 0) {
$imageOptions['endColNum'] = round($height / 15); // MY EDIT
$imageOptions['endRowNum'] = round($width / 40); // MY EDIT
}
$endColOffset = round($width * 1);
$endRowOffset = round($height * 1);
$imageRelationshipXML .= '
<xdr:twoCellAnchor editAs="oneCell">
<xdr:from>
<xdr:col>' . $imageOptions['startColNum'] . '</xdr:col>
<xdr:colOff>0</xdr:colOff>
<xdr:row>' . $imageOptions['startRowNum'] . '</xdr:row>
<xdr:rowOff>0</xdr:rowOff>
</xdr:from>
<xdr:to>
<xdr:col>' . $imageOptions['endColNum'] . '</xdr:col>
<xdr:colOff>' . $endColOffset . '</xdr:colOff>
<xdr:row>' . $imageOptions['endRowNum'] . '</xdr:row>
<xdr:rowOff>' . $endRowOffset . '</xdr:rowOff>
</xdr:to>
<xdr:pic>
<xdr:nvPicPr>
<xdr:cNvPr id="' . $imageId . '" name="Picture ' . $imageId . '">
<a:extLst>
<a:ext uri="{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}">
<a16:creationId xmlns:a16="http://schemas.microsoft.com/office/drawing/2014/main" id="{D536D061-A3D2-4F2B-ACAF-CD70361876FA}" />
</a:ext>
</a:extLst>
</xdr:cNvPr>
<xdr:cNvPicPr>
<a:picLocks noChangeAspect="1" />
</xdr:cNvPicPr>
</xdr:nvPicPr>
<xdr:blipFill>
<a:blip xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:embed="rId'.$imageId.'" cstate="print">
<a:extLst>
<a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
<a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0" />
</a:ext>
</a:extLst>
</a:blip>
<a:stretch>
<a:fillRect/>
</a:stretch>
</xdr:blipFill>
<xdr:spPr>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
</xdr:spPr>
</xdr:pic>
<xdr:clientData />
</xdr:twoCellAnchor>';
}
if($imageRelationshipXML != '') {
$imageRelationshipXML .= '</xdr:wsDr>';
}
return $imageRelationshipXML;
}
/**
* @return string
*/
protected function buildContentTypesXML()
{
$content_types_xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>' . "\n";
$content_types_xml .= '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">';
$content_types_xml .= '
<Default Extension="jpeg" ContentType="image/jpeg" />
<Default Extension="png" ContentType="image/png" />
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />
<Default Extension="xml" ContentType="application/xml" />
';
foreach ($this->sheets as $sheet_name => $sheet) {
$content_types_xml .= '<Override PartName="/xl/worksheets/' . ($sheet->xmlname) . '" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>';
}
$content_types_xml .= '<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>';
$content_types_xml .= '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>';
if (count($this->images) > 0) {
$i = 1;
foreach ($this->sheets as $sheet_name => $sheet) {
$content_types_xml .= '<Override PartName="/xl/drawings/drawing' . ($i++) . '.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml" />';
}
}
$content_types_xml .= "\n";
$content_types_xml .= '</Types>';
return $content_types_xml;
}
/**
* @param $sheet_name
*/
protected function finalizeSheet($sheet_name, $i = 1)
{
if (empty($sheet_name) || $this->sheets[$sheet_name]->finalized)
return;
$sheet = &$this->sheets[$sheet_name];
$sheet->file_writer->write('</sheetData>');
if (!empty($sheet->merge_cells)) {
$sheet->file_writer->write('<mergeCells>');
foreach ($sheet->merge_cells as $range) {
$sheet->file_writer->write('<mergeCell ref="' . $range . '"/>');
}
$sheet->file_writer->write('</mergeCells>');
}
$sheet->file_writer->write('<printOptions headings="false" gridLines="false" gridLinesSet="true" horizontalCentered="false" verticalCentered="false"/>');
$sheet->file_writer->write('<pageMargins left="0.5" right="0.5" top="1.0" bottom="1.0" header="0.5" footer="0.5"/>');
$sheet->file_writer->write('<pageSetup blackAndWhite="false" cellComments="none" copies="1" draft="false" firstPageNumber="1" fitToHeight="1" fitToWidth="1" horizontalDpi="300" orientation="portrait" pageOrder="downThenOver" paperSize="1" scale="100" useFirstPageNumber="true" usePrinterDefaults="false" verticalDpi="300"/>');
$sheet->file_writer->write('<headerFooter differentFirst="false" differentOddEven="false">');
$sheet->file_writer->write('<oddHeader>&amp;C&amp;&quot;Times New Roman,Regular&quot;&amp;12&amp;A</oddHeader>');
$sheet->file_writer->write('<oddFooter>&amp;C&amp;&quot;Times New Roman,Regular&quot;&amp;12Page &amp;P</oddFooter>');
$sheet->file_writer->write('</headerFooter>');
if(count($this->getIgnoredErrorsCells()) > 0){
$sheet->file_writer->write('<ignoredErrors>');
foreach($this->getIgnoredErrorsCells() as $ignoredErrorsCell) {
$sheet->file_writer->write('<ignoredError sqref="' . $ignoredErrorsCell . '" numberStoredAsText="1"/>');
}
$sheet->file_writer->write('</ignoredErrors>');
}
if (count($this->images) > 0) {
$sheet->file_writer->write('<drawing r:id="rId' . $i . '" />');
}
$sheet->file_writer->write('</worksheet>');
$max_cell = $this->xlsCell($sheet->row_count - 1, count($sheet->columns) - 1);
$max_cell_tag = '<dimension ref="A1:' . $max_cell . '"/>';
$padding_length = $sheet->max_cell_tag_end - $sheet->max_cell_tag_start - strlen($max_cell_tag);
$sheet->file_writer->fseek($sheet->max_cell_tag_start);
$sheet->file_writer->write($max_cell_tag . str_repeat(" ", $padding_length));
$sheet->file_writer->close();
$sheet->finalized = true;
}
/**
* @return string
*/
public function buildDrawingRelationshipXML()
{
$drawingXML = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>' . "\n";
$drawingXML .= '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">';
foreach ($this->images as $imageId => $image) {
$drawingXML .= '<Relationship Id="rId' . $imageId . '" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/' . $image['name'] . '"/>';
}
$drawingXML .= "\n" . '</Relationships>';
return $drawingXML;
}
/**
* @param int $sheetId
* @return string
*/
public function buildSheetRelationshipXML($sheetId)
{
$lastRelationshipId = 0;
$rels_xml = "";
$rels_xml .= '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>' . "\n";
$rels_xml .= '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">';
if (count($this->images) > 0) {
foreach ($this->images as $imageId => $image) {
$rels_xml .= '<Relationship Id="rId' . (++$lastRelationshipId) . '" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing" Target="../drawings/drawing' . $sheetId . '.xml"/>';
}
}
$rels_xml .= "\n";
$rels_xml .= '</Relationships>';
return $rels_xml;
}
}
@NitemareReal
Copy link

New changes to show the picture with its original size if no end coordinates given

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment