生成 mask
图片加载
/**
* 加载图片
*/
export const imageLoad = (url: string): Promise<HTMLImageElement> => {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = (): void => {
resolve(img);
};
img.onerror = (err): void => {
reject(err);
};
img.src = url;
});
};
/**
* 图片url转成base64格式
*/
export const convertImageToBase64 = (imgUrl: string, background?: string): Promise<string> => {
const proxyURL = getProxyImageURL(imgUrl);
return new Promise<string>((resolve, reject) => {
const image = new Image();
image.crossOrigin = 'anonymous';
image.src = proxyURL;
image.onload = (): void => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) return;
canvas.height = image.naturalHeight;
canvas.width = image.naturalWidth;
if (!isEmpty(background)) {
ctx.fillStyle = background;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
ctx?.drawImage(image, 0, 0);
const base64data = canvas.toDataURL('image/png');
resolve(base64data);
};
image.onerror = (error): void => {
reject(`图片转base64失败${JSON.stringify(error)}`);
};
});
};
/**
* file转换为base64
* @param {*} data
* @param {*} filename
* @returns
*/
export const fileToBase64 = (file) => {
const reader = new FileReader();
reader.readAsDataURL(file);
return new Promise((resolve) => {
reader.addEventListener('load', (e) => {
const base64 = e.target.result;
resolve(base64);
});
});
};
/**
* 图片调整大小
* @param image
* @param width
* @param height
*/
export function imageResize (image: File, width: number, height: number) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => {
const img = new Image();
img.src = e.target?.result as string;
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
ctx?.drawImage(img, 0, 0, width, height);
// base64
const base64 = canvas.toDataURL('image/png');
resolve(base64);
};
};
reader.readAsDataURL(image);
});
}
1:1图片转 3:4
/**
* 1:1 图片转换 3:4
*/
export const imageToThreeFour = (imageStr: string): Promise<string> => {
return new Promise((resolve) => {
const image = new Image();
image.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) return;
const width = image.width;
const height = image.height;
console.log('change 11 34',width,height)
if(width != height) {
resolve(imageStr);
return;
}
const newWidth = width / 4 * 3;
const newHeight = height;
canvas.width = newWidth;
canvas.height = newHeight;
// 缩小的宽度去掉两边
const x = (width - newWidth) / 2;
// 裁剪
ctx.drawImage(image, x, 0, newWidth, height, 0, 0, newWidth, newHeight);
const base64 = canvas.toDataURL('image/png');
console.log('change 11 34',base64);
resolve(base64);
};
image.crossOrigin = 'Anonymous';
image.src = imageStr;
});
}
寻找最小图片边缘
// 裁剪图片至其最小尺寸的函数
export const cropImageToMinSize = (imageUrl: string): Promise<string> => {
return new Promise((resolve) => {
// 创建一个Image对象用于加载图片
const img = new Image();
// 设置图片加载完成后的回调函数
img.onload = function () {
// 创建一个Canvas元素
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) {
// 如果无法获取绘图上下文,则返回
return;
}
// 设置Canvas尺寸与图片尺寸相同
canvas.width = img.width;
canvas.height = img.height;
// 在Canvas上绘制图片
ctx.drawImage(img, 0, 0);
// 获取图片像素数据
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// 寻找图片内容的上下左右边界
let top = findEdge(data, canvas.width, canvas.height, true);
let bottom = findEdge(data, canvas.width, canvas.height, false);
let left = findEdge(data, canvas.height, img.width, true);
let right = findEdge(data, canvas.height, img.width, false);
// 定义寻找边缘的函数
function findEdge(data, length, width, isVertical) {
let edge;
for (edge = 0; edge < length; edge++) {
for (let i = 0; i < width; i++) {
const alpha = data[(isVertical ? edge : i) * width + (isVertical ? i : edge)] * 4 + 3;
if (alpha > 0) break;
}
if (i < width) break;
}
return edge;
}
// 计算裁剪后的图片尺寸
const croppedWidth = right - left + 1;
const croppedHeight = bottom - top + 1;
// 创建新的Canvas用于裁剪
const croppedCanvas = document.createElement('canvas');
const croppedCtx = croppedCanvas.getContext('2d');
// 设置新Canvas的尺寸与裁剪后的图片尺寸相同
croppedCanvas.width = croppedWidth;
croppedCanvas.height = croppedHeight;
// 在新Canvas上绘制裁剪后的图片
croppedCtx.drawImage(
img,
left,
top,
croppedWidth,
croppedHeight,
0,
0,
croppedWidth,
croppedHeight
);
// 将裁剪后的图片转换为base64格式
const croppedBase64 = croppedCanvas.toDataURL();
// 执行回调函数,返回结果
resolve(croppedBase64);
};
// 设置图片的跨域属性
img.crossOrigin = 'Anonymous';
// 加载图片
img.src = imageUrl;
});
};
自定义上传样式
/**
* 上传图片 点击
*/
const uploadImagesClick = (): void => {
const uploadCustomImage = document.getElementById('uploadCustomImage');
uploadCustomImage.click();
};
const prepareUploadFile: React.ChangeEventHandler<HTMLInputElement> = async (event) => {
const inputElement = event.target as HTMLInputElement;
// 获取单个文件
const file = inputElement.files?.[0];
if (isEmpty(file)) return;
// 仅支持 1 比 1 图片,不满足条件提示返回 获取图片宽高
const img = await imageLoad(await fileToBase64(file));
if (img.width !== img.height) {
message.error('图片宽高比例不符合要求,请重新选择');
return;
}
// TODO 调整图片大小为 1024 * 1024
customScenceImageBase64Ref.current = file;
setInpaintVisible(true);
};
<div className="item-option-wrap" onClick={uploadImagesClick}>
<input className="upload-input" type="file" id="uploadCustomImage" style={{ display: 'none' }}
accept=".png, .jpg, .jpeg" onChange={prepareUploadFile}/>
<PlusOutlined/>
<span className="local-upload-text">上传图片</span>
</div>
isEmpty
export const isEmpty = (key: any): boolean => {
if (key === undefined || key === '' || key === null) {
return true;
}
if (typeof (key) === 'string') {
key = key.replace(trimReg, '');
if (key == '' || key == null || key == 'null' || key == undefined || key == 'undefined') {
return true;
}
return false;
} else if (typeof (key) === 'undefined') {
return true;
} else if (typeof (key) === 'object') {
for (const i in key) {
return false;
}
return true;
} else if (typeof (key) === 'boolean') {
return false;
} else if (typeof (key) === 'number') {
return isNaN(key);
}
};
/**
* 不等于空
* @param key
*/
export const isNotEmpty = (key: any): boolean => {
return !isEmpty(key);
};
getAnyImage
export const getImageBodyAny = async (anyObj: any) => {
try {
if (isEmpty(anyObj)) {
return null;
}
// 如果是import('@fastify/multipart').MultipartFile 直接返回
if (anyObj[0]?.data) {
return anyObj[0].data;
}
if (typeof anyObj === 'string') {
// 判断是否为网络 url
if (anyObj.startsWith('http://') || anyObj.startsWith('https://')) {
const response: any = await got(anyObj, { responseType: 'buffer' });
return response.body;
} else if (checkStrIsBase64(anyObj)) {
// 将拿到的img由base64转换为byte[]
return base64ToFileObject(anyObj, 'test.jpg').buffer;
}
// 转buffer
return Buffer.from(anyObj);
} else if (anyObj instanceof Buffer) {
return anyObj;
}
return anyObj;
} catch (err) {
return null;
}
};
uploadOss
async uploadFile (fileDirType, buffer, fileNameSuffix) {
const { userId } = this.baseService.getUserInfo() || {};
const params = {
file: buffer,
uploadDir: generateOssFilePath(fileDirType, fileNameSuffix, userId),
};
// 上传文件到oss
const res = await this.ossService.uploadFile(params);
if (res.res.status !== 200) {
this.logger.error(`【volcengine_tss】上传文件到oss失败:${JSON.stringify(res)}`);
throw new CustomException({
code: 500,
message: `【volcengine_tss】上传文件到oss失败:${JSON.stringify(res)}`,
});
}
return res.url;
}
async formatImageAsURL (imageData: any, fileDirType:keyof typeof OssFileDir, fileNameSuffix: string): Promise<string> {
const buffer = await getImageBodyAny(imageData);
// 上传oss
return this.uploadFile(fileDirType, buffer, fileNameSuffix);
}