pro unlimited code gps
<html lang="id">
<head>
<meta charset="UTF-8"></meta>
<meta content="width=device-width, initial-scale=1.0" name="viewport"></meta>
<title>Orange Geotag Pro</title>
<style>
*{
margin:0;
padding:0;
box-sizing:border-box;
}
body{
background:#f1f1f1;
font-family:'Segoe UI',sans-serif;
padding:20px;
}
.wrapper{
max-width:1400px;
margin:auto;
display:grid;
grid-template-columns:350px 1fr;
gap:20px;
}
.panel{
background:#fff;
border-radius:25px;
padding:25px;
box-shadow:0 10px 30px rgba(0,0,0,0.08);
}
.logo{
display:flex;
align-items:center;
gap:12px;
margin-bottom:25px;
}
.logo h1{
font-size:32px;
color:#ff7b00;
}
.logo p{
color:#666;
}
.upload-btn,
button{
width:100%;
border:none;
background:#ff7b00;
color:white;
padding:18px;
border-radius:15px;
font-size:18px;
font-weight:bold;
cursor:pointer;
}
.card{
margin-top:20px;
background:#fafafa;
border-radius:20px;
padding:20px;
border:1px solid #eee;
}
.card h3{
margin-bottom:15px;
color:#333;
}
label{
display:block;
margin-bottom:8px;
color:#444;
font-weight:600;
}
textarea,
input,
select{
width:100%;
padding:14px;
border-radius:12px;
border:1px solid #ddd;
margin-bottom:15px;
font-size:15px;
}
.grid{
display:grid;
grid-template-columns:1fr 1fr;
gap:12px;
}
.preview{
background:#fff;
border-radius:25px;
padding:20px;
box-shadow:0 10px 30px rgba(0,0,0,0.08);
}
canvas{
width:100%;
border-radius:20px;
background:#ddd;
}
.actions{
display:flex;
justify-content:space-between;
gap:15px;
margin-top:20px;
}
.download{
flex:1;
text-align:center;
background:#2ebd59;
color:white;
text-decoration:none;
padding:18px;
border-radius:15px;
font-weight:bold;
display:none;
}
.status{
margin-top:15px;
padding:14px;
border-radius:12px;
background:#f3fff5;
color:#1c7f38;
}
@media(max-width:900px){
.wrapper{
grid-template-columns:1fr;
}
}
</style>
</head>
<body>
<div class="wrapper">
<div class="panel">
<div class="logo">
<div style="font-size: 45px;">📍</div>
<div>
<h1>Orange</h1>
<p>Geotag Pro Ultimate</p>
</div>
</div>
<label class="upload-btn">
📸 Upload / Ambil Foto
<input accept="image/*" capture="environment" hidden="" id="upload" type="file" />
</label>
<div class="card">
<h3>📌 Informasi Lokasi</h3>
<label>Alamat</label>
<textarea id="address" rows="3"></textarea>
<div class="grid">
<div>
<label>Latitude</label>
<input id="lat" type="text" />
</div>
<div>
<label>Longitude</label>
<input id="lon" type="text" />
</div>
</div>
</div>
<div class="card">
<h3>⚙ Pengaturan Watermark</h3>
<label>Ukuran Peta</label>
<select id="mapSize">
<option value="small">Kecil</option>
<option selected="" value="medium">Sedang</option>
<option value="large">Besar</option>
</select>
<label>Posisi Peta</label>
<select id="mapPosition">
<option value="bottom-right">Kanan Bawah</option>
<option value="bottom-left">Kiri Bawah</option>
<option value="top-right">Kanan Atas</option>
<option value="top-left">Kiri Atas</option>
</select>
<label>Transparansi Peta</label>
<input id="opacity" max="100" min="20" type="range" value="75" />
<button id="processBtn">
🚀 Proses Geotag Foto
</button>
</div>
<div class="status" id="status">
Menunggu upload foto...
</div>
</div>
<div class="preview">
<canvas id="canvas"></canvas>
<div class="actions">
<button onclick="location.reload()">
🔄 Reset
</button>
<a class="download" id="downloadBtn">
⬇ Download Foto
</a>
</div>
</div>
</div>
<script>
const upload = document.getElementById('upload');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const processBtn = document.getElementById('processBtn');
const downloadBtn = document.getElementById('downloadBtn');
const status = document.getElementById('status');
let originalImage = null;
upload.addEventListener('change', function(e){
const file = e.target.files[0];
if(!file) return;
status.innerHTML = '⏳ Memuat foto...';
const reader = new FileReader();
reader.onload = function(event){
const img = new Image();
img.onload = function(){
originalImage = img;
drawBaseImage();
getLocation();
status.innerHTML = '✅ Foto berhasil dimuat. Mengambil lokasi GPS...';
}
img.src = event.target.result;
}
reader.readAsDataURL(file);
});
function drawBaseImage(){
const maxWidth = 1400;
let width = originalImage.width;
let height = originalImage.height;
if(width > maxWidth){
height *= maxWidth / width;
width = maxWidth;
}
canvas.width = width;
canvas.height = height;
ctx.drawImage(originalImage, 0, 0, width, height);
}
function getLocation(){
if (!navigator.geolocation) {
status.innerHTML = '❌ Geolocation tidak didukung browser ini.';
return;
}
navigator.geolocation.getCurrentPosition(
async function(position){
const lat = position.coords.latitude.toFixed(6);
const lon = position.coords.longitude.toFixed(6);
document.getElementById('lat').value = lat;
document.getElementById('lon').value = lon;
try{
status.innerHTML = '⏳ Menghubungkan ke OpenStreetMap...';
const response = await fetch(
`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lon}`
);
const data = await response.json();
document.getElementById('address').value = data.display_name || 'Alamat tidak ditemukan';
status.innerHTML = '✅ GPS dan Alamat siap diproses!';
}catch(err){
console.log(err);
status.innerHTML = '⚠️ Gagal mengambil alamat, silakan isi manual.';
}
},
function(error) {
status.innerHTML = '⚠️ Akses GPS ditolak. Silakan isi manual.';
}
);
}
processBtn.addEventListener('click', function(){
if(!originalImage) {
alert('Silakan upload foto terlebih dahulu!');
return;
}
status.innerHTML = '⏳ Memproses Geotag...';
drawBaseImage();
const lat = document.getElementById('lat').value || '0.000000';
const lon = document.getElementById('lon').value || '0.000000';
const address = document.getElementById('address').value || '-';
const opacity = document.getElementById('opacity').value / 100;
const mapSize = document.getElementById('mapSize').value;
const mapPosition = document.getElementById('mapPosition').value;
let mapWidth = 260;
let mapHeight = 160;
if(mapSize === 'small'){
mapWidth = 220;
mapHeight = 130;
}
if(mapSize === 'large'){
mapWidth = 340;
mapHeight = 200;
}
const mapImage = new Image();
mapImage.crossOrigin = 'anonymous';
// INTEGRASI YANDEX STATIC MAPS API
// Format Yandex: ll=longitude,latitude & pt=longitude,latitude,style_marker
mapImage.src = `https://static-maps.yandex.ru/1.x/?ll=${lon},${lat}&z=16&l=map&size=450,300&pt=${lon},${lat},pm2orl`;
mapImage.onload = function(){
let mapX = 25;
let mapY = 25;
if(mapPosition === 'top-right'){
mapX = canvas.width - mapWidth - 25;
mapY = 25;
}
if(mapPosition === 'bottom-right'){
mapX = canvas.width - mapWidth - 25;
mapY = canvas.height - mapHeight - 195; // Jarak aman agar box teks hitam di bawah tidak tertimpa
}
if(mapPosition === 'bottom-left'){
mapX = 25;
mapY = canvas.height - mapHeight - 195; // Jarak aman agar box teks hitam di bawah tidak tertimpa
}
if(mapPosition === 'top-left'){
mapX = 25;
mapY = 25;
}
// 1. Gambar Peta Mini dengan Sudut Melengkung (Borders)
ctx.save();
ctx.globalAlpha = opacity;
roundRect(mapX, mapY, mapWidth, mapHeight, 18);
ctx.clip();
ctx.drawImage(mapImage, mapX, mapY, mapWidth, mapHeight);
ctx.restore();
// 2. Gambar Bingkai Putih di Sekeliling Peta
ctx.save();
ctx.lineWidth = 4;
ctx.strokeStyle = 'rgba(255,255,255,0.9)';
roundRect(mapX, mapY, mapWidth, mapHeight, 18);
ctx.stroke();
ctx.restore();
// 3. Tulis Informasi Data Geotag (Teks)
drawText(address, lat, lon);
// 4. Ekspor ke Tombol Download
exportImage();
};
mapImage.onerror = function() {
// Fallback jika terjadi gangguan koneksi ke server Yandex
drawText(address, lat, lon);
exportImage();
status.innerHTML = '⚠️ Selesai tanpa Peta Mini (Gagal memuat server Yandex)';
};
});
function drawText(address, lat, lon){
const overlayHeight = 170;
// Latar belakang box hitam transparan di bawah foto
ctx.fillStyle = 'rgba(0,0,0,0.55)';
ctx.fillRect(0, canvas.height - overlayHeight, canvas.width, overlayHeight);
ctx.fillStyle = '#fff';
ctx.font = 'bold 22px "Segoe UI", sans-serif';
const now = new Date();
const tanggal = now.toLocaleDateString('id-ID', { day: 'numeric', month: 'long', year: 'numeric' });
const jam = now.toLocaleTimeString('id-ID') + ' WIB';
let y = canvas.height - 125;
// Bungkus teks alamat agar otomatis turun baris jika kepanjangan
const maxTextWidth = canvas.width - 60;
const addressLines = wrapText(ctx, '📍 ' + address, maxTextWidth);
addressLines.forEach(line => {
ctx.fillText(line, 30, y);
y += 30;
});
ctx.fillText('🌍 Latitude : ' + lat, 30, y);
y += 30;
ctx.fillText('🧭 Longitude : ' + lon, 30, y);
y += 30;
ctx.fillText('📅 ' + tanggal + ' | ⏰ ' + jam, 30, y);
}
function wrapText(context, text, maxWidth) {
const words = text.split(' ');
const lines = [];
let currentLine = words[0];
for (let i = 1; i < words.length; i++) {
const word = words[i];
const width = context.measureText(currentLine + " " + word).width;
if (width < maxWidth) {
currentLine += " " + word;
} else {
lines.push(currentLine);
currentLine = word;
}
}
lines.push(currentLine);
return lines.slice(0, 2); // Maksimal ambil 2 baris alamat agar rapi
}
function exportImage(){
try {
const finalImage = canvas.toDataURL('image/jpeg', 0.95);
downloadBtn.href = finalImage;
downloadBtn.download = 'orange-geotag-pro-' + Date.now() + '.jpg';
downloadBtn.style.display = 'block';
status.innerHTML = '✅ Watermark mini map berhasil dibuat!';
} catch(err) {
console.error(err);
status.innerHTML = '❌ Gagal ekspor gambar karena masalah keamanan browser (CORS).';
}
}
function roundRect(x,y,w,h,r){
ctx.beginPath();
ctx.moveTo(x+r,y);
ctx.lineTo(x+w-r,y);
ctx.quadraticCurveTo(x+w,y,x+w,y+r);
ctx.lineTo(x+w,y+h-r);
ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);
ctx.lineTo(x+r,y+h);
ctx.quadraticCurveTo(x,y+h,x,y+h-r);
ctx.lineTo(x,y+r);
ctx.quadraticCurveTo(x,y,x+r,y);
ctx.closePath();
}
</script>
</body>
</html>
Posting Komentar