Skip to main content

QR

Dependencias necesarias (Servidor correos)

import qrcode #qr-code
from PIL import Image #PILLOW
import io
import base64

Función para generar QR en Python

def generar_qr_base64(data):
# Generar la imagen QR
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=4,
)
qr.add_data(data)
qr.make(fit=True)

img = qr.make_image(fill='black', back_color='white')

# Guardar la imagen en un buffer y convertirla a base64
buffer = io.BytesIO()
img.save(buffer, format='PNG')
qr_image_base64 = base64.b64encode(buffer.getvalue()).decode()

return qr_image_base64

Añadir QR en el correo electrónico

Añadir después de mensaje_email["To"] = destinatario
No te olvides de pasar el código para generar el qr

qr_base64 = generar_qr_base64("prueba qr") # Pasar aqui el codigo para convertirlo imagen qr
# Incrustar el QR como una imagen inline
img_data = base64.b64decode(qr_base64)
image = MIMEImage(img_data, name="qr_code.png")
image.add_header('Content-ID', '<qr_code>') # Usar un ID único para referenciar en el HTML
mensaje_email.attach(image)

EndPoint para lectura del QR

@app.route('/read_qr')
def read_qr():
return render_template('read_qr.html')
read_qr.html
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Escanear QR con Flask</title>
</head>
<body>
<h1>Escanea un Código QR</h1>
<video id="video" autoplay playsinline></video>
<canvas id="canvas" hidden></canvas>
<p id="qrResult">Esperando QR...</p>

<script src="/static/jsQR.js"></script>
<script src="/static/script.js"></script>
</body>
</html>

Scripts para el funcionamiento de la cámara (Javascript)

Crear en el directorio static del proyecto.

const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const qrResult = document.getElementById('qrResult');

// Función para escanear el QR
function scanQR() {
if (video.readyState === video.HAVE_ENOUGH_DATA) {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
context.drawImage(video, 0, 0, canvas.width, canvas.height);

const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
const qrCode = jsQR(imageData.data, imageData.width, imageData.height);

if (qrCode) {
qrResult.textContent = `QR Detectado: ${qrCode.data}`;
sendQRData(qrCode.data);
} else {
qrResult.textContent = "Buscando QR...";
requestAnimationFrame(scanQR);
}
} else {
requestAnimationFrame(scanQR);
}
}

// Función para enviar los datos del QR al servidor
function sendQRData(qrData) {
fetch('/qr-data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ qr_data: qrData })
})
.then(response => response.json())
.then(data => {
if (data.content === "qr_ok") {
window.location.href = '/qr_ok';
} else {
window.location.href = '/qr_fail';
}
})
.catch(err => {
console.error("Error enviando QR:", err);
});
}

// Función para iniciar la cámara
function startCamera() {
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
console.error("getUserMedia no es compatible con este navegador.");
qrResult.textContent = "Tu navegador no soporta acceso a la cámara.";
return;
}

navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } })
.then(stream => {
video.srcObject = stream;
video.setAttribute("playsinline", true); // Para iOS
video.play();
requestAnimationFrame(scanQR);
})
.catch(err => {
console.error("Error al acceder a la cámara:", err.message);
qrResult.textContent = `Error: ${err.message}. Verifica permisos.`;
});
}

// Iniciar la cámara al cargar la página
startCamera();

En el mismo directorio static, crear el archivo jsQR.js y pega el contenido de este archivo: https://github.com/cozmo/jsQR/blob/master/dist/jsQR.js También puedes descargar y poner el archivo en la ruta de proyecto.

Rutas para el manejo del QR

@app.route('/qr_ok')
def qr_ok():
return render_template('qr_ok.html')

@app.route('/qr_fail')
def qr_fail():
return render_template('qr_fail.html')


@app.route('/qr-data', methods=['POST'])
def qr_data():
if request.is_json:
qr_content = request.json.get('qr_data')
print("Contenido del QR:", qr_content)

# Responder con JSON indicando éxito y redirigir en el cliente
return jsonify({"message": "QR recibido", "content": "qr_fail"})

else:
return jsonify({"error": "No se recibió JSON válido"}), 400

Generar certificado autofirmado

Abrir la consola de Pycharm y ejecutar el siguiente comando en la ruta por defecto que te abra:

openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365

Es importante poner en commonName la IP de tu equipo.

Especificar los certificados al iniciar:

app.run(ssl_context=('cert.pem', 'key.pem'), host='0.0.0.0', port=5000, debug=True)
OJO

Al ejecutar el servidor web con este certificado, la página web del cliente en Java Swing DEJA DE FUNCIONAR (hasta que lo lancemos a producción)
Formas de solucionar esto:

  1. Ejecutar app.run(host='0.0.0.0', port=5000, debug=True) para poder ver la página, y con certificados app.run(ssl_context=('cert.pem', 'key.pem'), host='0.0.0.0', port=5000, debug=True) si queremos ejecutar la camara. Es decir, parar el servidor, comentar una línea y descomentar otra.
  2. Crear un propio servidor de camara web. Crea un nuevo proyecto y especifíca un nuevo puerto. Recuerda especificar ese nuevo puerto al llamar al endpoint, además del protocolo https.
    Por ejemplo, si tu servidor de camara web está en el 5003: https://tuip:5003/read_qr