fix: Use base64-encoded PNG for QR code in PDF stickers
DomPDF renders embedded PNG images more reliably than inline SVG. Changed QR code generation to OUTPUT_IMAGE_PNG with base64 encoding, then embed as img tag in the PDF HTML.
This commit is contained in:
@@ -85,16 +85,16 @@ class QrStickerService
|
|||||||
*/
|
*/
|
||||||
private function generatePdf(Order $order, string $qrUrl): string
|
private function generatePdf(Order $order, string $qrUrl): string
|
||||||
{
|
{
|
||||||
// Generate inline QR code as SVG
|
// Generate QR code as base64-encoded PNG (DomPDF handles this better than SVG)
|
||||||
$options = new QROptions([
|
$options = new QROptions([
|
||||||
'outputType' => QRCode::OUTPUT_MARKUP_SVG,
|
'outputType' => QRCode::OUTPUT_IMAGE_PNG,
|
||||||
'eccLevel' => QRCode::ECC_H,
|
'eccLevel' => QRCode::ECC_H,
|
||||||
'scale' => 4,
|
'scale' => 8,
|
||||||
'imageBase64' => false,
|
'imageBase64' => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$qrCode = new QRCode($options);
|
$qrCode = new QRCode($options);
|
||||||
$qrSvg = $qrCode->render($qrUrl);
|
$qrBase64 = $qrCode->render($qrUrl);
|
||||||
|
|
||||||
// Determine order type
|
// Determine order type
|
||||||
$orderType = $order->type === 'standard' ? 'STOCK ORDER' : 'CUSTOM ORDER';
|
$orderType = $order->type === 'standard' ? 'STOCK ORDER' : 'CUSTOM ORDER';
|
||||||
@@ -111,15 +111,14 @@ class QrStickerService
|
|||||||
$nameParts = explode(' ', trim($customerName));
|
$nameParts = explode(' ', trim($customerName));
|
||||||
$customerSurname = end($nameParts);
|
$customerSurname = end($nameParts);
|
||||||
|
|
||||||
// Build HTML directly (no view file dependency)
|
// Build HTML with proper SVG embedding (avoid heredoc issues)
|
||||||
$html = <<<HTML
|
$html = '<!DOCTYPE html>
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
body { font-family: Arial, sans-serif; }
|
body { font-family: Arial, sans-serif; margin: 0; padding: 0; }
|
||||||
.sticker {
|
.sticker {
|
||||||
width: 148mm;
|
width: 148mm;
|
||||||
height: 105mm;
|
height: 105mm;
|
||||||
@@ -127,6 +126,7 @@ class QrStickerService
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 5mm;
|
padding: 5mm;
|
||||||
background: white;
|
background: white;
|
||||||
|
page-break-after: avoid;
|
||||||
}
|
}
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -141,10 +141,11 @@ class QrStickerService
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.qr-section {
|
.qr-section {
|
||||||
width: 55mm;
|
width: 50mm;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
border-bottom: 1pt solid #ddd;
|
border-bottom: 1pt solid #ddd;
|
||||||
@@ -207,12 +208,8 @@ class QrStickerService
|
|||||||
.qr-code {
|
.qr-code {
|
||||||
width: 50mm;
|
width: 50mm;
|
||||||
height: 50mm;
|
height: 50mm;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: white;
|
|
||||||
}
|
}
|
||||||
.qr-code svg {
|
.qr-code img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
@@ -222,7 +219,6 @@ class QrStickerService
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
border-top: 0.5pt solid #eee;
|
border-top: 0.5pt solid #eee;
|
||||||
padding-top: 1mm;
|
padding-top: 1mm;
|
||||||
margin-top: auto;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@@ -231,49 +227,47 @@ class QrStickerService
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="info-section">
|
<div class="info-section">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span class="order-type">{$orderType}</span>
|
<span class="order-type">' . htmlspecialchars($orderType) . '</span>
|
||||||
<div class="order-number">{$order->order_number}</div>
|
<div class="order-number">' . htmlspecialchars($order->order_number) . '</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="customer-info">
|
<div class="customer-info">
|
||||||
<div class="label">Customer</div>
|
<div class="label">Customer</div>
|
||||||
<div class="name">{$customerSurname}</div>
|
<div class="name">' . htmlspecialchars($customerSurname) . '</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
<div class="detail-row">
|
<div class="detail-row">
|
||||||
<span class="detail-label">Design:</span>
|
<span class="detail-label">Design:</span>
|
||||||
<span class="detail-value" style="font-size: 6.5pt;">
|
<span class="detail-value" style="font-size: 6.5pt;">' . htmlspecialchars($this->truncate($designName, 12)) . '</span>
|
||||||
{$this->truncate($designName, 12)}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-row">
|
<div class="detail-row">
|
||||||
<span class="detail-label">Date:</span>
|
<span class="detail-label">Date:</span>
|
||||||
<span class="detail-value">{$order->created_at->format('M d')}</span>
|
<span class="detail-value">' . htmlspecialchars($order->created_at->format('M d')) . '</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-row">
|
<div class="detail-row">
|
||||||
<span class="detail-label">Status:</span>
|
<span class="detail-label">Status:</span>
|
||||||
<span class="detail-value" style="text-transform: capitalize;">
|
<span class="detail-value">' . htmlspecialchars($this->formatStatus($order->status)) . '</span>
|
||||||
{$this->formatStatus($order->status)}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
Gen: {$order->created_at->format('Y-m-d H:i')}
|
Gen: ' . htmlspecialchars($order->created_at->format('Y-m-d H:i')) . '
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="qr-section">
|
<div class="qr-section">
|
||||||
<div class="qr-code">
|
<div class="qr-code">
|
||||||
{$qrSvg}
|
<img src="' . $qrBase64 . '" alt="QR Code" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>';
|
||||||
HTML;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$pdf = Pdf::loadHTML($html);
|
$pdf = Pdf::loadHTML($html);
|
||||||
$pdf->setPaper([0, 0, 420.94, 297.64], 'portrait');
|
// Set to A6 size (105mm × 148mm) in portrait orientation
|
||||||
|
// 105mm = 297.64 points, 148mm = 420.94 points
|
||||||
|
$pdf->setPaper([0, 0, 297.64, 420.94], 'portrait');
|
||||||
|
$pdf->setOption('isRemoteEnabled', true);
|
||||||
|
|
||||||
$filename = "{$order->uuid}.pdf";
|
$filename = "{$order->uuid}.pdf";
|
||||||
$path = "qr-stickers/{$filename}";
|
$path = "qr-stickers/{$filename}";
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<?php $__env->startSection('content'); ?>
|
||||||
|
<div class="container mx-auto px-4 py-8">
|
||||||
|
<h1 class="text-3xl font-bold mb-6">QR Sticker Preview</h1>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
<!-- Order Info -->
|
||||||
|
<div class="md:col-span-1 bg-white rounded-lg shadow-md p-6">
|
||||||
|
<h2 class="text-xl font-semibold mb-4">Order Details</h2>
|
||||||
|
|
||||||
|
<div class="space-y-3 text-sm">
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-600">Order Number</p>
|
||||||
|
<p class="font-semibold"><?php echo e($order->order_number); ?></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-600">UUID</p>
|
||||||
|
<p class="font-mono text-xs"><?php echo e($order->uuid); ?></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-600">Status</p>
|
||||||
|
<p class="font-semibold capitalize"><?php echo e(str_replace('_', ' ', $order->status)); ?></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-600">Customer</p>
|
||||||
|
<p class="font-semibold"><?php echo e($order->user?->name ?? 'N/A'); ?></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-600">Created</p>
|
||||||
|
<p class="font-semibold"><?php echo e($order->created_at->format('M d, Y H:i')); ?></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if(\Livewire\Mechanisms\ExtendBlade\ExtendBlade::isRenderingLivewireComponent()): ?><!--[if BLOCK]><![endif]--><?php endif; ?><?php if($order->items->count() > 0): ?>
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-600">Design</p>
|
||||||
|
<p class="font-semibold text-sm"><?php echo e($order->items->first()?->product?->name ?? 'Custom'); ?></p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?><?php if(\Livewire\Mechanisms\ExtendBlade\ExtendBlade::isRenderingLivewireComponent()): ?><!--[if ENDBLOCK]><![endif]--><?php endif; ?>
|
||||||
|
|
||||||
|
<div class="pt-4 border-t">
|
||||||
|
<p class="text-gray-600 text-xs">Sticker Path</p>
|
||||||
|
<p class="font-mono text-xs break-all"><?php echo e($stickerPath); ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Download Link -->
|
||||||
|
<a href="<?php echo e(route('ops.order.sticker.download', $order)); ?>" class="mt-6 inline-block w-full text-center bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
|
||||||
|
📥 Download PDF
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PDF Preview -->
|
||||||
|
<div class="md:col-span-2 bg-white rounded-lg shadow-md p-6">
|
||||||
|
<h2 class="text-xl font-semibold mb-4">PDF Preview (A6 Sticker)</h2>
|
||||||
|
|
||||||
|
<div class="bg-gray-100 rounded border-2 border-gray-300 p-4" style="min-height: 400px;">
|
||||||
|
<iframe
|
||||||
|
src="<?php echo e($pdfUrl); ?>"
|
||||||
|
class="w-full h-full border-0"
|
||||||
|
style="min-height: 500px;"
|
||||||
|
title="Sticker PDF">
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-xs text-gray-500 mt-4">
|
||||||
|
If the PDF doesn't display above, it may be loading. Try refreshing or downloading the PDF directly.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Back Link -->
|
||||||
|
<div class="mt-8">
|
||||||
|
<a href="/" class="text-blue-600 hover:text-blue-800">← Back to Home</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php $__env->stopSection(); ?>
|
||||||
|
|
||||||
|
<?php echo $__env->make('layouts.app', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?><?php /**PATH /var/www/additional_design/resources/views/test/sticker-display.blade.php ENDPATH**/ ?>
|
||||||
Reference in New Issue
Block a user