Path: C:\
<?php
include 'vendor/autoload.php';
use BaconQrCode\Renderer\ImageRenderer;
use BaconQrCode\Renderer\Image\SvgImageBackEnd;
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
use BaconQrCode\Writer;
$renderer = new ImageRenderer(
new RendererStyle(160),
new SvgImageBackEnd()
);
$writer = new Writer($renderer);
if (isset($_POST['texto'])) {
$url = $_POST['texto'];
} else {
$url = 'Vazio';
}
if (isset($_POST['arq'])) {
$nome_arq = $_POST['arq'];
} else {
$nome_arq = 'Vazio';
}
if (isset($_POST['funciona'])) {
$nome_func = $_POST['funciona'];
} else {
$nome_func = 'Vazio';
}
$funcao = isset($_POST['funcao']) ? trim($_POST['funcao']) : '';
$rg = isset($_POST['rg']) ? trim($_POST['rg']) : '';
$cpf = isset($_POST['cpf']) ? trim($_POST['cpf']) : '';
$pis = isset($_POST['pis']) ? trim($_POST['pis']) : '';
$vinculo = isset($_POST['vinculo']) ? trim($_POST['vinculo']) : '';
if (!mb_check_encoding($funcao, 'UTF-8')) {
$funcao = mb_convert_encoding($funcao, 'UTF-8', 'ISO-8859-1');
}
if (!mb_check_encoding($vinculo, 'UTF-8')) {
$vinculo = mb_convert_encoding($vinculo, 'UTF-8', 'ISO-8859-1');
}
$name = $nome_arq;
if (!mb_check_encoding($nome_arq, 'UTF-8')) {
$nome_arq = mb_convert_encoding($nome_arq, 'UTF-8', 'ISO-8859-1');
}
if (!mb_check_encoding($url, 'UTF-8')) {
$url = mb_convert_encoding($url, 'UTF-8', 'ISO-8859-1');
}
$name = $nome_arq;
$split_name = explode(" ", $name);
if (count($split_name) > 2) {
for ($i = 1; (count($split_name) - 1) > $i; $i++) {
if (mb_strlen($split_name[$i], 'UTF-8') > 3) {
$split_name[$i] = mb_substr($split_name[$i], 0, 1, 'UTF-8') . ".";
}
}
}
$final = implode(" ", $split_name);
// QR Code codifica nome, rg, cpf e pis separados por ponto e virgula
$qrcode_payload = $nome_arq . ';' . $rg . ';' . $cpf . ';' . $pis;
$qrcode = $writer->writeString($qrcode_payload);
// Obter dimensoes reais da imagem template para manter proporcao exata
$templateFile = __DIR__ . '/QRHTML.png';
$imgSize = getimagesize($templateFile);
$imgW = $imgSize[0]; // 578
$imgH = $imgSize[1]; // 844
$displayW = 240;
$displayH = round($displayW * $imgH / $imgW); // calculo proporcional exato
// Sangria de 1px transparente em volta do cartao. Sem ela a borda arredondada
// fica exatamente no limite da captura e o html2canvas, que arredonda a altura
// para baixo (350 x 2,954 = 1033,96 -> 1033), come a ultima linha do desenho.
// A folga e transparente, entao quem perde o pixel do arredondamento e ela.
$sangria = 1;
$boxW = $displayW + ($sangria * 2);
$boxH = $displayH + ($sangria * 2);
// Alvo de impressao: 6 cm de largura a 300 DPI, ja contando a sangria.
$printW = 709; // 6,0 cm * 300 dpi
$captureScale = $printW / $boxW;
$printH = round($boxH * $captureScale);
// Nome do arquivo baixado. Precisa ser unico por pessoa: o navegador nao
// sobrescreve downloads, ele cria "_Cracha (1).png", e o usuario acaba abrindo
// o arquivo antigo achando que a geracao nao funcionou.
// (iconv //TRANSLIT no Windows vira "JO~AO", por isso o mapa explicito)
$acentos = [
'á'=>'a','à'=>'a','ã'=>'a','â'=>'a','ä'=>'a','é'=>'e','ê'=>'e','è'=>'e','ë'=>'e',
'í'=>'i','ì'=>'i','î'=>'i','ï'=>'i','ó'=>'o','ò'=>'o','õ'=>'o','ô'=>'o','ö'=>'o',
'ú'=>'u','ù'=>'u','û'=>'u','ü'=>'u','ç'=>'c','ñ'=>'n',
'Á'=>'A','À'=>'A','Ã'=>'A','Â'=>'A','Ä'=>'A','É'=>'E','Ê'=>'E','È'=>'E','Ë'=>'E',
'Í'=>'I','Ì'=>'I','Î'=>'I','Ï'=>'I','Ó'=>'O','Ò'=>'O','Õ'=>'O','Ô'=>'O','Ö'=>'O',
'Ú'=>'U','Ù'=>'U','Û'=>'U','Ü'=>'U','Ç'=>'C','Ñ'=>'N',
];
$slug = preg_replace('/[^A-Za-z0-9]+/', '_', strtr($final, $acentos));
$slug = trim($slug, '_');
$nomeDownload = ($slug !== '' ? $slug : 'Cracha') . '_Cracha.png';
echo '
<script src="./js/html2canvas.js"></script>
<script type="text/javascript">
function doCapture() {
var alvo = document.getElementById("cracha-wrapper");
var img = alvo.querySelector("img");
var scrollAnterior = { x: window.scrollX, y: window.scrollY };
function devolverScroll() {
window.scrollTo(scrollAnterior.x, scrollAnterior.y);
}
// Só captura depois que o template terminou de carregar, senao o
// html2canvas grava o cartao sem o fundo.
var pronto = (img && img.complete) ? Promise.resolve() : new Promise(function (ok) {
img.addEventListener("load", ok);
img.addEventListener("error", ok);
});
pronto.then(function () {
// Com a pagina rolada o html2canvas erra a origem do desenho e o
// cartao sai deslocado/cortado. Capturamos no topo e devolvemos o
// scroll logo depois.
window.scrollTo(0, 0);
return new Promise(function (ok) { setTimeout(ok, 120); });
}).then(function () {
// Sem width/height/windowWidth fixos: o html2canvas usa o tamanho
// real do elemento, o que torna a captura independente do zoom.
return html2canvas(alvo, {
useCORS: true,
backgroundColor: null,
scale: ' . $captureScale . ',
logging: false,
scrollX: 0,
scrollY: 0,
// O clone e renderizado numa janela sem barra de rolagem. Como
// o cartao esta centralizado, ele escorregava meia-barra (~7px)
// para a direita e era cortado. clientWidth ja desconta a
// barra e nao muda com o zoom.
windowWidth: document.documentElement.clientWidth,
windowHeight: document.documentElement.clientHeight
});
}).then(function (canvas) {
devolverScroll();
// Mostra a medida real do que foi gravado, sem estimativa.
var lbl = document.getElementById("cracha-dimensoes");
if (lbl) {
var cmL = (canvas.width / 300 * 2.54).toFixed(1).replace(".", ",");
var cmA = (canvas.height / 300 * 2.54).toFixed(1).replace(".", ",");
lbl.innerHTML = canvas.width + " x " + canvas.height + " px • " + cmL + " x " + cmA + " cm a 300 DPI";
}
var ajax = new XMLHttpRequest();
ajax.open("POST", "save-capture.php?arq=' . rawurlencode($final) . '", true);
ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
ajax.send("image=" + encodeURIComponent(canvas.toDataURL("image/png")));
ajax.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
var a = document.createElement("a");
a.download = "' . $nomeDownload . '";
a.href = "_Cracha.png?" + Date.now();
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
};
}).catch(function (err) {
devolverScroll();
console.error(err);
alert("Erro ao gerar imagem.");
});
}
function fecharPreview() {
document.getElementById("aqui").innerHTML = \'<div class="text-center opacity-25" style="margin-top:20%;"><i class="ph ph-identification-badge" style="font-size: 6rem;"></i><p class="mt-2 text-uppercase tracking-widest small">Pronto para Renderização</p></div>\';
}
</script>
<style>
.hero-image {
height: ' . $displayH . 'px;
width: ' . $displayW . 'px;
position: relative;
}
.hero-qrcode {
text-align: center;
position: absolute;
width: 160px;
top: 84px;
left: 40px;
z-index: 2;
}
.hero-qrtxt {
text-align: center;
position: absolute;
line-height: 95%;
top: 260px;
width: 216px;
left: 12px;
z-index: 2;
}
</style>
<div style="display:flex; flex-direction:column; align-items:center; gap:16px; padding:16px 0;">
<div id="cracha-wrapper" style="padding: ' . $sangria . 'px; background: transparent; width: ' . $boxW . 'px; height: ' . $boxH . 'px; box-sizing: border-box; position: relative;">
<div class="hero-image" id="cracha" data-bs-theme="light">
<img src="QRHTML.png" style="position: absolute; top:0; left:0; width: 100%; height: 100%; z-index: 1;" crossorigin="anonymous" />
<div class="hero-qrcode">' . $qrcode . '</div>
<div class="hero-qrtxt" style="color:#000;">
<strong style="font-size: 18px; display:block; margin-bottom:5px; line-height: 1.1;">' . $final . '</strong>
</div>
</div>
</div>
<div class="text-center small text-muted" style="line-height:1.5;">
<div>Arquivo: <strong>' . $nomeDownload . '</strong></div>
<div id="cracha-dimensoes">aprox. ' . $printW . ' x ' . $printH . ' px a 300 DPI</div>
</div>
<div style="display:flex; gap:10px; justify-content:center;">
<button type="button" class="btn btn-primary px-4 fw-bold" onclick="doCapture();" style="border-radius:8px;"><i class="ph ph-download-simple me-2"></i>Gravar Crachá Local</button>
<button type="button" class="btn btn-outline-secondary px-4 fw-bold" onclick="fecharPreview();" style="border-radius:8px;"><i class="ph ph-x me-2"></i>Fechar</button>
</div>
</div>
';
?>