Skip to content

Commit eb48626

Browse files
committed
Support Current Office Theme
A while back, Microsoft introduced changes to the default theme colors and fonts. We are adding support for this new theme so that users can use it easily on new spreadsheets if they wish. (It is already supported when using the Xlsx Reader to load an appropriate file.) The old theme was described by constants COLOR_SCHEME_2013_PLUS_NAME and COLOR_SCHEME_2013_PLUS; these are deprecated in favor of COLOR_SCHEME_2013_2022_NAME and COLOR_SCHEME_2013_2022. The new theme is described by constants COLOR_SCHEME_2023_PLUS_NAME and COLOR_SCHEME_2023_PLUS. PhpSpreadsheet's default theme remains COLOR_SCHEME_2007_2010, to avoid breaking changes. A third optional parameter `$spreadsheet` is added to setThemeColorName. If specified, the default font names for the theme will be applied to the default style for the spreadsheet. You can thus use the new theme with its relatively new default `Aptos Narrow` font. IMHO, that isn't necessarily a good choice, but it is available. MS stores the new font in a different location than other system fonts, and that can lead to portability problems, e.g. if your spreadsheet uses Aptos and you export it to Html, browsers will not be able to find the font and a substitute font will be used.
1 parent 44c3bd5 commit eb48626

File tree

4 files changed

+139
-8
lines changed

4 files changed

+139
-8
lines changed

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/Style/Font.php

Lines changed: 9 additions & 0 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
{
@@ -124,6 +125,14 @@ public function __construct(bool $isSupervisor = false, bool $isConditional = fa
124125
}
125126
}
126127

128+
public function applyThemeFonts(Theme $theme): void
129+
{
130+
$this->setName($theme->getMinorFontLatin());
131+
$this->setLatin($theme->getMinorFontLatin());
132+
$this->setEastAsian($theme->getMinorFontEastAsian());
133+
$this->setComplexScript($theme->getMinorFontComplexScript());
134+
}
135+
127136
/**
128137
* Get the shared style component for the currently active cell in currently active sheet.
129138
* Only used for style supervisor.

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
}

tests/PhpSpreadsheetTests/Writer/Xlsx/ThemeColorsTest.php

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
88
use PhpOffice\PhpSpreadsheet\Spreadsheet;
9+
use PhpOffice\PhpSpreadsheet\Style\Style;
910
use PhpOffice\PhpSpreadsheet\Theme as SpreadsheetTheme;
1011
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
1112

@@ -14,11 +15,48 @@ class ThemeColorsTest extends AbstractFunctional
1415
public function testOffice2013Theme(): void
1516
{
1617
$spreadsheet = new Spreadsheet();
17-
$spreadsheet->getTheme()->setThemeColorName(SpreadsheetTheme::COLOR_SCHEME_2013_PLUS_NAME);
18+
$spreadsheet->getTheme()
19+
->setThemeColorName(
20+
SpreadsheetTheme::COLOR_SCHEME_2013_PLUS_NAME //* @phpstan-ignore-line
21+
);
1822
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
1923
$spreadsheet->disconnectWorksheets();
20-
self::assertSame('Office 2013+', $reloadedSpreadsheet->getTheme()->getThemeColorName());
24+
self::assertSame(
25+
SpreadsheetTheme::COLOR_SCHEME_2013_PLUS_NAME, //* @phpstan-ignore-line
26+
$reloadedSpreadsheet->getTheme()->getThemeColorName()
27+
);
2128
self::assertSame('FFC000', $reloadedSpreadsheet->getTheme()->getThemeColors()['accent4']);
29+
self::assertSame('Calibri Light', $reloadedSpreadsheet->getTheme()->getMajorFontLatin());
30+
self::assertSame('Calibri', $reloadedSpreadsheet->getTheme()->getMinorFontLatin());
31+
$defaultFont2 = $reloadedSpreadsheet->getDefaultStyle()->getFont()->getName();
32+
self::assertSame('Calibri', $defaultFont2);
33+
$font3 = $reloadedSpreadsheet->getActiveSheet()
34+
->getStyle('Z10')->getFont()->getName();
35+
self::assertSame('Calibri', $font3);
36+
$reloadedSpreadsheet->disconnectWorksheets();
37+
}
38+
39+
public function testOffice2013Theme2(): void
40+
{
41+
$spreadsheet = new Spreadsheet();
42+
$spreadsheet->getTheme()
43+
->setThemeColorName(
44+
SpreadsheetTheme::COLOR_SCHEME_2013_2022_NAME
45+
);
46+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
47+
$spreadsheet->disconnectWorksheets();
48+
self::assertSame(
49+
SpreadsheetTheme::COLOR_SCHEME_2013_2022_NAME,
50+
$reloadedSpreadsheet->getTheme()->getThemeColorName()
51+
);
52+
self::assertSame('FFC000', $reloadedSpreadsheet->getTheme()->getThemeColors()['accent4']);
53+
self::assertSame('Calibri Light', $reloadedSpreadsheet->getTheme()->getMajorFontLatin());
54+
self::assertSame('Calibri', $reloadedSpreadsheet->getTheme()->getMinorFontLatin());
55+
$defaultFont2 = $reloadedSpreadsheet->getDefaultStyle()->getFont()->getName();
56+
self::assertSame('Calibri', $defaultFont2);
57+
$font3 = $reloadedSpreadsheet->getActiveSheet()
58+
->getStyle('Z10')->getFont()->getName();
59+
self::assertSame('Calibri', $font3);
2260
$reloadedSpreadsheet->disconnectWorksheets();
2361
}
2462

@@ -30,6 +68,13 @@ public function testOffice2007Theme(): void
3068
$spreadsheet->disconnectWorksheets();
3169
self::assertSame('Office 2007-2010', $reloadedSpreadsheet->getTheme()->getThemeColorName());
3270
self::assertSame('8064A2', $reloadedSpreadsheet->getTheme()->getThemeColors()['accent4']);
71+
self::assertSame('Cambria', $reloadedSpreadsheet->getTheme()->getMajorFontLatin());
72+
self::assertSame('Calibri', $reloadedSpreadsheet->getTheme()->getMinorFontLatin());
73+
$defaultFont2 = $reloadedSpreadsheet->getDefaultStyle()->getFont()->getName();
74+
self::assertSame('Calibri', $defaultFont2);
75+
$font3 = $reloadedSpreadsheet->getActiveSheet()
76+
->getStyle('Z10')->getFont()->getName();
77+
self::assertSame('Calibri', $font3);
3378
$reloadedSpreadsheet->disconnectWorksheets();
3479
}
3580

@@ -40,6 +85,13 @@ public function testDefaultTheme(): void
4085
$spreadsheet->disconnectWorksheets();
4186
self::assertSame('Office', $reloadedSpreadsheet->getTheme()->getThemeColorName());
4287
self::assertSame('8064A2', $reloadedSpreadsheet->getTheme()->getThemeColors()['accent4']);
88+
self::assertSame('Cambria', $reloadedSpreadsheet->getTheme()->getMajorFontLatin());
89+
self::assertSame('Calibri', $reloadedSpreadsheet->getTheme()->getMinorFontLatin());
90+
$defaultFont2 = $reloadedSpreadsheet->getDefaultStyle()->getFont()->getName();
91+
self::assertSame('Calibri', $defaultFont2);
92+
$font3 = $reloadedSpreadsheet->getActiveSheet()
93+
->getStyle('Z10')->getFont()->getName();
94+
self::assertSame('Calibri', $font3);
4395
$reloadedSpreadsheet->disconnectWorksheets();
4496
}
4597

@@ -53,4 +105,37 @@ public function testGalleryTheme(): void
53105
self::assertSame('795FAF', $reloadedSpreadsheet->getTheme()->getThemeColors()['accent4']);
54106
$reloadedSpreadsheet->disconnectWorksheets();
55107
}
108+
109+
public function testOffice2023Theme(): void
110+
{
111+
$spreadsheet = new Spreadsheet();
112+
$spreadsheet->getTheme()
113+
->setThemeColorName(
114+
SpreadsheetTheme::COLOR_SCHEME_2023_PLUS_NAME,
115+
null,
116+
$spreadsheet
117+
);
118+
self::assertSame('Aptos Narrow', $spreadsheet->getDefaultStyle()->getFont()->getName(), 'default style is attached to spreadsheet');
119+
$style = new Style();
120+
self::assertSame('Calibri', $style->getFont()->getName(), 'style not attached to spreadsheet');
121+
$style2 = $spreadsheet->getActiveSheet()->getStyle('A7');
122+
self::assertSame('Aptos Narrow', $style2->getFont()->getName(), 'font is attached to spreadsheet');
123+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
124+
$spreadsheet->disconnectWorksheets();
125+
self::assertSame(
126+
SpreadsheetTheme::COLOR_SCHEME_2023_PLUS_NAME,
127+
$reloadedSpreadsheet->getTheme()->getThemeColorName()
128+
);
129+
self::assertSame('0F9ED5', $reloadedSpreadsheet->getTheme()->getThemeColors()['accent4']);
130+
self::assertSame('Aptos Display', $reloadedSpreadsheet->getTheme()->getMajorFontLatin());
131+
self::assertSame('Aptos Narrow', $reloadedSpreadsheet->getTheme()->getMinorFontLatin());
132+
$defaultFont = $reloadedSpreadsheet->getDefaultStyle()->getFont()->getName();
133+
self::assertSame('Aptos Narrow', $defaultFont);
134+
$defaultFont2 = $reloadedSpreadsheet->getDefaultStyle()->getFont()->getName();
135+
self::assertSame('Aptos Narrow', $defaultFont2);
136+
$font3 = $reloadedSpreadsheet->getActiveSheet()
137+
->getStyle('Z10')->getFont()->getName();
138+
self::assertSame('Aptos Narrow', $font3);
139+
$reloadedSpreadsheet->disconnectWorksheets();
140+
}
56141
}

0 commit comments

Comments
 (0)