vue3-watermark-camera
Version:
A Vue 3 component for taking photos with watermark support
2 lines (1 loc) • 10.6 kB
JavaScript
;Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("vue");function R(){return{width:window.innerWidth,height:window.innerHeight,clientWidth:document.documentElement.clientWidth,clientHeight:document.documentElement.clientHeight}}function z(a,t,o={}){return new Promise((e,r)=>{const{showTime:i=!0,showLocation:d=!0,showName:u=!0,showCompany:g=!0,backgroundColor:f="rgba(0,0,0,0.5)",textColor:p="#fff",fontSize:k=14}=o,y=t.name||"用户",b=t.company||"公司",N=R(),E=N.width,v=N.height,c=window.devicePixelRatio||1,n=document.getElementById("watermarkCanvas"),s=n.getContext("2d")||{};n.width=E*c,n.height=v*c,n.style.width=E+"px",n.style.height=v+"px",s.setTransform(c,0,0,c,0,0);const h=new Image;h.crossOrigin="anonymous",h.onload=()=>{var U;s.drawImage(h,0,0,E,v);const w=16,L=E-w*2,S=12,A=o.height||110,P=v-A-w-20,V=w;s.fillStyle=f,J(s,V,P,L,A,S),s.fill(),s.fillStyle=p,s.textBaseline="top";let B=P+26;const W=L*.4,F=L*.6,D=V,C=V+W;if(i&&t.time){const m=((U=t.time.split(" ")[1])==null?void 0:U.slice(0,5))||"";s.font="bold 32px Arial";const x=s.measureText(m).width,K=D+(W-x)/2;s.fillText(m,K,B),B+=36;const _=t.time.split(" ")[0]||"";s.font=`bold ${k}px Arial`;const O=s.measureText(_).width,q=D+(W-O)/2;s.fillText(_,q,B)}s.beginPath(),s.moveTo(C-16,P+12),s.lineTo(C-16,P+A-12),s.strokeStyle=p,s.lineWidth=2,s.stroke();let T=P+16;if(s.textAlign="left",u&&(s.font="bold 18px Arial",s.fillText(y,C+16,T),T+=24),g){s.font=`${k}px Arial`;let m=b;const x=F-24;if(s.measureText(m).width>x){for(;s.measureText(m+"...").width>x&&m.length>0;)m=m.slice(0,-1);m+="..."}s.fillText(m,C,T),T+=20}if(d&&t.lat&&t.lng){const m=Y(t.lat,t.lng);s.font=`${k}px Arial`,s.fillText(m,C,T),T+=20}if(d&&t.address){s.font=`${k}px Arial`;let m=t.address;m.length>30&&(m=m.slice(0,30)+"..."),G(s,m,C,T,F-12,18,!1)}const M=n.toDataURL("image/jpeg",.9);e(M)},h.onerror=()=>r(new Error("图片加载失败")),h.src=a})}function G(a,t,o,e,r,i,d=!1){let u="";for(let f=0;f<t.length;f++){const p=u+t[f];if(a.measureText(p).width>r&&f>0){let y=o;if(d){const b=a.measureText(u).width;y=o+(r-b)/2}a.fillText(u,y,e),e+=i,u=t[f]}else u=p}let g=o;if(d){const f=a.measureText(u).width;g=o+(r-f)/2}a.fillText(u,g,e)}function J(a,t,o,e,r,i){a.beginPath(),a.moveTo(t+i,o),a.lineTo(t+e-i,o),a.arcTo(t+e,o,t+e,o+i,i),a.lineTo(t+e,o+r-i),a.arcTo(t+e,o+r,t+e-i,o+r,i),a.lineTo(t+i,o+r),a.arcTo(t,o+r,t,o+r-i,i),a.lineTo(t,o+i),a.arcTo(t,o,t+i,o,i),a.closePath()}function Y(a,t){return!a||!t?"":`${Number(a).toFixed(6)}°N,${Number(t).toFixed(6)}°E`}async function j(){return new Promise((a,t)=>{if(!navigator.geolocation){t(new Error("浏览器不支持定位"));return}navigator.geolocation.getCurrentPosition(o=>{const{latitude:e,longitude:r}=o.coords;a({latitude:e,longitude:r})},o=>{t(o)},{enableHighAccuracy:!0,timeout:8e3,maximumAge:6e4})})}async function Q(){return new Promise((a,t)=>{if(typeof window.dd>"u"){t(new Error("钉钉 JSAPI 未加载"));return}window.dd.getLocation({targetAccuracy:"200",cacheTimeout:20,coordinate:"1",useCache:!0,withReGeocode:!0,type:1,success:o=>{const{address:e,latitude:r,longitude:i}=o;a({latitude:r,longitude:i,address:e})},fail:o=>{t(o)}})})}async function Z(a,t,o){return new Promise((e,r)=>{const i=new XMLHttpRequest;i.open("GET",`https://restapi.amap.com/v3/geocode/regeo?key=${o}&location=${t},${a}`),i.onload=()=>{try{const d=JSON.parse(i.responseText);d&&d.regeocode?e(d.regeocode.formatted_address):e("")}catch(d){r(d)}},i.onerror=()=>r(new Error("网络请求失败")),i.send()})}function H(){if(typeof navigator>"u")return"browser";const a=navigator.userAgent.toLowerCase();return a.includes("dingtalk")?"dingtalk":a.includes("micromessenger")?"wechat":a.includes("alipay")?"alipay":"browser"}async function ee(a){const t=a||"https://quan.suning.com/getSysTime.do";return new Promise(o=>{const e=new XMLHttpRequest;e.open("GET",t),e.onload=()=>{try{const r=JSON.parse(e.responseText);r&&r.sysTime2?o(r.sysTime2):o(new Date().toLocaleString())}catch{o(new Date().toLocaleString())}},e.onerror=()=>o(new Date().toLocaleString()),e.send()})}function $(){return new Date().toLocaleString()}async function te(a){return new Promise((t,o)=>{const e=document.createElement("input");e.type="file",e.accept="image/*",e.capture=a==null?void 0:a.facingMode,e.style.display="none",document.body.appendChild(e),e.onchange=r=>{var d;const i=(d=r.target.files)==null?void 0:d[0];if(i){const u=new FileReader;u.onload=g=>{var p;const f=(p=g.target)==null?void 0:p.result;t(f),document.body.removeChild(e)},u.onerror=()=>{o(new Error("文件读取失败")),document.body.removeChild(e)},u.readAsDataURL(i)}else o(new Error("未选择文件")),document.body.removeChild(e)},e.onerror=()=>{o(new Error("相机调用失败")),document.body.removeChild(e)},e.click()})}async function oe(a,t,o){const e=new FormData;e.append("file",a);const r=await fetch(t,{method:"POST",body:e,headers:{...o}});if(!r.ok)throw new Error(`上传失败: ${r.status}`);return r.json()}function I(a,t){var u;const o=a.split(","),e=((u=o[0].match(/:(.*?);/))==null?void 0:u[1])||"image/jpeg",r=atob(o[1]);let i=r.length;const d=new Uint8Array(i);for(;i--;)d[i]=r.charCodeAt(i);return new File([d],t,{type:e})}const ne={class:"watermark-camera"},ae={key:0,class:"camera-btn-group"},re={key:1,class:"photo-thumb"},ie=["src"],se={class:"modal-content"},le=["src"],ce=l.defineComponent({__name:"WatermarkCamera",props:{modelValue:{},name:{default:"用户"},company:{default:"公司"},action:{default:""},amapKey:{default:""},watermarkConfig:{default:()=>({showTime:!0,showLocation:!0,showName:!0,showCompany:!0,backgroundColor:"rgba(0,0,0,0.5)",textColor:"#fff",fontSize:14,height:110})},locationConfig:{default:()=>({enableLocation:!0,locationProvider:"h5"})},timeConfig:{default:()=>({enableNetworkTime:!0,networkTimeUrl:"https://quan.suning.com/getSysTime.do"})},uploadConfig:{default:()=>({enableAutoUpload:!0})},cameraConfig:{default:()=>({enableCamera:!0})}},emits:["update:modelValue","upload-success","location-success","location-error","time-success","time-error","camera-success","camera-error"],setup(a,{expose:t,emit:o}){const e=a,r=o,i=l.ref(e.modelValue||""),d=l.ref(!1),u=l.ref(H()),g=l.ref(!1),f=R(),p=f.width,k=f.height;l.watch(()=>e.modelValue,c=>i.value=c||""),l.watch(i,c=>r("update:modelValue",c)),l.watch(d,c=>{c?document.body.style.overflow="hidden":document.body.style.overflow=""});async function y(){try{const{locationConfig:c}=e;if(!(c!=null&&c.enableLocation))throw new Error("定位功能已禁用");let n;switch(c.locationProvider){case"dingtalk":n=await Q();break;case"custom":if(c.customLocationFn)n=await c.customLocationFn();else throw new Error("自定义定位函数未提供");break;case"h5":default:n=await j();break}if(e.amapKey&&!n.address)try{n.address=await Z(n.latitude,n.longitude,e.amapKey)}catch(s){console.warn("获取地址信息失败:",s),n.address="位置信息获取失败了,请申请高德地图key,再配置amapKey,啊哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈"}return r("location-success",n),n}catch(c){throw r("location-error",c),c}}async function b(){try{const{timeConfig:c}=e;let n;return c!=null&&c.enableNetworkTime&&c.customTimeFn?n=await c.customTimeFn():c!=null&&c.enableNetworkTime?n=await ee(c.networkTimeUrl):n=$(),r("time-success",n),n}catch(c){return r("time-error",c),$()}}async function N(c){try{const n=await te({facingMode:c});g.value=!0;const[s,h]=await Promise.allSettled([y(),b()]),w=s.status==="fulfilled"?s.value:{latitude:0,longitude:0,address:"位置信息获取失败了,请申请高德地图key,再配置amapKey,啊哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈"},L=h.status==="fulfilled"?h.value:$(),S=await z(n,{address:w.address||"位置信息获取失败了,请申请高德地图key,再配置amapKey,啊哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈",time:L,lat:w.latitude,lng:w.longitude,name:e.name,company:e.company},e.watermarkConfig);i.value=S,d.value=!0,await E(S)}catch(n){console.error("拍照失败:",n),alert("拍照失败,请重试")}}async function E(c){try{const{uploadConfig:n,action:s}=e;if(!(n!=null&&n.enableAutoUpload))return null;let h;if(n.customUploadFn){const w=I(c,"photo.jpg");h=await n.customUploadFn(w)}else{const w=I(c,"photo.jpg");h=await oe(w,s)}return r("upload-success",h),h}catch(n){return console.error("上传失败:",n),null}}function v(){i.value=""}return t({takePhoto:()=>N("environment"),deletePhoto:v,getLocation:y,getNetworkTime:b}),l.onMounted(()=>{u.value=H()}),(c,n)=>(l.openBlock(),l.createElementBlock("div",ne,[i.value?(l.openBlock(),l.createElementBlock("div",re,[l.createElementVNode("img",{src:i.value,class:"thumb-img",onClick:n[1]||(n[1]=s=>d.value=!0)},null,8,ie),l.createElementVNode("span",{class:"delete-btn",onClick:v},n[5]||(n[5]=[l.createElementVNode("svg",{viewBox:"0 0 24 24",width:"16",height:"16"},[l.createElementVNode("line",{x1:"6",y1:"6",x2:"18",y2:"18",stroke:"#fff","stroke-width":"2","stroke-linecap":"round"}),l.createElementVNode("line",{x1:"18",y1:"6",x2:"6",y2:"18",stroke:"#fff","stroke-width":"2","stroke-linecap":"round"})],-1)]))])):(l.openBlock(),l.createElementBlock("div",ae,[l.createElementVNode("button",{class:"camera-btn",onClick:n[0]||(n[0]=s=>N("environment"))},n[4]||(n[4]=[l.createElementVNode("span",{class:"camera-icon"},null,-1)]))])),(l.openBlock(),l.createBlock(l.Teleport,{to:"body"},[d.value?(l.openBlock(),l.createElementBlock("div",{key:0,class:"modal-mask",onClick:n[3]||(n[3]=s=>d.value=!1)},[l.createElementVNode("div",{class:"close-btn",onClick:n[2]||(n[2]=l.withModifiers(s=>d.value=!1,["stop"]))},n[6]||(n[6]=[l.createElementVNode("svg",{viewBox:"0 0 24 24",width:"24",height:"24"},[l.createElementVNode("line",{x1:"6",y1:"6",x2:"18",y2:"18",stroke:"#fff","stroke-width":"2","stroke-linecap":"round"}),l.createElementVNode("line",{x1:"18",y1:"6",x2:"6",y2:"18",stroke:"#fff","stroke-width":"2","stroke-linecap":"round"})],-1)])),l.createElementVNode("div",se,[l.createElementVNode("img",{src:i.value,class:"modal-img-full"},null,8,le)])])):l.createCommentVNode("",!0)])),g.value?(l.openBlock(),l.createElementBlock("canvas",{key:2,"canvas-id":"watermarkCanvas",id:"watermarkCanvas",style:l.normalizeStyle(`width:${l.unref(p)}px; height:${l.unref(k)}px; position: absolute; left: -9999px; top: -9999px;`),type:"2d"},null,4)):l.createCommentVNode("",!0)]))}}),de=(a,t)=>{const o=a.__vccOpts||a;for(const[e,r]of t)o[e]=r;return o},X=de(ce,[["__scopeId","data-v-6321a964"]]),ue=a=>{a.component("WatermarkCamera",X)};exports.WatermarkCamera=X;exports.install=ue;