浏览代码

Реализована генерация таблиц (с дебагом)

Вадим Королёв 1 年之前
父节点
当前提交
e6d863f305
共有 4 个文件被更改,包括 165 次插入63 次删除
  1. 0 4
      index.php
  2. 二进制
      resources/Lato-Regular.ttf
  3. 163 57
      src/Common/Commands.php
  4. 2 2
      src/bootstrap.php

+ 0 - 4
index.php

@@ -17,10 +17,6 @@ use BotKit\Enums\State;
 use BotKit\Enums\CallbackType;
 use BotKit\Keyboards\SelectGroupNameKeyboard;
 
-ini_set('display_errors', '1');
-ini_set('display_startup_errors', '1');
-error_reporting(E_ALL);
-
 $bot = new Bot();
 $drv = new TestDriver();
 $bot->loadDriver($drv);

二进制
resources/Lato-Regular.ttf


+ 163 - 57
src/Common/Commands.php

@@ -48,22 +48,26 @@ class Commands {
 
     // В тему разрешается добавлять и другие ключи, как, например в теме оценок
     
-    private array $theme_schedule =
+    private static array $theme_schedule =
     [
 		"line_spacing"=> 5,
 		"padding"=> 10,
 		"colors"=> [
 			"background"=> [220,220,220],
 			"title_color"=> [30, 30, 30],
-			"body_bg_even"=> [180, 180, 170],
-			"body_bg_odd" => [210, 210, 200],
+			"body_bg_even"=> [0, 255, 0],
+			"body_bg_odd" => [0, 255, 255],
+			//~ "body_bg_even"=> [180, 180, 170],
+			//~ "body_bg_odd" => [210, 210, 200],
 			"body_fg" => [40, 40, 40]
 		],
 		"title_font_size"=> 30,
 		"body_font_size"=> 20,
         "body_line_constraints" => [0, 40, 25],
         "title_line_constraints" => 35,
-        "font" => rootdir.'resources/Lato-Regular.ttf'
+        "font" => rootdir.'/resources/Lato-Regular.ttf',
+        "body_line_height" => 25,
+        "title_line_height" => 35
 	];
     #endregion
 
@@ -175,33 +179,54 @@ class Commands {
                 // 2. Попросить подождать
                 self::askWait($driver, $u);
 
-                // 3. Составить расписание
-                $data = $em->getRepository(Entities\Pair::class)
-                ->getPairsOfScheduleForGroup($schedule);
-
-                $text = "";
-                foreach ($data as $row) {
-                    $time = $row->getTime();
-                    $name = $row->getPairName()->getName();
-                    $details = $row->getConductionDetails();
-
-                    // Составление текста о преподавателе и месте проведения
-                    $details_texts = [];
-                    foreach ($details as $detail) {
-                        $initials = $detail->getEmployee()->getNameWithInitials();
-                        $place = $detail->getPlace()->getName();
-
-                        $details_text[] = $initials.' '.$place;
-                    }
-                    $details_text = implode(' / ', $details_text);
-
-                    $text .= $time->format('H:i');
-                    $text .= $name;
-                    $text .= ":".$details_text;
-                    $text .= "\n";
-                }
+                //~ // 3. Составить расписание
+                //~ $data = $em->getRepository(Entities\Pair::class)
+                //~ ->getPairsOfScheduleForGroup($schedule);
+
+                //~ $text = "";
+                //~ foreach ($data as $row) {
+                    //~ $time = $row->getTime();
+                    //~ $name = $row->getPairName()->getName();
+                    //~ $details = $row->getConductionDetails();
+
+                    //~ // Составление текста о преподавателе и месте проведения
+                    //~ $details_texts = [];
+                    //~ foreach ($details as $detail) {
+                        //~ $initials = $detail->getEmployee()->getNameWithInitials();
+                        //~ $place = $detail->getPlace()->getName();
+
+                        //~ $details_text[] = $initials.' '.$place;
+                    //~ }
+                    //~ $details_text = implode(' / ', $details_text);
+
+                    //~ $text .= $time->format('H:i');
+                    //~ $text .= $name;
+                    //~ $text .= ":".$details_text;
+                    //~ $text .= "\n";
+                //~ }
+
+                //$driver->sendMessage($u, Message::create($text));
+
+                $data =
+                [
+                    ["Время проведения", "Дисциплина", "Кто проводит"],
+                    ["12:28", "Матеша", "лол хз"],
+                    ["Виталий", "балбесина", "ахахах"],
+                    ["шучу", "шучу", "шучу"],
+                    ["12:28", "не матеша", "аааааааааааааааааааааааааааааааа я шучу жеееееееееееееееее"],
+                ];
+
+                $img = self::generateTable(
+                    $data,
+                    "Расписание на сегодня",
+                    self::$theme_schedule,
+                    [__CLASS__, "bodyLineDefault"]
+                );
+
+                $success = self::saveImage($img, "schedule");
+                $driver->varDump('success', $success);
 
-                $driver->sendMessage($u, Message::create($text));
+                //~ $driver->sendMessage($u, Message::create("gpicview ".$filename));
 
                 break;
             default:
@@ -492,7 +517,7 @@ class Commands {
 
     // Разбивает длинную строку на линии, перенося слова
     // (слова - это участки текста, разделённые пробелами)
-	private function splitLongString($text, $line_size) : array {
+	private static function splitLongString($text, $line_size) : array {
 
 		// Не разделять слова
 		if ($line_size == 0) {
@@ -546,12 +571,12 @@ class Commands {
     // $title - название
     // $theme - настройки рисования
     // $draw_body_line - функция отрисовки заднего фона таблицы
-    private function generateTable(
+    private static function generateTable(
         array $data,
         string $title,
         array $theme,
-        callable $draw_body_line) {
-
+        callable $draw_body_line)
+    {
         $width = count($data[0]);
 		$height = count($data);
 
@@ -588,6 +613,7 @@ class Commands {
                 // 2. Вычисление и сохранение размеров текста в яйчейке
                 list($cell_width, $cell_height) = self::getTextSize(
                     $cell_lines,
+                    $theme['body_line_height'],
                     $theme['line_spacing'],
                     $theme['font'],
                     $theme['body_font_size']
@@ -598,26 +624,25 @@ class Commands {
 
                 // 3. Определение макс. размера ширины колонки и высоты текущей
                 // строки
-                $col_sizes[$x] = max($cols_sizes[$x], $cell_width);
+                $col_sizes[$x] = max($col_sizes[$x], $cell_width);
                 $row_height = max($row_height, $cell_height);
             }
 
             $row_sizes[] = $row_height;
             $cells[] = $row_lines;
         }
-		$body_width = array_sum($col_sizes) + $theme['padding'] * 2;
-		$body_height = array_sum($row_sizes) + $theme['padding'] * 2;
+		$body_width = array_sum($col_sizes);
+		$body_height = array_sum($row_sizes);
 
         // Обработка названия таблицы
         $title_lines = self::splitLongString($title, $theme['title_line_constraints']);
         list($title_width, $title_height) = self::getTextSize(
             $title_lines,
+            $theme['title_line_height'],
             $theme['line_spacing'],
             $theme['font'],
             $theme['title_font_size']
         );
-        $title_width += $theme['padding'] * 2;
-        $title_height += $theme['padding'] * 2;
 
         // Вычисление размеров таблицы. Пытаемся сделать квадрат
         $table_width = max($body_width, $title_width);
@@ -632,7 +657,9 @@ class Commands {
         #endregion
 
         #region Отрисовка
-        $im = imagecreatetruecolor($table_width, $table_height);
+        $im = imagecreatetruecolor(
+            $table_width + $theme['padding'] * 2,
+            $table_height + $theme['padding'] * 2);
 
         $gdcolors = [];
 		foreach ($theme['colors'] as $color_name => $color) {
@@ -644,24 +671,44 @@ class Commands {
             );
 		}
 
+        // DEBUG START
+        $gdcolors['dbg_red'] = imagecolorallocate($im, 255, 0, 0);
+        // DEBUG END
+
         // Заполнение заднего фона
 		imagefilledrectangle(
             $im,
             0,
             0,
-            $table_width - 1,
-            $table_height - 1,
+            $table_width + $theme['padding'] * 2 - 1,
+            $table_height + $theme['padding'] * 2 - 1,
             $gdcolors['background']
         );
 
-        // Дальше мы всё рисуем снизу вверх, потому что зачем то разработчики
-        // GD решили в отрисовку текста передавать как Y координату
-        // нижний край, а не верхний
-
         // Отрисовка названия
-		$line_y = $title_height - $theme['padding'];
-		foreach (array_reverse($title_lines) as $line) {
-			$area = imagettftext(
+        // Пробел + высота одной строки
+		$line_y = $theme['padding'] + $theme['title_line_height'];
+		foreach ($title_lines as $line) {
+
+            // DEBUG START
+            $dbgarea = imagettfbbox(
+                $theme['title_font_size'],
+                0,
+                $theme['font'],
+                $line);
+            imagefilledrectangle(
+                $im,
+
+                $theme['padding'],
+                $line_y,
+
+                $theme['padding'] + abs($dbgarea[2] - $dbgarea[0]),
+                $line_y - $theme['title_line_height'],
+
+                $gdcolors['dbg_red']);
+            // DEBUG END
+
+            imagettftext(
                 $im,
                 $theme['title_font_size'],
                 0,
@@ -671,12 +718,19 @@ class Commands {
                 $theme['font'],
                 $line
             );
-			$line_y -= abs($area[1] - $area[5]) + $theme['line_spacing'];
+            // Добавление ещё строки
+			$line_y += $theme['title_line_height'] + $theme['line_spacing'];
 		}
 
         // Отрисовка тела таблицы
-		$line_y = $body_height + $title_height;//+$theme['padding']-$theme['padding'];
-        for ($y = $height - 1; $y > -1; $y--) {
+        $body_y =
+            $theme['padding'] +
+            $theme['title_line_height'] +
+            $theme['padding'];
+        
+		$line_y = $body_y;
+        for ($y = 0; $y < $height; $y++) {
+            // Задний фон строки таблицы
             call_user_func(
                 $draw_body_line,
                 $im,
@@ -687,10 +741,48 @@ class Commands {
                 $theme['padding'], // x1
                 $line_y, // y1
 
-                $body_width - $theme['padding'], // x2
-                $line_y - $row_sizes[$y] // y2
+                $theme['padding'] + $body_width, // x2
+                $line_y + $row_sizes[$y] // y2
 			);
+
+            // Содержимое яйчеек
+            $celltext_x = $theme['padding'] * 2;
+            for ($x = 0; $x < $width; $x++) {
+                $celltext_y = $line_y + $theme['padding'];
+
+                foreach ($cells[$y][$x] as $cell_line) {
+                    imagettftext(
+                        $im,
+                        $theme['body_font_size'],
+                        0,
+                        $celltext_x,
+                        $celltext_y + $theme['body_line_height'],
+                        $gdcolors['body_fg'],
+                        $theme['font'],
+                        $cell_line
+                    );
+                    $celltext_y +=
+                        $theme['body_line_height'] +
+                        $theme['line_spacing'];
+                }
+                $celltext_x += $col_sizes[$x];
+            }
+
+            $line_y += $row_sizes[$y];
         }
+
+        // Рамка таблицы
+        imagerectangle(
+            $im,
+
+            $theme['padding'],
+            $body_y,
+
+            $theme['padding'] + $body_width,
+            $body_y + $body_height,
+
+            $gdcolors['dbg_red']
+        );
         
         #endregion
 
@@ -698,14 +790,21 @@ class Commands {
     }
 
     // Вычисляет высоту и ширину текста без padding в пикселях
-	private function getTextSize($lines, $line_spacing, $font, $font_size) {
+	private static function getTextSize(
+        $lines,
+        $line_height,
+        $line_spacing,
+        $font,
+        $font_size
+    )
+    {
 		$width = 0;
         $height = 0;
 
 		foreach ($lines as $line) {
 			$box = imagettfbbox($font_size, 0, $font, $line);
 			$width = max($width, abs($box[2] - $box[0]));
-            $height += abs($box[1] - $box[5]) + $line_spacing;
+            $height += $line_height + $line_spacing;
 		}
 
         // В последней строке не нужно добавлять расстояния между строками
@@ -715,7 +814,7 @@ class Commands {
 	}
 
     // Отрисовывает обычный задний фон строки таблицы
-    private function bodyLineDefault(
+    private static function bodyLineDefault(
         $im,
         $colors,
         $data,
@@ -732,5 +831,12 @@ class Commands {
 		}
     }
 
+    // Сохраняет изображение в директорию /tmp
+	private static function saveImage($image, $filename_base) : string {
+		$filename = "/home/vad/".$filename_base.rand(1111,9999).".png";
+		return imagepng($image, $filename);
+		return $filename;
+	}
+
     #endregion
 }

+ 2 - 2
src/bootstrap.php

@@ -4,13 +4,13 @@
 // bootstrap.php
 
 // Константы
-define('rootdir', __DIR__.'/../');
+define('rootdir', realpath(__DIR__.'/../'));
 
 // Мы живём в Кировской области
 date_default_timezone_set('Europe/Kirov');
 
 // Автозагрузка через composer
-require_once rootdir."vendor/autoload.php";
+require_once rootdir."/vendor/autoload.php";
 
 // Загрузка .env файла
 $dotenv = \Dotenv\Dotenv::createImmutable(rootdir);