Letterhead Generator - Free Business Letterhead Maker - Small Study Tools
100% Free · No Signup · Browser-Based
Letterhead Generator Design a professional letterhead — logo, contact details, QR code and social icons, framing blank space for your actual letter. Pro Mode adds a digital signature, watermark, custom fonts, tables, multiple logos and 300 DPI export.
● Pro Version is Free for now
Simple
Pro — Full Control
✓ Signature · Watermark · Custom fonts · Tables · Multiple logos/QR codes · 300 DPI · SVG export unlocked
100% Private — everything stays in your browser
Rows (comma-separated cells, one row per line)
Fonts
Company Name Font
DM Sans Poppins Playfair Display Space Grotesk
Download PDF
PNG
300 DPI PNG
SVG
Print
`);
w.document.close();
setTimeout(() => { w.print(); }, 300);
}// ── EXPORT: PDF ───────────────────────────────────────────────
function hexToRgb(hex) {
const c = hex.replace('#','');
return PDFLib.rgb(parseInt(c.slice(0,2),16)/255, parseInt(c.slice(2,4),16)/255, parseInt(c.slice(4,6),16)/255);
}
async function embedImgIfAny(pdfDoc, dataUrl) {
if (!dataUrl) return null;
try {
const bytes = await (await fetch(dataUrl)).arrayBuffer();
if (dataUrl.includes('image/png')) return await pdfDoc.embedPng(bytes);
return await pdfDoc.embedJpg(bytes);
} catch (e) { return null; }
}
async function getTitleFont(pdfDoc, fallback) {
if (!customFontBytes) return fallback;
try {
if (typeof fontkit !== 'undefined') pdfDoc.registerFontkit(fontkit);
const bytes = await (await fetch(customFontBytes)).arrayBuffer();
return await pdfDoc.embedFont(bytes);
} catch (e) { return fallback; }
}
async function downloadPDF() {
const theme = getActiveTheme();
const L = computeLetterheadLayout(currentPageSize, theme.layout);
const f = getFields();
const pdfDoc = await PDFDocument.create();
const bodyFont = await pdfDoc.embedFont(StandardFonts.Helvetica);
const boldFallback = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
const titleFont = isPro ? await getTitleFont(pdfDoc, boldFallback) : boldFallback;
const page = pdfDoc.addPage([L.page.w, L.page.h]);
const flip = y => L.page.h - y;
const textColor = hexToRgb(theme.text), accentColor = hexToRgb(theme.accent);const logoImg = await embedImgIfAny(pdfDoc, logoDataUrl);
if (logoImg) {
let lx = L.logo.x;
if (logoPosition === 'top-center' && theme.layout !== 'centered') lx = L.page.w/2 - L.logo.w/2;
else if (logoPosition === 'top-right' && theme.layout !== 'centered') lx = L.page.w - L.margin - L.logo.w;
page.drawImage(logoImg, { x: lx, y: L.logo.y, width: L.logo.w, height: L.logo.h });
}const drawAligned = (text, x, y, size, font_, color, centered) => {
if (centered) { const w = font_.widthOfTextAtSize(text, size); page.drawText(text, { x: x - w/2, y: flip(y), size, font: font_, color }); }
else page.drawText(text, { x, y: flip(y), size, font: font_, color });
};
drawAligned(truncate(f.company,40), L.companyName.x, L.companyName.y, 18, titleFont, textColor, L.companyName.centered);
if (f.tagline) drawAligned(truncate(f.tagline,60), L.tagline.x, L.tagline.y, 9, bodyFont, accentColor, L.tagline.centered);if (dividerStyle !== 'none') {
page.drawLine({ start:{x:L.contentX,y:flip(L.headerY)}, end:{x:L.contentX+L.contentW,y:flip(L.headerY)}, thickness:1.2, color: accentColor });
page.drawLine({ start:{x:L.contentX,y:flip(L.footerY+L.footerH)}, end:{x:L.contentX+L.contentW,y:flip(L.footerY+L.footerH)}, thickness:1.2, color: accentColor });
}if (isPro && watermarkEnabled) {
const cx = L.page.w/2, cy = L.page.h/2;
const wmText = f.watermark;
const w = titleFont.widthOfTextAtSize(wmText, 48);
page.drawText(wmText, { x: cx - w/2, y: flip(cy), size: 48, font: titleFont, color: textColor, opacity: 0.08, rotate: PDFLib.degrees(45) });
}if (isPro && sigEnabled) {
const sigY = L.bodyBottom + 50;
const sigImg = sigMode === 'upload' ? await embedImgIfAny(pdfDoc, sigImageDataUrl) : null;
if (sigImg) page.drawImage(sigImg, { x: L.contentX, y: flip(sigY+36)-34, width: 130, height: 34 });
else if (sigMode === 'typed' && f.sigName) page.drawText(f.sigName.split(',')[0]||f.sigName, { x: L.contentX, y: flip(sigY+8), size: 20, font: bodyFont, color: textColor });
page.drawLine({ start:{x:L.contentX,y:flip(sigY)}, end:{x:L.contentX+160,y:flip(sigY)}, thickness:1, color: textColor });
if (f.sigName) page.drawText(f.sigName, { x: L.contentX, y: flip(sigY-14), size: 9, font: bodyFont, color: rgb(0.58,0.64,0.72) });
}if (isPro && tableEnabled && f.tableData) {
const rows = parseTableData(f.tableData);
if (rows.length) {
const cols = Math.max(...rows.map(r => r.length));
const t = computeTableLayout(L.bodyTop, L.bodyBottom, L.contentX, L.contentW, rows.length, cols);
if (t.fits) {
rows.forEach((row, ri) => {
const rowY = t.tableTop - ri*t.rowH;
page.drawLine({ start:{x:L.contentX,y:flip(rowY)}, end:{x:L.contentX+L.contentW,y:flip(rowY)}, thickness:0.7, color: rgb(0.89,0.91,0.94) });
row.forEach((cell, ci) => {
page.drawText(truncate(cell,24), { x: L.contentX+ci*t.colW+6, y: flip(rowY-t.rowH+15), size: 9.5, font: ri===0?boldFallback:bodyFont, color: textColor });
});
});
page.drawLine({ start:{x:L.contentX,y:flip(t.tableBottom)}, end:{x:L.contentX+L.contentW,y:flip(t.tableBottom)}, thickness:0.7, color: rgb(0.89,0.91,0.94) });
}
}
}page.drawText(truncate(f.address,80), { x: L.contentX, y: flip(L.addressY), size: 9, font: bodyFont, color: textColor, opacity: 0.8 });
const contactParts = [f.phone, f.email, f.website].filter(Boolean).join(' | ');
page.drawText(truncate(contactParts,90), { x: L.contentX, y: flip(L.footerRowY), size: 9, font: bodyFont, color: textColor });const socialsForPdf = [['f',f.facebook],['@',f.instagram],['in',f.linkedin],['X',f.twitter]].filter(([,v]) => v);
socialsForPdf.forEach(([label], i) => {
const sx = L.contentX + 9 + i*24;
page.drawCircle({ x: sx, y: flip(L.socialRowY), size: 9, color: accentColor });
const lw = bodyFont.widthOfTextAtSize(label, 7);
page.drawText(label, { x: sx - lw/2, y: flip(L.socialRowY) - 2.5, size: 7, font: bodyFont, color: rgb(1,1,1) });
});if (logo2DataUrl && isPro) {
const logo2Img = await embedImgIfAny(pdfDoc, logo2DataUrl);
if (logo2Img) page.drawImage(logo2Img, { x: L.qr2X, y: L.qr2Y, width: L.qrSize, height: L.qrSize });
} else if (isPro && qr2Enabled) {
drawQrPdf(page, f.qr2Data || f.website, L.qr2X, flip(L.qr2Y+L.qrSize), L.qrSize, textColor);
}
if (qrEnabled) drawQrPdf(page, f.qrData || f.website, L.qrX, flip(L.qrY+L.qrSize), L.qrSize, textColor);const bytes = await pdfDoc.save();
triggerDownload(new Blob([bytes], { type:'application/pdf' }), 'letterhead.pdf');
toast('PDF downloaded!');
}
function drawQrPdf(page, text, x, y, size, color) {
const { count, modules } = buildQrMatrix(text || 'https://example.com');
const cell = size / count;
page.drawRectangle({ x, y, width: size, height: size, color: rgb(1,1,1) });
modules.forEach(([r,c]) => { page.drawRectangle({ x: x+c*cell, y: y+size-(r+1)*cell, width: cell+0.3, height: cell+0.3, color }); });
}// ── MODE ──────────────────────────────────────────────────────
function setMode(mode) {
isPro = mode === 'pro';
document.getElementById('btnSimple').classList.toggle('active', !isPro);
document.getElementById('btnPro').classList.toggle('active', isPro);
document.body.classList.toggle('pro-mode', isPro);
const pb = document.getElementById('proBar'); if (pb) pb.style.display = isPro ? 'flex' : 'none';
if (!isPro) {
if (TEMPLATES[currentTemplate].pro) currentTemplate = 'navy-classic-left';
qr2Enabled = false; sigEnabled = false; watermarkEnabled = false; tableEnabled = false;
document.getElementById('qr2Toggle').checked = false;
document.getElementById('sigToggle').checked = false;
document.getElementById('watermarkToggle').checked = false;
document.getElementById('tableToggle').checked = false;
}
renderAllUI();
}// ── UTILS ─────────────────────────────────────────────────────
function toast(msg) { const t = document.getElementById('toast'); t.textContent = msg; t.classList.add('show'); setTimeout(() => t.classList.remove('show'), 3200); }// ── INIT ──────────────────────────────────────────────────────
renderLogoPositionRow();
renderAllUI();
pushHistory();