Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Some earlier branches remain supported and security fixes are applied to them; i
- `Document\Properties::setLanguage()`: the language of a spreadsheet as a BCP 47 tag, written and read as `dc:language` in Xlsx and Ods; the Ods writer also gives it to the default cell style, where LibreOffice keeps a spreadsheet's language, as LibreOffice writes it (the Western, Asian or complex slot by script, and `style:rfc-language-tag` for a tag with more than a language and a country), and the Ods reader reads it from there when there is no `dc:language`. Html writes and reads it as the `lang` of the `html` element. [Issue #5040](https://github.com/PHPOffice/PhpSpreadsheet/issues/5040) [PR #5041](https://github.com/PHPOffice/PhpSpreadsheet/pull/5041)
- Xlsx Writer and Reader: `Chart::setDescription()` is the alternative text of a chart, written as `descr` of the chart's frame and read back, and the frame takes the chart's name; LibreOffice exports it as `/Alt` of the chart in a tagged PDF. [Issue #5038](https://github.com/PHPOffice/PhpSpreadsheet/issues/5038) [PR #5039](https://github.com/PHPOffice/PhpSpreadsheet/pull/5039)
- `BaseDrawing::setDecorative()` marks an image as decorative. Xlsx writes and reads it as Excel and LibreOffice do (`adec:decorative` in the image's `cNvPr`), Ods as LibreOffice does (`loext:decorative` in the frame's graphic style, which the writer now defines; the reader also takes ODF 1.4's `draw:decorative`); LibreOffice then leaves the image out of a tagged PDF as an artifact. Html writes and reads it as an empty `alt`. [Issue #5036](https://github.com/PHPOffice/PhpSpreadsheet/issues/5036) [PR #5037](https://github.com/PHPOffice/PhpSpreadsheet/pull/5037)
- Xlsx Writer and Reader: the description of a header/footer image is its alternative text, `alt` on the VML shape as Excel writes it. [Issue #5056](https://github.com/PHPOffice/PhpSpreadsheet/issues/5056) [PR #5057](https://github.com/PHPOffice/PhpSpreadsheet/pull/5057)

### Removed

Expand Down
1 change: 1 addition & 0 deletions src/PhpSpreadsheet/Reader/Xlsx.php
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
if (isset($imageData['title'])) {
$hfImages[$shapeId]->setName((string) $imageData['title']);
}
$hfImages[$shapeId]->setDescription((string) $shape['alt']);

$hfImages[$shapeId]->setPath('zip://' . File::realpath($filename) . '#' . $drawings[(string) $imageData['relid']], false, $zip);
$hfImages[$shapeId]->setResizeProportional(false);
Expand Down
4 changes: 4 additions & 0 deletions src/PhpSpreadsheet/Writer/Xlsx/Drawing.php
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,10 @@ private function writeVMLHeaderFooterImage(XMLWriter $objWriter, string $referen
$objWriter->writeAttribute('o:spid', '_x0000_s' . $id);
$objWriter->writeAttribute('type', '#_x0000_t75');
$objWriter->writeAttribute('style', "position:absolute;margin-left:{$marginLeft}px;margin-top:{$marginTop}px;width:{$width}px;height:{$height}px;z-index:1");
// The alternative text, as Excel writes it; o:title below is the name
if ($image->getDescription() !== '') {
$objWriter->writeAttribute('alt', $image->getDescription());
}

// v:imagedata
$objWriter->startElement('v:imagedata');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooter;
use PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooterDrawing;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;

class HeaderFooterImageDescriptionTest extends AbstractFunctional
{
private static function spreadsheet(): Spreadsheet
{
$spreadsheet = new Spreadsheet();
$headerFooter = $spreadsheet->getActiveSheet()->getHeaderFooter();
$headerFooter->setOddHeader('&L&G&R&G');
foreach ([HeaderFooter::IMAGE_HEADER_LEFT => 'Company logo', HeaderFooter::IMAGE_HEADER_RIGHT => ''] as $location => $description) {
$image = new HeaderFooterDrawing();
$image->setName("Image $location");
$image->setDescription($description);
$image->setPath('samples/images/blue_square.png');
$image->setHeight(12);
$headerFooter->addImage($image, $location);
}

return $spreadsheet;
}

public function testWrittenAsAlt(): void
{
$spreadsheet = self::spreadsheet();
$vml = (new XlsxWriter($spreadsheet))->getWriterPartDrawing()->writeVMLHeaderFooterImages($spreadsheet->getActiveSheet());
self::assertMatchesRegularExpression('/<v:shape id="LH"[^>]* alt="Company logo"><v:imagedata [^>]*o:title="Image LH"/', $vml);
self::assertSame(1, substr_count($vml, ' alt='));
$spreadsheet->disconnectWorksheets();
}

public function testDescriptionSurvivesTheRoundTrip(): void
{
$spreadsheetOld = self::spreadsheet();
$spreadsheet = $this->writeAndReload($spreadsheetOld, 'Xlsx');
$spreadsheetOld->disconnectWorksheets();
$images = $spreadsheet->getActiveSheet()->getHeaderFooter()->getImages();
self::assertSame('Company logo', $images['LH']->getDescription());
self::assertSame('Image LH', $images['LH']->getName());
self::assertSame('', $images['RH']->getDescription());
$spreadsheet->disconnectWorksheets();
}
}
Loading