Skip to content

Commit 9588592

Browse files
authored
Merge branch 'master' into parsehuge4
2 parents e4efeff + d25979f commit 9588592

File tree

16 files changed

+522
-28
lines changed

16 files changed

+522
-28
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
1111

1212
- VSTACK and HSTACK. [Issue #4485](https://github.com/PHPOffice/PhpSpreadsheet/issues/4485) [PR #4492](https://github.com/PHPOffice/PhpSpreadsheet/pull/4492)
1313
- TOCOL and TOROW. [PR #4493](https://github.com/PHPOffice/PhpSpreadsheet/pull/4493)
14+
- Support Current Office Theme. [PR #4500](https://github.com/PHPOffice/PhpSpreadsheet/pull/4500)
1415

1516
### Removed
1617

@@ -26,12 +27,15 @@ and this project adheres to [Semantic Versioning](https://semver.org).
2627

2728
### Deprecated
2829

29-
- Nothing yet.
30+
- Theme constants COLOR_SCHEME_2013_PLUS_NAME (use COLOR_SCHEME_2013_2022_NAME) and COLOR_SCHEME_2013_PLUS (use COLOR_SCHEME_2013_2022).
3031

3132
### Fixed
3233

3334
- Various Writers RichText TextElement Should Inherit Cell Style. [Issue #1154](https://github.com/PHPOffice/PhpSpreadsheet/issues/1154) [PR #4487](https://github.com/PHPOffice/PhpSpreadsheet/pull/4487)
3435
- Minor Changes to FILTER function. [PR #4491](https://github.com/PHPOffice/PhpSpreadsheet/pull/4491)
36+
- Allow Xlsx Reader/Writer to support Font Charset. [Issue #2760](https://github.com/PHPOffice/PhpSpreadsheet/issues/2760) [PR #4501](https://github.com/PHPOffice/PhpSpreadsheet/pull/4501)
37+
- AutoColor for LibreOffice Dark Mode [Discussion 4502](https://github.com/PHPOffice/PhpSpreadsheet/discussions/4502) [PR #4503](https://github.com/PHPOffice/PhpSpreadsheet/pull/4503)
38+
- Xlsx Style Writer Minor Refactoring. [PR #4508](https://github.com/PHPOffice/PhpSpreadsheet/pull/4508)
3539

3640
## 2025-05-26 - 4.3.1
3741

docs/topics/recipes.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,21 @@ All cells bound to the theme fonts (via the `Font::setScheme` method) can be eas
10991099
$spreadsheet->resetThemeFonts();
11001100
```
11011101

1102+
### Charset for Arabic and Persian Fonts
1103+
1104+
It is unknown why this should be needed. However, some Excel
1105+
users have reported better results if the internal declaration for an
1106+
Arabic/Persian font includes a `charset` declaration.
1107+
This seems like a bug in Excel, but, starting with release 4.4,
1108+
this can be accomplished at the spreadsheet level, via:
1109+
```php
1110+
$spreadsheet->addFontCharset('C Nazanin');
1111+
```
1112+
As many charsets as desired can be added in this manner.
1113+
There is a second optional parameter specifying the charset id
1114+
to this method, but, since this seems to be needed only for
1115+
Arabic/Persian, that is its default value.
1116+
11021117
### Styling cell borders
11031118

11041119
In PhpSpreadsheet it is easy to apply various borders on a rectangular

samples/Chart33a/33_Chart_create_area_2.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
/** @var PhpOffice\PhpSpreadsheet\Helper\Sample $helper */
1414
$spreadsheet = new Spreadsheet();
1515
// same as 33_Chart_create_area, but with 2013+ schemes
16-
$spreadsheet->getTheme()->setThemeColorName(SpreadsheetTheme::COLOR_SCHEME_2013_PLUS_NAME);
16+
$spreadsheet->getTheme()->setThemeColorName(SpreadsheetTheme::COLOR_SCHEME_2013_2022_NAME);
1717
$worksheet = $spreadsheet->getActiveSheet();
1818
$worksheet->fromArray(
1919
[

src/PhpSpreadsheet/Reader/Xlsx.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,11 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
670670

671671
// add style to cellXf collection
672672
$objStyle = new Style();
673-
$this->styleReader->readStyle($objStyle, $style);
673+
$this->styleReader
674+
->readStyle($objStyle, $style);
675+
foreach ($this->styleReader->getFontCharsets() as $fontName => $charset) {
676+
$excel->addFontCharset($fontName, $charset);
677+
}
674678
if ($addingFirstCellXf) {
675679
$excel->removeCellXfByIndex(0); // remove the default style
676680
$addingFirstCellXf = false;

src/PhpSpreadsheet/Reader/Xlsx/Styles.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ class Styles extends BaseParserClass
3636

3737
private string $namespace = '';
3838

39+
/** @var array<string, int> */
40+
private array $fontCharsets = [];
41+
42+
/** @return array<string, int> */
43+
public function getFontCharsets(): array
44+
{
45+
return $this->fontCharsets;
46+
}
47+
3948
public function setNamespace(string $namespace): void
4049
{
4150
$this->namespace = $namespace;
@@ -85,6 +94,13 @@ public function readFontStyle(Font $fontStyle, SimpleXMLElement $fontStyleXml):
8594
if (isset($attr['val'])) {
8695
$fontStyle->setName((string) $attr['val']);
8796
}
97+
if (isset($fontStyleXml->charset)) {
98+
$charsetAttr = $this->getStyleAttributes($fontStyleXml->charset);
99+
if (isset($charsetAttr['val'])) {
100+
$charsetVal = (int) $charsetAttr['val'];
101+
$this->fontCharsets[$fontStyle->getName()] = $charsetVal;
102+
}
103+
}
88104
}
89105
if (isset($fontStyleXml->sz)) {
90106
$attr = $this->getStyleAttributes($fontStyleXml->sz);
@@ -136,6 +152,12 @@ public function readFontStyle(Font $fontStyle, SimpleXMLElement $fontStyleXml):
136152
$attr = $this->getStyleAttributes($fontStyleXml->scheme);
137153
$fontStyle->setScheme((string) $attr['val']);
138154
}
155+
if (isset($fontStyleXml->auto)) {
156+
$attr = $this->getStyleAttributes($fontStyleXml->auto);
157+
if (isset($attr['val'])) {
158+
$fontStyle->setAutoColor(self::boolean((string) $attr['val']));
159+
}
160+
}
139161
}
140162

141163
private function readNumberFormat(NumberFormat $numfmtStyle, SimpleXMLElement $numfmtStyleXml): void

src/PhpSpreadsheet/Spreadsheet.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PhpOffice\PhpSpreadsheet\Document\Properties;
99
use PhpOffice\PhpSpreadsheet\Document\Security;
1010
use PhpOffice\PhpSpreadsheet\Shared\Date;
11+
use PhpOffice\PhpSpreadsheet\Shared\Font as SharedFont;
1112
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
1213
use PhpOffice\PhpSpreadsheet\Style\Style;
1314
use PhpOffice\PhpSpreadsheet\Worksheet\Iterator;
@@ -177,6 +178,36 @@ class Spreadsheet implements JsonSerializable
177178

178179
private ?IValueBinder $valueBinder = null;
179180

181+
/** @var array<string, int> */
182+
private array $fontCharsets = [
183+
'B Nazanin' => SharedFont::CHARSET_ANSI_ARABIC,
184+
];
185+
186+
/**
187+
* @param int $charset uses any value from Shared\Font,
188+
* but defaults to ARABIC because that is the only known
189+
* charset for which this declaration might be needed
190+
*/
191+
public function addFontCharset(string $fontName, int $charset = SharedFont::CHARSET_ANSI_ARABIC): void
192+
{
193+
$this->fontCharsets[$fontName] = $charset;
194+
}
195+
196+
public function getFontCharset(string $fontName): int
197+
{
198+
return $this->fontCharsets[$fontName] ?? -1;
199+
}
200+
201+
/**
202+
* Return all fontCharsets.
203+
*
204+
* @return array<string, int>
205+
*/
206+
public function getFontCharsets(): array
207+
{
208+
return $this->fontCharsets;
209+
}
210+
180211
public function getTheme(): Theme
181212
{
182213
return $this->theme;

src/PhpSpreadsheet/Style/Font.php

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PhpOffice\PhpSpreadsheet\Style;
44

55
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
6+
use PhpOffice\PhpSpreadsheet\Theme;
67

78
class Font extends Supervisor
89
{
@@ -85,6 +86,8 @@ class Font extends Supervisor
8586
*/
8687
protected Color $color;
8788

89+
protected bool $autoColor = false;
90+
8891
public ?int $colorIndex = null;
8992

9093
protected string $scheme = '';
@@ -124,6 +127,14 @@ public function __construct(bool $isSupervisor = false, bool $isConditional = fa
124127
}
125128
}
126129

130+
public function applyThemeFonts(Theme $theme): void
131+
{
132+
$this->setName($theme->getMinorFontLatin());
133+
$this->setLatin($theme->getMinorFontLatin());
134+
$this->setEastAsian($theme->getMinorFontEastAsian());
135+
$this->setComplexScript($theme->getMinorFontComplexScript());
136+
}
137+
127138
/**
128139
* Get the shared style component for the currently active cell in currently active sheet.
129140
* Only used for style supervisor.
@@ -166,7 +177,7 @@ public function getStyleArray(array $array): array
166177
* );
167178
* </code>
168179
*
169-
* @param array{name?: string, latin?: string, eastAsian?: string, complexScript?: string, bold?: bool, italic?: bool, superscript?: bool, subscript?: bool, underline?: bool|string, strikethrough?: bool, color?: string[], size?: ?int, chartColor?: ChartColor, scheme?: string, cap?: string} $styleArray Array containing style information
180+
* @param array{name?: string, latin?: string, eastAsian?: string, complexScript?: string, bold?: bool, italic?: bool, superscript?: bool, subscript?: bool, underline?: bool|string, strikethrough?: bool, color?: string[], size?: ?int, chartColor?: ChartColor, scheme?: string, cap?: string, autoColor?: bool} $styleArray Array containing style information
170181
*
171182
* @return $this
172183
*/
@@ -185,7 +196,9 @@ public function applyFromArray(array $styleArray): static
185196
$this->setEastAsian($styleArray['eastAsian']);
186197
}
187198
if (isset($styleArray['complexScript'])) {
188-
$this->setComplexScript($styleArray['complexScript']);
199+
$this->setComplexScript(
200+
$styleArray['complexScript']
201+
);
189202
}
190203
if (isset($styleArray['bold'])) {
191204
$this->setBold($styleArray['bold']);
@@ -203,7 +216,9 @@ public function applyFromArray(array $styleArray): static
203216
$this->setUnderline($styleArray['underline']);
204217
}
205218
if (isset($styleArray['strikethrough'])) {
206-
$this->setStrikethrough($styleArray['strikethrough']);
219+
$this->setStrikethrough(
220+
$styleArray['strikethrough']
221+
);
207222
}
208223
if (isset($styleArray['color'])) {
209224
/** @var array{rgb?: string, argb?: string, theme?: int} */
@@ -223,6 +238,9 @@ public function applyFromArray(array $styleArray): static
223238
if (isset($styleArray['cap'])) {
224239
$this->setCap($styleArray['cap']);
225240
}
241+
if (isset($styleArray['autoColor'])) {
242+
$this->setAutoColor($styleArray['autoColor']);
243+
}
226244
}
227245

228246
return $this;
@@ -736,6 +754,7 @@ public function getHashCode(): string
736754
. ($this->subscript ? 't' : 'f')
737755
. $this->underline
738756
. ($this->strikethrough ? 't' : 'f')
757+
. ($this->autoColor ? 't' : 'f')
739758
. $this->color->getHashCode()
740759
. $this->scheme
741760
. implode(
@@ -777,6 +796,7 @@ protected function exportArray1(): array
777796
$this->exportArray2($exportedArray, 'superscript', $this->getSuperscript());
778797
$this->exportArray2($exportedArray, 'underline', $this->getUnderline());
779798
$this->exportArray2($exportedArray, 'underlineColor', $this->getUnderlineColor());
799+
$this->exportArray2($exportedArray, 'autoColor', $this->getAutoColor());
780800

781801
return $exportedArray;
782802
}
@@ -831,6 +851,29 @@ public function setHyperlinkTheme(): self
831851
return $this;
832852
}
833853

854+
public function setAutoColor(bool $autoColor): self
855+
{
856+
if ($this->isSupervisor) {
857+
$styleArray = $this->getStyleArray(['autoColor' => $autoColor]);
858+
$this->getActiveSheet()
859+
->getStyle($this->getSelectedCells())
860+
->applyFromArray($styleArray);
861+
} else {
862+
$this->autoColor = $autoColor;
863+
}
864+
865+
return $this;
866+
}
867+
868+
public function getAutoColor(): bool
869+
{
870+
if ($this->isSupervisor) {
871+
return $this->getSharedComponent()->getAutoColor();
872+
}
873+
874+
return $this->autoColor;
875+
}
876+
834877
/**
835878
* Implement PHP __clone to create a deep clone, not just a shallow copy.
836879
*/

src/PhpSpreadsheet/Theme.php

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ class Theme
99
private string $themeFontName = 'Office';
1010

1111
public const HYPERLINK_THEME = 10;
12-
public const COLOR_SCHEME_2013_PLUS_NAME = 'Office 2013+';
13-
public const COLOR_SCHEME_2013_PLUS = [
12+
public const COLOR_SCHEME_2013_2022_NAME = 'Office 2013-2022';
13+
public const COLOR_SCHEME_2013_2022 = [
1414
'dk1' => '000000',
1515
'lt1' => 'FFFFFF',
1616
'dk2' => '44546A',
@@ -24,6 +24,10 @@ class Theme
2424
'hlink' => '0563C1',
2525
'folHlink' => '954F72',
2626
];
27+
/** @deprecated 4.4.0 Use COLOR_SCHEME_2013_2022_NAME */
28+
public const COLOR_SCHEME_2013_PLUS_NAME = 'Office 2013+';
29+
/** @deprecated 4.4.0 Use COLOR_SCHEME_2013_2022 */
30+
public const COLOR_SCHEME_2013_PLUS = self::COLOR_SCHEME_2013_2022;
2731

2832
public const COLOR_SCHEME_2007_2010_NAME = 'Office 2007-2010';
2933
public const COLOR_SCHEME_2007_2010 = [
@@ -41,6 +45,22 @@ class Theme
4145
'folHlink' => '800080',
4246
];
4347

48+
public const COLOR_SCHEME_2023_PLUS_NAME = 'Office 2023+';
49+
public const COLOR_SCHEME_2023_PLUS = [
50+
'dk1' => '000000',
51+
'lt1' => 'FFFFFF',
52+
'dk2' => '0E2841',
53+
'lt2' => 'E8E8E8',
54+
'accent1' => '156082',
55+
'accent2' => 'E97132',
56+
'accent3' => '196B24',
57+
'accent4' => '0F9ED5',
58+
'accent5' => 'A02B93',
59+
'accent6' => '4EA72E',
60+
'hlink' => '467886',
61+
'folHlink' => '96607D',
62+
];
63+
4464
/** @var string[] */
4565
private array $themeColors = self::COLOR_SCHEME_2007_2010;
4666

@@ -155,17 +175,34 @@ public function getThemeColorName(): string
155175
}
156176

157177
/** @param null|string[] $themeColors */
158-
public function setThemeColorName(string $name, ?array $themeColors = null): self
178+
public function setThemeColorName(string $name, ?array $themeColors = null, ?Spreadsheet $spreadsheet = null): self
159179
{
160180
$this->themeColorName = $name;
161181
if ($name === self::COLOR_SCHEME_2007_2010_NAME) {
162182
$themeColors = $themeColors ?? self::COLOR_SCHEME_2007_2010;
163-
} elseif ($name === self::COLOR_SCHEME_2013_PLUS_NAME) {
164-
$themeColors = $themeColors ?? self::COLOR_SCHEME_2013_PLUS;
183+
$this->majorFontLatin = 'Cambria';
184+
$this->minorFontLatin = 'Calibri';
185+
} elseif ($name === self::COLOR_SCHEME_2013_PLUS_NAME) { //* @phpstan-ignore-line
186+
// delete this block when deprecated constants removed
187+
$themeColors = $themeColors ?? self::COLOR_SCHEME_2013_PLUS; //* @phpstan-ignore-line
188+
$this->majorFontLatin = 'Calibri Light';
189+
$this->minorFontLatin = 'Calibri';
190+
} elseif ($name === self::COLOR_SCHEME_2013_2022_NAME) {
191+
$themeColors = $themeColors ?? self::COLOR_SCHEME_2013_2022;
192+
$this->majorFontLatin = 'Calibri Light';
193+
$this->minorFontLatin = 'Calibri';
194+
} elseif ($name === self::COLOR_SCHEME_2023_PLUS_NAME) {
195+
$themeColors = $themeColors ?? self::COLOR_SCHEME_2023_PLUS;
196+
$this->majorFontLatin = 'Aptos Display';
197+
$this->minorFontLatin = 'Aptos Narrow';
165198
}
166199
if ($themeColors !== null) {
167200
$this->themeColors = $themeColors;
168201
}
202+
if ($spreadsheet !== null) {
203+
$spreadsheet->getDefaultStyle()->getFont()
204+
->applyThemeFonts($this);
205+
}
169206

170207
return $this;
171208
}

src/PhpSpreadsheet/Writer/Ods/Cell/Style.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,15 +204,26 @@ protected function writeTextProperties(CellStyle $style): void
204204

205205
if ($font->getBold()) {
206206
$this->writer->writeAttribute('fo:font-weight', 'bold');
207-
$this->writer->writeAttribute('style:font-weight-complex', 'bold');
208-
$this->writer->writeAttribute('style:font-weight-asian', 'bold');
207+
$this->writer->writeAttribute(
208+
'style:font-weight-complex',
209+
'bold'
210+
);
211+
$this->writer->writeAttribute(
212+
'style:font-weight-asian',
213+
'bold'
214+
);
209215
}
210216

211217
if ($font->getItalic()) {
212218
$this->writer->writeAttribute('fo:font-style', 'italic');
213219
}
214220

215-
$this->writer->writeAttribute('fo:color', sprintf('#%s', $font->getColor()->getRGB()));
221+
if ($font->getAutoColor()) {
222+
$this->writer
223+
->writeAttribute('style:use-window-font-color', 'true');
224+
} else {
225+
$this->writer->writeAttribute('fo:color', sprintf('#%s', $font->getColor()->getRGB()));
226+
}
216227

217228
if ($family = $font->getName()) {
218229
$this->writer->writeAttribute('fo:font-family', $family);

0 commit comments

Comments
 (0)