Алгоритм упаковки или расчёт паркета и его укладка

Постановка задачи
Был у меня однажды интересный заказ. Владелец одной крупной украинской компании «Укрзолото» захотел сэкономить на дизайнерах и автоматически генерировать PDF-файлы уже готовые к печати, в которых компактно и красиво были бы расположены изображения (разрешением 300 dpi специально для печати) ювелирных изделий. Все изображения изделий (кстати, размеры разные) предварительно через админ-web-интерфейс загружались на сервер и после через форму выбора формировался массив идентификаторов данных из базы, плюс настройки самого PDF. Для генерации PDF была выбрана библиотека FPDF.



Необходимо выбрать категорию ювелирных изделий:


Для наглядности показать изображения, выбрать формат будущего документа (А4, А5), язык (русский, украинский, английский) и, само-собой, отметить чекбоксами те изображения, которые должны попасть в PDF:


После нажатия на кнопку «Печатная версия (PDF)» появляется запрос скачать и сохранить уже сгенерированный файл:

В имени файла присутствует номер категории. В данном случае при выборе серёжек категория равна 10.

Для наглядности выбрал «Серьги» и «Броши».
Результат можно скачать и посмотреть:
Серьги 10-ukrzoloto.pdf
Броши 27-ukrzoloto.pdf

Реализация
Но нас интересует самое главное — скрипт с алгоритмом генерации! Итак, сначала настройки.
// подключаем всё, что можно подключить
define("FPDF_FONTPATH","путь к папке /font/");
require("путь к классу fpdf.class.php");
include_once "путь к файлу подключения к базе данных";

Тепперь небольшой нюанс. Дело в том, что требования к печати диктуют 300 точек на дюйм, а значит нам необходим коэффициент перерасчёта.
// A4 portrait - 210x297 mm = 2480x3508 px (300dpi)
// A5 landscape - 210x148.5 mm = 2480x1754 px (300dpi)
// коэффициент перехода при 300dpi
$k=11.8;

Определяем формат будущего файла исходя из данных формы:
// если формат А5, то альбомное расположение
// если формат А4, то книжное расположение
if($_POST['format45']=="A5") $_POST['formatPL']="L";
if($_POST['format45']=="A4") $_POST['formatPL']="P";

Создаём экземпляр класса с тонкими настройками (расположение, миллиметры, формат):
$pdf = new FPDF($_POST['formatPL'],'mm',$_POST['format45']);

Далее:
$pdf->SetAuthor("ukrzoloto"); // автор документа
$pdf->SetCreator("programilla.com"); // создатель документа
$pdf->SetTitle("ukrzoloto"); // заголовок документа
$pdf->SetMargins(10,10,10,10); // отступы по краям страниц в миллиметрах
$pdf->AddFont("BalticaC","","Baltica.php"); // Подключаем кириллический шрифт
$pdf-> SetFont("BalticaC","",9); // устанавливаем шрифт
$pdf->SetDrawColor(181,161,153); // устанавливаем цвет рамки изображения

Далее надо напомнить, что у нас есть массив индентификаторов товаров
// массив идентификаторов товаров
$arrId = какие-то преобразования с массивом($_POST['arrId']);

Создаём все необходимые массивы: для ширины и высоты изображений, для артикула и имён файлов, для веса.
for($i=0; $i<count($arrId); $i++){
    ...
    $arrJpg[$i] // массив названий файлов
    $arrArt[$i] // массив артикулов
    $arrW[$i] // массив ширин файлов в пикселях
    $arrH[$i] // массив высот файлов в пикселях
    $arrM[$i] // массив масс товаров в граммах
    ...
};

Находим максимальные значения ширины и высоты изображений в mm
$maxW=max($arrW)/$k;
$maxH=max($arrH)/$k;

Определяем расстояния (отступы) между колонками и строками изображений. Эти параметры выставляются вручную из соображения визуальной эстетики )))
$tabX=4; // расстояние по оси X (по ширине)
$tabY=15; // расстояние по оси Y (по высоте)

Расчитываем количество колонок (20 берётся из отступов 10+10 по краям документа, см. выше)
$numTD=floor((210-20+$tabX)/($maxW+$tabX));

Расчитываем количесво строк на странице
if($_POST['format45']=="A4"){ $numTR=floor((297-20)/($maxH+$tabY)); };
if($_POST['format45']=="A5"){ $numTR=floor((148.5-20)/($maxH+$tabY)); };

Расчитываем количество товаров на одной странице
$numIdPerPage=$numTD*$numTR;

Расчитываем количество страниц
$numP=ceil(count($arrId)/$numIdPerPage);

Установку языка можно опустить по причинам несущественности в рамках задачи.

Алгоритм

for($page=0; $page<$numP; $page++){

	$pdf->AddPage(); // создаём страницу PDF

    for($tr=0; $tr<$numTR; $tr++){

    	for($td=0; $td<$numTD; $td++){

    		// вводим индентификатор товара-файла
    		$i=$td+$tr*$numTD+$page*$numIdPerPage;

			// если файл-изображение найден и существует, то прорисовывать вывод всех данных
    		if(file_exists("../img/data/".$arrJpg[$i].".jpg")){

    			// вводим индикатор перехода на новую строку
                if($td==$numTD-1){ $ind=1; }else{ $ind=0; };

                // определяем отступы для центрирования изображения в рамке
                $tabW=($maxW-$arrW[$i]/$k)/2; // отступ по оси X (по ширине)
                $tabH=($maxH-$arrH[$i]/$k)/2; // отступ по оси Y (по высоте)

				// показываем изображения
    			$pdf->Image("../img/data/".$arrJpg[$i].".jpg",(10+$td*($maxW+$tabX)+$tabW),(10+$tr*($maxH+$tabY)+$tabH),$arrW[$i]/$k);

				// показываем рамки для картинок
                $pdf->SetXY((10+$td*($maxW+$tabX)),(10+$tr*($maxH+$tabY))); // устанавливаем координаты
				$pdf->Cell($maxW,$maxH,'',1,$ind,'C'); // рисуем рамку
				$pdf->Cell($tabX,0,'',0,$ind); // делаем отступ вправо для следующей рамки

				// показываем вес
				$pdf->SetXY((10+$td*($maxW+$tabX)),(10+$maxH+1+$tr*($maxH+$tabY))); // устанавливаем координаты
				$pdf->Cell($maxW,5,$lng_mass.$arrM[$i],0,$ind,'C'); // пишем массу
				$pdf->Cell($tabX,0,'',0,$ind); // делаем отступ вправо для следующей записи

				// показываем артикул
				$pdf->SetXY((10+$td*($maxW+$tabX)),(10+$maxH+5+$tr*($maxH+$tabY))); // устанавливаем координаты
				$pdf->Cell($maxW,5,$lng_art.$arrArt[$i],0,$ind,'C'); // пишем артикул
				$pdf->Cell($tabX,0,'',0,$ind); // делаем отступ вправо для следующей записи

    			};

    		};

    	};

	};

Рисуем PDF с таким-то именем, параметр D — отправить в браузер и предложить скачать
$pdf->Output($art_cat_title."-ukrzoloto.pdf", "D");


Собственно говоря и всё. Если Вы скачаете небольшие два сгенерированных документа, то в них всё будет наглядно показано, как с помощью PHP и библиотеки FPDF можно действительно делать такую красоту. Для тех, кто хочет развить тему могу посоветовать сделать оригинальную красивую подложку для документа и буклет полностью готов!

Комментарии (1)

RSS свернуть / развернуть
+
0
FPDF такая штука… может понадобится в любой момент, хорошо что напомнил… занесу в избранное
avatar

halkin

  • 22 апреля 2010, 09:38

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.
Не забываем смотреть статистику:

Яндекс цитирования