mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-10 18:02:55 +00:00
perf: 优化缩略图
This commit is contained in:
parent
d799c06017
commit
8db34c6ee6
@ -96,14 +96,25 @@ class Handler extends ExceptionHandler
|
||||
$path = $request->path();
|
||||
|
||||
// 处理图片
|
||||
$pattern = '/^(uploads\/.*\.(png|jpg|jpeg))\/crop\/([^\/]+)$/';
|
||||
if (preg_match($pattern, $path, $matches)) {
|
||||
$patternCrop = '/^(uploads\/.*\.(png|jpg|jpeg))\/crop\/([^\/]+)$/';
|
||||
$patternThumb = '/^(uploads\/.*)_thumb\.(png|jpg|jpeg)$/';
|
||||
$matchesCrop = null;
|
||||
$matchesThumb = null;
|
||||
if (preg_match($patternCrop, $path, $matchesCrop) || preg_match($patternThumb, $path, $matchesThumb)) {
|
||||
// 获取参数
|
||||
$file = $matches[1];
|
||||
$ext = $matches[2];
|
||||
$rules = preg_replace('/\s+/', '', $matches[3]);
|
||||
$rules = str_replace(['=', '&'], [':', ','], $rules);
|
||||
$rules = explode(',', $rules);
|
||||
if ($matchesCrop) {
|
||||
$file = $matchesCrop[1];
|
||||
$ext = $matchesCrop[2];
|
||||
$rules = preg_replace('/\s+/', '', $matchesCrop[3]);
|
||||
$rules = str_replace(['=', '&'], [':', ','], $rules);
|
||||
$rules = explode(',', $rules);
|
||||
} elseif ($matchesThumb) {
|
||||
$file = $matchesThumb[1];
|
||||
$ext = $matchesThumb[2];
|
||||
$rules = ['percentage:320x0'];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (empty($rules)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
27
resources/assets/js/functions/common.js
vendored
27
resources/assets/js/functions/common.js
vendored
@ -1199,6 +1199,33 @@ const timezone = require("dayjs/plugin/timezone");
|
||||
}
|
||||
return result;
|
||||
}, {});
|
||||
},
|
||||
|
||||
/**
|
||||
* 从HTML中提取图片参数
|
||||
* @param imgTag
|
||||
* @returns {{original, src: (*|null), width: (number|*), height: (number|*)}}
|
||||
*/
|
||||
extractImageParameter(imgTag) {
|
||||
const srcMatch = imgTag.match(/\s+src=(["'])([^'"]*)\1/i);
|
||||
const widthMatch = imgTag.match(/\s+width=(["'])([^'"]*)\1/i);
|
||||
const heightMatch = imgTag.match(/\s+height=(["'])([^'"]*)\1/i);
|
||||
return {
|
||||
src: srcMatch ? srcMatch[2] : null,
|
||||
width: $A.runNum(widthMatch ? widthMatch[2] : 0),
|
||||
height: $A.runNum(heightMatch ? heightMatch[2] : 0),
|
||||
original: imgTag,
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 从HTML中提取所有图片参数
|
||||
* @param html
|
||||
* @returns {{original, src: (*|null), width: (number|*), height: (number|*)}[]}
|
||||
*/
|
||||
extractImageParameterAll(html) {
|
||||
const imgTags = html.match(/<img\s+[^>]*?>/g) || [];
|
||||
return imgTags.map(imgTag => this.extractImageParameter(imgTag));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
153
resources/assets/js/functions/web.js
vendored
153
resources/assets/js/functions/web.js
vendored
@ -249,26 +249,17 @@ import {MarkdownPreview} from "../store/markdown";
|
||||
text = text.replace(/<img\s+class="emoticon"[^>]*?>/g, `[${$A.L('动画表情')}]`)
|
||||
if (imgClassName) {
|
||||
text = text.replace(/<img\s+class="browse"[^>]*?src="(\S+)"[^>]*?>/g, function (res, src) {
|
||||
const widthMatch = res.match("width=\"(\\d+)\""),
|
||||
heightMatch = res.match("height=\"(\\d+)\"");
|
||||
if (widthMatch && heightMatch) {
|
||||
const data = {
|
||||
width: parseInt(widthMatch[1]),
|
||||
height: parseInt(heightMatch[1]),
|
||||
maxSize: 40,
|
||||
src
|
||||
}
|
||||
const ratioExceed = $A.imageRatioExceed(data.width, data.height, 2)
|
||||
if (ratioExceed > 0 && /\.(png|jpg|jpeg)$/.test(data.src)) {
|
||||
src = $A.thumbRestore(data.src) + `/crop/ratio:${ratioExceed},percentage:80x0`
|
||||
if (data.width > data.height) {
|
||||
data.width = data.height * ratioExceed;
|
||||
} else {
|
||||
data.height = data.width * ratioExceed;
|
||||
}
|
||||
}
|
||||
const scale = $A.scaleToScale(data.width, data.height, data.maxSize);
|
||||
imgClassName = `${imgClassName}" style="width:${scale.width}px;height:${scale.height}px`
|
||||
const item = $A.extractImageParameter(res);
|
||||
if (item.width && item.height) {
|
||||
const data = $A.imageRatioHandle({
|
||||
src: item.src,
|
||||
width: item.width,
|
||||
height: item.height,
|
||||
crops: {ratio: 2, percentage: '80x0'},
|
||||
scaleSize: 40,
|
||||
})
|
||||
src = data.src
|
||||
imgClassName = `${imgClassName}" style="width:${data.width}px;height:${data.height}px`
|
||||
}
|
||||
return `[image:${src}]`
|
||||
})
|
||||
@ -344,44 +335,25 @@ import {MarkdownPreview} from "../store/markdown";
|
||||
}).join("")
|
||||
}
|
||||
// 处理图片显示尺寸
|
||||
const array = text.match(/<img\s+[^>]*?>/g);
|
||||
if (array) {
|
||||
const widthReg = new RegExp("width=\"(\\d+)\""),
|
||||
heightReg = new RegExp("height=\"(\\d+)\"")
|
||||
array.some(res => {
|
||||
const widthMatch = res.match(widthReg),
|
||||
heightMatch = res.match(heightReg);
|
||||
if (widthMatch && heightMatch) {
|
||||
const data = {
|
||||
res,
|
||||
width: parseInt(widthMatch[1]),
|
||||
height: parseInt(heightMatch[1]),
|
||||
maxSize: res.indexOf("emoticon") > -1 ? 150 : 220, // 跟css中的设置一致
|
||||
}
|
||||
if (data.maxSize === 220) {
|
||||
const ratioExceed = $A.imageRatioExceed(data.width, data.height)
|
||||
if (ratioExceed > 0) {
|
||||
const srcMatch = res.match(/src=(["'])(([^'"]*)\.(png|jpg|jpeg))\1/);
|
||||
if (srcMatch) {
|
||||
data.res = data.res.replace(srcMatch[2], $A.thumbRestore(srcMatch[2]) + `/crop/ratio:${ratioExceed},percentage:320x0`)
|
||||
if (data.width > data.height) {
|
||||
data.width = data.height * ratioExceed;
|
||||
} else {
|
||||
data.height = data.width * ratioExceed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const scale = $A.scaleToScale(data.width, data.height, data.maxSize);
|
||||
const value = data.res
|
||||
.replace(widthReg, `original-width="${data.width}"`)
|
||||
.replace(heightReg, `original-height="${data.height}" style="width:${scale.width}px;height:${scale.height}px"`)
|
||||
text = text.replace(res, value)
|
||||
} else {
|
||||
text = text.replace(res, `<div class="no-size-image-box">${res}</div>`);
|
||||
}
|
||||
})
|
||||
}
|
||||
const items = $A.extractImageParameterAll(text);
|
||||
items.some(item => {
|
||||
if (item.src && item.width && item.height) {
|
||||
const data = $A.imageRatioHandle({
|
||||
src: item.src,
|
||||
width: item.width,
|
||||
height: item.height,
|
||||
crops: {ratio: 3, percentage: '320x0'},
|
||||
scaleSize: item.original.indexOf("emoticon") > -1 ? 150 : 220,
|
||||
})
|
||||
const value = item.original
|
||||
.replace(/\s+width=/, ` original-width=`)
|
||||
.replace(/\s+height=/, ` original-height=`)
|
||||
.replace(/\s+src=(["'])([^'"]*)\1/i, ` style="width:${data.width}px;height:${data.height}px" src="${data.src}"`)
|
||||
text = text.replace(item.original, value)
|
||||
} else {
|
||||
text = text.replace(item.original, `<div class="no-size-image-box">${item.original}</div>`);
|
||||
}
|
||||
})
|
||||
return text;
|
||||
},
|
||||
|
||||
@ -462,23 +434,14 @@ import {MarkdownPreview} from "../store/markdown";
|
||||
if (msg.type == 'img') {
|
||||
if (imgClassName) {
|
||||
// 缩略图,主要用于回复消息预览
|
||||
const data = {
|
||||
const data = $A.imageRatioHandle({
|
||||
src: msg.thumb,
|
||||
width: parseInt(msg.width),
|
||||
height: parseInt(msg.height),
|
||||
maxSize: 40,
|
||||
thumb: msg.thumb
|
||||
}
|
||||
const ratioExceed = $A.imageRatioExceed(data.width, data.height, 2)
|
||||
if (ratioExceed > 0 && /\.(png|jpg|jpeg)$/.test(data.thumb)) {
|
||||
data.thumb = $A.thumbRestore(data.thumb) + `/crop/ratio:${ratioExceed},percentage:80x0`
|
||||
if (data.width > data.height) {
|
||||
data.width = data.height * ratioExceed;
|
||||
} else {
|
||||
data.height = data.width * ratioExceed;
|
||||
}
|
||||
}
|
||||
const scale = $A.scaleToScale(data.width, data.height, data.maxSize);
|
||||
return `<img class="${imgClassName}" style="width:${scale.width}px;height:${scale.height}px" src="${data.thumb}">`
|
||||
crops: {ratio: 2, percentage: '80x0'},
|
||||
scaleSize: 40,
|
||||
})
|
||||
return `<img class="${imgClassName}" style="width:${data.width}px;height:${data.height}px" src="${data.src}">`
|
||||
}
|
||||
return `[${$A.L('图片')}]`
|
||||
} else if (msg.ext == 'mp4') {
|
||||
@ -564,6 +527,46 @@ import {MarkdownPreview} from "../store/markdown";
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* 图片尺寸比例超出
|
||||
* @param params {{src: *, width: (number|*), height: (number|*), crops: {percentage: string, ratio: number}, scaleSize: (number)}}
|
||||
* src, // 原图地址
|
||||
* width, // 原图宽度
|
||||
* height, // 原图高度
|
||||
* crops, // 裁剪参数,如:{ratio:3, percentage:"80x0"}
|
||||
* scaleSize, // 返回尺寸缩放最高尺寸
|
||||
*/
|
||||
imageRatioHandle(params) {
|
||||
if (!/\.(png|jpg|jpeg)$/.test(params.src)) {
|
||||
return params
|
||||
}
|
||||
|
||||
if (!$A.isJson(params.crops)) {
|
||||
return params
|
||||
}
|
||||
|
||||
params.src = $A.thumbRestore(params.src) + "/crop/" + Object.keys(params.crops).map(key => {
|
||||
return `${key}:${params.crops[key]}`
|
||||
}).join(",")
|
||||
|
||||
const ratio = $A.imageRatioExceed(params.width, params.height, params.crops.ratio)
|
||||
if (ratio > 0) {
|
||||
if (params.width > params.height) {
|
||||
params.width = params.height * ratio;
|
||||
} else {
|
||||
params.height = params.width * ratio;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.scaleSize) {
|
||||
const scale = $A.scaleToScale(params.width, params.height, params.scaleSize);
|
||||
params.width = scale.width;
|
||||
params.height = scale.height;
|
||||
}
|
||||
|
||||
return params;
|
||||
},
|
||||
|
||||
/**
|
||||
* 图片尺寸比例超出
|
||||
* @param width
|
||||
@ -572,8 +575,8 @@ import {MarkdownPreview} from "../store/markdown";
|
||||
* @param float
|
||||
* @returns {number}
|
||||
*/
|
||||
imageRatioExceed(width, height, ratio = 3, float = 0.5) {
|
||||
if (width && height) {
|
||||
imageRatioExceed(width, height, ratio, float = 0.5) {
|
||||
if (width && height && ratio) {
|
||||
if (width / height > (ratio + float) || height / width > (ratio + float)) {
|
||||
return ratio
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ export default {
|
||||
|
||||
imageStyle({width, height, ext}, type = 'style') {
|
||||
if (width && height) {
|
||||
const ratioExceed = $A.imageRatioExceed(width, height)
|
||||
const ratioExceed = $A.imageRatioExceed(width, height, 3)
|
||||
if (['png', 'jpg', 'jpeg'].includes(ext) && ratioExceed > 0) {
|
||||
if (width > height) {
|
||||
width = height * ratioExceed;
|
||||
@ -90,7 +90,7 @@ export default {
|
||||
},
|
||||
|
||||
imageSrc({width, height, ext, thumb}) {
|
||||
const ratioExceed = $A.imageRatioExceed(width, height)
|
||||
const ratioExceed = $A.imageRatioExceed(width, height, 3)
|
||||
if (['png', 'jpg', 'jpeg'].includes(ext) && ratioExceed > 0) {
|
||||
thumb = $A.thumbRestore(thumb) + `/crop/ratio:${ratioExceed},percentage:320x0`;
|
||||
}
|
||||
|
||||
@ -69,6 +69,6 @@ Route::middleware(['webapi'])->group(function () {
|
||||
Route::any('/{method}', IndexController::class);
|
||||
Route::any('/{method}/{action}', IndexController::class);
|
||||
Route::any('/{method}/{action}/{child}', IndexController::class);
|
||||
Route::any('/{method}/{action}/{child}/{n}', IndexController::class);
|
||||
Route::any('/{method}/{action}/{child}/{n}/{c}', IndexController::class);
|
||||
Route::any('/{method}/{action}/{child}/{n}', IndexController::class)->where('method', '^(?!uploads).*');
|
||||
Route::any('/{method}/{action}/{child}/{n}/{c}', IndexController::class)->where('method', '^(?!uploads).*');
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user