MiniPrint

...
Ligar
Conecte primeiro! 👆
📸
Impressão Fotográfica
Edite e imprima suas fotos
💭
Pensamento
do Dia
Uma frase surpresa
🔮
Horóscopo
Sincero
Verdades ácidas
🧩
Sudoku
Imprima e jogue
🔍
Caça
Palavras
Ache se puder
🎞️
Foto
Cabine
Tiras vintage
🖼️
Coleções
de Pintar
Complete os álbuns
🎲
Bingo
Cartelas e Sorteio
🌸
Mandala
para Colorir
Única toda vez
🔗
Gerador de
QR Code
Links e Textos
💖
Apoie o MiniPrint
Ajude o app a crescer!

Impressão

📷
Selecionar foto Toque para escolher da galeria
Preview
Trocar foto
✨ Análise Inteligente
Foto Suave
Desenho Preto puro
Polaroid Com borda
Brilho0
Contraste0
Nitidez0
💡

Escolha uma foto da galeria e ajuste brilho, contraste e nitidez com os controles. Experimente os modos Foto, Desenho e Polaroid. O botão Análise Inteligente sugere os melhores ajustes automaticamente!

Pensamento

🤫
Surpresa do Dia
Aperte o botão para imprimir uma mensagem misteriosa só para você.
💡

Pressione o botão e segure o dedo no sensor até a leitura completar. Uma frase surpresa e inédita será impressa. Você pode imprimir uma frase por dia.

""
-

Bingo

🎫 Imprimir Cartela

Escolha o limite de bolas no sorteio (imprime 1 cartela por clique):

1 a 20
1 a 30
1 a 40
1 a 50
Pronto para imprimir.
💡

Imprima uma cartela diferente para cada jogador — o app garante que nenhuma seja igual! Depois use o sorteador aqui embaixo: os números saem e ficam marcados no histórico.

🎲 Sorteio
?
Números Sorteados

Coleções

📚 Escolha o Álbum
Álbum: Pinturas Famosas
Progresso
0/0
    Um pacote misterioso te espera.
    💡

    Escolha um álbum e toque em Obter Figura — uma obra surpresa será impressa e desbloqueada no seu progresso. Complete todos os itens do álbum para zerar a coleção!

    Foto Cabine

    Faça uma pose diferente a cada flash!

    💡

    Toque em Iniciar Sessão e prepare-se! O app tira 4 fotos automáticas com contagem regressiva de 3 segundos cada. Ao final, monta uma tira vintage pronta para imprimir!

    Mandala

    🌸 Configurar Mandala
    Complexidade 4
    Pétalas 8
    💡

    Use os controles para ajustar a complexidade (número de camadas) e a quantidade de pétalas. Clique em Nova Mandala para gerar um design diferente — cada uma é única e perfeita para colorir!

    Sudoku

    🧩 Gerar Novo Jogo
    Fácil
    Médio
    Difícil
    Pronto para gerar.
    💡

    Escolha o nível de dificuldade: Fácil deixa mais números visíveis, Médio é o equilíbrio perfeito e Difícil é para os mestres! Cada impressão gera um tabuleiro completamente novo.

    Caça Palavras

    🔍 Configurar Jogo
    Tema: Animais
    Normal (12x12)
    Grande (15x15)
    Pronto para gerar o desafio.
    💡

    Escolha o tema e o tamanho da grade. As palavras ficam escondidas na horizontal, vertical e diagonal — a lista para encontrar vem impressa no rodapé. Tente no tamanho 15×15 para um desafio maior!

    Gerador de QR Code

    🔗 Criar Código

    Link ou texto:

    Texto abaixo do QR (opcional):

    Fonte:

    Aa Padrão
    Aa Serifa
    Aa Código
    Aa Cursiva

    Formatação:

    N
    I
    Tamanho: M

    Alinhamento:

    Pré-visualização:

    💡

    A pré-visualização mostra exatamente como será impresso. Ajuste a fonte, formatação e alinhamento ao vivo!

    Horóscopo Sincero

    🔮
    Conselho Cósmico

    Informe seu nascimento para alinhar as humilhações:

    Dia
    Mês
    Ano
    💡

    Informe sua data de nascimento e toque em Imprimir Verdade. Segure o dedo no cristal durante o ritual cósmico até o destino ser traçado.

    Toque e segure
    Para ler sua energia...
    👆
    🖨️
    Preparando sua surpresa...
    Aguarde a impressão terminar!
    `; tela.appendChild(adBox); } }); } injetarEspacosDeAnuncio(); // ========================================== // LÓGICA DO QR CODE // ========================================== let qrFonteSelecionada = 'sans-serif'; let qrNegrito = false; let qrItalico = false; let qrTamanhoIdx = 1; let qrAlinhamento = 'center'; let qrCanvasCache = null; const qrTamanhos = [ { label: 'Tamanho: P', px: 30 }, { label: 'Tamanho: M', px: 36 }, { label: 'Tamanho: G', px: 42 } ]; function selecionarFonteQR(el, fonte) { qrFonteSelecionada = fonte; document.querySelectorAll('.qr-font-btn').forEach(b => { b.style.background = '#fff'; b.style.borderColor = '#e0e5ec'; b.style.color = 'var(--text-muted)'; }); el.style.background = 'var(--icon-blue)'; el.style.borderColor = 'var(--icon-blue-text)'; el.style.color = 'var(--icon-blue-text)'; atualizarPreviewQR(); } function toggleFormatQR(tipo) { if (tipo === 'bold') { qrNegrito = !qrNegrito; const btn = document.getElementById('btnQRBold'); btn.style.background = qrNegrito ? 'var(--icon-blue)' : '#fff'; btn.style.borderColor = qrNegrito ? 'var(--icon-blue-text)' : '#e0e5ec'; btn.style.color = qrNegrito ? 'var(--icon-blue-text)' : 'var(--text-muted)'; } else { qrItalico = !qrItalico; const btn = document.getElementById('btnQRItalic'); btn.style.background = qrItalico ? 'var(--icon-blue)' : '#fff'; btn.style.borderColor = qrItalico ? 'var(--icon-blue-text)' : '#e0e5ec'; btn.style.color = qrItalico ? 'var(--icon-blue-text)' : 'var(--text-muted)'; } atualizarPreviewQR(); } function toggleTamanhoQR() { qrTamanhoIdx = (qrTamanhoIdx + 1) % 3; const btn = document.getElementById('btnQRSize'); btn.textContent = qrTamanhos[qrTamanhoIdx].label; btn.style.background = qrTamanhoIdx > 0 ? 'var(--icon-blue)' : '#fff'; btn.style.borderColor = qrTamanhoIdx > 0 ? 'var(--icon-blue-text)' : '#e0e5ec'; btn.style.color = qrTamanhoIdx > 0 ? 'var(--icon-blue-text)' : 'var(--text-muted)'; atualizarPreviewQR(); } function selecionarAlinhamento(align) { qrAlinhamento = align; ['Left', 'Center', 'Right'].forEach(a => { const btn = document.getElementById('btnAlign' + a); const ativo = a.toLowerCase() === align; btn.style.background = ativo ? 'var(--icon-blue)' : '#fff'; btn.style.borderColor = ativo ? 'var(--icon-blue-text)' : '#e0e5ec'; btn.style.color = ativo ? 'var(--icon-blue-text)' : 'var(--text-muted)'; }); atualizarPreviewQR(); } async function gerarCanvasQR() { const texto = document.getElementById('qrInput').value || "https://printplay.app"; const textoExtra = document.getElementById('qrTextoExtra').value.trim(); const W = 384; const fontSize = qrTamanhos[qrTamanhoIdx].px; const temTexto = textoExtra.length > 0; const qrTemp = document.createElement('div'); qrTemp.style.cssText = 'position:absolute;left:-9999px;top:-9999px;'; document.body.appendChild(qrTemp); new QRCode(qrTemp, { text: texto, width: 300, height: 300, colorDark: "#000000", colorLight: "#ffffff", correctLevel: QRCode.CorrectLevel.H }); await new Promise(resolve => { const img = qrTemp.querySelector('img'); if (!img || img.complete) { resolve(); return; } img.onload = resolve; img.onerror = resolve; setTimeout(resolve, 800); }); // Calcula linhas do texto extra const tempCanvas = document.createElement('canvas'); tempCanvas.width = W; const tempCtx = tempCanvas.getContext('2d'); const estiloFonte = `${qrItalico ? 'italic ' : ''}${qrNegrito ? 'bold ' : ''}${fontSize}px ${qrFonteSelecionada}`; tempCtx.font = estiloFonte; let linhas = []; if (temTexto) { const maxWidth = W - 60; const palavras = textoExtra.split(' '); let linhaAtual = ''; for (const p of palavras) { const teste = linhaAtual ? linhaAtual + ' ' + p : p; if (tempCtx.measureText(teste).width > maxWidth && linhaAtual) { linhas.push(linhaAtual); linhaAtual = p; } else { linhaAtual = teste; } } if (linhaAtual) linhas.push(linhaAtual); } const alturaTexto = linhas.length > 0 ? linhas.length * (fontSize + 10) + 30 : 0; const H = 440 + alturaTexto; const canvas = document.createElement('canvas'); canvas.width = W; canvas.height = H; const ctx = canvas.getContext('2d'); ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, W, H); // Desenha QR const fonte = qrTemp.querySelector('canvas') || qrTemp.querySelector('img'); const qrSize = 300; const offsetX = (W - qrSize) / 2; ctx.drawImage(fonte, offsetX, 30, qrSize, qrSize); document.body.removeChild(qrTemp); // Linha separadora ctx.strokeStyle = '#000000'; ctx.lineWidth = 1; ctx.setLineDash([4, 4]); ctx.beginPath(); ctx.moveTo(40, 348); ctx.lineTo(W - 40, 348); ctx.stroke(); ctx.setLineDash([]); // Rodapé fixo ctx.fillStyle = '#000000'; ctx.textAlign = 'center'; ctx.font = '13px sans-serif'; ctx.fillText('Gerado por PrintPlay', W / 2, 370); // Texto extra if (linhas.length > 0) { ctx.font = estiloFonte; ctx.fillStyle = '#000000'; let xPos; if (qrAlinhamento === 'left') { ctx.textAlign = 'left'; xPos = 30; } else if (qrAlinhamento === 'right') { ctx.textAlign = 'right'; xPos = W - 30; } else { ctx.textAlign = 'center'; xPos = W / 2; } linhas.forEach((linha, i) => { ctx.fillText(linha, xPos, 405 + i * (fontSize + 10)); }); } // Floyd-Steinberg dithering const imgData = ctx.getImageData(0, 0, W, H); const d = imgData.data; const grayBuf = new Float32Array(W * H); for (let i = 0; i < W * H; i++) { grayBuf[i] = 0.299 * d[i*4] + 0.587 * d[i*4+1] + 0.114 * d[i*4+2]; } for (let y = 0; y < H; y++) { for (let x = 0; x < W; x++) { const idx = y * W + x; const old = grayBuf[idx]; const nov = old > 128 ? 255 : 0; const err = old - nov; grayBuf[idx] = nov; if (x + 1 < W) grayBuf[idx + 1] += err * 7/16; if (y + 1 < H) { if (x > 0) grayBuf[idx + W - 1] += err * 3/16; grayBuf[idx + W] += err * 5/16; if (x + 1 < W) grayBuf[idx + W + 1] += err * 1/16; } } } for (let i = 0; i < W * H; i++) { const v = grayBuf[i] > 128 ? 255 : 0; d[i*4] = d[i*4+1] = d[i*4+2] = v; d[i*4+3] = 255; } ctx.putImageData(imgData, 0, 0); return canvas; } async function atualizarPreviewQR() { const previewCanvas = document.getElementById('qrPreviewCanvas'); if (!previewCanvas) return; const canvas = await gerarCanvasQR(); qrCanvasCache = canvas; previewCanvas.width = canvas.width; previewCanvas.height = canvas.height; previewCanvas.getContext('2d').drawImage(canvas, 0, 0); } async function imprimirQRCode() { if (!btCharWrite) { await iniciarConexao(); if (!btCharWrite) return; fecharConnectPopup(); } const statusEl = document.getElementById('printStatusQR'); statusEl.textContent = 'Preparando...'; const canvas = qrCanvasCache || await gerarCanvasQR(); const { width, height, data: px } = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height); const BPR = width / 8; const delay = ms => new Promise(r => setTimeout(r, ms)); try { statusEl.textContent = 'Imprimindo...'; await printerInit(btCharWrite.writeValueWithoutResponse.bind(btCharWrite), delay); for (let y = 0; y < height; y++) { const row = new Uint8Array(BPR); for (let x = 0; x < width; x++) { if (px[(y * width + x) * 4] < 128) row[Math.floor(x / 8)] |= (1 << (x % 8)); } await btCharWrite.writeValueWithoutResponse(pkt(0xA2, row)); await delay(15); } await printerFoot(btCharWrite.writeValueWithoutResponse.bind(btCharWrite), delay); statusEl.textContent = '✅ QR Code impresso!'; } catch(e) { statusEl.textContent = '❌ Erro: ' + e.message; } } // Gera preview ao entrar na tela window.addEventListener('load', () => { if (document.getElementById('qrPreviewCanvas')) atualizarPreviewQR(); });