From ee9bb7b560ac9ce5dd87b32257025a473e896107 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Sat, 1 Aug 2026 03:57:43 +0530 Subject: [PATCH] Fix ABHA card barcode print rendering --- app/Controllers/Abha.php | 85 ++++++++++++++++++++++++++++++++++++---- app/Views/abha/card.php | 68 ++++++++++++-------------------- 2 files changed, 102 insertions(+), 51 deletions(-) diff --git a/app/Controllers/Abha.php b/app/Controllers/Abha.php index 618ba3a..6ec9911 100644 --- a/app/Controllers/Abha.php +++ b/app/Controllers/Abha.php @@ -454,6 +454,7 @@ class Abha extends BaseController $mobileVerified = (int) ($patient['abha_mobile_verified'] ?? 0) === 1; $abhaQrUrl = 'https://api.qrserver.com/v1/create-qr-code/?size=180x180&data=' . urlencode($abhaNumClean); $barcodeSvg = $this->buildCode39Svg($hmsId); + $barcodeImage = $this->buildCode39ImageDataUri($hmsId, $barcodeSvg); return view('abha/card', [ 'patient' => $patient, @@ -468,6 +469,7 @@ class Abha extends BaseController 'brand_name' => (string) ($hospitalBrand['brand_name'] ?? 'HMS'), 'hms_id' => $hmsId, 'hms_barcode_svg' => $barcodeSvg, + 'hms_barcode_image' => $barcodeImage, 'profile_photo_url' => $profilePhotoUrl, 'abha_qr_url' => $abhaQrUrl, 'patient_mobile' => $mobileNo, @@ -591,10 +593,76 @@ class Abha extends BaseController } private function buildCode39Svg(string $value): string + { + $layout = $this->buildCode39Layout($value); + if ($layout === null) { + return ''; + } + + $rects = []; + foreach ($layout['bars'] as $bar) { + $rects[] = ''; + } + + return '' + . implode('', $rects) + . ''; + } + + private function buildCode39ImageDataUri(string $value, string $svgFallback = ''): string + { + $layout = $this->buildCode39Layout($value); + if ($layout === null) { + return ''; + } + + if (! function_exists('imagecreatetruecolor') || ! function_exists('imagepng')) { + $svg = $svgFallback !== '' ? $svgFallback : $this->buildCode39Svg($value); + return $svg !== '' ? 'data:image/svg+xml;base64,' . base64_encode($svg) : ''; + } + + $img = imagecreatetruecolor($layout['width'], $layout['height']); + if ($img === false) { + $svg = $svgFallback !== '' ? $svgFallback : $this->buildCode39Svg($value); + return $svg !== '' ? 'data:image/svg+xml;base64,' . base64_encode($svg) : ''; + } + + $white = imagecolorallocate($img, 255, 255, 255); + $black = imagecolorallocate($img, 17, 17, 17); + imagefilledrectangle($img, 0, 0, $layout['width'], $layout['height'], $white); + + foreach ($layout['bars'] as $bar) { + imagefilledrectangle( + $img, + $bar['x'], + 0, + $bar['x'] + $bar['w'] - 1, + $layout['height'], + $black + ); + } + + ob_start(); + imagepng($img); + $pngBinary = ob_get_clean(); + imagedestroy($img); + + if (! is_string($pngBinary) || $pngBinary === '') { + $svg = $svgFallback !== '' ? $svgFallback : $this->buildCode39Svg($value); + return $svg !== '' ? 'data:image/svg+xml;base64,' . base64_encode($svg) : ''; + } + + return 'data:image/png;base64,' . base64_encode($pngBinary); + } + + /** + * @return array{bars: list, width:int, height:int}|null + */ + private function buildCode39Layout(string $value): ?array { $normalized = strtoupper(trim($value)); if ($normalized === '') { - return ''; + return null; } $supported = [ @@ -623,7 +691,7 @@ class Abha extends BaseController } if ($clean === '') { - return ''; + return null; } $narrow = 2; @@ -633,14 +701,14 @@ class Abha extends BaseController $gap = 2; $x = $quiet; - $rects = []; + $bars = []; $cleanLen = strlen($clean); for ($i = 0; $i < $cleanLen; $i++) { $pattern = $supported[$clean[$i]]; for ($j = 0; $j < 9; $j++) { $w = ($pattern[$j] === 'w') ? $wide : $narrow; if ($j % 2 === 0) { - $rects[] = ''; + $bars[] = ['x' => $x, 'w' => $w]; } $x += $w; } @@ -649,10 +717,11 @@ class Abha extends BaseController } } - $width = $x + $quiet; - return '' - . implode('', $rects) - . ''; + return [ + 'bars' => $bars, + 'width' => $x + $quiet, + 'height' => $height, + ]; } /** diff --git a/app/Views/abha/card.php b/app/Views/abha/card.php index 3ff8295..ce7b7fc 100644 --- a/app/Views/abha/card.php +++ b/app/Views/abha/card.php @@ -44,21 +44,20 @@ display: flex; align-items: center; gap: 10px; - padding: 6px 10px; - border: 1px solid #d5e4f7; - border-radius: 10px; - background: #f7fbff; + padding: 0; + border: none; + border-radius: 0; + background: transparent; min-width: 0; } - .brand-wrap.right { background: #ffffff; } .brand-wrap.left { justify-content: flex-start; } .brand-logo { width: 48px; height: 48px; object-fit: contain; border-radius: 8px; - background: #fff; - border: 1px solid #d7e5f8; + background: transparent; + border: none; flex: 0 0 auto; } .brand-text { min-width: 0; line-height: 1.05; } @@ -76,40 +75,25 @@ margin-bottom: 12px; display: flex; align-items: center; - justify-content: space-between; + justify-content: center; gap: 8px; } - .hospital-info { - display: flex; - align-items: center; - gap: 8px; - min-width: 0; - } - .hospital-mini-logo { - width: 32px; - height: 32px; - object-fit: contain; - border-radius: 6px; - border: 1px solid #cfe0f8; - background: #fff; - flex: 0 0 auto; - } - .hospital-name { - font-size: 13px; - color: #1e4a82; - min-width: 0; - } - .hospital-name strong { color: #0f3f7d; } .patient-id-strip { - width: 180px; + width: 100%; background: #fff; border: 1px solid #d4e3f8; border-radius: 8px; - padding: 4px 6px; + padding: 6px 8px; text-align: center; - flex: 0 0 auto; + flex: 1 1 auto; + min-width: 0; + } + .patient-id-barcode { + display: block; + width: 100%; + height: 28px; + object-fit: contain; } - .patient-id-strip svg { width: 100%; height: 28px; } .patient-id-label { font-size: 9px; color: #5f7291; @@ -254,7 +238,7 @@ $profilePhotoUrl = (string) ($profile_photo_url ?? '/assets/images/no_image.svg' $profilePhotoUrlEsc = esc($profilePhotoUrl); $hmsId = esc($hms_id ?? ''); $abhaQrUrl = esc($abha_qr_url ?? ''); -$barcodeSvg = (string) ($hms_barcode_svg ?? ''); +$barcodeImage = esc($hms_barcode_image ?? ''); $patientMobile = esc($patient_mobile ?? ''); $mobileVerified = (bool) ($mobile_verified ?? false); ?> @@ -279,19 +263,17 @@ $mobileVerified = (bool) ($mobile_verified ?? false); -
-
- -
Hospital:
-
- + +
Patient ID Barcode
-
+ + Patient ID Barcode +
- -
+
+