mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-09-28 08:05:29 +00:00
bb54c89cde
Fix #3405. Autosize is definitely not working well with CJK characters (column is not wide enough). User reports a workaround using `mb_strwidth` to calculate and set the column width. PhpSpreadsheet uses `mb_strlen` for width calculations. Change it to use mb_strwidth instead. For non-CJK strings, the results will be identical (and there are already unit tests on such strings which assert the expected results, and these tests did not need to change). For CJK strings, the results will be wider. The string I'm using to test comes from the issue. It currently results in a column width of 30.564. When I open the resulting sheet in Excel and auto-fit the column width, the width winds up as 43.00. So, as long as the computed width exceeds 43.00, the spreadsheet will show the full cell. With the new calculation, the computed width is 55.2722, satisfying our condition. This is wider than expected, but that is generally true for this type of computation. For example, for 'abcdefghijklmnopqrstuvwxyz', the computed width (before and after this change) is 31.7065, but Excel auto-fit actually uses 24.73. Disappointingly, "exact width calculation" does not solve this problem. It does seem to do a little better than "approximate" for non-CJK, but its CJK calculation is not wide enough. This might or might not indicate a bug in Php function `imagegetttfbbox`; I do not know enough about it to report a bug. Anyhow, since we're dependent on that result, there is no equivalent in this case for swapping mb_strlen out for mb_strwidth.
138 lines
4.6 KiB
PHP
138 lines
4.6 KiB
PHP
<?php
|
|
|
|
namespace PhpOffice\PhpSpreadsheetTests\Shared;
|
|
|
|
use PhpOffice\PhpSpreadsheet\Shared\Font;
|
|
use PhpOffice\PhpSpreadsheet\Style\Font as StyleFont;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class FontTest extends TestCase
|
|
{
|
|
const FONT_PRECISION = 1.0E-12;
|
|
|
|
public function testGetAutoSizeMethod(): void
|
|
{
|
|
$expectedResult = Font::AUTOSIZE_METHOD_APPROX;
|
|
|
|
$result = Font::getAutoSizeMethod();
|
|
self::assertEquals($expectedResult, $result);
|
|
}
|
|
|
|
public function testSetAutoSizeMethod(): void
|
|
{
|
|
$autosizeMethodValues = [
|
|
Font::AUTOSIZE_METHOD_EXACT,
|
|
Font::AUTOSIZE_METHOD_APPROX,
|
|
];
|
|
|
|
foreach ($autosizeMethodValues as $autosizeMethodValue) {
|
|
$result = Font::setAutoSizeMethod($autosizeMethodValue);
|
|
self::assertTrue($result);
|
|
}
|
|
}
|
|
|
|
public function testSetAutoSizeMethodWithInvalidValue(): void
|
|
{
|
|
$unsupportedAutosizeMethod = 'guess';
|
|
|
|
$result = Font::setAutoSizeMethod($unsupportedAutosizeMethod);
|
|
self::assertFalse($result);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider providerFontSizeToPixels
|
|
*
|
|
* @param mixed $expectedResult
|
|
* @param mixed $size
|
|
*/
|
|
public function testFontSizeToPixels($expectedResult, $size): void
|
|
{
|
|
$result = Font::fontSizeToPixels($size);
|
|
self::assertEquals($expectedResult, $result);
|
|
}
|
|
|
|
public function providerFontSizeToPixels(): array
|
|
{
|
|
return require 'tests/data/Shared/FontSizeToPixels.php';
|
|
}
|
|
|
|
/**
|
|
* @dataProvider providerInchSizeToPixels
|
|
*
|
|
* @param mixed $expectedResult
|
|
* @param mixed $size
|
|
*/
|
|
public function testInchSizeToPixels($expectedResult, $size): void
|
|
{
|
|
$result = Font::inchSizeToPixels($size);
|
|
self::assertEqualsWithDelta($expectedResult, $result, self::FONT_PRECISION);
|
|
}
|
|
|
|
public function providerInchSizeToPixels(): array
|
|
{
|
|
return require 'tests/data/Shared/InchSizeToPixels.php';
|
|
}
|
|
|
|
/**
|
|
* @dataProvider providerCentimeterSizeToPixels
|
|
*
|
|
* @param mixed $expectedResult
|
|
* @param mixed $size
|
|
*/
|
|
public function testCentimeterSizeToPixels($expectedResult, $size): void
|
|
{
|
|
$result = Font::centimeterSizeToPixels($size);
|
|
self::assertEqualsWithDelta($expectedResult, $result, self::FONT_PRECISION);
|
|
}
|
|
|
|
public function providerCentimeterSizeToPixels(): array
|
|
{
|
|
return require 'tests/data/Shared/CentimeterSizeToPixels.php';
|
|
}
|
|
|
|
public function testVerdanaRotation(): void
|
|
{
|
|
$font = new StyleFont();
|
|
$font->setName('Verdana')->setSize(10);
|
|
$width = Font::getTextWidthPixelsApprox('n', $font, 0);
|
|
self::assertEquals(8, $width);
|
|
$width = Font::getTextWidthPixelsApprox('n', $font, 45);
|
|
self::assertEquals(7, $width);
|
|
$width = Font::getTextWidthPixelsApprox('n', $font, -165);
|
|
self::assertEquals(4, $width);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider providerCalculateApproximateColumnWidth
|
|
*/
|
|
public function testCalculateApproximateColumnWidth(
|
|
float $expectedWidth,
|
|
StyleFont $font,
|
|
string $text,
|
|
int $rotation,
|
|
StyleFont $defaultFont,
|
|
bool $filter,
|
|
int $indent
|
|
): void {
|
|
$columnWidth = Font::calculateColumnWidth($font, $text, $rotation, $defaultFont, $filter, $indent);
|
|
self::assertEquals($expectedWidth, $columnWidth);
|
|
}
|
|
|
|
public function providerCalculateApproximateColumnWidth(): array
|
|
{
|
|
return [
|
|
[13.9966, new StyleFont(), 'Hello World', 0, new StyleFont(), false, 0],
|
|
[16.2817, new StyleFont(), 'Hello World', 0, new StyleFont(), true, 0],
|
|
[16.2817, new StyleFont(), 'Hello World', 0, new StyleFont(), false, 1],
|
|
[18.7097, new StyleFont(), 'Hello World', 0, new StyleFont(), false, 2],
|
|
[20.9949, new StyleFont(), 'Hello World', 0, new StyleFont(), false, 3],
|
|
[6.9983, new StyleFont(), "Hello\nWorld", 0, new StyleFont(), false, 0],
|
|
[9.2834, new StyleFont(), "Hello\nWorld", 0, new StyleFont(), true, 0],
|
|
[17.5671, new StyleFont(), 'PhpSpreadsheet', 0, new StyleFont(), false, 0],
|
|
[19.8523, new StyleFont(), 'PhpSpreadsheet', 0, new StyleFont(), false, 1],
|
|
'CJK characters width must be >= 43.00' => [55.2722, new StyleFont(), '如果某一列是CJK 其中的一种,这样的设置方式无效', 0, new StyleFont(), false, 0],
|
|
'non-CJK characters width must be >= 24.73' => [31.7065, new StyleFont(), 'abcdefghijklmnopqrstuvwxyz', 0, new StyleFont(), false, 0],
|
|
];
|
|
}
|
|
}
|