qrcodegenerator / index.html
martiantrader's picture
add more features for generating qr codes
5883f8a verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>QRGenX - Free QR Code Generator</title>
<script src="https://cdn.tailwindcss.com">
// Get current location
function getCurrentLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
function(position) {
document.getElementById('locationLatitude').value = position.coords.latitude.toFixed(6);
document.getElementById('locationLongitude').value = position.coords.longitude.toFixed(6);
},
function(error) {
showError("Unable to get current location: " + error.message);
}
);
} else {
showError("Geolocation is not supported by this browser");
}
}
</script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.qr-placeholder {
background-image:
linear-gradient(45deg, #f0f0f0 25%, transparent 25%),
linear-gradient(-45deg, #f0f0f0 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #f0f0f0 75%),
linear-gradient(-45deg, transparent 75%, #f0f0f0 75%);
background-size: 20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
}
.color-picker {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 100%;
height: 40px;
background-color: transparent;
border: none;
cursor: pointer;
}
.color-picker::-webkit-color-swatch {
border-radius: 8px;
border: 2px solid #e5e7eb;
}
.color-picker::-moz-color-swatch {
border-radius: 8px;
border: 2px solid #e5e7eb;
}
.custom-file-input::-webkit-file-upload-button {
visibility: hidden;
}
.custom-file-input::before {
content: 'Choose icon';
display: inline-block;
background: linear-gradient(to bottom, #f9f9f9, #e3e3e3);
border: 1px solid #999;
border-radius: 6px;
padding: 8px 16px;
outline: none;
white-space: nowrap;
cursor: pointer;
font-weight: 500;
font-size: 14px;
color: #333;
}
.custom-file-input:hover::before {
border-color: #666;
}
.custom-file-input:active::before {
background: linear-gradient(to bottom, #e3e3e3, #f9f9f9);
}
#previewCanvas {
max-width: 100%;
height: auto;
transition: all 0.3s ease;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="text-center mb-12">
<div class="flex justify-center items-center gap-2 mb-4">
<i class="fas fa-qrcode text-4xl text-blue-600"></i>
<h1 class="text-4xl font-bold text-gray-800">QRGenX</h1>
</div>
<p class="text-lg text-gray-600 max-w-2xl mx-auto">
Create beautiful, customizable QR codes for free. No registration required.
</p>
</header>
<div class="flex flex-col lg:flex-row gap-8">
<!-- QR Code Generator Form -->
<div class="w-full lg:w-1/2 bg-white rounded-xl shadow-md p-6">
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Customize Your QR Code</h2>
<form id="qrForm" class="space-y-6">
<!-- Content Type -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Content Type</label>
<div class="grid grid-cols-2 gap-3">
<button type="button" data-type="url" class="qr-type-btn py-2 px-4 border rounded-lg font-medium flex items-center justify-center gap-2" onclick="setActiveType(this)">
<i class="fas fa-link"></i>
URL
</button>
<button type="button" data-type="text" class="qr-type-btn py-2 px-4 border rounded-lg font-medium flex items-center justify-center gap-2" onclick="setActiveType(this)">
<i class="fas fa-font"></i>
Text
</button>
<button type="button" data-type="wifi" class="qr-type-btn py-2 px-4 border rounded-lg font-medium flex items-center justify-center gap-2" onclick="setActiveType(this)">
<i class="fas fa-wifi"></i>
WiFi
</button>
<button type="button" data-type="contact" class="qr-type-btn py-2 px-4 border rounded-lg font-medium flex items-center justify-center gap-2" onclick="setActiveType(this)">
<i class="fas fa-user"></i>
Contact
</button>
<button type="button" data-type="email" class="qr-type-btn py-2 px-4 border rounded-lg font-medium flex items-center justify-center gap-2" onclick="setActiveType(this)">
<i class="fas fa-envelope"></i>
Email
</button>
<button type="button" data-type="sms" class="qr-type-btn py-2 px-4 border rounded-lg font-medium flex items-center justify-center gap-2" onclick="setActiveType(this)">
<i class="fas fa-comment"></i>
SMS
</button>
<button type="button" data-type="phone" class="qr-type-btn py-2 px-4 border rounded-lg font-medium flex items-center justify-center gap-2" onclick="setActiveType(this)">
<i class="fas fa-phone"></i>
Phone
</button>
<button type="button" data-type="location" class="qr-type-btn py-2 px-4 border rounded-lg font-medium flex items-center justify-center gap-2" onclick="setActiveType(this)">
<i class="fas fa-map-marker-alt"></i>
Location
</button>
</div>
</div>
<!-- URL Input (Default) -->
<div id="urlInput" class="content-input">
<label for="qrContent" class="block text-sm font-medium text-gray-700 mb-2">Website URL</label>
<div class="flex">
<span class="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 text-sm">
<i class="fas fa-link"></i>
</span>
<input type="url" id="qrContent" name="qrContent" placeholder="https://example.com" class="flex-1 min-w-0 block w-full px-3 py-2 rounded-none rounded-r-md border border-gray-300 focus:ring-blue-500 focus:border-blue-500" required>
</div>
</div>
<!-- Text Input -->
<div id="textInput" class="content-input hidden">
<label for="qrTextContent" class="block text-sm font-medium text-gray-700 mb-2">Text Content</label>
<textarea id="qrTextContent" name="qrTextContent" rows="3" placeholder="Enter any text you want to encode" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"></textarea>
</div>
<!-- WiFi Input -->
<div id="wifiInput" class="content-input hidden">
<div class="space-y-4">
<div>
<label for="wifiSsid" class="block text-sm font-medium text-gray-700 mb-2">Network Name (SSID)</label>
<input type="text" id="wifiSsid" name="wifiSsid" placeholder="MyWiFiNetwork" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="wifiPassword" class="block text-sm font-medium text-gray-700 mb-2">Password</label>
<input type="text" id="wifiPassword" name="wifiPassword" placeholder="Password123" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Security Type</label>
<select id="wifiSecurity" name="wifiSecurity" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
<option value="WPA">WPA/WPA2</option>
<option value="WEP">WEP</option>
<option value="">None</option>
</select>
</div>
</div>
</div>
<!-- Contact Input -->
<div id="contactInput" class="content-input hidden">
<div class="space-y-4">
<div>
<label for="contactName" class="block text-sm font-medium text-gray-700 mb-2">Name</label>
<input type="text" id="contactName" name="contactName" placeholder="John Doe" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="contactPhone" class="block text-sm font-medium text-gray-700 mb-2">Phone</label>
<input type="tel" id="contactPhone" name="contactPhone" placeholder="+1234567890" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="contactEmail" class="block text-sm font-medium text-gray-700 mb-2">Email</label>
<input type="email" id="contactEmail" name="contactEmail" placeholder="john@example.com" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
</div>
</div>
</div>
<!-- Email Input -->
<div id="emailInput" class="content-input hidden">
<div class="space-y-4">
<div>
<label for="emailTo" class="block text-sm font-medium text-gray-700 mb-2">Recipient Email</label>
<input type="email" id="emailTo" name="emailTo" placeholder="recipient@example.com" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="emailSubject" class="block text-sm font-medium text-gray-700 mb-2">Subject</label>
<input type="text" id="emailSubject" name="emailSubject" placeholder="Email Subject" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="emailBody" class="block text-sm font-medium text-gray-700 mb-2">Message</label>
<textarea id="emailBody" name="emailBody" rows="3" placeholder="Your message here..." class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"></textarea>
</div>
</div>
</div>
<!-- SMS Input -->
<div id="smsInput" class="content-input hidden">
<div class="space-y-4">
<div>
<label for="smsNumber" class="block text-sm font-medium text-gray-700 mb-2">Phone Number</label>
<input type="tel" id="smsNumber" name="smsNumber" placeholder="+1234567890" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="smsMessage" class="block text-sm font-medium text-gray-700 mb-2">Message</label>
<textarea id="smsMessage" name="smsMessage" rows="3" placeholder="Your SMS message..." class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"></textarea>
</div>
</div>
</div>
<!-- Phone Input -->
<div id="phoneInput" class="content-input hidden">
<div>
<label for="phoneNumber" class="block text-sm font-medium text-gray-700 mb-2">Phone Number</label>
<input type="tel" id="phoneNumber" name="phoneNumber" placeholder="+1234567890" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
</div>
</div>
<!-- Location Input -->
<div id="locationInput" class="content-input hidden">
<div class="space-y-4">
<div class="grid grid-cols-2 gap-4">
<div>
<label for="locationLatitude" class="block text-sm font-medium text-gray-700 mb-2">Latitude</label>
<input type="number" id="locationLatitude" name="locationLatitude" step="0.000001" placeholder="40.7128" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="locationLongitude" class="block text-sm font-medium text-gray-700 mb-2">Longitude</label>
<input type="number" id="locationLongitude" name="locationLongitude" step="0.000001" placeholder="-74.0060" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
</div>
</div>
<div>
<button type="button" onclick="getCurrentLocation()" class="w-full py-2 px-4 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-gray-50 hover:bg-gray-100 flex items-center justify-center gap-2">
<i class="fas fa-location-arrow"></i> Use Current Location
</button>
</div>
</div>
</div>
<!-- Design Options -->
<div class="pt-4 border-t border-gray-200">
<h3 class="text-lg font-medium text-gray-800 mb-4">Design Options</h3>
<!-- Colors -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">QR Color</label>
<div class="flex items-center gap-3">
<input type="color" id="qrColor" value="#000000" class="color-picker">
<span id="qrColorHex" class="text-sm font-mono bg-gray-100 px-2 py-1 rounded">#000000</span>
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Background Color</label>
<div class="flex items-center gap-3">
<input type="color" id="bgColor" value="#ffffff" class="color-picker">
<span id="bgColorHex" class="text-sm font-mono bg-gray-100 px-2 py-1 rounded">#ffffff</span>
</div>
</div>
</div>
<!-- Custom Icon -->
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">Custom Icon</label>
<div class="flex items-center gap-3">
<input type="file" id="logoFile" accept="image/*" class="custom-file-input">
<button type="button" id="removeLogo" class="text-sm text-red-600 hover:text-red-800 hidden">
<i class="fas fa-trash-alt"></i> Remove
</button>
</div>
</div>
<!-- Icon Size and Position -->
<div class="grid grid-cols-2 gap-4 mb-4" id="logoOptions" style="display: none;">
<div>
<label for="logoSize" class="block text-sm font-medium text-gray-700 mb-2">Icon Size (%)</label>
<input type="range" id="logoSize" min="5" max="30" value="15" class="w-full">
<div class="flex justify-between">
<span class="text-xs text-gray-500">5%</span>
<span class="text-xs text-gray-500" id="logoSizeValue">15%</span>
<span class="text-xs text-gray-500">30%</span>
</div>
</div>
<div>
<label for="logoBorderRadius" class="block text-sm font-medium text-gray-700 mb-2">Icon Radius</label>
<select id="logoBorderRadius" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
<option value="0">Sharp</option>
<option value="5">Slightly rounded</option>
<option value="15" selected>Rounded</option>
<option value="50">Circle</option>
</select>
</div>
</div>
<!-- QR Style -->
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">QR Style</label>
<div class="flex gap-3">
<button type="button" data-style="square" onclick="setQRStyle(this)" class="qr-style-btn active:scale-95 px-4 py-2 border rounded-lg font-medium flex items-center justify-center gap-2 bg-blue-100 border-blue-300">
<i class="fas fa-square-full"></i>
Squares
</button>
<button type="button" data-style="dots" onclick="setQRStyle(this)" class="qr-style-btn active:scale-95 px-4 py-2 border rounded-lg font-medium flex items-center justify-center gap-2">
<i class="fas fa-circle"></i>
Dots
</button>
<button type="button" data-style="rounded" onclick="setQRStyle(this)" class="qr-style-btn active:scale-95 px-4 py-2 border rounded-lg font-medium flex items-center justify-center gap-2">
<i class="fas fa-circle-notch"></i>
Rounded
</button>
</div>
</div>
<!-- Error Correction -->
<div>
<label for="errorCorrection" class="block text-sm font-medium text-gray-700 mb-2">Error Correction Level</label>
<select id="errorCorrection" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
<option value="L">Low (7%)</option>
<option value="M" selected>Medium (15%)</option>
<option value="Q">Quartile (25%)</option>
<option value="H">High (30%)</option>
</select>
<p class="mt-1 text-xs text-gray-500">Higher levels make the QR code more resistant to damage but increase complexity.</p>
</div>
</div>
<!-- Generate Button -->
<div>
<button type="button" onclick="generateQRCode()" class="w-full flex justify-center items-center py-3 px-4 border border-transparent rounded-md shadow-sm text-lg font-medium text-white bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-all">
<i class="fas fa-qrcode mr-2"></i> Generate QR Code
</button>
</div>
</form>
</div>
<!-- QR Code Preview -->
<div class="w-full lg:w-1/2">
<div class="bg-white rounded-xl shadow-md p-6 sticky top-4">
<div class="flex justify-between items-center mb-4">
<h2 class="text-2xl font-semibold text-gray-800">QR Code Preview</h2>
<div id="downloadBtns" class="hidden">
<button id="downloadPNG" onclick="downloadQR('png')" class="px-3 py-1.5 border border-gray-300 rounded-lg text-sm font-medium hover:bg-gray-50 flex items-center gap-1">
<i class="fas fa-download text-blue-600"></i> PNG
</button>
</div>
</div>
<div id="qrPreview" class="flex flex-col items-center justify-center p-8 border-2 border-dashed border-gray-300 rounded-lg qr-placeholder min-h-[300px]">
<i class="fas fa-qrcode text-5xl text-gray-400 mb-4"></i>
<p class="text-gray-500 text-center">Your custom QR code will appear here.<br>Configure options on the left and click "Generate".</p>
</div>
<div id="qrResult" class="hidden mt-6">
<canvas id="previewCanvas" class="mx-auto"></canvas>
<div class="mt-6 space-y-4">
<div class="flex gap-2 justify-center">
<button id="downloadSVG" onclick="downloadQR('svg')" class="px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 flex items-center gap-2">
<i class="fas fa-download"></i> SVG
</button>
<button id="downloadJPEG" onclick="downloadQR('jpeg')" class="px-4 py-2 bg-green-600 text-white rounded-lg font-medium hover:bg-green-700 flex items-center gap-2">
<i class="fas fa-download"></i> JPEG
</button>
<button id="downloadPDF" onclick="downloadQR('pdf')" class="px-4 py-2 bg-red-600 text-white rounded-lg font-medium hover:bg-red-700 flex items-center gap-2">
<i class="fas fa-download"></i> PDF
</button>
</div>
<div class="bg-blue-50 p-3 rounded-lg text-blue-800 text-sm flex items-start gap-2">
<i class="fas fa-info-circle mt-0.5"></i>
<div>
<strong>Tip:</strong> Test your QR code with your phone camera before sharing. If you added a logo, make sure the QR remains scannable.
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- How To Use Section -->
<section class="mt-16 bg-white rounded-xl shadow-md p-6">
<h2 class="text-2xl font-semibold text-gray-800 mb-4">How To Use</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="bg-gray-50 p-4 rounded-lg">
<div class="flex items-center gap-3 mb-3">
<div class="bg-blue-100 w-8 h-8 rounded-full flex items-center justify-center text-blue-700">
<span class="font-bold">1</span>
</div>
<h3 class="font-medium text-gray-800">Enter Content</h3>
</div>
<p class="text-gray-600 text-sm">Choose what type of content you want to encode (URL, text, WiFi, or contact info).</p>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<div class="flex items-center gap-3 mb-3">
<div class="bg-blue-100 w-8 h-8 rounded-full flex items-center justify-center text-blue-700">
<span class="font-bold">2</span>
</div>
<h3 class="font-medium text-gray-800">Customize Design</h3>
</div>
<p class="text-gray-600 text-sm">Adjust colors, add a logo, change the style, or set error correction level.</p>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<div class="flex items-center gap-3 mb-3">
<div class="bg-blue-100 w-8 h-8 rounded-full flex items-center justify-center text-blue-700">
<span class="font-bold">3</span>
</div>
<h3 class="font-medium text-gray-800">Download & Share</h3>
</div>
<p class="text-gray-600 text-sm">Generate and download your QR code in multiple formats (PNG, SVG, JPEG, PDF).</p>
</div>
</div>
</section>
</div>
<script src="https://cdn.jsdelivr.net/npm/qrcode@1.5.1/build/qrcode.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jspdf@2.5.1/dist/jspdf.umd.min.js"></script>
<script>
// Variables
let activeType = "url";
let qrStyle = "square";
let currentLogo = null;
let qrCodeDataURL = null;
// Initialize
document.addEventListener('DOMContentLoaded', function() {
// Set up color pickers
document.getElementById('qrColor').addEventListener('input', function() {
document.getElementById('qrColorHex').textContent = this.value;
});
document.getElementById('bgColor').addEventListener('input', function() {
document.getElementById('bgColorHex').textContent = this.value;
});
// Set up logo upload
document.getElementById('logoFile').addEventListener('change', function(e) {
if (e.target.files && e.target.files[0]) {
const reader = new FileReader();
reader.onload = function(event) {
currentLogo = event.target.result;
document.getElementById('logoOptions').style.display = 'grid';
document.getElementById('removeLogo').classList.remove('hidden');
};
reader.readAsDataURL(e.target.files[0]);
}
});
document.getElementById('removeLogo').addEventListener('click', function() {
currentLogo = null;
document.getElementById('logoOptions').style.display = 'none';
document.getElementById('logoFile').value = '';
this.classList.add('hidden');
if (document.getElementById('qrResult').classList.contains('hidden') === false) {
generateQRCode();
}
});
// Live preview updates for certain controls
const liveUpdateElements = ['logoSize', 'logoBorderRadius', 'qrColor', 'bgColor', 'errorCorrection'];
liveUpdateElements.forEach(id => {
document.getElementById(id).addEventListener('input', function() {
if (this.id === 'logoSize') {
document.getElementById('logoSizeValue').textContent = this.value + '%';
}
if (document.getElementById('qrResult').classList.contains('hidden') === false) {
generateQRCode();
}
});
});
});
// Set active content type
function setActiveType(button) {
activeType = button.getAttribute('data-type');
// Update active button state
document.querySelectorAll('.qr-type-btn').forEach(btn => {
btn.classList.remove('bg-blue-100', 'border-blue-300');
});
button.classList.add('bg-blue-100', 'border-blue-300');
// Show the correct input section
document.querySelectorAll('.content-input').forEach(section => {
section.classList.add('hidden');
});
document.getElementById(activeType + 'Input').classList.remove('hidden');
}
// Set QR style
function setQRStyle(button) {
qrStyle = button.getAttribute('data-style');
// Update active button state
document.querySelectorAll('.qr-style-btn').forEach(btn => {
btn.classList.remove('bg-blue-100', 'border-blue-300');
});
button.classList.add('bg-blue-100', 'border-blue-300');
if (document.getElementById('qrResult').classList.contains('hidden') === false) {
generateQRCode();
}
}
// Generate QR code
function generateQRCode() {
let content = '';
// Get content based on active type
switch(activeType) {
case 'url':
content = document.getElementById('qrContent').value;
if (!content) {
showError("Please enter a URL");
return;
}
if (!content.startsWith('http://') && !content.startsWith('https://')) {
content = 'https://' + content;
}
break;
case 'text':
content = document.getElementById('qrTextContent').value;
if (!content) {
showError("Please enter some text");
return;
}
break;
case 'wifi':
const ssid = document.getElementById('wifiSsid').value;
if (!ssid) {
showError("Please enter a WiFi network name");
return;
}
const password = document.getElementById('wifiPassword').value || '';
const security = document.getElementById('wifiSecurity').value;
if (security) {
content = `WIFI:T:${security};S:${ssid};P:${password};;`;
} else {
content = `WIFI:T:nopass;S:${ssid};;`;
}
break;
case 'contact':
const name = document.getElementById('contactName').value || '';
const phone = document.getElementById('contactPhone').value || '';
const email = document.getElementById('contactEmail').value || '';
if (!name && !phone && !email) {
showError("Please enter at least one contact field");
return;
}
content = 'BEGIN:VCARD\nVERSION:3.0\n';
if (name) content += `FN:${name}\nN:${name.split(' ').reverse().join(';')};;;\n`;
if (phone) content += `TEL:${phone}\n`;
if (email) content += `EMAIL:${email}\n`;
content += 'END:VCARD';
break;
case 'email':
const emailTo = document.getElementById('emailTo').value;
const emailSubject = document.getElementById('emailSubject').value || '';
const emailBody = document.getElementById('emailBody').value || '';
if (!emailTo) {
showError("Please enter a recipient email address");
return;
}
content = `mailto:${emailTo}`;
if (emailSubject || emailBody) {
content += '?';
if (emailSubject) content += `subject=${encodeURIComponent(emailSubject)}`;
if (emailSubject && emailBody) content += '&';
if (emailBody) content += `body=${encodeURIComponent(emailBody)}`;
}
break;
case 'sms':
const smsNumber = document.getElementById('smsNumber').value;
const smsMessage = document.getElementById('smsMessage').value || '';
if (!smsNumber) {
showError("Please enter a phone number");
return;
}
content = `smsto:${smsNumber}`;
if (smsMessage) {
content += `:${encodeURIComponent(smsMessage)}`;
}
break;
case 'phone':
const phoneNumber = document.getElementById('phoneNumber').value;
if (!phoneNumber) {
showError("Please enter a phone number");
return;
}
content = `tel:${phoneNumber}`;
break;
case 'location':
const latitude = document.getElementById('locationLatitude').value;
const longitude = document.getElementById('locationLongitude').value;
if (!latitude || !longitude) {
showError("Please enter both latitude and longitude coordinates");
return;
}
content = `geo:${latitude},${longitude}`;
break;
}
// Get design options
const qrColor = document.getElementById('qrColor').value;
const bgColor = document.getElementById('bgColor').value;
const errorCorrection = document.getElementById('errorCorrection').value;
const logoBorderRadius = document.getElementById('logoBorderRadius').value;
const logoSize = parseInt(document.getElementById('logoSize').value) / 100;
// Clear any previous errors
document.querySelectorAll('.error-message').forEach(el => el.remove());
// Hide placeholder and show result container
document.getElementById('qrPreview').classList.add('hidden');
document.getElementById('qrResult').classList.remove('hidden');
document.getElementById('downloadBtns').classList.remove('hidden');
// Generate QR code with options
const canvas = document.getElementById('previewCanvas');
// Apply style options
let dotOptions = { type: 'square' };
if (qrStyle === 'dots') {
dotOptions = { type: 'dots' };
} else if (qrStyle === 'rounded') {
dotOptions = { type: 'rounded' };
}
QRCode.toCanvas(canvas, content, {
width: 300,
color: {
dark: qrColor,
light: bgColor
},
errorCorrectionLevel: errorCorrection,
margin: 1,
...dotOptions
}, function(error) {
if (error) {
showError("Failed to generate QR code: " + error.message);
return;
}
qrCodeDataURL = canvas.toDataURL('image/png');
// Add logo if provided
if (currentLogo) {
addLogoToQR(canvas, currentLogo, logoSize, logoBorderRadius);
}
});
}
// Add logo to QR code
function addLogoToQR(canvas, logoData, sizePercent, borderRadius) {
const ctx = canvas.getContext('2d');
// Create a temporary canvas to draw the rounded logo
const logoCanvas = document.createElement('canvas');
const logoCtx = logoCanvas.getContext('2d');
const logoImg = new Image();
logoImg.onload = function() {
// Logo dimensions (15-30% of QR code size)
const logoSize = canvas.width * sizePercent;
const center = canvas.width / 2;
// Draw rounded logo on temp canvas
logoCanvas.width = logoSize;
logoCanvas.height = logoSize;
// Create rounded path
logoCtx.beginPath();
logoCtx.moveTo(borderRadius, 0);
logoCtx.lineTo(logoSize - borderRadius, 0);
logoCtx.quadraticCurveTo(logoSize, 0, logoSize, borderRadius);
logoCtx.lineTo(logoSize, logoSize - borderRadius);
logoCtx.quadraticCurveTo(logoSize, logoSize, logoSize - borderRadius, logoSize);
logoCtx.lineTo(borderRadius, logoSize);
logoCtx.quadraticCurveTo(0, logoSize, 0, logoSize - borderRadius);
logoCtx.lineTo(0, borderRadius);
logoCtx.quadraticCurveTo(0, 0, borderRadius, 0);
logoCtx.closePath();
logoCtx.clip();
// Draw logo image
logoCtx.drawImage(logoImg, 0, 0, logoSize, logoSize);
// Draw temp canvas on QR code
ctx.drawImage(logoCanvas, center - logoSize/2, center - logoSize/2);
};
logoImg.src = logoData;
}
// Download QR code
function downloadQR(format) {
if (!qrCodeDataURL) {
showError("Please generate a QR code first");
return;
}
const canvas = document.getElementById('previewCanvas');
const link = document.createElement('a');
let filename = 'qr-code';
switch(activeType) {
case 'url':
const url = document.getElementById('qrContent').value;
filename = url.replace(/^https?:\/\//, '').split('/')[0] || 'qr-code';
break;
case 'text':
filename = 'qr-code-text';
break;
case 'wifi':
filename = 'wifi-' + document.getElementById('wifiSsid').value;
break;
case 'contact':
const name = document.getElementById('contactName').value || 'contact';
filename = name.toLowerCase().replace(/\s+/g, '-');
break;
}
switch(format) {
case 'png':
link.href = canvas.toDataURL('image/png');
link.download = filename + '.png';
break;
case 'jpeg':
link.href = canvas.toDataURL('image/jpeg', 0.92);
link.download = filename + '.jpg';
break;
case 'svg':
// For SVG, we'll recreate the QR code as SVG
let content = '';
switch(activeType) {
case 'url': content = document.getElementById('qrContent').value; break;
case 'text': content = document.getElementById('qrTextContent').value; break;
case 'wifi':
const ssid = document.getElementById('wifiSsid').value;
const password = document.getElementById('wifiPassword').value || '';
const security = document.getElementById('wifiSecurity').value;
content = security ? `WIFI:T:${security};S:${ssid};P:${password};;` : `WIFI:T:nopass;S:${ssid};;`;
break;
case 'contact':
const nameC = document.getElementById('contactName').value || '';
const phone = document.getElementById('contactPhone').value || '';
const email = document.getElementById('contactEmail').value || '';
content = 'BEGIN:VCARD\nVERSION:3.0\n';
if (nameC) content += `FN:${nameC}\nN:${nameC.split(' ').reverse().join(';')};;;\n`;
if (phone) content += `TEL:${phone}\n`;
if (email) content += `EMAIL:${email}\n`;
content += 'END:VCARD';
break;
case 'email':
content = document.getElementById('emailTo').value;
break;
case 'sms':
content = document.getElementById('smsNumber').value;
break;
case 'phone':
content = document.getElementById('phoneNumber').value;
break;
case 'location':
content = `${document.getElementById('locationLatitude').value},${document.getElementById('locationLongitude').value}`;
break;
}
QRCode.toString(content, {
type: 'svg',
color: {
dark: document.getElementById('qrColor').value,
light: document.getElementById('bgColor').value
},
errorCorrectionLevel: document.getElementById('errorCorrection').value,
margin: 1
}, function(err, svg) {
if (err) {
showError("Failed to generate SVG: " + err.message);
return;
}
const blob = new Blob([svg], {type: 'image/svg+xml'});
link.href = URL.createObjectURL(blob);
link.download = filename + '.svg';
link.click();
URL.revokeObjectURL(link.href);
});
return;
case 'pdf':
const { jsPDF } = window.jspdf;
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'mm'
});
// Add QR code image
const qrWidth = 50; // mm
const qrHeight = (canvas.height / canvas.width) * qrWidth;
pdf.addImage(canvas, 'PNG',
(pdf.internal.pageSize.getWidth() - qrWidth) / 2,
(pdf.internal.pageSize.getHeight() - qrHeight) / 2 - 10,
qrWidth, qrHeight);
// Add content text
let pdfContent = '';
switch(activeType) {
case 'url': pdfContent = document.getElementById('qrContent').value; break;
case 'text': pdfContent = document.getElementById('qrTextContent').value; break;
case 'wifi':
pdfContent = `WiFi Network: ${document.getElementById('wifiSsid').value}\n`;
if (document.getElementById('wifiPassword').value) {
pdfContent += `Password: ${document.getElementById('wifiPassword').value}\n`;
}
break;
case 'contact':
if (document.getElementById('contactName').value) {
pdfContent += `Name: ${document.getElementById('contactName').value}\n`;
}
if (document.getElementById('contactPhone').value) {
pdfContent += `Phone: ${document.getElementById('contactPhone').value}\n`;
}
if (document.getElementById('contactEmail').value) {
pdfContent += `Email: ${document.getElementById('contactEmail').value}\n`;
}
break;
case 'email':
pdfContent += `To: ${document.getElementById('emailTo').value}\n`;
if (document.getElementById('emailSubject').value) {
pdfContent += `Subject: ${document.getElementById('emailSubject').value}\n`;
}
if (document.getElementById('emailBody').value) {
pdfContent += `Message: ${document.getElementById('emailBody').value}\n`;
}
break;
case 'sms':
pdfContent += `To: ${document.getElementById('smsNumber').value}\n`;
if (document.getElementById('smsMessage').value) {
pdfContent += `Message: ${document.getElementById('smsMessage').value}\n`;
}
break;
case 'phone':
pdfContent += `Phone: ${document.getElementById('phoneNumber').value}\n`;
break;
case 'location':
pdfContent += `Latitude: ${document.getElementById('locationLatitude').value}\n`;
pdfContent += `Longitude: ${document.getElementById('locationLongitude').value}\n`;
break;
}
if (pdfContent) {
pdf.setFontSize(10);
pdf.setTextColor(100);
pdf.text(pdfContent,
pdf.internal.pageSize.getWidth() / 2,
(pdf.internal.pageSize.getHeight() - qrHeight) / 2 + qrHeight + 10,
{ align: 'center' }
);
}
pdf.save(filename + '.pdf');
return;
}
link.click();
}
// Show error message
function showError(message) {
// Remove any existing error messages
document.querySelectorAll('.error-message').forEach(el => el.remove());
const errorEl = document.createElement('div');
errorEl.className = 'error-message bg-red-50 text-red-700 p-3 text-sm rounded-lg mb-4 flex items-start gap-2';
errorEl.innerHTML = `<i class="fas fa-exclamation-circle mt-0.5"></i><span>${message}</span>`;
const form = document.getElementById('qrForm');
form.insertBefore(errorEl, form.firstChild);
}
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=martiantrader/qrcodegenerator" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>