Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

read hyperlink for drawing image #490

Closed
wants to merge 19 commits into from
18 changes: 18 additions & 0 deletions docs/references/features-cross-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,24 @@
<td></td>
<td></td>
</tr>
<tr>
<td style="padding-left: 1em;">Drawing hyperlink</td>
<td></td>
<td style="text-align: center; color: green;">✔</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td style="text-align: center; color: green;">✔</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>$drawing->getHyperlink()->getUrl()</td>
<td>$drawing->setHyperlink()->setUrl($url)</td>
</tr>
<tr>
<td><strong>Cell Formatting</strong></td>
<td></td>
Expand Down
58 changes: 58 additions & 0 deletions samples/Reader/20_Reader_worksheet_hyperlink_image.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

use PhpOffice\PhpSpreadsheet\Spreadsheet;

require __DIR__ . '/../Header.php';
$inputFileType = 'Xlsx';


$helper->log('Start');


$spreadsheet = new Spreadsheet();

$aSheet = $spreadsheet->getActiveSheet();

$gdImage = @imagecreatetruecolor(120, 20);
$textColor = imagecolorallocate($gdImage, 255, 255, 255);
imagestring($gdImage, 1, 5, 5, 'Created with PhpSpreadsheet', $textColor);

$baseUrl = 'https://phpspreadsheet.readthedocs.io/';

$drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing();
$drawing->setName('In-Memory image 1');
$drawing->setDescription('In-Memory image 1');
$drawing->setCoordinates('A1');
$drawing->setImageResource($gdImage);
$drawing->setRenderingFunction(
\PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::RENDERING_JPEG
);
$drawing->setMimeType(\PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_DEFAULT);
$drawing->setHeight(36);
$helper->log('Write image');

$hyperLink = new \PhpOffice\PhpSpreadsheet\Cell\Hyperlink($baseUrl, 'test image');
$drawing->setHyperlink($hyperLink);
$helper->log('Write link: ' . $baseUrl);

$drawing->setWorksheet($aSheet);


$filename = tempnam(\PhpOffice\PhpSpreadsheet\Shared\File::sysGetTempDir(), 'phpspreadsheet-test');


$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, $inputFileType);
$writer->save($filename);

$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);

$reloadedSpreadsheet = $reader->load($filename);
unlink($filename);

$helper->log('reloaded Spreadsheet');

foreach ($reloadedSpreadsheet->getActiveSheet()->getDrawingCollection() as $pDrawing) {
$helper->log('Read link: ' . $pDrawing->getHyperlink()->getUrl());
}

$helper->log('end');
8 changes: 8 additions & 0 deletions src/PhpSpreadsheet/Cell/Hyperlink.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ public function isInternal()
return strpos($this->url, 'sheet://') !== false;
}

/**
* @return string
*/
public function getTypeHyperlink()
{
return $this->isInternal() ? '' : 'External';
}

/**
* Get hash code.
*
Expand Down
37 changes: 36 additions & 1 deletion src/PhpSpreadsheet/Reader/Xlsx.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace PhpOffice\PhpSpreadsheet\Reader;

use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\Hyperlink;
use PhpOffice\PhpSpreadsheet\Document\Properties;
use PhpOffice\PhpSpreadsheet\NamedRange;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Chart;
Expand Down Expand Up @@ -1669,9 +1670,12 @@ public function load($pFilename)
Settings::getLibXmlLoaderOptions()
);
$images = [];

$hyperlinks = [];
if ($relsDrawing && $relsDrawing->Relationship) {
foreach ($relsDrawing->Relationship as $ele) {
if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink') {
$hyperlinks[(string) $ele['Id']] = (string) $ele['Target'];
}
if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
$images[(string) $ele['Id']] = self::dirAdd($fileDrawing, $ele['Target']);
} elseif ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart') {
Expand Down Expand Up @@ -1699,6 +1703,9 @@ public function load($pFilename)
$xfrm = $oneCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
/** @var SimpleXMLElement $outerShdw */
$outerShdw = $oneCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->effectLst->outerShdw;
/** @var \SimpleXMLElement $hlinkClick */
$hlinkClick = $oneCellAnchor->pic->nvPicPr->cNvPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->hlinkClick;

$objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$objDrawing->setName((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name'));
$objDrawing->setDescription((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr'));
Expand Down Expand Up @@ -1729,6 +1736,9 @@ public function load($pFilename)
$shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
$shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
}

$this->readHyperLinkDrawing($objDrawing, $oneCellAnchor, $hyperlinks);

$objDrawing->setWorksheet($docSheet);
} else {
// ? Can charts be positioned with a oneCellAnchor ?
Expand All @@ -1746,6 +1756,7 @@ public function load($pFilename)
$blip = $twoCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
$xfrm = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
$outerShdw = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->effectLst->outerShdw;
$hlinkClick = $twoCellAnchor->pic->nvPicPr->cNvPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->hlinkClick;
$objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$objDrawing->setName((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name'));
$objDrawing->setDescription((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr'));
Expand Down Expand Up @@ -1777,6 +1788,9 @@ public function load($pFilename)
$shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
$shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
}

$this->readHyperLinkDrawing($objDrawing, $twoCellAnchor, $hyperlinks);

$objDrawing->setWorksheet($docSheet);
} elseif (($this->includeCharts) && ($twoCellAnchor->graphicFrame)) {
$fromCoordinate = Coordinate::stringFromColumnIndex(((string) $twoCellAnchor->from->col) + 1) . ($twoCellAnchor->from->row + 1);
Expand Down Expand Up @@ -2385,6 +2399,27 @@ private static function boolean($value)
return $value === 'true' || $value === 'TRUE';
}

/**
* @param \PhpOffice\PhpSpreadsheet\Worksheet\Drawing $objDrawing
* @param \SimpleXMLElement $cellAnchor
* @param array $hyperlinks
*/
private function readHyperLinkDrawing($objDrawing, $cellAnchor, $hyperlinks)
{
$hlinkClick = $cellAnchor->pic->nvPicPr->cNvPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->hlinkClick;

if ($hlinkClick->count() === 0) {
return;
}

$hlinkId = (string) $hlinkClick->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships')['id'];
$hyperlink = new Hyperlink(
$hyperlinks[$hlinkId],
(string) self::getArrayItem($cellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name')
);
$objDrawing->setHyperlink($hyperlink);
}

private function readProtection(Spreadsheet $excel, SimpleXMLElement $xmlWorkbook)
{
if (!$xmlWorkbook->workbookProtection) {
Expand Down
24 changes: 24 additions & 0 deletions src/PhpSpreadsheet/Worksheet/BaseDrawing.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace PhpOffice\PhpSpreadsheet\Worksheet;

use PhpOffice\PhpSpreadsheet\Cell\Hyperlink;
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
use PhpOffice\PhpSpreadsheet\IComparable;

Expand Down Expand Up @@ -98,6 +99,13 @@ class BaseDrawing implements IComparable
*/
protected $shadow;

/**
* Image hyperlink.
*
* @var null | Hyperlink
*/
private $hyperlink;

/**
* Create a new BaseDrawing.
*/
Expand Down Expand Up @@ -508,4 +516,20 @@ public function __clone()
}
}
}

/**
* @param null | Hyperlink $pHyperlink
*/
public function setHyperlink(Hyperlink $pHyperlink = null)
{
$this->hyperlink = $pHyperlink;
}

/**
* @return null | Hyperlink
*/
public function getHyperlink()
{
return $this->hyperlink;
}
}
30 changes: 28 additions & 2 deletions src/PhpSpreadsheet/Writer/Xlsx/Drawing.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ public function writeDrawings(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWo
$i = 1;
$iterator = $pWorksheet->getDrawingCollection()->getIterator();
while ($iterator->valid()) {
$this->writeDrawing($objWriter, $iterator->current(), $i);
/** @var BaseDrawing $pDrawing */
$pDrawing = $iterator->current();
$pRelationId = $i;
$pHlinkClickId = $pDrawing->getHyperlink() === null ? null : ++$i;

$this->writeDrawing($objWriter, $pDrawing, $pRelationId, $pHlinkClickId);

$iterator->next();
++$i;
Expand Down Expand Up @@ -150,10 +155,11 @@ public function writeChart(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Chart
* @param XMLWriter $objWriter XML Writer
* @param BaseDrawing $pDrawing
* @param int $pRelationId
* @param null|int $pHlinkClickId
*
* @throws WriterException
*/
public function writeDrawing(XMLWriter $objWriter, BaseDrawing $pDrawing, $pRelationId = -1)
public function writeDrawing(XMLWriter $objWriter, BaseDrawing $pDrawing, $pRelationId = -1, $pHlinkClickId = null)
{
if ($pRelationId >= 0) {
// xdr:oneCellAnchor
Expand Down Expand Up @@ -187,6 +193,10 @@ public function writeDrawing(XMLWriter $objWriter, BaseDrawing $pDrawing, $pRela
$objWriter->writeAttribute('id', $pRelationId);
$objWriter->writeAttribute('name', $pDrawing->getName());
$objWriter->writeAttribute('descr', $pDrawing->getDescription());

//a:hlinkClick
$this->writeHyperLinkDrawing($objWriter, $pHlinkClickId);

$objWriter->endElement();

// xdr:cNvPicPr
Expand Down Expand Up @@ -490,4 +500,20 @@ public function allDrawings(Spreadsheet $spreadsheet)

return $aDrawings;
}

/**
* @param XMLWriter $objWriter
* @param null | int $pHlinkClickId
*/
private function writeHyperLinkDrawing(XMLWriter $objWriter, $pHlinkClickId)
{
if ($pHlinkClickId === null) {
return;
}

$objWriter->startElement('a:hlinkClick');
$objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
$objWriter->writeAttribute('r:id', 'rId' . $pHlinkClickId);
$objWriter->endElement();
}
}
33 changes: 32 additions & 1 deletion src/PhpSpreadsheet/Writer/Xlsx/Rels.php
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,16 @@ public function writeDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Wo
if ($iterator->current() instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing
|| $iterator->current() instanceof MemoryDrawing) {
// Write relationship for image drawing
/** @var \PhpOffice\PhpSpreadsheet\Worksheet\Drawing $drawing */
$drawing = $iterator->current();
$this->writeRelationship(
$objWriter,
$i,
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
'../media/' . str_replace(' ', '', $iterator->current()->getIndexedFilename())
'../media/' . str_replace(' ', '', $drawing->getIndexedFilename())
);

$i = $this->writeDrawingHyperLink($objWriter, $drawing, $i);
}

$iterator->next();
Expand Down Expand Up @@ -432,4 +436,31 @@ private function writeRelationship(XMLWriter $objWriter, $pId, $pType, $pTarget,
throw new WriterException('Invalid parameters passed.');
}
}

/**
* @param $objWriter
* @param \PhpOffice\PhpSpreadsheet\Worksheet\Drawing $drawing
* @param $i
*
* @throws WriterException
*
* @return int
*/
private function writeDrawingHyperLink($objWriter, $drawing, $i)
{
if ($drawing->getHyperlink() === null) {
return $i;
}

++$i;
$this->writeRelationship(
$objWriter,
$i,
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink',
$drawing->getHyperlink()->getUrl(),
$drawing->getHyperlink()->getTypeHyperlink()
);

return $i;
}
}
51 changes: 51 additions & 0 deletions tests/PhpSpreadsheetTests/Functional/DrawingImageHyperlinkTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
/**
* Created by PhpStorm.
* User: yuzhakov
* Date: 08.05.18
* Time: 12:00.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not use file comment blocks, please remove. You will be credited in the commit information.


namespace PhpOffice\PhpSpreadsheetTests\Functional;

use PhpOffice\PhpSpreadsheet\Cell\Hyperlink;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;

class DrawingImageHyperlinkTest extends AbstractFunctional
{
/**
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public function testDrawingImageHyperlinkTest()
{
$baseUrl = 'https://github.com/PHPOffice/PhpSpreadsheet';
$spreadsheet = new Spreadsheet();

$aSheet = $spreadsheet->getActiveSheet();

$gdImage = @imagecreatetruecolor(120, 20);
$textColor = imagecolorallocate($gdImage, 255, 255, 255);
imagestring($gdImage, 1, 5, 5, 'Created with PhpSpreadsheet', $textColor);

$drawing = new MemoryDrawing();
$drawing->setName('In-Memory image 1');
$drawing->setDescription('In-Memory image 1');
$drawing->setCoordinates('A1');
$drawing->setImageResource($gdImage);
$drawing->setRenderingFunction(
MemoryDrawing::RENDERING_JPEG
);
$drawing->setMimeType(MemoryDrawing::MIMETYPE_DEFAULT);
$drawing->setHeight(36);
$hyperLink = new Hyperlink($baseUrl, 'test image');
$drawing->setHyperlink($hyperLink);
$drawing->setWorksheet($aSheet);

$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');

foreach ($reloadedSpreadsheet->getActiveSheet()->getDrawingCollection() as $pDrawing) {
self::assertEquals('https://github.com/PHPOffice/PhpSpreadsheet', $pDrawing->getHyperlink()->getUrl(), 'functional test drawing hyperlink');
}
}
}