TransWar File Browser

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 &bull; " + 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>
	';
?>