|
|
|
|
@ -264,6 +264,11 @@ class StudyTourDeclarationExporter
|
|
|
|
|
$full = storage_path('app/public/'.$rel);
|
|
|
|
|
$real = realpath($full);
|
|
|
|
|
$root = realpath(storage_path('app/public'));
|
|
|
|
|
if ($real === false || $root === false || ! is_file($real)) {
|
|
|
|
|
$full = public_path('storage/'.$rel);
|
|
|
|
|
$real = realpath($full);
|
|
|
|
|
$root = realpath(public_path('storage'));
|
|
|
|
|
}
|
|
|
|
|
if ($real === false || $root === false || ! is_file($real)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
@ -393,7 +398,7 @@ class StudyTourDeclarationExporter
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$size = self::coverImageSize($path);
|
|
|
|
|
$size = self::fitImageSize($path, 360, 240);
|
|
|
|
|
try {
|
|
|
|
|
$section->addImage($path, [
|
|
|
|
|
'width' => $size['width'],
|
|
|
|
|
@ -409,15 +414,13 @@ class StudyTourDeclarationExporter
|
|
|
|
|
/**
|
|
|
|
|
* @return array{width: int, height: int}
|
|
|
|
|
*/
|
|
|
|
|
private static function coverImageSize(string $path): array
|
|
|
|
|
private static function fitImageSize(string $path, int $maxW, int $maxH): array
|
|
|
|
|
{
|
|
|
|
|
$maxW = 360;
|
|
|
|
|
$maxH = 240;
|
|
|
|
|
$info = @getimagesize($path);
|
|
|
|
|
$w = is_array($info) ? (int) ($info[0] ?? 0) : 0;
|
|
|
|
|
$h = is_array($info) ? (int) ($info[1] ?? 0) : 0;
|
|
|
|
|
if ($w <= 0 || $h <= 0) {
|
|
|
|
|
return ['width' => $maxW, 'height' => 180];
|
|
|
|
|
return ['width' => $maxW, 'height' => (int) max(1, round($maxH * 0.75))];
|
|
|
|
|
}
|
|
|
|
|
$scale = min($maxW / $w, $maxH / $h, 1);
|
|
|
|
|
|
|
|
|
|
@ -429,18 +432,77 @@ class StudyTourDeclarationExporter
|
|
|
|
|
|
|
|
|
|
private static function addHtmlAsParagraphs($section, string $html): void
|
|
|
|
|
{
|
|
|
|
|
$text = self::htmlToPlainText($html);
|
|
|
|
|
if ($text === '') {
|
|
|
|
|
$html = trim($html);
|
|
|
|
|
$hasImage = (bool) preg_match('/<img\b/iu', $html);
|
|
|
|
|
if ($html === '' || (! $hasImage && self::htmlToPlainText($html) === '')) {
|
|
|
|
|
$section->addText('(暂无)', ['color' => '86909C'], ['spaceAfter' => 160]);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
foreach (preg_split('/\R/u', $text) ?: [] as $line) {
|
|
|
|
|
$line = trim($line);
|
|
|
|
|
if ($line === '') {
|
|
|
|
|
|
|
|
|
|
$parts = preg_split('/(<img\b[^>]*>)/iu', $html, -1, PREG_SPLIT_DELIM_CAPTURE) ?: [$html];
|
|
|
|
|
$wrote = false;
|
|
|
|
|
foreach ($parts as $part) {
|
|
|
|
|
$part = trim((string) $part);
|
|
|
|
|
if ($part === '') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (preg_match('/^<img\b/iu', $part)) {
|
|
|
|
|
self::addInlineImage($section, self::imgSrcFromTag($part), 480, 400);
|
|
|
|
|
$wrote = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$text = self::htmlToPlainText($part);
|
|
|
|
|
if ($text === '') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$section->addText($line, [], ['spaceAfter' => 80]);
|
|
|
|
|
foreach (preg_split('/\R/u', $text) ?: [] as $line) {
|
|
|
|
|
$line = trim($line);
|
|
|
|
|
if ($line === '') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$section->addText($line, [], ['spaceAfter' => 80]);
|
|
|
|
|
$wrote = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! $wrote) {
|
|
|
|
|
$section->addText('(暂无)', ['color' => '86909C'], ['spaceAfter' => 160]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function imgSrcFromTag(string $imgTag): ?string
|
|
|
|
|
{
|
|
|
|
|
if (! preg_match('/\bsrc\s*=\s*(?:(["\'])(.*?)\1|([^\s>]+))/iu', $imgTag, $matches)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
$quoted = trim((string) ($matches[2] ?? ''));
|
|
|
|
|
$bare = trim((string) ($matches[3] ?? ''));
|
|
|
|
|
$src = html_entity_decode($quoted !== '' ? $quoted : $bare, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
|
|
|
|
$src = trim($src);
|
|
|
|
|
|
|
|
|
|
return $src === '' ? null : $src;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function addInlineImage($section, ?string $src, int $maxW, int $maxH): void
|
|
|
|
|
{
|
|
|
|
|
$path = self::resolvePublicImagePath($src);
|
|
|
|
|
if ($path === null) {
|
|
|
|
|
$section->addText('(图片无法嵌入文档)', ['color' => '86909C'], ['spaceAfter' => 80]);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$size = self::fitImageSize($path, $maxW, $maxH);
|
|
|
|
|
try {
|
|
|
|
|
$section->addImage($path, [
|
|
|
|
|
'width' => $size['width'],
|
|
|
|
|
'height' => $size['height'],
|
|
|
|
|
'wrappingStyle' => 'inline',
|
|
|
|
|
]);
|
|
|
|
|
$section->addTextBreak(1);
|
|
|
|
|
} catch (\Throwable) {
|
|
|
|
|
$section->addText('(图片无法嵌入文档)', ['color' => '86909C'], ['spaceAfter' => 80]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|