import resizeImage from "resize-image"; function mergeImages(sources = [], options = {}) { // Defaults let defaultOptions = { format: 'image/png', quality: 0.92, width: undefined, height: undefined, Canvas: undefined }; return new Promise(resolve => { options = Object.assign({}, defaultOptions, options); sources = sources.filter(source => source !== null && source !== undefined); // Setup browser/Node.js specific variables const canvas = options.Canvas ? new options.Canvas() : window.document.createElement('canvas'); const Image = options.Canvas ? options.Canvas.Image : window.Image; if (options.Canvas) { options.quality *= 100; } let targetSize = 64; let divider = 1; var size = 0; switch (sources.length) { case 2: size = (targetSize - 3 * divider) / 2; break; case 3: size = (targetSize - 3 * divider) / 2; break; case 4: size = (targetSize - 3 * divider) / 2; break; case 5: size = (targetSize - 4 * divider) / 3; break; case 6: size = (targetSize - 4 * divider) / 3; break; case 7: size = (targetSize - 4 * divider) / 3; break; case 8: size = (targetSize - 4 * divider) / 3; break; case 9: size = (targetSize - 4 * divider) / 3; break; default: break; } sources = sources.slice(0, sources.length >= 9 ? 9 : sources.length); // Load sources const images = sources.map(source => new Promise((resolve, reject) => { // Convert sources to objects if (source.constructor.name !== 'Object') { source = {src: source}; } // Resolve source and img when loaded const img = new Image(); img.setAttribute('crossOrigin', 'anonymous'); //img.onerror = () => reject(new Error('Couldn\'t load image')); img.onerror = () => resolve(null); img.onload = () => resolve(Object.assign({}, source, {data: resizeImage.resize(img, size, size, resizeImage.PNG)})); img.src = source.src; })); const loadResizedImages = (resizedImagesBase64) => resizedImagesBase64.map(image => new Promise((resolve, reject) => { // Resolve source and img when loaded const img = new Image(); img.setAttribute('crossOrigin', 'anonymous'); //img.onerror = () => reject(new Error('Couldn\'t load image2')); img.onerror = () => resolve(null); img.onload = () => resolve(Object.assign({}, {img})); img.src = image.data; })); // Get canvas context const ctx = canvas.getContext('2d'); // When sources have loaded resolve(Promise.all(images) .then((images) => { images = images.filter(i => i !== null); return Promise.all(loadResizedImages(images)); }) .then(images => { images = images.filter(i => i !== null); // Set canvas dimensions // const getSize = dim => options[dim] || Math.max(...images.map(image => image.img[dim])); // canvas.width = getSize('width'); // canvas.height = getSize('height'); canvas.width = targetSize; canvas.height = targetSize; switch (images.length) { case 2: images[0].x = divider; images[0].y = targetSize / 4; images[1].x = images[0].x + size + divider; images[1].y = images[0].y; break; case 3: images[0].x = targetSize / 4; images[0].y = divider; images[1].x = divider; images[1].y = images[0].y + size + divider; images[2].x = images[1].x + size + divider; images[2].y = images[1].y; break; case 4: images[0].x = divider; images[0].y = divider; images[1].x = images[0].x + size + divider; images[1].y = divider; images[2].x = divider; images[2].y = images[0].y + size + divider; images[3].x = images[2].x + size + divider; images[3].y = images[2].y; break; case 5: images[0].x = (targetSize - 2 * size - divider) / 2; images[0].y = (targetSize - 2 * size - divider) / 2; images[1].x = images[0].x + size + divider; images[1].y = images[0].y; images[2].x = divider; images[2].y = images[1].y + size + divider; images[3].x = images[2].x + size + divider; images[3].y = images[2].y; images[4].x = images[3].x + size + divider; images[4].y = images[2].y; break; case 6: images[0].x = divider; images[0].y = (targetSize - 2 * size - divider) / 2; images[1].x = images[0].x + size + divider; images[1].y = images[0].y; images[2].x = images[1].x + size + divider; images[2].y = images[0].y; images[3].x = divider; images[3].y = images[0].y + size + divider; images[4].x = images[3].x + size + divider; images[4].y = images[3].y; images[5].x = images[4].x + size + divider; images[5].y = images[3].y; break; case 7: images[0].x = divider + size + divider; images[0].y = divider; images[1].x = divider; images[1].y = images[0].y + size + divider; images[2].x = images[1].x + size + divider; images[2].y = images[1].y; images[3].x = images[2].x + size + divider; images[3].y = images[1].y; images[4].x = divider; images[4].y = images[1].y + size + divider; images[5].x = images[4].x + size + divider; images[5].y = images[4].y; images[6].x = images[5].x + size + divider; images[6].y = images[4].y; break; case 8: images[0].x = (targetSize - 2 * size - divider) / 2; images[0].y = divider; images[1].x = images[0].x + size + divider; images[1].y = images[0].y; images[2].x = divider; images[2].y = images[0].y + size + divider; images[3].x = images[2].x + size + divider; images[3].y = images[2].y images[4].x = images[3].x + size + divider; images[4].y = images[2].y; images[5].x = divider; images[5].y = images[2].y + size + divider; images[6].x = images[5].x + size + divider; images[6].y = images[5].y; images[7].x = images[6].x + size + divider; images[7].y = images[5].y; break; case 9: images[0].x = divider; images[0].y = divider; images[1].x = images[0].x + size + divider; images[1].y = images[0].y; images[2].x = images[1].x + size + divider; images[2].y = images[0].y; images[3].x = divider; images[3].y = images[0].y + size + divider; images[4].x = images[3].x + size + divider; images[4].y = images[3].y; images[5].x = images[4].x + size + divider; images[5].y = images[3].y; images[6].x = divider; images[6].y = images[3].y + size + divider; images[7].x = images[6].x + size + divider; images[7].y = images[6].y; images[8].x = images[7].x + size + divider; images[8].y = images[6].y; break; } ctx.fillStyle = '#CCCCCC'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw images to canvas images.forEach(image => { ctx.globalAlpha = image.opacity ? image.opacity : 1; return ctx.drawImage(image.img, image.x || 0, image.y || 0); }); if (options.Canvas && options.format === 'image/jpeg') { // Resolve data URI for node-canvas jpeg async return new Promise(resolve => { canvas.toDataURL(options.format, { quality: options.quality, progressive: false }, (err, jpeg) => { if (err) { throw err; } resolve(jpeg); }); }); } // Resolve all other data URIs sync return canvas.toDataURL(options.format, options.quality); })); }) } let groupPortraitMap = new Map(); window.__groupPortraitMap = groupPortraitMap; async function genGroupPortrait(groupMemberUsers) { let groupMemberPortraits = []; for (let i = 0; i < Math.min(9, groupMemberUsers.length); i++) { groupMemberPortraits.push(groupMemberUsers[i].portrait) } return await mergeImages(groupMemberPortraits); } // return {data uri, width, height} function imageThumbnail(file) { return new Promise((resolve, reject) => { var img = new Image(); img.setAttribute('crossOrigin', 'anonymous'); img.onload = () => { let resizedCanvas = resizeImage.resize2Canvas(img, 200, 200); resizedCanvas.toBlob((blob) => { var reader = new FileReader(); reader.readAsDataURL(blob); reader.onloadend = () => { let base64data = reader.result; resolve({thumbnail: base64data, width: img.naturalWidth, height: img.naturalHeight}); } reader.onerror = () => { resolve(null); } }, 'image/jpeg', 0.4); }; img.onerror = () => { resolve(null); } if (file.path) { if (file.path.startsWith('/')) { img.src = 'local-resource://' + (file.path.indexOf(file.name) > -1 ? file.path : file.path + file.name); // local image url } else { img.src = file.path; } } else { let reader = new FileReader(); reader.onload = function (event) { img.src = event.target.result; }; reader.readAsDataURL(file); } }); } // return {data uri, width, height} function videoThumbnail(file) { return new Promise( (resolve, reject) => { let video = document.getElementById('bgvid'); video.onplay = () => { console.log('------------ video onplay'); var canvas = document.createElement("canvas"); canvas.width = video.videoWidth; canvas.height = video.videoHeight; canvas.getContext('2d') .drawImage(video, 0, 0, canvas.width, canvas.height); var img = document.createElement("img"); img.src = canvas.toDataURL(); img.onload = () => { let resizedCanvas = resizeImage.resize2Canvas(img, 200, 200); resizedCanvas.toBlob((blob) => { var reader = new FileReader(); reader.readAsDataURL(blob); reader.onloadend = () => { let base64data = reader.result; resolve({thumbnail: base64data, width: video.videoWidth, height: video.videoHeight}); video.src = null; }; reader.onerror = () => { resolve(null); } }, 'image/jpeg', 0.4); }; img.onerror = () => { resolve(null); }; }; video.onerror = () => { resolve(null); }; _loadVideo(file) console.log('----------', video); }); } function _loadVideo(file) { let video = document.getElementById('bgvid'); if (file.path) { if (file.path.startsWith('/')) { video.src = 'local-resource://' + (file.path.indexOf(file.name) > -1 ? file.path : file.path + file.name); // local video url } else { video.src = file.path; } } else { let reader = new FileReader(); reader.onload = function (event) { video.src = event.target.result; }; reader.readAsDataURL(file); } } function videoDuration(file) { return new Promise( (resolve, reject) => { let video = document.getElementById('bgvid'); video.onplay = () => { resolve(video.duration); }; video.onerror = () => { resolve(0); }; _loadVideo(file) console.log('----------', video); }); } function dataURItoBlob(dataURI) { // convert base64 to raw binary data held in a string // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this let byteString = atob(dataURI.split(',')[1]); // separate out the mime component let mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; // write the bytes of the string to an ArrayBuffer let ab = new ArrayBuffer(byteString.length); let ia = new Uint8Array(ab); for (let i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ab], {type: mimeString}); } function fileFromDataUri(dataUri, fileName) { const blob = dataURItoBlob(dataUri); const resultFile = new File([blob], fileName); return resultFile; } function scaleDown(width, height, maxWidth, maxHeight) { if (width < maxWidth && height < maxHeight) { return {width, height} } const widthRatio = maxWidth / width; const heightRatio = maxHeight / height; // 计算比例最小的缩放倍数 const scale = Math.min(widthRatio, heightRatio); // 缩放后的宽度和高度 const scaledWidth = width * scale; const scaledHeight = height * scale; return {width: Math.ceil(scaledWidth), height: Math.ceil(scaledHeight)}; } export {mergeImages, genGroupPortrait, videoThumbnail, videoDuration, imageThumbnail, fileFromDataUri, scaleDown};