美好生活&吃喝玩乐购

加水印代码再次优化

代码会自动:

阻止原图上传(返回false)

给图片添加水印

上传水印图

更新表单

// 图片上传控件 - 上传前 V8 事件
// 直接处理水印后上传,保留多图片

function getCurrentTime() {
    const date = new Date();
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    const seconds = String(date.getSeconds()).padStart(2, '0');
    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

const nowTime = getCurrentTime();
var userName = V8.CurrentUser.Name;
var dept = V8.CurrentUser.DeptName;

const watermarkConfig = {
    texts: [
        {
            text: nowTime,
            font: '16px "Microsoft YaHei"',
            color: 'rgba(0, 0, 0, 1)',
            position: 'bottomLeft',
            margin: 20,
            offsetX: 150,
            offsetY: -120,
            rotation: 0
        },
        {
            text: '记录人:' + userName,
            font: '20px Arial',
            color: 'rgba(0, 0, 0, 1)',
            position: 'bottomLeft',
            margin: 20,
            offsetX: 40,
            offsetY: -75,
            rotation: 0
        },
        {
            text: '记录部门:' + dept,
            font: '20px Arial',
            color: 'rgba(0, 0, 0, 1)',
            position: 'bottomLeft',
            margin: 20,
            offsetX: 40,
            offsetY: -35,
            rotation: 0
        }
    ],
    
    tile: false,
    tileSpacing: 200,
    
    logoUrl: 'https://x.pdyou.com/public/itdos/img/sy.png',
    logoWidth: 330,
    logoHeight: 200,
    logoOpacity: 0.8,
    logoPosition: 'bottomLeft',
    logoMargin: 20,
    logoOffsetX: 0,
    logoOffsetY: 0,
    logoRotation: 0,
    
    showMode: 'both'
};

function fileToBase64(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
        reader.onerror = reject;
        reader.readAsDataURL(file);
    });
}

function loadImage(src) {
    return new Promise((resolve, reject) => {
        const img = new Image();
        img.crossOrigin = 'anonymous';
        img.onload = () => resolve(img);
        img.onerror = reject;
        img.src = src;
    });
}

function getSingleTextPosition(canvas, textConfig) {
    const ctx = canvas.getContext('2d');
    ctx.font = textConfig.font;
    
    const lines = textConfig.text.split('\n');
    const fontSize = parseInt(textConfig.font) || 24;
    const lineHeight = fontSize * 1.5;
    const maxWidth = Math.max(...lines.map(line => ctx.measureText(line).width));
    const totalHeight = lines.length * lineHeight;
    
    let x, y;
    const margin = textConfig.margin || 20;
    const position = textConfig.position || 'bottomRight';
    
    switch (position) {
        case 'topLeft':
            x = margin + maxWidth / 2;
            y = margin + lineHeight;
            break;
        case 'topRight':
            x = canvas.width - margin - maxWidth / 2;
            y = margin + lineHeight;
            break;
        case 'bottomLeft':
            x = margin + maxWidth / 2;
            y = canvas.height - margin - totalHeight + lineHeight;
            break;
        case 'center':
            x = canvas.width / 2;
            y = canvas.height / 2;
            break;
        default:
            x = canvas.width - margin - maxWidth / 2;
            y = canvas.height - margin - totalHeight + lineHeight;
            break;
    }
    
    x += textConfig.offsetX || 0;
    y += textConfig.offsetY || 0;
    
    return { x, y, lines, lineHeight };
}

function drawSingleText(ctx, canvas, textConfig, globalTile, tileSpacing) {
    const text = textConfig.text || '';
    if (!text) return;
    
    ctx.save();
    ctx.font = textConfig.font;
    ctx.fillStyle = textConfig.color;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    
    const useTile = textConfig.tile !== undefined ? textConfig.tile : globalTile;
    const spacing = textConfig.tileSpacing || tileSpacing || 200;
    
    if (useTile) {
        if (textConfig.rotation) {
            ctx.translate(canvas.width / 2, canvas.height / 2);
            ctx.rotate(textConfig.rotation * Math.PI / 180);
            ctx.translate(-canvas.width / 2, -canvas.height / 2);
        }
        
        for (let px = spacing / 2; px < canvas.width; px += spacing) {
            for (let py = spacing / 2; py < canvas.height; py += spacing) {
                const lines = text.split('\n');
                const fontSize = parseInt(textConfig.font) || 24;
                const lineHeight = fontSize * 1.5;
                lines.forEach((line, index) => {
                    ctx.fillText(line, px, py + (index - (lines.length - 1) / 2) * lineHeight);
                });
            }
        }
    } else {
        const { x, y, lines, lineHeight } = getSingleTextPosition(canvas, textConfig);
        
        if (textConfig.rotation) {
            ctx.translate(x, y);
            ctx.rotate(textConfig.rotation * Math.PI / 180);
            ctx.translate(-x, -y);
        }
        
        lines.forEach((line, index) => {
            ctx.fillText(line, x, y + (index - (lines.length - 1) / 2) * lineHeight);
        });
    }
    
    ctx.restore();
}

function drawTextWatermark(ctx, canvas, config) {
    const texts = config.texts || [];
    texts.forEach(textConfig => {
        drawSingleText(ctx, canvas, textConfig, config.tile, config.tileSpacing);
    });
}

function getLogoPosition(canvas, logoWidth, logoHeight, config) {
    let x, y;
    const margin = config.logoMargin || 20;
    const position = config.logoPosition || 'bottomRight';
    
    switch (position) {
        case 'topLeft':
            x = margin;
            y = margin;
            break;
        case 'topRight':
            x = canvas.width - logoWidth - margin;
            y = margin;
            break;
        case 'bottomLeft':
            x = margin;
            y = canvas.height - logoHeight - margin;
            break;
        case 'center':
            x = (canvas.width - logoWidth) / 2;
            y = (canvas.height - logoHeight) / 2;
            break;
        default:
            x = canvas.width - logoWidth - margin;
            y = canvas.height - logoHeight - margin;
            break;
    }
    
    x += config.logoOffsetX || 0;
    y += config.logoOffsetY || 0;
    
    return { x, y };
}

async function drawLogoWatermark(ctx, canvas, config) {
    if (!config.logoUrl) return;
    
    try {
        const logo = await loadImage(config.logoUrl);
        
        const logoWidth = config.logoWidth || 100;
        const logoHeight = config.logoHeight || 50;
        
        ctx.save();
        ctx.globalAlpha = config.logoOpacity || 0.5;
        
        if (config.tile) {
            const spacing = config.tileSpacing || 200;
            for (let px = spacing / 2; px < canvas.width; px += spacing) {
                for (let py = spacing / 2; py < canvas.height; py += spacing) {
                    ctx.drawImage(logo, px - logoWidth / 2, py - logoHeight / 2, logoWidth, logoHeight);
                }
            }
        } else {
            const { x, y } = getLogoPosition(canvas, logoWidth, logoHeight, config);
            
            if (config.logoRotation) {
                ctx.translate(x + logoWidth / 2, y + logoHeight / 2);
                ctx.rotate(config.logoRotation * Math.PI / 180);
                ctx.translate(-(x + logoWidth / 2), -(y + logoHeight / 2));
            }
            
            ctx.drawImage(logo, x, y, logoWidth, logoHeight);
        }
        
        ctx.restore();
    } catch (e) {
        console.error('Logo 加载失败:', e);
    }
}

async function addWatermarkToBase64(base64, config) {
    const img = await loadImage(base64);
    
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = img.width;
    canvas.height = img.height;
    
    ctx.drawImage(img, 0, 0);
    
    const showMode = config.showMode || 'both';
    
    if (showMode === 'text') {
        drawTextWatermark(ctx, canvas, config);
    } else if (showMode === 'logo') {
        await drawLogoWatermark(ctx, canvas, config);
    } else if (showMode === 'both') {
        await drawLogoWatermark(ctx, canvas, config);
        drawTextWatermark(ctx, canvas, config);
    }
    
    return canvas.toDataURL('image/png');
}

function base64ToBlob(base64Data) {
    const byteCharacters = atob(base64Data);
    const byteNumbers = new Array(byteCharacters.length);
    for (let i = 0; i < byteCharacters.length; i++) {
        byteNumbers[i] = byteCharacters.charCodeAt(i);
    }
    return new Blob([new Uint8Array(byteNumbers)], { type: 'image/jpeg' });
}

function uploadWatermarkedImage(base64, fileName) {
    return new Promise((resolve, reject) => {
        const base64Data = base64.split(',')[1];
        const blob = base64ToBlob(base64Data);
        const timestamp = new Date().getTime();
        const nameParts = fileName.split('.');
        const ext = nameParts.pop();
        const baseName = nameParts.join('.');
        const watermarkedFileName = `${baseName}_watermarked_${timestamp}.jpg`;
        const file = new File([blob], watermarkedFileName, { type: 'image/jpeg' });
        
        const formData = new FormData();
        formData.append('file', file);
        formData.append('Path', '/img');
        formData.append('Limit', false);
        formData.append('Preview', false);
        
        V8.Post({
            url: '/api/HDFS/Upload',
            data: formData,
            success: (result) => {
                if (result && result.Code === 1) {
                    resolve(result);
                } else {
                    reject(new Error(result?.Msg || '上传失败'));
                }
            },
            fail: reject
        });
    });
}

// ========== 主流程 ==========
async function processUpload() {
    const originalFile = V8.ThisValue;
    const fieldName = 'YongpinTP';
    
    if (!originalFile) return false;
    
    // 检查是否已经是水印图
    if (originalFile.name && originalFile.name.includes('watermarked')) {
        console.log('已经是水印图,允许上传');
        return true;
    }
    
    let isMultiple = false;
    try {
        if (V8.Field?.[fieldName]?.Config?.ImgUpload?.Multiple === true) {
            isMultiple = true;
        }
    } catch (e) {}
    
    let existingImages = [];
    if (isMultiple) {
        let val = V8.Form[fieldName];
        if (typeof val === 'string') {
            try { val = JSON.parse(val); } catch (e) { val = []; }
        }
        if (Array.isArray(val)) {
            // 只保留已经是水印图的图片
            existingImages = val.filter(item => item.State === 1 && item.Name && item.Name.includes('watermarked'));
        }
    }
    
    try {
        console.log('处理水印:', originalFile.name);
        
        const base64 = await fileToBase64(originalFile);
        const watermarkedBase64 = await addWatermarkToBase64(base64, watermarkConfig);
        const uploadResult = await uploadWatermarkedImage(watermarkedBase64, originalFile.name);
        
        console.log('水印上传成功');
        
        const data = uploadResult.Data || {};
        const fileObject = {
            Id: data.Id,
            State: 1,
            Name: data.Name || originalFile.name,
            Size: data.Size || originalFile.size,
            CreateTime: data.CreateTime || new Date().toISOString().replace('T', ' ').split('.')[0],
            Path: data.Path
        };
        
        // 保留已有的水印图,添加新的
        if (isMultiple) {
            const allImages = [...existingImages, fileObject];
            V8.Form[fieldName] = allImages;
            console.log('当前图片数量:', allImages.length);
        } else {
            V8.Form[fieldName] = JSON.stringify(fileObject);
        }
        
        const fileServer = V8.SysConfig.FileServer || '';
        let realPath = data.Path;
        if (!realPath.startsWith('http') && fileServer) {
            realPath = fileServer + (realPath.startsWith('/') ? '' : '/') + realPath;
        }
        V8.Form[`${fieldName}_${data.Id}_RealPath`] = realPath;
        if (!isMultiple) {
            V8.Form[`${fieldName}_${fieldName}_RealPath`] = realPath;
        }
        
        if (V8.FieldSet) {
            V8.FieldSet(fieldName, 'Value', V8.Form[fieldName]);
        }
        
        V8.Tips('水印添加成功', true);
        
    } catch (e) {
        console.error('失败:', e);
        V8.Tips('水印添加失败', false);
    }
    
    // 返回 false 阻止原图上传
    return false;
}

processUpload();

 

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享