From 2c141579dd0993938a201db143629a7d73dd4142 Mon Sep 17 00:00:00 2001 From: Chris Olin Date: Fri, 2 May 2025 07:14:47 -0400 Subject: [PATCH 1/2] adds support for GenericTape label printers, includes class for 53mm tape printer --- .../Labels/Tapes/Generic/GenericTape.php | 103 ++++++++++++++++++ app/Models/Labels/Tapes/Generic/Tape_53mm.php | 32 ++++++ .../Labels/Tapes/Generic/Tape_53mm_A.php | 77 +++++++++++++ .../Labels/Tapes/Generic/Tape_53mm_B.php | 78 +++++++++++++ 4 files changed, 290 insertions(+) create mode 100644 app/Models/Labels/Tapes/Generic/GenericTape.php create mode 100644 app/Models/Labels/Tapes/Generic/Tape_53mm.php create mode 100644 app/Models/Labels/Tapes/Generic/Tape_53mm_A.php create mode 100644 app/Models/Labels/Tapes/Generic/Tape_53mm_B.php diff --git a/app/Models/Labels/Tapes/Generic/GenericTape.php b/app/Models/Labels/Tapes/Generic/GenericTape.php new file mode 100644 index 000000000000..3825d54e2e6a --- /dev/null +++ b/app/Models/Labels/Tapes/Generic/GenericTape.php @@ -0,0 +1,103 @@ +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; + } +} \ No newline at end of file diff --git a/app/Models/Labels/Tapes/Generic/Tape_53mm.php b/app/Models/Labels/Tapes/Generic/Tape_53mm.php new file mode 100644 index 000000000000..fc46838d6688 --- /dev/null +++ b/app/Models/Labels/Tapes/Generic/Tape_53mm.php @@ -0,0 +1,32 @@ +tapeHeight = $height; + } + + /** + * Get the barcode size ratio for calculations + * + * @return float + */ + public function getBarcodeRatio() { + return 0.9; // Barcode should use 90% of available width + } +} \ No newline at end of file diff --git a/app/Models/Labels/Tapes/Generic/Tape_53mm_A.php b/app/Models/Labels/Tapes/Generic/Tape_53mm_A.php new file mode 100644 index 000000000000..399efbe11cde --- /dev/null +++ b/app/Models/Labels/Tapes/Generic/Tape_53mm_A.php @@ -0,0 +1,77 @@ +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; + } + } + } +} \ No newline at end of file diff --git a/app/Models/Labels/Tapes/Generic/Tape_53mm_B.php b/app/Models/Labels/Tapes/Generic/Tape_53mm_B.php new file mode 100644 index 000000000000..e297a30248a6 --- /dev/null +++ b/app/Models/Labels/Tapes/Generic/Tape_53mm_B.php @@ -0,0 +1,78 @@ +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; + + static::write2DBarcode( + $pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type, + $barcodeX, $currentY, + $barcodeSize, $barcodeSize + ); + $currentX += $barcodeSize + $this->barcodeMargin; + $usableWidth -= $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; + } + } + } +} \ No newline at end of file From 248a05a916b2be38feafc87638d81bd951d18e86 Mon Sep 17 00:00:00 2001 From: Chris Olin Date: Sun, 4 May 2025 14:47:54 -0400 Subject: [PATCH 2/2] adds support for continuous 53mm and 0.59in printers --- .../Labels/Tapes/Generic/Continuous_53mm.php | 104 +++++++++++ ...{Tape_53mm_B.php => Continuous_53mm_A.php} | 15 +- .../Generic/Continuous_Landscape_0_59in.php | 170 ++++++++++++++++++ .../Generic/Continuous_Landscape_0_59in_A.php | 157 ++++++++++++++++ 4 files changed, 436 insertions(+), 10 deletions(-) create mode 100644 app/Models/Labels/Tapes/Generic/Continuous_53mm.php rename app/Models/Labels/Tapes/Generic/{Tape_53mm_B.php => Continuous_53mm_A.php} (88%) create mode 100644 app/Models/Labels/Tapes/Generic/Continuous_Landscape_0_59in.php create mode 100644 app/Models/Labels/Tapes/Generic/Continuous_Landscape_0_59in_A.php diff --git a/app/Models/Labels/Tapes/Generic/Continuous_53mm.php b/app/Models/Labels/Tapes/Generic/Continuous_53mm.php new file mode 100644 index 000000000000..4e06e2c96de1 --- /dev/null +++ b/app/Models/Labels/Tapes/Generic/Continuous_53mm.php @@ -0,0 +1,104 @@ +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); + } + } +} \ No newline at end of file diff --git a/app/Models/Labels/Tapes/Generic/Tape_53mm_B.php b/app/Models/Labels/Tapes/Generic/Continuous_53mm_A.php similarity index 88% rename from app/Models/Labels/Tapes/Generic/Tape_53mm_B.php rename to app/Models/Labels/Tapes/Generic/Continuous_53mm_A.php index e297a30248a6..632695ea1a71 100644 --- a/app/Models/Labels/Tapes/Generic/Tape_53mm_B.php +++ b/app/Models/Labels/Tapes/Generic/Continuous_53mm_A.php @@ -2,16 +2,12 @@ namespace App\Models\Labels\Tapes\Generic; -use Illuminate\Support\Collection; -use TCPDF; - -class Tape_53mm_B extends Tape_53mm +class Continuous_53mm_A extends Continuous_53mm { - - + public function getUnit() { return 'mm'; } public function getSupportAssetTag() { return false; } - public function getSupport1DBarcode() { return false; } + public function getSupport1DBarcode() { return true; } public function getSupport2DBarcode() { return true; } public function getSupportFields() { return 5; } public function getSupportLogo() { return false; } @@ -44,15 +40,14 @@ public function write($pdf, $record) { $barcodeSize = min($usableHeight * 0.8, $usableWidth * $this->getBarcodeRatio()); if ($record->has('barcode2d')) { - $barcodeX = $pa->x1; + $barcodeX = $pa->x1 + ($usableWidth - $barcodeSize) / 2; static::write2DBarcode( $pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type, $barcodeX, $currentY, $barcodeSize, $barcodeSize ); - $currentX += $barcodeSize + $this->barcodeMargin; - $usableWidth -= $barcodeSize + $this->barcodeMargin; + $currentY += $barcodeSize + $this->barcodeMargin; } if ($record->has('fields')) { diff --git a/app/Models/Labels/Tapes/Generic/Continuous_Landscape_0_59in.php b/app/Models/Labels/Tapes/Generic/Continuous_Landscape_0_59in.php new file mode 100644 index 000000000000..5efd88ff063f --- /dev/null +++ b/app/Models/Labels/Tapes/Generic/Continuous_Landscape_0_59in.php @@ -0,0 +1,170 @@ +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); + } + } +} \ No newline at end of file diff --git a/app/Models/Labels/Tapes/Generic/Continuous_Landscape_0_59in_A.php b/app/Models/Labels/Tapes/Generic/Continuous_Landscape_0_59in_A.php new file mode 100644 index 000000000000..7c5774e17d3a --- /dev/null +++ b/app/Models/Labels/Tapes/Generic/Continuous_Landscape_0_59in_A.php @@ -0,0 +1,157 @@ +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 + } + } + } + } +} \ No newline at end of file