Ширина и высота строки в пикселях

zzzzza
Offline
Зарегистрирован: 18.11.2016

Всем привет!

Вопросы касаются дисплея от "Nokia" (1.44 128x128). Используется библиотека "SPI.h", "Adafruit_GFX.h" и "TFT_ILI9163C.h".

Первый вопрос: как узнать высоту и ширину строки в пикселях, которая отрисовывается на дисплее? (Нужно, чтобы отрисовать строку ровно по середине. А не подбирать вручную)

Второй вопрос: есть функция "setTextSize", которая может принимать 3 значения (1,2 и 3). Значение 1 для меня слишком маленькое, а 2 - слишком большое. Можно ли как-то изменить размер внутри библиотеки?

Заранее спасибо!

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

zzzzza пишет:

Первый вопрос: как узнать высоту и ширину строки в пикселях, которая отрисовывается на дисплее? (Нужно, чтобы отрисовать строку ровно по середине. А не подбирать вручную)

Высоту - посмотреть высоту шрифта в библиотеке. Ширину - сложить вместе ширину всех напечатанных символов.

zzzzza пишет:

Второй вопрос: есть функция "setTextSize", которая может принимать 3 значения (1,2 и 3). Значение 1 для меня слишком маленькое, а 2 - слишком большое. Можно ли как-то изменить размер внутри библиотеки?

Можно добавить свой шрифт или залезть в библиотеку и поменятьсуществующий.

zzzzza
Offline
Зарегистрирован: 18.11.2016

Покопался в исходниках и нашел ответ на первый вопрос:

Чтобы найти высоту и ширину дисплея, надо использовать функции "height()" и "width()" соответственно.

Для определения высоты и ширины строки существует функция "getTextBounds(char*, int16_t, int16_t, int16_t*, int16_t*, uint16_t*, uint16_t*)" (более красивый вид "getTextBounds(string, x, y, &x1, &y1, &w, &h)"), где 

первый аргумент - строка.

второй - координата x, откуда рисуется строка.

третий - координата y, откуда рисуется строка.

четвертый - в него будет записана координата x1, то есть где заканчивается строка по x.

третий - в него будет записана координата y1, то есть где заканчивается строка по y.

пятый - в него будет записана ширина строки в пикселях.

шестой - в него будет записана высота строки в пикселях.

Получается, чтобы нарисовать строку посередине (по x), нужно вычислить "(width()-w)/2". 

Проблемы, которые были замечаны:

1) Функция "getTextBounds" не возвращает x1 и y1 (точнее возвращает "0").

2) В старых версиях библиотеки "Adafruit_GFX.h" функция "getTextBounds" постоянно возвращает значение w и h (ширины и длины) равное"65565". В последней версии на текущую дату, ширина и длина возвращаются корректно, кроме случая, когда строка состоит из русских букв. В этом случае надо поделить w и h на 2. (почему так происходит - не знаю. Найдено экспериментально).

3) Если засунуть строку (то есть переменную типа "String" или просто написать, допустим, "Hello World") в первый аргумент функции "getTextBounds", то появится предупреждение, так как первый аргумент - это "char*", а не "String". На работу это никак не повлияет, но кого-то может смутить, поэтому можно использовать функцию, которая будет преобразовывать "String" в "char*" (функция "string2char" в примере ниже).

Пример:

1) Подключение и определение всего необходимого:

#include <string.h> //Библиотека для работы со строками.

/*Все, что относится к дисплею*/
#include <SPI.h>            // Подключаем библиотеку для работы с устройством по интерфейсу SPI
#include <Adafruit_GFX.h>   // Подключаем библиотеку для работы с текстом и графикой
#include <TFT_ILI9163C.h>   // Подключаем библиотеку программных драйверов для работы с дисплеем 1.44 128x128 SPI 

// В следующих 8-и строках опеределяем названия и соответствующие им RGB обозначения цветов, которые будем выводить на дисплей
#define BLACK  0x0000
#define BLUE    0x001F
#define RED     0xF800  
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0  
#define WHITE   0xFFFF

#define __CS 10                                           // Определяем пин к которому подключен разъем CS дисплея
#define __DC 9                                            // Определяем пин к которому подключен разъем A0 дисплея
#define __RES 8                                           // Определяем пин к которому подключен разъем RESET дисплея
TFT_ILI9163C display = TFT_ILI9163C(__CS, __DC, __RES);   // Связываем объект display с библиотекой TFT_ILI9163C и сообщаем библиотеке определенные для работы с дисплеем пины
/*Конец того, что относится к дисплею*/

2) Специальные функции:

/******************************************СПЕЦИАЛЬНЫЕ ФУНКЦИИ*************************************************************/
/* Recode russian fonts from UTF-8 to Windows-1251 */
String utf8rus(String source)     // Функция для конвертации русских символов из кодировки CP1251 в UTF8
{
  int i,k;
  String target;
  unsigned char n;
  char m[2] = { '0', '\0' };
  k = source.length(); i = 0;
  while (i < k) {
    n = source[i]; i++;
 
    if (n >= 0xBF){
      switch (n) {
        case 0xD0: {
          n = source[i]; i++;
          if (n == 0x81) { n = 0xA8; break; }
          if (n >= 0x90 && n <= 0xBF) n = n + 0x2F;
          break;
        }
        case 0xD1: {
          n = source[i]; i++;
          if (n == 0x91) { n = 0xB7; break; }
          if (n >= 0x80 && n <= 0x8F) n = n + 0x6F;
          break;
        }
      }
    }
    m[0] = n; target = target + String(m);
  }
  return target;
}



char* string2char(String command) //Нужна, чтобы переводить строку в массив char. (Чтобы считать ширину и высоту строки)
 {
    if(command.length()!=0){
        char *p = const_cast<char*>(command.c_str());
        return p;
    }
 }
/*******************************************************************************************************************/

3) Функции рисования:

/******************************************DRAW ФУНКЦИИ*************************************************************/
void drawScreen1() //Рисует все, что отображено на первом экране.
 {
  //рисуем заголовок.
  display.setTextSize(2); //Определяем размер шрифта.
  display.setTextColor(BLACK); //Определяем цвет вывода на дисплей

  int16_t x1, y1;
  uint16_t w, h;
  String str = "Privet!";
  display.getTextBounds(string2char(str), 0, 0, &x1, &y1, &w, &h);
  display.setCursor((display.width()-w)/2, 2); //Устанавливаем курсор.
  display.print(str);
 }
/*******************************************************************************************************************/

4) "Setup" и "Void":

/******************************************SETUP***************************************************************/
void setup()
 {
  /*Все, что относится к дисплею*/
  display.begin(); // Иницализируем дисплей.

  drawScreen1(); //Рисуем первый экран.
  /*Конец того, что относится к дисплею*/
 }
/**************************************************************************************************************/





/******************************************LOOP*****************************************************************/
void loop()
 {
  
 }
/**************************************************************************************************************/

Со второй проблемой пока что не разобрался.

DenSyo
Offline
Зарегистрирован: 13.01.2017

zzzzza пишет:
В последней версии на текущую дату, ширина и длина возвращаются корректно, кроме случая, когда строка состоит из русских букв. В этом случае надо поделить w и h на 2. (почему так происходит - не знаю. Найдено экспериментально).

display.getTextBounds(string2char(utf8rus(str)), 0, 0, &x1, &y1, &w, &h);

потому что смысл работы с русскими буквами сводится к противоположному сказанному в коментариях кода, функция utf8rus возвращает строку CP1251 из UTF8. однобайтовое значение из двухбайтового. в случае моноширных шрифтов можно смело делить ширину на два, а с пропорциональными будет лажа. читать

arduinec
Offline
Зарегистрирован: 01.09.2015

Есть версия utf8rus(), которая работает со строками *char: #40 http://arduino.ru/forum/programmirovanie/rusifikatsiya-biblioteki-adafru...