PageSourceSearch

https://relahconvert.com/assets/watermark-pdf-ClTb7oS3.js

js relahconvert.com collected 2026-09-25 23:03:24 UTC 33,754 bytes, 164 lines download raw bytes

1import{_ as Pe}from"./preload-helper-BXl3LOEh.js";import{i as De}from"./header-DTc-a7mb.js";import{L as Me}from"./utils-DERB7IkV.js";import{l as Fe,r as ze,y as W,u as $e}from"./theme-BwSXwi2g.js";import{P as xe,S as Te,r as je,d as Ae}from"./PDFButton-CaOlM0Mj.js";import"./_commonjsHelpers-CE1G-McA.js";const l=Fe(),Oe=l.nav_short&&l.nav_short["watermark-pdf"]||"Watermark PDF";l.seo&&l.seo["watermark-pdf"];const We=l.wmpdf_desc||l.card_watermark_pdf_desc||"Add text watermarks to your PDF files. Choose text, font size, opacity, color, and position.",Ne=l.wmpdf_select||l.pdfpng_select||"Select PDFs",Re=l.wmpdf_drop_hint||l.pdfpng_drop_hint||"or drop PDFs anywhere";l.download;const qe=l.download_zip||"Download ZIP",ye=l.wmpdf_apply||"Add Watermark",Ue=l.wmpdf_applying||"Adding watermark…",He=l.wmpdf_loading||"Loading PDFs…";l.wmpdf_pages||l.pdfpng_pages;const G=Me.MAX_FILES,Ve=50*1024*1024,be=Oe.split(" "),Ge=be[0],Ze=be.slice(1).join(" "),re="https://cdn.jsdelivr.net/npm/[email protected]/build";let x=null;async function Je(){return x||(window.pdfjsLib?(x=window.pdfjsLib,x):new Promise((n,e)=>{const t=document.createElement("script");t.src=`${re}/pdf.min.mjs`,t.type="module",t.onload=()=>{x=window.pdfjsLib,x?(x.GlobalWorkerOptions.workerSrc=`${re}/pdf.worker.min.mjs`,n(x)):e(new Error("PDF.js did not load"))},t.onerror=()=>e(new Error("PDF.js CDN failed")),document.head.appendChild(t)}))}async function Xe(){return x||new Promise((n,e)=>{const t=document.createElement("script");t.src="https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.min.js",t.onload=()=>{x=window.pdfjsLib,x?(x.GlobalWorkerOptions.workerSrc="https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.worker.min.js",n(x)):e(new Error("PDF.js fallback did not load"))},t.onerror=()=>e(new Error("PDF.js fallback CDN failed")),document.head.appendChild(t)})}async function Ye(){try{return await Je()}catch{return await Xe()}}document.body.style.cssText="margin:0;padding:0;min-height:100vh;background:var(--bg-page);";const he=document.createElement("style");he.textContent=`
2  @keyframes fadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
3  #app>div{animation:fadeUp 0.4s ease both}
4  .upload-label{display:inline-flex;align-items:center;gap:8px;background:var(--accent);color:var(--text-on-accent);font-family:'DM Sans',sans-serif;font-weight:600;font-size:14px;padding:10px 20px;border-radius:8px;cursor:pointer;transition:background 0.15s;}
5  .upload-label:hover{background:var(--accent-hover);}
6  .wmpdf-drop-zone{display:flex;flex-direction:column;align-items:center;justify-content:center;margin-top:16px;padding:48px 24px;border:2px dashed var(--border-light);border-radius:14px;cursor:pointer;transition:border-color 0.2s,background 0.2s;background:var(--bg-card);}
7  .wmpdf-drop-zone:hover,.wmpdf-drop-zone.over{border-color:var(--accent);background:var(--accent-bg,rgba(200,75,49,0.04));}
8  .tool-layout{display:grid;grid-template-columns:1fr 300px;gap:20px;align-items:start;}
9  .image-col{background:var(--bg-card);border-radius:14px;border:1.5px solid var(--border);min-height:320px;display:flex;flex-direction:column;padding:16px;gap:10px;overflow:hidden;}
10  .controls-col{background:var(--bg-card);border-radius:14px;border:1.5px solid var(--border);padding:16px;font-family:'DM Sans',sans-serif;max-height:85vh;overflow-y:auto;}
11  .controls-col h3{font-family:'Fraunces',serif;font-size:16px;font-weight:700;color:var(--text-primary);margin:0 0 12px;}
12  .section-label{font-size:11px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:var(--text-muted);margin-bottom:6px;font-family:'DM Sans',sans-serif;}
13  .divider{height:1px;background:#F0EAE3;margin:12px 0;}
14  .ctrl-input{width:100%;padding:8px 10px;border:1.5px solid var(--border-light);border-radius:8px;font-size:13px;font-family:'DM Sans',sans-serif;background:var(--bg-card);color:var(--text-primary);outline:none;box-sizing:border-box;}
15  .ctrl-input:focus{border-color:var(--accent);}
16  input[type=range]{width:100%;accent-color:var(--accent);margin:3px 0;}
17  .range-row{display:flex;align-items:center;gap:8px;margin-bottom:10px;}
18  .range-val{font-size:12px;color:var(--text-muted);min-width:36px;text-align:right;font-family:'DM Sans',sans-serif;}
19  .swatches{display:flex;gap:6px;flex-wrap:wrap;margin-top:5px;margin-bottom:10px;}
20  .swatch{width:24px;height:24px;border-radius:50%;border:2.5px solid var(--border);cursor:pointer;transition:transform 0.15s,border-color 0.15s;flex-shrink:0;}
21  .swatch:hover{transform:scale(1.15);}
22  .swatch.active{border-color:var(--accent);transform:scale(1.15);}
23  .pos-grid{display:grid;grid-template-columns:repeat(3,28px);grid-template-rows:repeat(3,28px);gap:3px;margin-top:5px;margin-bottom:10px;}
24  .pos-cell{background:var(--bg-surface,#F5F0EB);border:1.5px solid var(--border-light);border-radius:5px;cursor:pointer;transition:all 0.15s;display:flex;align-items:center;justify-content:center;}
25  .pos-cell:hover{border-color:var(--accent);background:var(--accent-bg,rgba(200,75,49,0.04));}
26  .pos-cell.active{background:var(--accent);border-color:var(--accent);}
27  .pos-cell.active .pos-dot{background:#fff;}
28  .pos-dot{width:8px;height:8px;border-radius:50%;background:var(--text-muted);}
29  .file-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px;}
30  .file-chip{display:flex;align-items:center;gap:5px;background:var(--bg-surface);border-radius:20px;padding:4px 10px;font-size:11px;font-family:'DM Sans',sans-serif;color:var(--text-secondary);cursor:pointer;transition:all 0.15s;border:1.5px solid transparent;}
31  .file-chip:hover{border-color:var(--accent);}
32  .file-chip.active{border-color:var(--accent);color:var(--accent);}
33  .file-chip button{background:none;border:none;cursor:pointer;color:var(--text-muted);font-size:12px;line-height:1;padding:0;}
34  .file-chip button:hover{color:var(--accent);}
35  .thumb-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px;width:100%;}
36  .thumb-wrap{position:relative;background:var(--bg-surface,#F5F0EB);border-radius:8px;overflow:hidden;border:1.5px solid var(--border-light);aspect-ratio:0.707;}
37  .thumb-wrap canvas{width:100%;height:100%;object-fit:contain;display:block;}
38  .thumb-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none;overflow:hidden;}
39  .thumb-overlay-text{font-family:Helvetica,Arial,sans-serif;white-space:nowrap;transform-origin:center center;}
40  .thumb-label{position:absolute;bottom:4px;right:6px;font-size:10px;color:var(--text-muted);font-family:'DM Sans',sans-serif;background:rgba(255,255,255,0.75);border-radius:4px;padding:1px 5px;}
41  .action-btn{padding:12px 20px;border:none;border-radius:10px;background:var(--accent);color:var(--text-on-accent);font-size:14px;font-family:'Fraunces',serif;font-weight:700;cursor:pointer;transition:all 0.18s;width:100%;margin-bottom:8px;}
42  .action-btn:hover{background:var(--accent-hover);transform:translateY(-1px);}
43  .action-btn:disabled{background:var(--btn-disabled);cursor:not-allowed;opacity:0.7;transform:none;}
44  .action-btn.dark{background:var(--btn-dark);color:var(--text-on-dark-btn);}
45  .action-btn.dark:hover{background:var(--btn-dark-hover);}
46  .status-text{font-size:13px;color:var(--text-tertiary);font-family:'DM Sans',sans-serif;margin-top:6px;min-height:18px;}
47  .diag-row{display:flex;align-items:center;gap:8px;margin-bottom:10px;font-size:13px;color:var(--text-primary);font-family:'DM Sans',sans-serif;cursor:pointer;user-select:none;}
48  .diag-row input[type=checkbox]{accent-color:var(--accent);width:16px;height:16px;cursor:pointer;}
49  .next-steps{margin-top:20px;}
50  .next-steps-label{font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.1em;margin-bottom:10px;font-family:'DM Sans',sans-serif;}
51  .next-link{padding:8px 16px;border-radius:8px;border:1.5px solid var(--border-light);font-size:13px;font-weight:500;color:var(--text-primary);text-decoration:none;background:var(--bg-card);cursor:pointer;font-family:'DM Sans',sans-serif;transition:all 0.15s;}
52  .next-link:hover{border-color:var(--accent);color:var(--accent);}
53  @media(max-width:700px){.tool-layout{grid-template-columns:1fr;}.image-col{min-height:220px;}}
54  .seo-section{max-width:700px;margin:0 auto;padding:0 16px 60px;font-family:'DM Sans',sans-serif;}
55  .seo-section h2{font-family:'Fraunces',serif;font-size:17px;font-weight:700;color:var(--text-primary);margin:32px 0 10px;}
56  .seo-section h3{font-family:'Fraunces',serif;font-size:15px;font-weight:700;color:var(--text-primary);margin:24px 0 8px;}
57  .seo-section ol{padding-left:20px;margin:0 0 12px;}
58  .seo-section ol li{font-size:13px;color:var(--text-secondary);line-height:1.6;margin-bottom:6px;}
59  .seo-section p{font-size:13px;color:var(--text-secondary);line-height:1.6;margin:0 0 12px;}
60  .seo-links{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px;}
61  .seo-link{padding:7px 14px;background:var(--bg-card);border:1.5px solid var(--border-light);border-radius:8px;font-size:13px;font-weight:600;color:var(--text-primary);text-decoration:none;font-family:'DM Sans',sans-serif;transition:all 0.15s;}
62  .seo-link:hover{border-color:var(--accent);color:var(--accent);}
63  .seo-section .faq-item{background:var(--bg-card);border-radius:12px;padding:18px 20px;margin-bottom:10px;box-shadow:0 1px 4px rgba(0,0,0,0.06);}
64  .seo-section .faq-item h4{font-family:'Fraunces',serif;font-size:15px;font-weight:700;color:var(--text-primary);margin:0 0 6px;}
65  .seo-section .faq-item p{margin:0;}
66`;document.head.appendChild(he);ze("watermark-pdf");document.querySelector("#app").innerHTML=`
67  <div id="wmpdf_main" style="max-width:900px;margin:32px auto;padding:0 16px 60px;font-family:'DM Sans',sans-serif;">
68    <div style="margin-bottom:20px;">
69      <h1 style="font-family:'Fraunces',serif;font-size:clamp(24px,4vw,36px);font-weight:400;color:var(--text-primary);margin:0 0 6px;line-height:1;letter-spacing:-0.02em;">${Ge} <em style="font-style:italic;color:var(--accent);">${Ze}</em></h1>
70      <p style="font-size:13px;color:var(--text-tertiary);margin:0 0 14px;">${We}</p>
71      <label class="upload-label" for="wmpdf_fileInput"><span style="font-size:18px;">+</span> ${Ne}</label>
72      <span style="font-size:12px;color:var(--text-muted);margin-left:10px;">${Re}</span>
73      <input type="file" id="wmpdf_fileInput" accept="application/pdf,.pdf" multiple style="display:none;" />
74      <label for="wmpdf_fileInput" id="wmpdf_dropZone" class="wmpdf-drop-zone">
75        <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="var(--text-muted)" stroke-width="1.5" stroke-linecap="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12"/></svg>
76        <span style="font-size:13px;color:var(--text-secondary);margin-top:8px;font-weight:600;">${l.pdfpng_drop_hint||"Drop PDFs here"}</span>
77      </label>
78    </div>
79    <div class="tool-layout" id="wmpdf_toolLayout" style="display:none;">
80      <div class="image-col" id="wmpdf_imageCol">
81        <div class="file-chips" id="wmpdf_fileChips"></div>
82        <div class="thumb-grid" id="wmpdf_thumbGrid"></div>
83      </div>
84      <div class="controls-col" id="wmpdf_controlsCol">
85        <h3>${l.wmpdf_options_title||"Watermark Options"}</h3>
86
87        <div style="display:flex;gap:0;border:1.5px solid var(--border-light);border-radius:10px;overflow:hidden;margin-bottom:14px;">
88          <button id="wmpdf_modeText" style="flex:1;padding:9px 0;border:none;font-size:13px;font-weight:600;font-family:'DM Sans',sans-serif;cursor:pointer;background:var(--accent);color:var(--text-on-accent);transition:all 0.15s;">Text</button>
89          <button id="wmpdf_modeImage" style="flex:1;padding:9px 0;border:none;font-size:13px;font-weight:600;font-family:'DM Sans',sans-serif;cursor:pointer;background:var(--bg-card);color:var(--text-secondary);transition:all 0.15s;">Image</button>
90        </div>
91
92        <div id="wmpdf_textPanel">
93          <div class="section-label">${l.wmpdf_text_label||"Text"}</div>
94          <input type="text" class="ctrl-input" id="wmpdf_text" value="CONFIDENTIAL" maxlength="100" style="margin-bottom:10px;" />
95
96          <div class="section-label">${l.wmpdf_font_size||"Font Size"}</div>
97          <div class="range-row">
98            <input type="number" class="ctrl-input" id="wmpdf_fontSize" value="48" min="20" max="120" step="1" style="width:70px;" />
99            <span class="range-val">pt</span>
100          </div>
101
102          <div class="section-label">${l.wmpdf_color||"Color"}</div>
103          <div style="display:flex;align-items:center;gap:10px;margin-bottom:10px;">
104            <input type="color" id="wmpdf_colorPicker" value="#808080" style="width:44px;height:36px;border:1.5px solid var(--border-light);border-radius:8px;
104cursor:pointer;padding:2px;background:var(--bg-card);" />
105            <span id="wmpdf_colorHex" style="font-size:12px;color:var(--text-muted);font-family:'DM Sans',sans-serif;">#808080</span>
106          </div>
107
108          <label class="diag-row"><input type="checkbox" id="wmpdf_diagonal" checked /> ${l.wmpdf_diagonal||"Diagonal"}</label>
109
110          <div class="section-label">${l.wmpdf_rotation||"Rotation"}</div>
111          <div class="range-row">
112            <input type="range" id="wmpdf_rotation" min="-90" max="90" step="1" value="-45" />
113            <span class="range-val" id="wmpdf_rotationVal">-45&deg;</span>
114          </div>
115        </div>
116
117        <div id="wmpdf_imagePanel" style="display:none;">
118          <label class="upload-label" for="wmpdf_imgInput" style="width:100%;justify-content:center;margin-bottom:10px;">
119            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg>
120            Choose Image
121          </label>
122          <input type="file" id="wmpdf_imgInput" accept="image/png,image/jpeg" style="display:none;" />
123          <div id="wmpdf_imgPreview" style="display:none;margin:0 0 12px;text-align:center;">
124            <img id="wmpdf_imgPreviewImg" style="max-width:100%;max-height:120px;border-radius:8px;border:1.5px solid var(--border-light);" />
125            <button id="wmpdf_imgRemove" style="display:block;margin:6px auto 0;background:none;border:none;color:var(--accent);font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;text-decoration:underline;">Remove image</button>
126          </div>
127
128          <div class="section-label">Scale</div>
129          <div class="range-row">
130            <input type="range" id="wmpdf_imgScale" min="10" max="100" value="30" />
131            <span class="range-val" id="wmpdf_imgScaleVal">30%</span>
132          </div>
133        </div>
134
135        <div class="section-label">${l.wmpdf_opacity||"Opacity"}</div>
136        <div class="range-row">
137          <input type="range" id="wmpdf_opacity" min="5" max="50" step="1" value="15" />
138          <span class="range-val" id="wmpdf_opacityVal">15%</span>
139        </div>
140
141        <div class="section-label">${l.wmpdf_position||"Position"}</div>
142        <div class="pos-grid" id="wmpdf_posGrid"></div>
143
144        <div class="divider"></div>
145        <div id="wmpdf_applyModeToggle" style="display:none;margin-bottom:12px;">
146          <div style="display:flex;gap:0;border:1.5px solid var(--border-light);border-radius:10px;overflow:hidden;">
147            <button id="wmpdf_modeAll" style="flex:1;padding:8px 0;border:none;font-size:12px;font-weight:600;font-family:'DM Sans',sans-serif;cursor:pointer;background:var(--accent);color:var(--text-on-accent);transition:all 0.15s;">Apply to All</button>
148            <button id="wmpdf_modeIndiv" style="flex:1;padding:8px 0;border:none;font-size:12px;font-weight:600;font-family:'DM Sans',sans-serif;cursor:pointer;background:var(--bg-card);color:var(--text-secondary);transition:all 0.15s;">Individual</button>
149          </div>
150        </div>
151        <button class="action-btn" id="wmpdf_applyBtn" disabled>${ye}</button>
152        <div id="wmpdf_zipWrap" style="display:none;">
153          <a id="wmpdf_zipBtn" class="action-btn dark" style="display:block;text-align:center;text-decoration:none;">⬇ ${qe}</a>
154          <p id="wmpdf_zipNote" style="font-size:11px;color:var(--text-muted);text-align:center;margin:4px 0 0;font-family:'DM Sans',sans-serif;"></p>
155        </div>
156        <div class="status-text" id="wmpdf_status"></div>
157      </div>
158    </div>
159    <div id="wmpdf_nextSteps" style="display:none;" class="next-steps">
160      <div class="next-steps-label">${l.whats_next||"What's Next?"}</div>
161      <div style="display:flex;gap:10px;flex-wrap:wrap;" id="wmpdf_nextButtons"></div>
162    </div>
163  </div>
164`;De();let c=[],m=0,L=[],U="text",D=null,C=null,f=null;const r={text:"CONFIDENTIAL",fontSize:48,opacity:15,color:"#808080",position:"center",diagonal:!0,rotation:-45,imgScale:30};function Qe(){return{text:"CONFIDENTIAL",fontSize:48,opacity:15,color:"#808080",position:"center",diagonal:!0,rotation:-45,imgScale:30}}function ve(){E!=="individual"||!c[m]||(c[m].opts={...r},c[m].wmImageFile=D,c[m].wmMode=U)}function Ke(){if(E!=="individual"||!c[m])return;const n=c[m].opts;if(!n)return;Object.assign(r,n);const e=document.getElementById("wmpdf_textInput"),t=document.getElementById("wmpdf_fontSize"),o=document.getElementById("wmpdf_colorPicker"),a=document.getElementById("wmpdf_colorHex"),i=document.getElementById("wmpdf_diagonal"),s=document.getElementById("wmpdf_rotation"),d=document.getElementById("wmpdf_rotationVal"),p=document.getElementById("wmpdf_opacity"),h=document.getElementById("wmpdf_opacityVal"),I=document.getElementById("wmpdf_imgScale"),M=document.getElementById("wmpdf_imgScaleVal");e&&(e.value=r.text),t&&(t.value=r.fontSize),o&&(o.value=r.color,a&&(a.textContent=r.color.toUpperCase())),i&&(i.checked=r.diagonal),s&&(s.value=r.rotation,d&&(d.innerHTML=r.rotation+"&deg;")),p&&(p.value=r.opacity,h&&(h.textContent=r.opacity+"%")),I&&(I.value=r.
164imgScale,M&&(M.textContent=r.imgScale+"%")),document.querySelectorAll(".pos-cell").forEach(y=>{y.classList.toggle("active",y.dataset.pos===r.position)});const v=c[m].wmImageFile,F=c[m].wmMode||"text";if(D=v||null,v){f&&URL.revokeObjectURL(f),f=URL.createObjectURL(v),document.getElementById("wmpdf_imgPreviewImg").src=f,document.getElementById("wmpdf_imgPreview").style.display="block";const y=new Image;y.onload=()=>{C=y,u()},y.src=f}else C=null,f&&(URL.revokeObjectURL(f),f=null),document.getElementById("wmpdf_imgPreviewImg").src="",document.getElementById("wmpdf_imgPreview").style.display="none";typeof q=="function"?q(F):U=F,u()}function et(n){const e=n.replace("#","");return{r:parseInt(e.substring(0,2),16)/255,g:parseInt(e.substring(2,4),16)/255,b:parseInt(e.substring(4,6),16)/255}}const O=document.getElementById("wmpdf_fileInput"),P=document.getElementById("wmpdf_dropZone"),we=document.getElementById("wmpdf_toolLayout");document.getElementById("wmpdf_imageCol");const se=document.getElementById("wmpdf_fileChips"),z=document.getElementById("wmpdf_thumbGrid"),le=document.getElementById("wmpdf_text"),de=document.getElementById("wmpdf_fontSize"),ce=document.getElementById("wmpdf_opacity"),tt=document.getElementById("wmpdf_opacityVal"),Z=document.getElementById("wmpdf_posGrid"),N=document.getElementById("wmpdf_diagonal"),R=document.getElementById("wmpdf_rotation"),Q=document.getElementById("wmpdf_rotationVal"),_=document.getElementById("wmpdf_applyBtn"),K=document.getElementById("wmpdf_modeText"),ee=document.getElementById("wmpdf_modeImage"),nt=document.getElementById("wmpdf_textPanel"),ot=document.getElementById("wmpdf_imagePanel"),J=document.getElementById("wmpdf_imgInput"),_e=document.getElementById("wmpdf_imgPreview"),Ie=document.getElementById("wmpdf_imgPreviewImg"),pe=document.getElementById("wmpdf_imgScale"),at=document.getElementById("wmpdf_imgScaleVal"),it=document.getElementById("wmpdf_zipWrap");document.getElementById("wmpdf_zipBtn");document.getElementById("wmpdf_zipNote");const g=document.getElementById("wmpdf_status"),oe=document.getElementById("wmpdf_nextSteps"),me=document.getElementById("wmpdf_nextButtons");function q(n){U=n;const e=n==="text";K.style.background=e?"var(--accent)":"var(--bg-card)",K.style.color=e?"var(--text-on-accent)":"var(--text-secondary)",ee.style.background=e?"var(--bg-card)":"var(--accent)",ee.style.color=e?"var(--text-secondary)":"var(--text-on-accent)",nt.style.display=e?"block":"none",ot.style.display=e?"none":"block",u()}K.addEventListener("click",()=>q("text"));ee.addEventListener("click",()=>q("image"));const rt=["top-left","top-center","top-right","center-left","center","center-right","bottom-left","bottom-center","bottom-right"];function st(){Z.innerHTML="",rt.forEach(n=>{const e=document.createElement("div");e.className="pos-cell"+(n===r.position?" active":""),e.dataset.pos=n,e.innerHTML='<div class="pos-dot"></div>',e.addEventListener("click",()=>{r.position=n,Z.querySelectorAll(".pos-cell").forEach(t=>t.classList.toggle("active",t.dataset.pos===n)),u()}),Z.appendChild(e)})}st();le.addEventListener("input",()=>{r.text=le.value.trim()||"CONFIDENTIAL",u()});de.addEventListener("input",()=>{let n=parseInt(de.value)||48;n=Math.max(20,Math.min(120,n)),r.fontSize=n,u()});ce.addEventListener("input",()=>{r.opacity=parseInt(ce.value),tt.textContent=r.opacity+"%",u()});const X=document.getElementById("wmpdf_colorPicker"),lt=document.getElementById("wmpdf_colorHex");X.addEventListener("input",()=>{r.color=X.value,lt.textContent=X.value.toUpperCase(),u()});N.addEventListener("change",()=>{r.diagonal=N.checked,r.diagonal?(r.rotation=-45,R.value=-45,Q.innerHTML="-45&deg;"):(r.rotation=0,R.value=0,Q.innerHTML="0&deg;"),u()});R.addEventListener("input",()=>{r.rotation=parseInt(R.value),Q.innerHTML=r.rotation+"&deg;",N.checked=r.rotation===-45,r.diagonal=N.checked,u()});J.addEventListener("change",()=>{const n=J.files[0];if(!n)return;D=n,f&&URL.revokeObjectURL(f),f=URL.createObjectURL(n),Ie.src=f,_e.style.display="block",E==="individual"&&c[m]&&(c[m].wmImageFile=n);const e=new Image;e.onload=()=>{C=e,u()},e.src=f,J.value=""});document.getElementById("wmpdf_imgRemove").addEventListener("click",()=>{D=null,C=null,f&&(URL.revokeObjectURL(f),f=null),Ie.src="",_e.style.display="none",E==="individual"&&c[m]&&(c[m].wmImageFile=null),u()});pe.addEventListener("input",()=>{r.imgScale=parseInt(pe.value),at.textContent=r.imgScale+"%",u()});
164function dt(){const n=r.color||"#808080",e=r.opacity/100,t=r.rotation;let o="center",a="center";const i=r.position;i.startsWith("top")?o="flex-start":i.startsWith("bottom")&&(o="flex-end"),i.endsWith("left")?a="flex-start":i.endsWith("right")&&(a="flex-end");let s="0",d="0",p="0",h="0";return i.startsWith("top")&&(s="8%"),i.startsWith("bottom")&&(d="8%"),i.endsWith("left")&&(p="6%"),i.endsWith("right")&&(h="6%"),{color:n,opac:e,rot:t,alignItems:o,justifyContent:a,padTop:s,padBottom:d,padLeft:p,padRight:h}}function u(){const n=z.querySelectorAll(".thumb-overlay"),e=dt();n.forEach(t=>{t.style.alignItems=e.alignItems,t.style.justifyContent=e.justifyContent,t.style.paddingTop=e.padTop,t.style.paddingBottom=e.padBottom,t.style.paddingLeft=e.padLeft,t.style.paddingRight=e.padRight;const o=t.querySelector(".thumb-overlay-text");let a=t.querySelector(".thumb-overlay-img");if(U==="text"){if(o){o.style.display="",o.textContent=r.text||"CONFIDENTIAL",o.style.color=e.color,o.style.opacity=e.opac,o.style.transform=`rotate(${e.rot}deg)`;const i=t.parentElement.offsetWidth||120,s=Math.max(6,Math.round(r.fontSize*(i/600)));o.style.fontSize=s+"px",o.style.fontWeight="bold"}a&&(a.style.display="none")}else o&&(o.style.display="none"),C?(a||(a=document.createElement("img"),a.className="thumb-overlay-img",a.style.cssText="max-width:100%;max-height:100%;object-fit:contain;",t.appendChild(a)),a.style.display="",a.src=C.src,a.style.opacity=e.opac,a.style.width=r.imgScale+"%",a.style.height="auto"):a&&(a.style.display="none")})}function te(){se.innerHTML="",!(c.length<=1)&&c.forEach((n,e)=>{const t=document.createElement("div");t.className="file-chip"+(e===m?" active":"");const o=n.name.replace(/\.[^.]+$/,"").slice(0,14);t.innerHTML=`<span>${o}</span><button data-idx="${e}">✕</button>`,t.querySelector("span").addEventListener("click",()=>{ve(),m=e,Ke(),te(),ne()}),t.querySelector("button").addEventListener("click",a=>{a.stopPropagation(),c.splice(e,1),m>=c.length&&(m=Math.max(0,c.length-1)),c.length===0&&(we.style.display="none",P.style.display="flex",_.disabled=!0),te(),ne()}),se.appendChild(t)})}async function ne(){z.innerHTML="";const n=c[m];if(n){if(n.thumbCanvases&&n.thumbCanvases.length){n.thumbCanvases.forEach((e,t)=>{const o=fe(e,t+1);z.appendChild(o)}),u();return}try{const o=await(await Ye()).getDocument({data:n.bytes.slice(0)}).promise;n.thumbCanvases=[];for(let a=1;a<=o.numPages;a++){const i=await o.getPage(a),s=i.getViewport({scale:.5}),d=document.createElement("canvas");d.width=s.width,d.height=s.height;const p=d.getContext("2d");await i.render({canvasContext:p,viewport:s}).promise,n.thumbCanvases.push(d);const h=fe(d,a);z.appendChild(h)}u()}catch(e){console.error("[watermark-pdf] thumbnail render failed:",e),z.innerHTML='<p style="font-size:12px;color:var(--text-muted);padding:20px;">Preview not available. Watermark will still be applied.</p>'}}}function fe(n,e){const t=document.createElement("div");t.className="thumb-wrap",t.appendChild(n);const o=document.createElement("div");o.className="thumb-overlay";const a=document.createElement("span");a.className="thumb-overlay-text",o.appendChild(a),t.appendChild(o);const i=document.createElement("span");return i.className="thumb-label",i.textContent=e,t.appendChild(i),t}async function ae(n){const e=Array.from(n).filter(a=>a.type==="application/pdf"||a.name.toLowerCase().endsWith(".pdf"));if(!e.length){g.textContent=l.warn_wrong_fmt_short||"Please select PDF files.";return}oe.style.display="none",it.style.display="none";const t=G-c.length;if(t<=0){g.textContent=(l.wmpdf_max_files||"Maximum")+` ${G} files.`;return}const o=e.slice(0,t);o.length<e.length?g.textContent=(l.wmpdf_max_files||"Maximum")+` ${G} files. ${e.length-o.length} skipped.`:g.textContent=He;for(const a of o){if(a.size>Ve){g.textContent=`${a.name}: `+(l.wmpdf_too_large||"File too large. Maximum size is 50 MB.");continue}try{const i=await a.arrayBuffer(),s=await xe.load(i);c.push({name:a.name,bytes:new Uint8Array(i.slice(0)),pageCount:s.getPageCount(),thumbCanvases:null,opts:Qe()})}catch(i){console.error("[watermark-pdf] load failed:",a.name,i),g.textContent=`${a.name}: `+(l.wmpdf_load_error||"Could not load PDF: ")+(i?.message||i)}}c.length&&(we.style.display="grid",document.getElementById("wmpdf_main").style.maxWidth="900px",P.style.display="none",_.disabled=!1,g.textContent="",ft(),te(),await ne())}O.addEventListener("change",()=>{O.files.length&&ae(O.files),O.value=""});document.addEventListener("dragover",n=>n.preventDefault());document.addEventListener("drop",n=>{n.preventDefault(),n.dataTransfer.files.length&&ae(n.dataTransfer.files)});P.addEventListener("dragenter",()=>P.classList.add("over"));P.addEventListener("dragleave",()=>P.classList.remove("over"));function ge(n,e,t,o,a){const i=a*.8;let s,d;return n.endsWith("left")?s=i:n.endsWith("right")?s=e-o-i:s=e/2-o/2,n.startsWith("top")?d=t-a-i:n.startsWith("bottom")?d=i:d=t/2-a/2,{x:s,y:d}}function ct(n,e,t,o,a){const i=Math.min(e,t)*.04;let s,d;return n.endsWith("left")?s=i:n.endsWith("right")?s=e-o-i:s=(e-o)/2,n.startsWith("top")?d=t-a-i:n.startsWith("bottom")?d=i:d=(t-a)/2,{x:s,y:d}}async function ue(n,e,t){const o=t||r,a=await xe.load(n.bytes),i=a.getPageCount(),s=o.opacity/100,d=n.wmImageFile||D,p=o.text&&o.text.trim().length>0,h=!!d;let I,M;if(p){I=await a.embedFont(Te.Helvetica);const b=et(o.color);M=je(b.r,b.g,b.b)}let v;if(h){const b=new Uint8Array(await d.arrayBuffer());d.type==="image/png"?v=await a.embedPng(b):v=await a.embedJpg(b)}const F=o.text||"CONFIDENTIAL",y=o.fontSize,j=o.rotation;for(let b=0;b<i;b++){e&&e(b+1,i);const H=a.getPage(b),{width:A,height:V}=H.getSize();if(p&&I){const S=I.widthOfTextAtSize(F,y);let k,B;if(o.diagonal||Math.abs(j)>5){const w=ge(o.position,A,V,S,y),ie=Math.abs(j)*Math.PI/180,Le=Math.cos(ie),Ce=Math.sin(ie);k=w.x+S/2*(1-Le),B=w.y+S/2*Ce*(j<0?-1:1)}else{const w=ge(o.position,A,V,S,y);k=w.x,B=w.y}H.drawText(F,{x:k,y:B,size:y,font:I,color:M,opacity:s,rotate:Ae(j)})}if(h&&v){const S=v.width/v.height,k=A*(o.imgScale/100),B=k/S,w=ct(o.position,A,V,k,B);H.drawImage(v,{x:w.x,y:w.y,width:k,height:B,opacity:s})}}const Ee=await a.save(),Se=new Blob([Ee],{type:"application/pdf"}),Be=`${n.name.replace(/\.[^.]+$/,"")}-watermarked.pdf`;return{blob:Se,filename:Be,totalPages:i}}function Y(n,e){const t=URL.createObjectURL(n),o=document.createElement("a");o.href=t,o.download=e,o.click(),setTimeout(()=>URL.revokeObjectURL(t),1e4)}function pt(n,e){if(!n.has(e))return n.add(e),e;const t=e.lastIndexOf("."),o=t!==-1?e.slice(0,t):e,a=t!==-1?e.slice(t):"";let i=1;for(;n.has(`${o}-${i}${a}`);)i++;const s=`${o}-${i}${a}`;return n.add(s),s}const mt=document.getElementById("wmpdf_applyModeToggle"),$=document.getElementById("wmpdf_modeAll"),T=document.getElementById("wmpdf_modeIndiv");let E="all";$.addEventListener("click",()=>{E="all",$.style.background="var(--accent)",$.style.color="var(--text-on-accent)",T.style.background="var(--bg-card)",T.style.color="var(--text-secondary)"});T.addEventListener("click",()=>{E="individual",T.style.background="var(--accent)",T.style.color="var(--text-on-accent)",$.style.background="var(--bg-card)",$.style.color="var(--text-secondary)"});function ft(){mt.style.display=c.length>1?"block":"none"}_.addEventListener("click",async()=>
164{if(!c.length)return;if(!(r.text&&r.text.trim()||D||c[m]&&c[m].wmImageFile)){g.textContent="Enter watermark text or choose an image.";return}_.disabled=!0,_.textContent=Ue,g.textContent="",oe.style.display="none",L=[],ve();const e=E==="all"||c.length===1;try{if(e){const t=[];for(let a=0;a<c.length;a++){const i=c[a],s=await ue(i,(d,p)=>{g.textContent=`Adding watermark (${a+1}/${c.length}) — ${i.name} (page ${d}/${p})`});t.push(s)}if(t.length===1)Y(t[0].blob,t[0].filename),L=[{blob:t[0].blob,name:t[0].filename,type:"application/pdf"}];else{g.textContent="Creating ZIP…";const a=(await Pe(async()=>{const{default:p}=await import("https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js");return{default:p}},[])).default||window.JSZip,i=new a,s=new Set;for(const p of t)i.file(pt(s,p.filename),p.blob);const d=await i.generateAsync({type:"blob",compression:"STORE"});Y(d,"watermarked-pdfs.zip"),L=t.map(p=>({blob:p.blob,name:p.filename,type:"application/pdf"}))}const o=t.reduce((a,i)=>a+i.totalPages,0);g.textContent=`Done! Watermark added to ${o} pages across ${t.length} files.`,window.showReviewPrompt&&window.showReviewPrompt()}else{const t=c[m],o=await ue(t,(a,i)=>{g.textContent=`Adding watermark — ${t.name} (page ${a}/${i})`},t.opts);Y(o.blob,o.filename),L=[{blob:o.blob,name:o.filename,type:"application/pdf"}],g.textContent=`Done! Watermark added to ${o.totalPages} ${o.totalPages===1?"page":"pages"}.`,window.showReviewPrompt&&window.showReviewPrompt(),window.rcShowSaveButton?.(_.parentElement,o.blob,o.filename,"watermark-pdf")}yt()}catch(t){console.error("[watermark-pdf] apply all failed:",t),g.textContent=`Failed: ${t?.message||t}`}_.disabled=!1,_.textContent=ye});function ke(){return new Promise((n,e)=>{const t=indexedDB.open("relahconvert",1);t.onupgradeneeded=o=>o.target.result.createObjectStore("pending",{keyPath:"id"}),t.onsuccess=o=>n(o.target.result),t.onerror=()=>e(new Error("IndexedDB open failed"))})}async function gt(n){const e=await ke();return new Promise((t,o)=>{const a=e.transaction("pending","readwrite"),i=a.objectStore("pending");i.clear(),n.forEach((s,d)=>i.put({id:d,blob:s.blob,name:s.name,type:s.type})),a.oncomplete=()=>t(),a.onerror=()=>o(new Error("IDB write failed"))})}async function ut(){const t=(await ke()).transaction("pending","readwrite").objectStore("pending");return new Promise((o,a)=>{const i=t.getAll();i.onsuccess=()=>{t.clear(),o(i.result||[])},i.onerror=()=>a(new Error("IDB read failed"))})}async function xt(){if(sessionStorage.getItem("pendingFromIDB")){sessionStorage.removeItem("pendingFromIDB");try{const n=await ut();if(!n.length)return;const e=n.map(t=>new File([t.blob],t.name,{type:t.type||"application/pdf"}));ae(e)}catch(n){console.warn("[watermark-pdf] IDB autoload failed:",n)}}}function yt(){const n=l.nav_short||{},e=[{label:n["compress-pdf"]||"Compress PDF",href:W("compress-pdf")},{label:n["add-page-numbers"]||"Add Page Numbers",href:W("add-page-numbers")},{label:n["pdf-to-png"]||"PDF to PNG",href:W("pdf-to-png")}];me.innerHTML="",e.forEach(t=>{const o=document.createElement("button");o.className="next-link",o.textContent=t.label,o.addEventListener("click",async()=>{if(L.length)try{await gt(L),sessionStorage.setItem("pendingFromIDB","1")}catch{}window.location.href=t.href}),me.appendChild(o)}),oe.style.display="block"}xt();(function(){const e=l.seo&&l.seo["watermark-pdf"];if(!e)return;const t=l.seo_faq_title||"Frequently Asked Questions",o=l.seo_also_try||"Also Try",a=document.createElement("div");a.className="seo-section",$e(e.faqs),a.innerHTML=`<h2>${e.h2a}</h2><ol>${e.steps.map(i=>`<li>${i}</li>`).join("")}</ol><h2>${e.h2b}</h2>${e.body}<h3>${e.h3why}</h3><p>${e.why}</p><h3>${t}</h3>${e.faqs.map(i=>`<div class="faq-item"><h4>${i.q}</h4><p>${i.a}</p></div>`).join("")}<h3>${o}</h3><div class="seo-links">${e.links.map(i=>`<a class="seo-link" href="${W(i.href.slice(1))}">${i.label}</a>`).join("")}</div>`,document.querySelector("#app").appendChild(a)})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.