Tags
PHPImageMagick
I was given the task to design and produce staff badges. This is typically a print task I’d do in Indesign, but I was hope was to automate the entire process so that I could send data via API (or CSV) from our CRM directly to PDF ready for production. (Additionally, Indesign Data Merge doesn’t handle dual-sided imposition for when you need two sided name badges).
Pseudo-Code Overview
Read/Parse CSV → Generate Name Badge Images (individually) → Comp them together into PDF → Send to print server ✨
// read the csv file
$csv = parseCSV("listOfUsersBadges.csv");
// loop through results and draw each card
foreach($csv as $row){
// create image from template
$image = new Imagick();
$image->readImage("template.png");
// create new draw object
$draw = new ImagickDraw();
// align text to center
$draw->setTextAlignment(\Imagick::ALIGN_CENTER);
// set font (from custom file)
$draw->setFont('Avenir.ttf');
// set size and weight
$draw->setFontSize(120);
$draw->setFontWeight(551);
// add first name and last name to image
$image->annotateImage($draw, 380, 765, 0, $row["First name"]);
$image->annotateImage($draw, 380, 895, 0, $row["Last name"]);
// save image out
$image->writeImages("badge.png", false);
}
Now that we’ve dynamically generated the individual name tags we just need to merge them into a dual-sided document with correct margins, bleed, etc.
$imageDirectory = "Individual Badges";
$backPageLeftOffset = 0;
$cardWidth = 820;
$cardHeight = 1295;
// storage
$imageArray = array();
$cards = array();
$pdfCount = 0;
$pagesArray = array();
// delete pages
$images = glob("$imageDirectory/" . "*.png");
foreach($images as $image)
{
array_push($imageArray, str_replace("$imageDirectory/", "", $image));
}
// split by every 4 cards to a page
$cards = array_chunk($imageArray, 4);
// loop through each 4 twice
foreach($cards as $cardList){
//place the front cards
placeCardsInPDF($cardList);
//place the back cards
placeCardsInPDF($cardList, true);
}
function placeCardsInPDF($cards, $reversed = false){
global $pdfCount, $backPageLeftOffset, $pagesArray, $cardWidth, $cardHeight;
$pdfCount++;
$imageLeftMargin = 435;
$imageTopMargin = 20;
$spaceBetweenImages = 8;
$image = new Imagick();
$image->readImage("Templates/Tag Template.png");
// top left
$image = compositeImage($image, $cards[($reversed ? 1 : 0)], ($reversed ? $backPageLeftOffset : 0) + $imageLeftMargin, $imageTopMargin);
// top right
$image = compositeImage($image, $cards[($reversed ? 0 : 1)], ($reversed ? $backPageLeftOffset : 0) + $imageLeftMargin + $spaceBetweenImages + $cardWidth, $imageTopMargin);
//bottom left
$image = compositeImage($image, $cards[($reversed ? 3 : 2)], ($reversed ? $backPageLeftOffset : 0) + $imageLeftMargin, $imageTopMargin + $cardHeight + $spaceBetweenImages+5);
//bottom right
$image = compositeImage($image, $cards[($reversed ? 2 : 3)], ($reversed ? $backPageLeftOffset : 0) + $imageLeftMargin + $spaceBetweenImages + $cardWidth, $imageTopMargin + $cardHeight + $spaceBetweenImages+5);
$image->writeImage("page$pdfCount.png");
array_push($pagesArray, "page$pdfCount.png");
}
function compositeImage($image, $cardName, $x, $y){
global $cardHeight, $cardWidth, $tagType;
if(!$cardName){
return $image;
}
$card = new Imagick("$imageDirectory/$cardName");
$card->scaleImage($cardWidth, 0);
$padding = new Imagick("Templates/$tagType Padding.png");
$padding->scaleImage(906, 0);
$padding->compositeImage($card, Imagick::COMPOSITE_DEFAULT, 43, 43);
$padding->scaleImage(840, 0);
$image->compositeImage($padding, Imagick::COMPOSITE_DEFAULT, $x, $y);
return $image;
}
function combineImages(){
global $pagesArray;
$pdf = new Imagick($pagesArray);
$pdf->setImageFormat('pdf');
$pdf->writeImages('namebadges.pdf', true);
}
combineImages();
And VOILÀ 🪄 you have a PDF of name badges from the list of names in your CSV file.