PHP. Преобразование таблицы в картинку. Создание информеров.

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

Однажды задумал я сделать некоторое количество информеров с тем, чтобы привлечь дополнительных посетителей на сайт. Я уже упомянул о том, что его основной темой была футбольная статистика, и естественно было бы предложить пользователям таблицы различных чемпионатов, вот тогда-то и появилась идея написать функцию для конвертирования двумерного массива в картинку. Использование изображения показалось мне наиболее приемлемым вариантом, потому как в это случае информер можно расположить, где угодно, в том числе и на многочисленных форумах и блогах.

Цель: Написать функцию, которая преобразует двумерный ассоциированный массив в соответствующую картинку. Предполагается что первый индекс массива - число, а второй строка.

Итак, функция для формирования таблицы выглядит следующим образом.

  1.  
  2. function ImageCreateTable($array, $config)
  3. {
  4. //Определение некоторых параметров по умолчанию
  5. if(!defined('IMAGE_CREATE_TABLE_DEFAULTS'))
  6. { //set default values
  7. define('IMAGE_CREATE_TABLE_DEFAULTS', 1);
  8. define('IMGCT_SPACE', 4);
  9. define('IMGCT_FONT', "verdana");
  10. define('IMGCT_FONT_SIZE', 10);
  11. }
  12.  
  13. //Определение параметров для отрисовки картинки
  14. $space = isset($config['space']) ? $config['space'] : IMGCT_SPACE;
  15. putenv('GDFONTPATH=' . realpath('.'));
  16. $font = isset($config['font']) ? $config['font'] : IMGCT_FONT;
  17. $font_size = isset($config['font_size']) ? $config['font_size'] : IMGCT_FONT_SIZE;
  18.  
  19. $color_white = array('r' => 255, 'g' => 255, 'b' => 255);
  20. $color_black = array('r' => 0, 'g' => 0, 'b' => 0);
  21. $color_blue = array('r' => 0, 'g' => 0, 'b' => 255);
  22.  
  23. $color_head = isset($config['color_head']) ? $config['color_head'] : $color_white;
  24. $color_odd = isset($config['color_odd']) ? $config['color_odd'] : $color_white;
  25. $color_even = isset($config['color_even']) ? $config['color_even'] : $color_white;
  26. $color_text = isset($config['color_text']) ? $config['color_text'] : $color_black;
  27. $color_line = isset($config['color_line']) ? $config['color_line'] : $color_black;
  28.  
  29. $fixed_height = isset($config['fixed_height']) ? $config['fixed_height'] : 0;
  30.  
  31. $width = 0;
  32. $height = 0;
  33.  
  34. $rows = count($array);
  35. //Временная картинка, в которой происходит отрисовка текста, с целью определения его размеров
  36. $tim = @ImageCreate (1, 1)
  37. or die ("Cannot Initialize new GD image stream");
  38.  
  39. $text_color = ImageColor($tim, $color_text);
  40.  
  41. //Отрисовка таблицы
  42. if($rows)
  43. {
  44. $cols = count($array[0]);
  45. $keys_list = array_keys($array[0]);
  46.  
  47. $cols_width = array();
  48. $rows_height = array();
  49. $coords = array();
  50.  
  51. $coords = ImageTTFText($tim, $font_size, 0, 0, 0, $text_color, $font, 'MagicString');
  52. $base_height = $coords[1]-$coords[5];
  53.  
  54. //Определение высоты заголовка и первоначальой ширины каждой колонки
  55. for($i=0; $i<$cols; $i++)
  56. {
  57. $head[$i] = isset($config["head_col$i"]) ? $config["head_col$i"] : $keys_list[$i];
  58. $coords = ImageTTFText($tim, $font_size, 0, 0, 0, $text_color, $font, ''.$head[$i]);
  59. $cols_width[$i] = $coords[2];
  60. $array[ -1][$keys_list[$i]] = $head[$i];
  61. if(!isset($rows_height[ -1]))
  62. {
  63. $rows_height[ -1] = 0;
  64. }
  65. $rows_height[ -1] = max($rows_height[ -1], $coords[1]-$coords[5]);
  66. }
  67.  
  68. //Определение высоты строк и ширины столбцов
  69. for($i=0; $i<$cols; $i++)
  70. {
  71. for($j=0; $j<$rows; $j++)
  72. {
  73. $array[$j][$keys_list[$i]] = str_replace("\t", " ", $array[$j][$keys_list[$i]]);
  74. $coords = ImageTTFText($tim, $font_size, 0, 0, 0, $text_color, $font, ''.$array[$j][$keys_list[$i]]);
  75. $cols_width[$i] = max($cols_width[$i], $coords[2]);
  76.  
  77. if(!isset($rows_height[$j]))
  78. {
  79. $rows_height[$j] = 0;
  80. }
  81. $rows_height[$j] = max($rows_height[$j], $coords[1]-$coords[5]);
  82.  
  83. $text = implode(', ', $cols_width);
  84. }
  85. }
  86.  
  87. //Переопределение высоты строк если для них задана фиксированная высота.
  88. if($fixed_height != 0)
  89. {
  90. for($j=-1; $j<$rows; $j++)
  91. {
  92. $rows_height[$j] = max($rows_height);
  93. }
  94. }
  95.  
  96. //Переопределение ширины столбцов. Конечно написано неоптимально, но отражает эволюцию кода,
  97. //в котором первоначально не было этих настроек.
  98. for($i=0; $i<$cols; $i++)
  99. {
  100. $cols_width[$i] = isset($config['width_base']) ? $config['width_base'] : $cols_width[$i];
  101. $cols_width[$i] = isset($config["width_col$i"]) ? $config["width_col$i"] : $cols_width[$i];
  102. }
  103.  
  104. $width = array_sum($cols_width);
  105. $height = array_sum($rows_height);
  106. }
  107.  
  108. //Расчет размеров итоговой картинки
  109. $width += $cols*$space*2 + 1;
  110. $height += $rows*$space*2 + 1;
  111. $height += $space * 2;
  112. $im = @ImageCreate ($width, $height)
  113. or die ("Cannot Initialize new GD image stream");
  114.  
  115. //Определение цветов
  116. $head_color = ImageColor($im, $color_head);
  117. $odd_color = ImageColor($im, $color_odd);
  118. $even_color = ImageColor($im, $color_even);
  119. $text_color = ImageColor($im, $color_text);
  120. $line_color = ImageColor($im, $color_line);
  121.  
  122. $x = 0;
  123.  
  124. //Отрисовка таблицы
  125. ImageLine($im, 0, 0, $width, 0, $line_color);
  126. ImageLine($im, 0, 0, 0, $height, $line_color);
  127. for($i=0; $i<$cols; $i++)
  128. {
  129. $y = 0;
  130. for($j=-1; $j<$rows; $j++)
  131. {
  132. $py /*previous value*/ = $y;
  133. $y += $rows_height[$j]+$space*2;
  134. if($i == 0)
  135. {
  136. if($j == -1)
  137. {
  138. ImageFilledRectangle($im, 1, $py + 1, $width - 1, $y - 1, $head_color);
  139. }
  140. else if($j%2)
  141. {
  142. ImageFilledRectangle($im, 1, $py + 1, $width - 1, $y - 1, $even_color);
  143. }
  144. else
  145. {
  146. ImageFilledRectangle($im, 1, $py + 1, $width - 1, $y - 1, $odd_color);
  147. }
  148. }
  149.  
  150. ImageTTFText($im, $font_size, 0,
  151. $x + $space / 2 + 2 /*magic number*/,
  152. $py + $base_height + $space / 2,
  153. $text_color, $font, ''.$array[$j][$keys_list[$i]]);
  154.  
  155. if($i == 0)
  156. {
  157. ImageLine($im, 0, $y, $width, $y, $line_color);
  158. }
  159. }
  160. $x += $cols_width[$i]+$space*2;
  161. ImageLine($im, $x, 0, $x, $height, $line_color);
  162. }
  163. return $im;
  164. }
  165. }
  166.  
  167.  

Для того чтобы настроить внешний вид получаемой таблицы пользователь может передать соответствующие настройки с помощью ассоциированного массива $config, указав значения для следующих ключей:

  • 'space' – расстояние от границы ячейки до текста, аналогично параметру cellpadding, который используется в html, должно быть не меньше 4 для корректного отображения;
  • 'font' – имя файла со шрифтом, значение по умолчанию – verdana.ttf;
  • 'font_size' – размер шрифта, значение по умолчанию – 10.

    Цвета, используемые в таблице, определяются как ассоциированный массив с ключами r, g и b. По умолчанию цвет фона всех строк белый, а текст и бордюр таблицы – черный.

  • 'color_head' – цвет фона для первой строки таблицы (заголовка);
  • 'color_odd' – цвет фона для нечетной строки;
  • 'color_even' – цвет фона для четной строки;
  • 'color_text' – цвет текста;
  • 'color_line' – цвет границы.

    Прочие настройки:

  • 'head_col#' – заголовок колонки, номер которой необходимо подставит взамен #, по умолчанию заголовком колонки будет соответствующий ключ массива;
  • 'width_base' – базовая ширина колонки;
  • 'width_col#' – ширина указанной колонки, по умолчанию размер колонки рассчитывается в зависимости от ее содержимого;
  • 'fixed_height' – высота строки, которая может принимать два значения: 0 для случая, когда высота каждой строки определяется ее содержимым и 1, если высоты строк должны быть равны, при этом в качестве эталона выбирается самая высокая.

    В тексте несколько раз встречался вызов функции ImageColor, которая необходима для назначения цвета.

    1.  
    2. function ImageColor($im, $color_array)
    3. {
    4. $im,
    5. isset($color_array['r']) ? $color_array['r'] : 0,
    6. isset($color_array['g']) ? $color_array['g'] : 0,
    7. isset($color_array['b']) ? $color_array['b'] : 0
    8. );
    9. }
    10.  
    11.  

    Теперь приведу код необходимый для отображения полученной картинки, необходимо отметить, что он должен располагаться в отдельном файле.

    1.  
    2.  
    3. function array_convert_encoding(&$array, $to_encoding = 'UTF-8', $from_encoding = 'windows-1251')
    4. {
    5. foreach ($array as $key => $value)
    6. {
    7. if(is_array($value))
    8. {
    9. array_convert_encoding($array[$key], $to_encoding, $from_encoding);
    10. }
    11. else
    12. {
    13. $array[$key] = mb_convert_encoding($value, $to_encoding, $from_encoding);
    14. }
    15. }
    16. }
    17.  
    18. $table = array(
    19. 0 => array('country' => 'Хорватия'
    20. , 'games' => '12', 'wins' => '9', 'draws' => '2', 'defeats' => '1', 'goals' => '26 - 8', 'points' => '29' )
    21. , 1 => array('country' => 'РОССИЯ'
    22. , 'games' => '12', 'wins' => '7', 'draws' => '3', 'defeats' => '2', 'goals' => '20 - 7', 'points' => '24' )
    23. , 2 => array('country' => 'Англия'
    24. , 'games' => '12', 'wins' => '7', 'draws' => '2', 'defeats' => '3', 'goals' => '24 - 7', 'points' => '23' )
    25. , 3 => array('country' => 'Израиль'
    26. , 'games' => '12', 'wins' => '7', 'draws' => '2', 'defeats' => '3', 'goals' => '20 - 12', 'points' => '23' )
    27. , 4 => array('country' => 'Македония'
    28. , 'games' => '12', 'wins' => '4', 'draws' => '2', 'defeats' => '6', 'goals' => '12 - 12', 'points' => '14' )
    29. , 5 => array('country' => 'Эстония'
    30. , 'games' => '12', 'wins' => '2', 'draws' => '1', 'defeats' => '9', 'goals' => '5 - 21', 'points' => '7' )
    31. , 6 => array('country' => 'Андорра'
    32. , 'games' => '12', 'wins' => '0', 'draws' => '0', 'defeats' => '12', 'goals' => '2 - 41', 'points' => '0' )
    33. );
    34. array_convert_encoding($table);
    35.  
    36. $config = array();
    37.  
    38. $im = ImageCreateTable($table, $config);
    39.  
    40. header ("Content-type: image/png");
    41. ImagePng ($im);
    42.  
    43.  

    Результатом работы этого скрипта будет следующее изображение.

    Теперь немного раскрасим таблицу, задав соответствующие настройки.

    1.  
    2. $config = array();
    3.  
    4. $config['color_head'] = array('r' => 160, 'g' => 200, 'b' => 250);
    5. $config['color_odd'] = array('r' => 220, 'g' => 220, 'b' => 220);
    6. $config['color_even'] = array('r' => 250, 'g' => 250, 'b' => 250);
    7. $config['head_col0'] = 'Страна';
    8. $config['head_col1'] = 'И';
    9. $config['head_col2'] = 'В';
    10. $config['head_col3'] = 'Н';
    11. $config['head_col4'] = 'П';
    12. $config['head_col5'] = 'М';
    13. $config['head_col6'] = 'О';
    14. $config['width_base'] = 50;
    15. $config['width_col0'] = 100;
    16. $config['fixed_height'] = 1;
    17.  
    18. array_convert_encoding($config);
    19.  
    20.  

    Очень часто таблицы являются наиболее удобным способом представления информации, а используя вышеописанную методику можно легко создавать табличные информеры.

    Читайте в блоге

    Повторное экранирование кавычек в PHP
    Полезные ссылки
    MFC. Использование HTML-интерфейса.

  • Комментарии:

    Александр @ 02.09.2011 19:05

    Здравствуйте. Должен Вам сказать, статья очень полезная. Но вот меня интересует как можно реализовать вот такой пример: http://www.avtobeginner.ru/nomer/
    Если Вас не затруднит, не могли бы мне помочь, пожалуйста?
    Андрей @ 05.10.2011 18:19

    Здравствуйте! Можно ли взять вышеприведенный код за основу для своего класса-враппера над таблицей данных?
    Владимир Рыбаков @ 05.10.2011 23:14

    Да, конечно, можно, как и любой другой код опубликованный на сайте.
    Ruslan Thumbo @ 25.03.2015 11:12

    Спасибо за скрипт! Пробовал запускать, выводит в картинку пустую таблицу без текста, все перепробовал ничего не получается. Как думаете в чем может быть проблема?

    Войдите на сайт, чтобы оставить комментарий