| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- // server/utils/textRegionCropper.js
- import sharp from 'sharp';
- class TextRegionCropper {
- constructor() {
- // 可以在这里添加配置参数
- }
- async cropTextRegion(imageBuffer, box, regionIndex) {
- try {
- const metadata = await sharp(imageBuffer).metadata();
- const imgWidth = metadata.width;
- const imgHeight = metadata.height;
- const left = Math.min(box.x1, box.x2, box.x3, box.x4);
- const top = Math.min(box.y1, box.y2, box.y3, box.y4);
- const right = Math.max(box.x1, box.x2, box.x3, box.x4);
- const bottom = Math.max(box.y1, box.y2, box.y3, box.y4);
- const originalWidth = right - left;
- const originalHeight = bottom - top;
- // 减少扩展,避免引入过多背景
- const widthExpand = 10;
- const heightExpand = 10;
- const newWidth = originalWidth + widthExpand;
- const newHeight = originalHeight + heightExpand;
- const centerX = (left + right) / 2;
- const centerY = (top + bottom) / 2;
- const expandedLeft = Math.max(0, centerX - newWidth / 2);
- const expandedTop = Math.max(0, centerY - newHeight / 2);
- const expandedRight = Math.min(imgWidth - 1, centerX + newWidth / 2);
- const expandedBottom = Math.min(imgHeight - 1, centerY + newHeight / 2);
- const finalWidth = expandedRight - expandedLeft;
- const finalHeight = expandedBottom - expandedTop;
- if (finalWidth <= 0 || finalHeight <= 0) {
- console.log(`❌ 区域 ${regionIndex}: 无效的裁剪区域`);
- return null;
- }
- let adjustedLeft = expandedLeft;
- let adjustedTop = expandedTop;
- let adjustedWidth = finalWidth;
- let adjustedHeight = finalHeight;
- if (expandedLeft < 0) {
- adjustedLeft = 0;
- adjustedWidth = expandedRight;
- }
- if (expandedTop < 0) {
- adjustedTop = 0;
- adjustedHeight = expandedBottom;
- }
- if (expandedRight > imgWidth) {
- adjustedWidth = imgWidth - adjustedLeft;
- }
- if (expandedBottom > imgHeight) {
- adjustedHeight = imgHeight - adjustedTop;
- }
- const croppedBuffer = await sharp(imageBuffer)
- .extract({
- left: Math.floor(adjustedLeft),
- top: Math.floor(adjustedTop),
- width: Math.floor(adjustedWidth),
- height: Math.floor(adjustedHeight)
- })
- .png()
- .toBuffer();
- console.log(`✂️ 区域 ${regionIndex}: 裁剪 ${Math.floor(adjustedWidth)}x${Math.floor(adjustedHeight)}`);
- return {
- buffer: croppedBuffer,
- boxInfo: {
- original: { left, top, right, bottom, width: originalWidth, height: originalHeight },
- expanded: {
- left: adjustedLeft,
- top: adjustedTop,
- right: adjustedLeft + adjustedWidth,
- bottom: adjustedTop + adjustedHeight,
- width: adjustedWidth,
- height: adjustedHeight
- }
- }
- };
- } catch (error) {
- console.error(`❌ 区域 ${regionIndex}: 裁剪失败`, error);
- return null;
- }
- }
- async rotateImage(imageBuffer, degrees) {
- return await sharp(imageBuffer)
- .rotate(degrees)
- .png()
- .toBuffer();
- }
- calculateExpansion(originalWidth, originalHeight, expansionFactor = 1.2) {
- return {
- width: originalWidth * expansionFactor,
- height: originalHeight * expansionFactor
- };
- }
- validateCropRegion(left, top, width, height, imgWidth, imgHeight) {
- if (width <= 0 || height <= 0) {
- return false;
- }
- if (left < 0 || top < 0) {
- return false;
- }
- if (left + width > imgWidth || top + height > imgHeight) {
- return false;
- }
- return true;
- }
- }
- export default TextRegionCropper;
|