Skip to content

Añade soporte para la generación y renderización de códigos QR en PDFs#1769

Merged
NeoRazorX merged 1 commit intoNeoRazorX:masterfrom
daniel89fg:pdf-qr
Aug 1, 2025
Merged

Añade soporte para la generación y renderización de códigos QR en PDFs#1769
NeoRazorX merged 1 commit intoNeoRazorX:masterfrom
daniel89fg:pdf-qr

Conversation

@daniel89fg
Copy link
Copy Markdown
Contributor

Necesitamos una opción para añadir imágenes fijas de QRs fijas en los pdf.

¿Cómo has probado los cambios?

Toda modificación debe haber sido mínimamente probada. Marca o describe las pruebas que has realizado:

  • He revisado mi código antes de enviarlo.
  • He probado que funciona correctamente en mi PC.
  • He probado que funciona correctamente con una base de datos vacía.
  • He ejecutado los tests unitarios.

Copilot AI review requested due to automatic review settings July 30, 2025 09:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for generating and rendering QR codes in PDF documents. The changes allow for QR images to be displayed in both the header and after document lines, with proper positioning and layout management.

  • Adds QR code rendering functionality with support for base64 and file path images
  • Implements a flexible layout system that adjusts header space allocation based on QR presence (80%/20% split when QR exists)
  • Includes text wrapping capabilities for QR titles with automatic line breaking
Comments suppressed due to low confidence (1)

Core/Lib/PDF/PDFDocument.php:734

  • The str_starts_with() function was introduced in PHP 8.0. If this project needs to support PHP versions prior to 8.0, use substr($qrImage, 0, 11) === 'data:image/' instead.
        if (str_starts_with($qrImage, 'data:image/')) {

try {
// Usar la función nativa de Cezpdf para añadir la imagen con dimensiones cuadradas
if ($mimeType === 'image/png') {
$this->pdf->addPngFromFile($tempFile, $qrX, $qrY - $qrSize, $qrSize, $qrSize);
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The catch block silently returns without any error logging or user feedback when image addition fails. Consider adding error logging or a fallback mechanism to inform users when QR code rendering fails.

Copilot uses AI. Check for mistakes.
Comment on lines +817 to +888
$words = explode(' ', $qrTitle);
$lines = [];
$currentLine = '';

// Si no hay espacios en el texto (es una sola "palabra"), dividir por caracteres
if (count($words) === 1) {
$text = $qrTitle;
$currentLine = '';

for ($i = 0; $i < strlen($text); $i++) {
$char = $text[$i];
$testLine = $currentLine . $char;
$testWidth = $this->pdf->getTextWidth(self::FONT_SIZE, $testLine);

if ($testWidth <= $availableTextWidth) {
$currentLine = $testLine;
} else {
if (!empty($currentLine)) {
$lines[] = $currentLine;
$currentLine = $char;
} else {
// Si un solo carácter no cabe, lo añadimos anyway
$lines[] = $char;
}
}
}

// Añadir la última línea si no está vacía
if (!empty($currentLine)) {
$lines[] = $currentLine;
}
} else {
// Hay espacios, dividir por palabras como antes
foreach ($words as $word) {
$testLine = empty($currentLine) ? $word : $currentLine . ' ' . $word;
$testWidth = $this->pdf->getTextWidth(self::FONT_SIZE, $testLine);

if ($testWidth <= $availableTextWidth) {
$currentLine = $testLine;
} else {
if (!empty($currentLine)) {
$lines[] = $currentLine;
$currentLine = $word;
} else {
// La palabra sola es demasiado larga, dividir por caracteres
$currentLine = '';
for ($i = 0; $i < strlen($word); $i++) {
$char = $word[$i];
$testLine = $currentLine . $char;
$testWidth = $this->pdf->getTextWidth(self::FONT_SIZE, $testLine);

if ($testWidth <= $availableTextWidth) {
$currentLine = $testLine;
} else {
if (!empty($currentLine)) {
$lines[] = $currentLine;
$currentLine = $char;
} else {
$lines[] = $char;
}
}
}
}
}
}

// Añadir la última línea si no está vacía
if (!empty($currentLine)) {
$lines[] = $currentLine;
}
}

Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The text wrapping logic in renderQRtitle() is overly complex with nested conditions and duplicated character-by-character splitting logic. Consider extracting this into a separate method like wrapTextToLines() to improve readability and maintainability.

Suggested change
$words = explode(' ', $qrTitle);
$lines = [];
$currentLine = '';
// Si no hay espacios en el texto (es una sola "palabra"), dividir por caracteres
if (count($words) === 1) {
$text = $qrTitle;
$currentLine = '';
for ($i = 0; $i < strlen($text); $i++) {
$char = $text[$i];
$testLine = $currentLine . $char;
$testWidth = $this->pdf->getTextWidth(self::FONT_SIZE, $testLine);
if ($testWidth <= $availableTextWidth) {
$currentLine = $testLine;
} else {
if (!empty($currentLine)) {
$lines[] = $currentLine;
$currentLine = $char;
} else {
// Si un solo carácter no cabe, lo añadimos anyway
$lines[] = $char;
}
}
}
// Añadir la última línea si no está vacía
if (!empty($currentLine)) {
$lines[] = $currentLine;
}
} else {
// Hay espacios, dividir por palabras como antes
foreach ($words as $word) {
$testLine = empty($currentLine) ? $word : $currentLine . ' ' . $word;
$testWidth = $this->pdf->getTextWidth(self::FONT_SIZE, $testLine);
if ($testWidth <= $availableTextWidth) {
$currentLine = $testLine;
} else {
if (!empty($currentLine)) {
$lines[] = $currentLine;
$currentLine = $word;
} else {
// La palabra sola es demasiado larga, dividir por caracteres
$currentLine = '';
for ($i = 0; $i < strlen($word); $i++) {
$char = $word[$i];
$testLine = $currentLine . $char;
$testWidth = $this->pdf->getTextWidth(self::FONT_SIZE, $testLine);
if ($testWidth <= $availableTextWidth) {
$currentLine = $testLine;
} else {
if (!empty($currentLine)) {
$lines[] = $currentLine;
$currentLine = $char;
} else {
$lines[] = $char;
}
}
}
}
}
}
// Añadir la última línea si no está vacía
if (!empty($currentLine)) {
$lines[] = $currentLine;
}
}
$lines = $this->wrapTextToLines($qrTitle, self::FONT_SIZE, $availableTextWidth);

Copilot uses AI. Check for mistakes.

// Crear archivo temporal
$extension = ($mimeType === 'image/png') ? '.png' : '.jpg';
$tempFile = tempnam(sys_get_temp_dir(), 'qr_') . $extension;
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using tempnam() with a predictable prefix could potentially lead to temporary file conflicts or security issues. Consider using a more unique prefix that includes the process ID or a random component.

Suggested change
$tempFile = tempnam(sys_get_temp_dir(), 'qr_') . $extension;
$tempFile = tempnam(sys_get_temp_dir(), 'qr_' . uniqid()) . $extension;

Copilot uses AI. Check for mistakes.
$imageData = base64_decode($base64Data);

// Verificar si la decodificación fue exitosa
if ($imageData === false) {
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When base64_decode() fails, the method silently returns without any indication of the failure. Consider logging this error or providing feedback about the invalid base64 data.

Suggested change
if ($imageData === false) {
if ($imageData === false) {
error_log('Failed to decode base64 data for QR image. Data: ' . substr($base64Data, 0, 50) . '...');

Copilot uses AI. Check for mistakes.
@NeoRazorX NeoRazorX merged commit e827adc into NeoRazorX:master Aug 1, 2025
17 checks passed
@daniel89fg daniel89fg deleted the pdf-qr branch August 1, 2025 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants