Files
mini-programs/src/components/UploadCover/upload-from-wx.tsx

154 lines
4.3 KiB
TypeScript

import React from "react";
import { View, Text } from "@tarojs/components";
import Taro from "@tarojs/taro";
import uploadApi from "@/services/uploadFiles";
import "./upload-from-wx.scss";
import { CoverImageValue } from ".";
export interface UploadFromWxProps {
onAdd: (
images: CoverImageValue[],
onFileUploaded: Promise<{ id: string; url: string }[]>
) => void;
maxCount: number;
}
async function convert_to_jpg_and_compress(
src: string,
{ width, height }
): Promise<string> {
const canvas = Taro.createOffscreenCanvas({ type: "2d", width, height });
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
const image = canvas.createImage();
await new Promise((resolve) => {
image.onload = resolve;
image.src = src;
});
ctx.clearRect(0, 0, width, height);
ctx.drawImage(image as unknown as CanvasImageSource, 0, 0, width, height);
// const imageData = ctx.getImageData(0, 0, width, height)
return new Promise((resolve, reject) => {
Taro.canvasToTempFilePath({
canvas: canvas as unknown as Taro.Canvas,
fileType: "jpg",
quality: 0.7,
success: (res) => resolve(res.tempFilePath),
fail: reject,
});
});
}
async function compressImage(files) {
const res: string[] = [];
for (const file of files) {
const compressed_image = await convert_to_jpg_and_compress(file.path, {
width: file.width,
height: file.height,
});
res.push(compressed_image);
}
return res;
}
// 图片标准容器为 360 * 240 3:2
// 压缩后图片最大宽高
const IMAGE_MAX_SIZE = {
width: 1080,
height: 720,
};
// 标准长宽比,判断标准
const STANDARD_ASPECT_RATIO = IMAGE_MAX_SIZE.width / IMAGE_MAX_SIZE.height;
type ChoosenImageRes = {
path: string;
size: number;
width: number;
height: number;
};
// 根据图片标准重新设置图片尺寸
async function onChooseImageSuccess(tempFiles) {
const result: ChoosenImageRes[] = [];
for (const tempFile of tempFiles) {
const { width, height } = await Taro.getImageInfo({ src: tempFile.path });
const image_aspect_ratio = width / height;
let fileRes: ChoosenImageRes = {
path: tempFile.path,
size: tempFile.size,
width: 0,
height: 0,
};
// 如果图片长宽比小于标准长宽比,则依照图片高度以及图片最大高度来重新设置图片尺寸
if (image_aspect_ratio < STANDARD_ASPECT_RATIO) {
fileRes = {
...fileRes,
...(height > IMAGE_MAX_SIZE.height
? {
width: Math.floor(IMAGE_MAX_SIZE.height * image_aspect_ratio),
height: IMAGE_MAX_SIZE.height,
}
: { width: Math.floor(height * image_aspect_ratio), height }),
};
} else {
fileRes = {
...fileRes,
...(width > IMAGE_MAX_SIZE.width
? {
width: IMAGE_MAX_SIZE.width,
height: Math.floor(IMAGE_MAX_SIZE.width / image_aspect_ratio),
}
: { width, height: Math.floor(width / image_aspect_ratio) }),
};
}
result.push(fileRes);
}
return result;
}
export default function UploadFromWx(props: UploadFromWxProps) {
const {
onAdd = () => void 0,
maxCount = 9, // calc from parent
} = props;
const handleImportFromWx = () => {
Taro.chooseImage({
count: maxCount,
sizeType: ["original", "compressed"],
sourceType: ["album", "camera"],
}).then(async (res) => {
const analyzedFiles = await onChooseImageSuccess(res.tempFiles);
// cropping image to standard size
const compressedTempFiles = await compressImage(analyzedFiles);
let start = Date.now();
const files = compressedTempFiles.map((path) => ({
filePath: path,
description: "封面图",
tags: "cover",
is_public: 1 as unknown as 0 | 1,
id: (start++).toString(),
}));
const onFileUpdate = uploadApi.batchUpload(files).then((res) => {
return res.map((item) => ({
id: item.id,
url: item ? item.data.file_url : "",
}));
});
onAdd(
files.map((item) => ({
id: item.id,
url: item.filePath,
})),
onFileUpdate
);
});
};
return (
<View onClick={handleImportFromWx}>
<Text className="upload-from-wx-text"></Text>
</View>
);
}