Merge remote-tracking branch 'origin/develop'

This commit is contained in:
snipe
2025-06-25 15:00:46 +01:00
7 changed files with 716 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
<?php
namespace App\Models\Labels\Tapes\Generic;
abstract class Continuous_53mm extends GenericTape
{
protected const TAPE_WIDTH = 53.0;
// Minimum height for the label
protected float $minHeight = 30.0;
private float $tapeHeight;
/**
* Constructor for 53mm tape
*
* Assumes tape is continuous, set to false and specify
* $spacing in concrete classfor die-cut labels
*
*
* @param float $height Height of the label in mm (default 60mm)
* @param bool $continuous Whether the tape is continuous or pre-cut
* @param float $spacing Spacing between labels for non-continuous tapes (in mm)
*/
public function __construct($height = 60.0, $continuous = true, $spacing = 0.0) {
parent::__construct(self::TAPE_WIDTH, $height, $continuous, $spacing);
$this->tapeHeight = $height;
}
public function getBarcodeRatio() {
return 0.9; // Barcode should use 90% of available width
}
/**
* Calculate the required height for the content
*
* @param $record The record to calculate height for
* @return float The calculated height in mm
*/
protected function calculateRequiredHeight($record) {
$height = $this->marginTop + $this->marginBottom;
// Add title height if present
if ($record->has('title') && $this->getSupportTitle()) {
$height += $this->titleSize + $this->titleMargin;
}
// Add barcode height if present
if (($record->has('barcode2d') && $this->getSupport2DBarcode()) ||
($record->has('barcode') && $this->getSupport1DBarcode())) {
$pa = $this->getPrintableArea();
$usableWidth = $pa->w;
$barcodeSize = $usableWidth * $this->getBarcodeRatio();
$height += $barcodeSize + $this->barcodeMargin;
}
// Add fields height if present
if ($record->has('fields') && $this->getSupportFields() > 0) {
foreach ($record->get('fields') as $field) {
$height += $this->labelSize + $this->labelMargin;
$height += $this->fieldSize + $this->fieldMargin;
}
}
// Add a small buffer to ensure everything fits
$height += 2.0;
// Ensure minimum height
return max($this->minHeight, $height);
}
/**
* Override the writeAll method to support dynamic page sizes for continuous tapes
*/
public function writeAll($pdf, $data) {
// Use auto-sizing for continuous tapes, fixed height for die-cut tapes
if ($this->continuous) {
$data->each(function ($record, $index) use ($pdf) {
// Calculate the required height for this record
$requiredHeight = $this->calculateRequiredHeight($record);
// Temporarily update the height property
$originalHeight = $this->height;
$this->height = $requiredHeight;
// Add a new page with the calculated dimensions
$pdf->AddPage(
$this->getOrientation(),
[$this->getWidth(), $requiredHeight],
false, // Don't reset page number
false // Don't reset object ID
);
// Write the content
$this->write($pdf, $record);
// Restore the original height
$this->height = $originalHeight;
});
} else {
// Use the default implementation for non-continuous (die-cut) tapes
parent::writeAll($pdf, $data);
}
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace App\Models\Labels\Tapes\Generic;
class Continuous_53mm_A extends Continuous_53mm
{
public function getUnit() { return 'mm'; }
public function getSupportAssetTag() { return false; }
public function getSupport1DBarcode() { return true; }
public function getSupport2DBarcode() { return true; }
public function getSupportFields() { return 5; }
public function getSupportLogo() { return false; }
public function getSupportTitle() { return true; }
public function preparePDF($pdf) {
$pdf->SetAutoPageBreak(false);
}
public function write($pdf, $record) {
$pa = $this->getPrintableArea();
$currentX = $pa->x1;
$currentY = $pa->y1;
$usableWidth = $pa->w;
$usableHeight = $pa->h;
if ($record->has('title')) {
static::writeText(
$pdf, $record->get('title'),
$pa->x1, $pa->y1,
'freesans', '', $this->titleSize, 'C',
$pa->w, $this->titleSize, true, 0
);
$currentY += $this->titleSize + $this->titleMargin;
$usableHeight -= $this->titleSize + $this->titleMargin;
}
// Make the barcode as large as possible while still leaving room for fields
$barcodeSize = min($usableHeight * 0.8, $usableWidth * $this->getBarcodeRatio());
if ($record->has('barcode2d')) {
$barcodeX = $pa->x1 + ($usableWidth - $barcodeSize) / 2;
static::write2DBarcode(
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
$barcodeX, $currentY,
$barcodeSize, $barcodeSize
);
$currentY += $barcodeSize + $this->barcodeMargin;
}
if ($record->has('fields')) {
foreach ($record->get('fields') as $field) {
static::writeText(
$pdf, $field['label'],
$currentX, $currentY,
'freesans', '', $this->labelSize, 'L',
$usableWidth, $this->labelSize, true, 0
);
$currentY += $this->labelSize + $this->labelMargin;
static::writeText(
$pdf, $field['value'],
$currentX, $currentY,
'freemono', 'B', $this->fieldSize, 'L',
$usableWidth, $this->fieldSize, true, 0, 0.01
);
$currentY += $this->fieldSize + $this->fieldMargin;
}
}
}
}

View File

@@ -0,0 +1,170 @@
<?php
namespace App\Models\Labels\Tapes\Generic;
use App\Helpers\Helper;
abstract class Continuous_Landscape_0_59in extends GenericTape
{
// abstract class for printers using 0.59in width paper in landscape orientation
// Using a larger TAPE_WIDTH value to increase font sizes
protected const TAPE_WIDTH = 0.59;
private float $tapeHeight;
protected float $minHeight = 1;
/**
* @param float $length Length of the label in inches (default 2.36in which is 60mm)
* @param bool $continuous Whether the tape is continuous or pre-cut
* @param float $spacing Spacing between labels for non-continuous tapes (in inches)
*/
public function __construct($length = 0.6, $continuous = true, $spacing = 0.0) {
// Swap width and height for landscape orientation
// The height becomes the width, and the length becomes the height
parent::__construct($length, self::TAPE_WIDTH, $continuous, $spacing);
$this->tapeHeight = $length;
$this->marginTop = 0.1;
$this->marginBottom = 0.1;
// Keep small horizontal margins
$this->marginLeft = self::TAPE_WIDTH * 0.2;
// $this->marginRight = self::TAPE_WIDTH * 0.1;
// Override font sizes to make them larger
// Calculate a larger base font size (3x the default)
$baseFontSize = self::TAPE_WIDTH * 0.16; // 3x the default 0.07
// Recalculate all element sizing based on the larger base font size
$this->titleSize = $baseFontSize; // Same as base font size
$this->titleMargin = $baseFontSize * 0.3; // 30% of base font size
$this->fieldSize = $baseFontSize * 1.1; // 110% of base font size
$this->fieldMargin = $baseFontSize * 0.1; // 10% of base font size
$this->labelSize = $baseFontSize * 0.7; // 70% of base font size
$this->labelMargin = $baseFontSize * -0.1; // -10% of base font size
$this->barcodeMargin = $baseFontSize * 0.9; // 20% of base font size
$this->tagSize = $baseFontSize * 0.8; // 80% of base font size
}
public function getBarcodeRatio() {
return 1.0; // Barcode should use 100% of available height
}
/**
* Calculate the required length for the content
*
* @param $record The record to calculate length for
* @return float The calculated length in inches
*/
protected function calculateRequiredLength($record) {
// Calculate length needed for barcode and fields side by side
$requiredLength = 0;
// Add barcode length if present
if (($record->has('barcode2d') && $this->getSupport2DBarcode()) ||
($record->has('barcode') && $this->getSupport1DBarcode())) {
// Use full tape width for barcode size
$barcodeSize = self::TAPE_WIDTH;
$requiredLength += $barcodeSize + $this->barcodeMargin * 0.3; // Minimal margin
}
// Add fields length if present - calculate based on actual content
if ($record->has('fields') && $this->getSupportFields() > 0) {
$fields = array_slice($record->get('fields')->toArray(), 0, $this->getSupportFields());
// Base width for field area
$fieldsWidth = self::TAPE_WIDTH;
// Calculate additional width based on text length
foreach ($fields as $field) {
// Get label and value text
$labelText = $field['label'] ?? '';
$valueText = $field['value'] ?? '';
// Calculate approximate width needed based on text length
// Increase character width to ensure enough space (0.15 inches per character)
$labelWidth = strlen($labelText) * 0.09;
$valueWidth = strlen($valueText) * 0.09;
// Use the longer of the two
$textWidth = max($labelWidth, $valueWidth);
// Ensure minimum width and add to total
$fieldsWidth = max($fieldsWidth, $textWidth);
}
// Add the calculated width for fields
$requiredLength += $fieldsWidth;
// Add minimal extra space for field padding
// Reduce padding to eliminate extraneous space on right edge
// $requiredLength += self::TAPE_WIDTH * 0.1;
}
// Ensure minimum length
return max($this->minHeight, $requiredLength);
}
/**
* Calculate text width accurately using the PDF object
*
* @param $pdf The PDF object
* @param string $text The text to measure
* @param string $font The font to use
* @param string $style The font style
* @param float $size The font size
* @return float The calculated width
*/
protected function calculateTextWidth($pdf, $text, $font, $style, $size) {
$originalFont = $pdf->getFontFamily();
$originalStyle = $pdf->getFontStyle();
$originalSize = $pdf->getFontSizePt();
$pdf->SetFont($font, $style, Helper::convertUnit($size, $this->getUnit(), 'pt', true));
$width = $pdf->GetStringWidth($text);
// Restore original font settings
$pdf->SetFont($originalFont, $originalStyle, $originalSize);
return $width;
}
/**
* Override the writeAll method to support dynamic page sizes for continuous tapes
*/
public function writeAll($pdf, $data) {
// Use auto-sizing for continuous tapes, fixed height for die-cut tapes
if ($this->continuous) {
$data->each(function ($record, $index) use ($pdf) {
// Calculate the required length by calling write with calculateOnly=true
$requiredLength = $this->write($pdf, $record);
// If write didn't return a length (old implementation), fall back to calculateRequiredLength
if ($requiredLength === null) {
$requiredLength = $this->calculateRequiredLength($record);
}
// Temporarily update the height property
$originalHeight = $this->height;
$this->height = self::TAPE_WIDTH; // Keep height fixed at tape width
// Add a new page with the calculated dimensions
// Keep height fixed at TAPE_WIDTH, use calculated length for width
$pdf->AddPage(
$this->getOrientation(),
[$requiredLength, self::TAPE_WIDTH],
false, // Don't reset page number
false // Don't reset object ID
);
// Write the content
$this->write($pdf, $record);
// Restore the original height
$this->height = $originalHeight;
});
} else {
// Use the default implementation for non-continuous (die-cut) tapes
parent::writeAll($pdf, $data);
}
}
}

View File

@@ -0,0 +1,157 @@
<?php
namespace App\Models\Labels\Tapes\Generic;
class Continuous_Landscape_0_59in_A extends Continuous_Landscape_0_59in
{
public function getUnit() { return 'in'; }
public function getSupportAssetTag() { return false; }
public function getSupport1DBarcode() { return true; }
public function getSupport2DBarcode() { return true; }
public function getSupportFields() { return 2; }
public function getSupportLogo() { return false; }
public function getSupportTitle() { return false; }
public function preparePDF($pdf) {
$pdf->SetAutoPageBreak(false);
}
public function write($pdf, $record, $calculateOnly = false) {
$pa = $this->getPrintableArea();
$currentX = $pa->x1;
$currentY = $pa->y1;
$usableWidth = $pa->w;
$usableHeight = $pa->h;
// Calculate required length based on content
$requiredLength = 0;
// Use full usable height for barcode
$barcodeSize = $usableHeight;
// Add barcode width to required length
if ($record->has('barcode2d') && $this->getSupport2DBarcode()) {
$requiredLength += $barcodeSize;
// Add gap between barcode and fields
$requiredLength += $this->barcodeMargin;
}
// Calculate fields width using accurate text measurement
if ($record->has('fields') && $this->getSupportFields() > 0) {
$fields = array_slice($record->get('fields')->toArray(), 0, $this->getSupportFields());
$fieldsWidth = 0;
foreach ($fields as $field) {
$labelText = $field['label'] ?? '';
$valueText = $field['value'] ?? '';
// Calculate accurate width using the PDF object
$labelWidth = $this->calculateTextWidth($pdf, $labelText, 'freesans', 'B', $this->labelSize * 1.2);
$valueWidth = $this->calculateTextWidth($pdf, $valueText, 'freemono', 'B', $this->fieldSize * 1.3);
// Use the longer of the two
$textWidth = max($labelWidth, $valueWidth);
$fieldsWidth = max($fieldsWidth, $textWidth);
}
$requiredLength += $fieldsWidth;
}
// Add more padding to prevent text from being cut off
// $requiredLength += self::TAPE_WIDTH * 0.8;
// Ensure minimum length
$requiredLength = max($this->minHeight, $requiredLength);
// If we're just calculating, return the length
if ($calculateOnly) {
return $requiredLength;
}
// Otherwise, render the content
// Position barcode on the left side
if ($record->has('barcode2d') && $this->getSupport2DBarcode()) {
// Position at top of usable area
static::write2DBarcode(
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
$currentX, $currentY,
$barcodeSize, $barcodeSize
);
$currentX += $barcodeSize + $this->barcodeMargin;
$usableWidth -= $barcodeSize + $this->barcodeMargin;
}
// Position fields to the right of the barcode
if ($record->has('fields') && $this->getSupportFields() > 0) {
// Limit to the number of supported fields
$fields = array_slice($record->get('fields')->toArray(), 0, $this->getSupportFields());
// Calculate total height needed for fields
$totalFieldsHeight = 0;
foreach ($fields as $field) {
$totalFieldsHeight += $this->labelSize * 1.2 + $this->labelMargin; // Increased label size by 20%
$totalFieldsHeight += $this->fieldSize * 1.3 + $this->fieldMargin * 2; // Increased field size by 30% and margin
}
// Start position - respect top margin
$fieldY = $currentY; // $currentY already includes the top margin
$fieldWidth = $usableWidth;
// Calculate available height for fields (respecting margins)
$availableHeight = $usableHeight;
// If fields don't fill available height, adjust spacing proportionally
// but don't exceed the available height
$scaleFactor = 1.0; // Default scale factor
if ($totalFieldsHeight < $availableHeight && count($fields) > 0) {
// Scale up to fill available height, but not too much
$scaleFactor = min(1.5, $availableHeight / $totalFieldsHeight);
} else if ($totalFieldsHeight > $availableHeight && count($fields) > 0) {
// Scale down to fit within available height
$scaleFactor = $availableHeight / $totalFieldsHeight;
}
foreach ($fields as $field) {
// Calculate scaled spacing
$labelHeight = $this->labelSize * 1.2 * $scaleFactor;
$labelSpacing = $this->labelMargin * $scaleFactor;
$fieldHeight = $this->fieldSize * 1.3 * $scaleFactor;
$fieldSpacing = $this->fieldMargin * 2 * $scaleFactor;
// Check if label is empty or null
$labelText = $field['label'] ?? '';
$valueText = $field['value'] ?? '';
if (empty(trim($labelText))) {
// If label is empty, just render the value at the current Y position
static::writeText(
$pdf, $valueText,
$currentX, $fieldY,
'freemono', 'B', $this->fieldSize * 1.3, 'L', // Increased field size by 30%
$fieldWidth, $fieldHeight, false, 0, 0.00
);
$fieldY += ($fieldHeight + $fieldSpacing) + 0.02; // Increased spacing after value
} else {
// If label has content, render both label and value
static::writeText(
$pdf, $labelText,
$currentX, $fieldY,
'freesans', 'B', $this->labelSize * 1.2, 'L', // Increased label size by 20% and made bold
$labelWidth, $labelHeight, false, 0,
);
$fieldY += ($labelHeight + $labelSpacing) + 0.01;
// Value
static::writeText(
$pdf, $valueText,
$currentX, $fieldY, // Position value directly below label
'freemono', 'B', $this->fieldSize * 1.3, 'L', // Increased field size by 30%
$fieldWidth, $fieldHeight, false, 0, 0.00
);
$fieldY += ($fieldHeight + $fieldSpacing) + 0.02; // Increased spacing after value
}
}
}
}
}

View File

@@ -0,0 +1,103 @@
<?php
namespace App\Models\Labels\Tapes\Generic;
use App\Helpers\Helper;
use App\Models\Labels\Label;
abstract class GenericTape extends Label
{
// Default tape width in mm
protected const TAPE_WIDTH = 42.0;
// Tape properties
protected float $width;
protected float $height;
protected bool $continuous;
protected float $spacing = 0.0; // Space between labels for non-continuous tapes
// Margins in mm
protected float $marginTop;
protected float $marginBottom;
protected float $marginLeft;
protected float $marginRight;
// Element sizing in mm
protected float $titleSize;
protected float $titleMargin;
protected float $fieldSize;
protected float $fieldMargin;
protected float $labelSize;
protected float $labelMargin;
protected float $barcodeMargin;
protected float $tagSize;
/**
* Constructor for generic tape
*
* @param float $width Width of the tape in mm
* @param float $height Height of the label in mm (for continuous tapes, this is the default height)
* @param bool $continuous Whether the tape is continuous or pre-cut
* @param float $spacing Spacing between labels for non-continuous tapes (in mm)
*/
public function __construct(float $width, float $height, bool $continuous = true, float $spacing = 0.0) {
$this->width = $width;
$this->height = $height;
$this->continuous = $continuous;
$this->spacing = $spacing;
// Calculate base font size (7% of tape width)
$baseFontSize = static::TAPE_WIDTH * 0.07;
// Calculate margin (4% of tape width)
$margin = static::TAPE_WIDTH * 0.04;
// Set margins
$this->marginTop = $margin;
$this->marginBottom = $margin;
$this->marginLeft = $margin;
$this->marginRight = $margin;
// Calculate and set element sizing based on base font size
$this->titleSize = $baseFontSize; // Same as base font size
$this->titleMargin = $baseFontSize * 0.3; // 30% of base font size
$this->fieldSize = $baseFontSize * 1.1; // 110% of base font size
$this->fieldMargin = $baseFontSize * 0.1; // 10% of base font size
$this->labelSize = $baseFontSize * 0.7; // 70% of base font size
$this->labelMargin = $baseFontSize * -0.1; // -10% of base font size
$this->barcodeMargin = $baseFontSize * 0.5; // 50% of base font size
$this->tagSize = $baseFontSize * 0.8; // 80% of base font size
}
// Unit of measurement
public function getUnit() { return 'mm'; }
// Label dimensions
public function getWidth() { return $this->width; }
public function getHeight() { return $this->height; }
// Margins
public function getMarginTop() { return $this->marginTop; }
public function getMarginBottom() { return $this->marginBottom; }
public function getMarginLeft() { return $this->marginLeft; }
public function getMarginRight() { return $this->marginRight; }
/**
* Check if this is a continuous tape
*
* @return bool
*/
public function isContinuous() {
return $this->continuous;
}
/**
* Get spacing between labels (for die-cut tapes)
*
* @return float
*/
public function getSpacing() {
return $this->spacing;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Models\Labels\Tapes\Generic;
abstract class Tape_53mm extends GenericTape
{
// Override tape width to 53mm
protected const TAPE_WIDTH = 53.0;
private float $tapeHeight;
/**
* Constructor for 53mm tape
*
* @param float $height Height of the label in mm (default 30mm)
* @param bool $continuous Whether the tape is continuous or pre-cut
* @param float $spacing Spacing between labels for non-continuous tapes (in mm)
*/
public function __construct(float $height = 30.0, bool $continuous = true, float $spacing = 0.0) {
parent::__construct(self::TAPE_WIDTH, $height, $continuous, $spacing);
$this->tapeHeight = $height;
}
/**
* Get the barcode size ratio for calculations
*
* @return float
*/
public function getBarcodeRatio() {
return 0.9; // Barcode should use 90% of available width
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace App\Models\Labels\Tapes\Generic;
class Tape_53mm_A extends Tape_53mm
{
public function __construct() {
parent::__construct(40.0, true, 0.0);
}
public function getUnit() { return 'mm'; }
public function getSupportAssetTag() { return false; }
public function getSupport1DBarcode() { return false; }
public function getSupport2DBarcode() { return true; }
public function getSupportFields() { return 5; }
public function getSupportLogo() { return false; }
public function getSupportTitle() { return true; }
public function preparePDF($pdf) {
$pdf->SetAutoPageBreak(false);
}
public function write($pdf, $record) {
$pa = $this->getPrintableArea();
$currentX = $pa->x1;
$currentY = $pa->y1;
$usableWidth = $pa->w;
$usableHeight = $pa->h;
if ($record->has('title')) {
static::writeText(
$pdf, $record->get('title'),
$pa->x1, $pa->y1,
'freesans', '', $this->titleSize, 'C',
$pa->w, $this->titleSize, true, 0
);
$currentY += $this->titleSize + $this->titleMargin;
$usableHeight -= $this->titleSize + $this->titleMargin;
}
// Make the barcode as large as possible while still leaving room for fields
$barcodeSize = min($usableHeight * 0.8, $usableWidth * $this->getBarcodeRatio());
if ($record->has('barcode2d')) {
$barcodeX = $pa->x1 + ($usableWidth - $barcodeSize) / 2;
static::write2DBarcode(
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
$barcodeX, $currentY,
$barcodeSize, $barcodeSize
);
$currentY += $barcodeSize + $this->barcodeMargin;
}
if ($record->has('fields')) {
foreach ($record->get('fields') as $field) {
static::writeText(
$pdf, $field['label'],
$currentX, $currentY,
'freesans', '', $this->labelSize, 'L',
$usableWidth, $this->labelSize, true, 0
);
$currentY += $this->labelSize + $this->labelMargin;
static::writeText(
$pdf, $field['value'],
$currentX, $currentY,
'freemono', 'B', $this->fieldSize, 'L',
$usableWidth, $this->fieldSize, true, 0, 0.01
);
$currentY += $this->fieldSize + $this->fieldMargin;
}
}
}
}