Skip to content

Example: another shipping label

A third shipping label, styled differently from the first one: three stacked blocks — ship from/to, contents, and a tracking barcode — separated by rule lines instead of full borders around every cell.

Example output image

<?php
require 'vendor/autoload.php';
use Kehet\ImagickLayoutEngine\Containers\ColumnContainer;
use Kehet\ImagickLayoutEngine\Containers\GridContainer;
use Kehet\ImagickLayoutEngine\Containers\RowContainer;
use Kehet\ImagickLayoutEngine\Enums\Gravity;
use Kehet\ImagickLayoutEngine\Enums\ImageMode;
use Kehet\ImagickLayoutEngine\Items\Image;
use Kehet\ImagickLayoutEngine\Items\Text;
use Kehet\ImagickLayoutEngine\Items\TextWrap;
function fieldLabel(string $text): Text
{
$draw = draw(fill: '#4b5563');
$draw->setFont('DejaVu-Sans');
$item = new Text($draw, $text, initialFontSize: 18, gravity: Gravity::TOP_LEFT);
$item->setLetterSpacing(2);
return $item;
}
function fieldValue(string $text, int $size = 26): TextWrap
{
$draw = draw(fill: 'black');
$draw->setFont('DejaVu-Sans-Bold');
return new TextWrap($draw, $text, initialFontSize: $size, gravity: Gravity::TOP_LEFT);
}
$width = 900;
$height = 960;
$imagick = new Imagick;
$imagick->newImage($width, $height, new ImagickPixel('white'));
$divider = draw(stroke: 'black', strokeWidth: 3);
$root = new ColumnContainer;
$root->setBorder(draw(stroke: 'black', strokeWidth: 5));
$root->setPadding(30);
// ---------------------------------------------------------------------
// Block 1: free-text ship from / ship to
// ---------------------------------------------------------------------
$block1 = new ColumnContainer;
$block1->setBorderBottom($divider);
$block1->setPadding(0, 0, 20, 0);
$block1->setGap(16);
$block1->addItem(fieldLabel('SHIP FROM'), forceSize: 24);
$block1->addItem(
fieldValue("ACME Distribution Ltd\nTeollisuuskatu 9\n00510 Helsinki, Finland", 22),
forceSize: 80
);
$shipToRow = new RowContainer;
$shipToLabelCol = new ColumnContainer;
$shipToLabelCol->setGap(10);
$shipToLabelCol->addItem(fieldLabel('SHIP TO'), forceSize: 24);
$shipToLabelCol->addItem(
fieldValue("Nordic Retail Group\nWarehouse 4, Logistikvagen 22\n164 40 Kista, Sweden", 30)
);
$shipToRow->addItem($shipToLabelCol);
$poCol = new ColumnContainer;
$poCol->setGap(10);
$poCol->addItem(fieldLabel('PURCHASE ORDER'), forceSize: 24);
$poCol->addItem(fieldValue('4471258', 30));
$shipToRow->addItem($poCol, forceSize: 220);
$block1->addItem($shipToRow, forceSize: 140);
$root->addItem($block1, forceSize: 320);
// ---------------------------------------------------------------------
// Block 2: contents, as a label/value grid
// ---------------------------------------------------------------------
$block2 = new ColumnContainer;
$block2->setBorderBottom($divider);
$block2->setPadding(20, 0);
$block2->setGap(16);
$block2->addItem(fieldLabel('CONTENTS'), forceSize: 24);
$block2->addItem(fieldValue('Organic Cranberry Juice 1 L x 24', 28), forceSize: 40);
$detailsGrid = new GridContainer;
$detailsGrid->setTemplateColumns(null, null);
$detailsGrid->setGap(14, 30);
$details = [
['label' => 'PRODUCT CODE', 'value' => '10614141122763'],
['label' => 'QUANTITY', 'value' => '24 EA'],
['label' => 'BATCH/LOT', 'value' => 'LOT2547'],
['label' => 'BEST BEFORE', 'value' => '2026-12-31'],
];
foreach ($details as $detail) {
$cell = new ColumnContainer;
$cell->setGap(2);
$cell->addItem(fieldLabel($detail['label']), forceSize: 22);
$cell->addItem(fieldValue($detail['value'], 24));
$detailsGrid->addItem($cell);
}
$block2->addItem($detailsGrid, forceSize: 160);
$root->addItem($block2, forceSize: 260);
// ---------------------------------------------------------------------
// Block 3: tracking barcode, always last so it's the easiest thing on
// the label for a handheld scanner to find
// ---------------------------------------------------------------------
$block3 = new ColumnContainer;
$block3->setPadding(20, 0, 0, 0);
$block3->setGap(10);
$block3->addItem(fieldLabel('TRACKING NUMBER'), forceSize: 24);
$block3->addItem(new Image(__DIR__.'/example-code-128.png', ImageMode::FIT), forceSize: 190);
$trackingDraw = draw(fill: 'black');
$trackingDraw->setFont('DejaVu-Sans-Bold');
$tracking = new Text($trackingDraw, '3 0614141 812345678 6', initialFontSize: 30, gravity: Gravity::CENTER);
$tracking->setLetterSpacing(2);
$block3->addItem($tracking, forceSize: 44);
$root->addItem($block3);
$root->draw($imagick, 0, 0, $width, $height);
$imagick->setImageFormat('png');
$imagick->writeImage(__DIR__.'/pallet-label.png');

Each block is a plain ColumnContainer; the rule lines between them are just setBorderBottom() on blocks 1 and 2, rather than a full border on every cell or a separate Rectangle divider. The contents block uses a GridContainer for its label/value pairs, and the tracking number reuses the same placeholder barcode image as the other label guides.

The same layout as a template. The fieldLabel()/fieldValue() helpers have no template equivalent, so their styling (fill, font, fontSize, letterSpacing) is repeated on every label/value node below, and setBorderBottom() becomes a border object with only a bottom key:

{
"type": "column",
"border": {"stroke": "black", "strokeWidth": 5},
"padding": 30,
"children": [
{
"type": "column",
"border": {"bottom": {"stroke": "black", "strokeWidth": 3}},
"padding": {"top": 0, "right": 0, "bottom": 20, "left": 0},
"gap": 16,
"size": 320,
"children": [
{"type":"text","text":"SHIP FROM","fill":"#4b5563","font":"DejaVu-Sans","fontSize":18,"letterSpacing":2,"size":24},
{"type":"text-wrap","text":"ACME Distribution Ltd\nTeollisuuskatu 9\n00510 Helsinki, Finland","fill":"black","font":"DejaVu-Sans-Bold","fontSize":22,"size":80},
{
"type": "row",
"size": 140,
"children": [
{
"type": "column",
"gap": 10,
"children": [
{"type":"text","text":"SHIP TO","fill":"#4b5563","font":"DejaVu-Sans","fontSize":18,"letterSpacing":2,"size":24},
{"type":"text-wrap","text":"Nordic Retail Group\nWarehouse 4, Logistikvagen 22\n164 40 Kista, Sweden","fill":"black","font":"DejaVu-Sans-Bold","fontSize":30}
]
},
{
"type": "column",
"gap": 10,
"size": 220,
"children": [
{"type":"text","text":"PURCHASE ORDER","fill":"#4b5563","font":"DejaVu-Sans","fontSize":18,"letterSpacing":2,"size":24},
{"type":"text-wrap","text":"4471258","fill":"black","font":"DejaVu-Sans-Bold","fontSize":30}
]
}
]
}
]
},
{
"type": "column",
"border": {"bottom": {"stroke": "black", "strokeWidth": 3}},
"padding": {"top": 20, "right": 0, "bottom": 20, "left": 0},
"gap": 16,
"size": 260,
"children": [
{"type":"text","text":"CONTENTS","fill":"#4b5563","font":"DejaVu-Sans","fontSize":18,"letterSpacing":2,"size":24},
{"type":"text-wrap","text":"Organic Cranberry Juice 1 L x 24","fill":"black","font":"DejaVu-Sans-Bold","fontSize":28,"size":40},
{
"type": "grid",
"templateColumns": [null, null],
"gap": [14, 30],
"size": 160,
"children": [
{
"type": "column",
"gap": 2,
"children": [
{"type":"text","text":"PRODUCT CODE","fill":"#4b5563","font":"DejaVu-Sans","fontSize":18,"letterSpacing":2,"size":22},
{"type":"text-wrap","text":"10614141122763","fill":"black","font":"DejaVu-Sans-Bold","fontSize":24}
]
},
{
"type": "column",
"gap": 2,
"children": [
{"type":"text","text":"QUANTITY","fill":"#4b5563","font":"DejaVu-Sans","fontSize":18,"letterSpacing":2,"size":22},
{"type":"text-wrap","text":"24 EA","fill":"black","font":"DejaVu-Sans-Bold","fontSize":24}
]
},
{
"type": "column",
"gap": 2,
"children": [
{"type":"text","text":"BATCH/LOT","fill":"#4b5563","font":"DejaVu-Sans","fontSize":18,"letterSpacing":2,"size":22},
{"type":"text-wrap","text":"LOT2547","fill":"black","font":"DejaVu-Sans-Bold","fontSize":24}
]
},
{
"type": "column",
"gap": 2,
"children": [
{"type":"text","text":"BEST BEFORE","fill":"#4b5563","font":"DejaVu-Sans","fontSize":18,"letterSpacing":2,"size":22},
{"type":"text-wrap","text":"2026-12-31","fill":"black","font":"DejaVu-Sans-Bold","fontSize":24}
]
}
]
}
]
},
{
"type": "column",
"padding": {"top": 20, "right": 0, "bottom": 0, "left": 0},
"gap": 10,
"children": [
{"type":"text","text":"TRACKING NUMBER","fill":"#4b5563","font":"DejaVu-Sans","fontSize":18,"letterSpacing":2,"size":24},
{"type":"image","file":"example-code-128.png","mode":"fit","size":190},
{"type":"text","text":"3 0614141 812345678 6","fill":"black","font":"DejaVu-Sans-Bold","fontSize":30,"gravity":"center","letterSpacing":2,"size":44}
]
}
]
}

llms.txt