diff --git a/src/Milon/Barcode/DNS1D.php b/src/Milon/Barcode/DNS1D.php
index 603ccba..50b08ca 100644
--- a/src/Milon/Barcode/DNS1D.php
+++ b/src/Milon/Barcode/DNS1D.php
@@ -149,15 +149,18 @@ public function getBarcodeHTML($code, $type, $w = 2, $h = 30, $color = 'black',
$this->ensureStorePath();
$this->setBarcode($code, $type);
$pad = $this->getPadding();
+ $eanLayout = $this->usesEanUpcLayout();
+ $labelMargin = ($showCode && $eanLayout) ? max(10, $w * 6) : 0;
+ $fontSize = is_bool($showCode) ? 12 : (int) $showCode;
$contentWidth = $this->barcode_array['maxw'] * $w;
- $html = '
' . "\n";
+ $html = '
' . "\n";
// print bars
- $x = $pad;
+ $x = $pad + $labelMargin;
foreach ($this->barcode_array['bcode'] as $k => $v) {
$bw = round(($v['w'] * $w), 3);
$bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
- if($showCode)
- $bh -= ($showCode + 12);
+ if($showCode && !$eanLayout)
+ $bh -= ($fontSize + 12);
if ($v['t']) {
$y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3) + $pad;
// draw a vertical bar
@@ -166,7 +169,11 @@ public function getBarcodeHTML($code, $type, $w = 2, $h = 30, $color = 'black',
$x += $bw;
}
if($showCode)
- $html .= '
' . $code . '
';
+ if ($eanLayout) {
+ $html .= $this->buildEanUpcHriHtml($color, $w, $h, $pad, $labelMargin, $contentWidth, $fontSize);
+ } else {
+ $html .= '
' . $code . '
';
+ }
$html .= '
' . "\n";
return $html;
@@ -402,6 +409,64 @@ protected function buildEanUpcHriSvg($color, $w, $h, $pad, $labelMargin, $conten
return $svg;
}
+ /**
+ * Draw retail-style human-readable digits for EAN/UPC (HTML).
+ *
+ * @param string $color
+ * @param float|int $w
+ * @param float|int $h
+ * @param int $pad
+ * @param int $labelMargin
+ * @param float|int $contentWidth
+ * @param int $fontSize
+ * @return string
+ */
+ protected function buildEanUpcHriHtml($color, $w, $h, $pad, $labelMargin, $contentWidth, $fontSize)
+ {
+ if (empty($this->barcode_array['hri']) || !is_array($this->barcode_array['hri'])) {
+ return '';
+ }
+
+ $hri = $this->barcode_array['hri'];
+ $barsLeft = $pad + $labelMargin;
+ $style = 'position:absolute;bottom:' . $pad . 'px;color:' . $color . ';font-size:' . $fontSize . 'px;line-height:1;';
+ $html = '';
+
+ if (isset($hri['left']) && $hri['left'] !== '') {
+ $html .= '
' . $hri['left'] . '
' . "\n";
+ }
+ if (isset($hri['right']) && $hri['right'] !== '') {
+ $html .= '
' . $hri['right'] . '
' . "\n";
+ }
+ if (isset($hri['middle']) && $hri['middle'] !== '') {
+ $html .= '
' . $hri['middle'] . '
' . "\n";
+
+ return $html;
+ }
+
+ $type = isset($this->barcode_array['ean_type']) ? $this->barcode_array['ean_type'] : 'EAN13';
+ if ($type === 'EAN8') {
+ $leftStart = 3;
+ $leftMods = 28;
+ $rightStart = 36;
+ $rightMods = 28;
+ } else {
+ $leftStart = 3;
+ $leftMods = 42;
+ $rightStart = 50;
+ $rightMods = 42;
+ }
+
+ if (isset($hri['middle_left']) && $hri['middle_left'] !== '') {
+ $html .= '
' . $hri['middle_left'] . '
' . "\n";
+ }
+ if (isset($hri['middle_right']) && $hri['middle_right'] !== '') {
+ $html .= '
' . $hri['middle_right'] . '
' . "\n";
+ }
+
+ return $html;
+ }
+
/**
* Return a .png file path which create in server
* @param $code (string) code to print
diff --git a/tests/UpcALayoutAndQrLogoTest.php b/tests/UpcALayoutAndQrLogoTest.php
index 8d2d7f4..15f08f2 100644
--- a/tests/UpcALayoutAndQrLogoTest.php
+++ b/tests/UpcALayoutAndQrLogoTest.php
@@ -44,6 +44,47 @@ public function testEan13HriKeepsFirstDigitSeparate(): void
$this->assertStringContainsString('>123457<', $svg);
}
+ public function testEan13HtmlRetailLayoutKeepsFullHeightAndSplitHri(): void
+ {
+ $dns = new DNS1D();
+ $html = $dns->getBarcodeHTML('5901234123457', 'EAN13', 2, 60, 'black', 14);
+
+ // Digit bars keep 7/11 of the height instead of subtracting showCode a second time.
+ $this->assertStringContainsString('height:38.182px', $html);
+ // Guard bars stay at full height and the root box does not grow.
+ $this->assertStringContainsString('height:60px', $html);
+ // Split human-readable digits, like the SVG/PNG output.
+ $this->assertStringContainsString('>5
', $html);
+ $this->assertStringContainsString('>901234', $html);
+ $this->assertStringContainsString('>123457', $html);
+ }
+
+ public function testEan13HtmlWithoutShowCodeHasNoDigits(): void
+ {
+ $dns = new DNS1D();
+ $html = $dns->getBarcodeHTML('5901234123457', 'EAN13', 2, 55);
+
+ $this->assertStringNotContainsString('text-align:center;color', $html);
+ }
+
+ public function testEan13HtmlShowCodeTrueUsesSvgDefaultFontSize(): void
+ {
+ $dns = new DNS1D();
+ $html = $dns->getBarcodeHTML('5901234123457', 'EAN13', 2, 60, 'black', true);
+
+ $this->assertStringContainsString('font-size:12px', $html);
+ }
+
+ public function testNonEanHtmlStillReservesSpaceForCode(): void
+ {
+ $dns = new DNS1D();
+ $html = $dns->getBarcodeHTML('TEST123', 'C128', 2, 50, 'black', 12);
+
+ // 50 - (12 + 12) = 26px, same as before the retail layout.
+ $this->assertStringContainsString('height:26px', $html);
+ $this->assertStringContainsString('font-size: 12px;">TEST123', $html);
+ }
+
public function testQrLogoIsCompositedInCenter(): void
{
$logoPath = sys_get_temp_dir() . '/milon-barcode-logo-' . uniqid('', true) . '.png';