Есть ли способ использовать эмодзи с «игрушечным» текстовым API Каира?

Есть ли какой-нибудь шрифт или метод, который я могу использовать с Cairo (через привязки Ruby) для рисования текста, содержащего смайлики? Все, что я читал, говорит: «используйте Pango для реальной обработки текста», но Cairo делает все остальное, что мне нужно, поэтому я надеюсь, что есть способ избежать добавления этого в качестве зависимости.

Вот упрощенная версия динамических изображений Open Graph, которые я пытаюсь сделать:

require 'cairo'

# Create a new image surface based on recommended OpenGraph dimensions
width = 1_200
height = 630
surface = Cairo::ImageSurface.new(width, height)

# Create a Cairo Context for the surface
cr = Cairo::Context.new(surface)

# Apply a background colour to the whole thing (almost white)
cr.set_source_rgb(0.95, 0.95, 0.95)
cr.paint

# Add a heading
heading = "Hi! 👋"
cr.set_source_rgb(0.31, 0.21, 0.27)
cr.select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_BOLD)
cr.set_font_size(100.0)
extents = cr.text_extents(heading)
centred_text_left_edge = width / 2 - extents.width / 2
cr.move_to(centred_text_left_edge, 130)
cr.show_text(heading)

# Write the image surface to a PNG file
surface.write_to_png("emoji-test-#{Time.now.strftime('%Y-%m-%dT%H:%M:%S.%L%z')}.png")

К сожалению, эмодзи отображается в виде прямоугольника (работает на macOS, может отличаться на других платформах):

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

Кажется, что «правильный» вариант — использовать Pango, но актуален ли этот совет и применим ли он к Ruby? Я не смог установить драгоценный камень Pango на свой M1 Mac, и даже если бы я мог, после долгих поисков единственное упоминание, которое я могу найти об использовании Pango с Cairo от Ruby, — это очень старый образец сценария, который больше не включен в Раздача Панго.

В противном случае, я думаю, мне придется сохранить смайлики в виде изображений и нарисовать их на поверхности/контексте. Это возможно для меня, потому что я хочу использовать только 3 конкретных смайлика, но он не масштабируется для включения произвольных смайликов.

Похоже, ваш смайлик имеет кодовую точку Unicode U+1F44B, и я уверен, что ваша программа справится с этим. Однако вы не говорите, как вы собираетесь «отображать» этот вывод. Включает ли программа, которая его отображает, шрифт, содержащий определения для U+1F44B?

user1934428 17.04.2023 16:22

Наверное, надо было немного понятнее. Я пытаюсь создавать динамические изображения OpenGraph (предварительный просмотр в социальных сетях, когда вы делитесь ссылкой), поэтому я визуализирую изображение в формате PNG с помощью surface.write_to_png

Matthew 19.04.2023 02:41

Никогда не работал с Cairo, но можно предположить, что файл определения шрифта, который вы выбираете с помощью cr.select_font_face, не содержит определения для U+1F44B. Есть ли способ указать в Cairo некоторый «запасной» шрифт на случай, если в выбранном шрифте не удается найти символ UTF8?

user1934428 19.04.2023 09:12

Cairo действительно не хочет заниматься выбором шрифта. Да, есть способ получить резервные шрифты. Они могут сделать это самостоятельно, выбрав шрифт. Это означает, что вместо cairo_show_text() вы можете играть с масштабируемыми шрифтами и API, такими как cairo_show_glyphs(). Если вы не хотите реализовывать необходимый код самостоятельно, вы можете использовать какую-то существующую реализацию. Например, Pango делает выбор шрифта.

Uli Schlachter 21.04.2023 11:59
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
0
4
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я с радостью приму другой ответ, если у кого-то есть лучшее решение, но в итоге я вернулся к рисованию смайликов в PNG. Дочитайте до конца минусы этого подхода.

Сначала я сохранил в формате PNG 96x96 пикселей смайлики, которые хотел использовать (например, wave.png). Затем я нарисовал их на поверхности. Вот ПОК:

require 'cairo'

# Create a new image surface based on recommended OpenGraph dimensions
width = 1_200
height = 630
surface = Cairo::ImageSurface.new(width, height)

# Create a Cairo Context for the surface
cr = Cairo::Context.new(surface)

# Apply a background colour to the whole thing (almost white)
cr.set_source_rgb(0.95, 0.95, 0.95)
cr.paint

# Set up the heading
string = "Hi!"
cr.set_source_rgb(0.31, 0.21, 0.27)
cr.select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_BOLD)
cr.set_font_size(100.0)
text_box = cr.text_extents(string)

# Set up the emoji image
image = Cairo::ImageSurface.from_png("wave.png")

# Position the text in the centre (taking into account the image width)
horizontal_gap = 20 # trial and error
top_of_text = 130 # trial and error
line_width = text_box.width + image.width + horizontal_gap
text_left_edge = (width - line_width) / 2 # centred on page
cr.move_to(text_left_edge, top_of_text)
cr.show_text(string)

# Position the image next to the text
top_of_image = top_of_text - 85 # trial and error
image_left_edge = text_left_edge + text_box.width + horizontal_gap
cr.set_source(image, image_left_edge, top_of_image)
cr.paint

# Write the image surface to a PNG file
surface.write_to_png("emoji-test.png")

Это генерирует мое изображение OpenGraph с текстом и эмодзи:

Недостатками такого подхода являются:

  • Вам нужно создать каждый смайлик PNG отдельно
  • Независимое масштабирование изображений оказалось для меня трудным (я также рисую логотип на поверхности), поэтому мне пришлось сделать PNG в точном размере, который я хотел, чтобы они отображались.
  • Потребовалось много проб и ошибок, чтобы текст и изображения были расположены удовлетворительно.
  • Риски авторского права... Я не юрист, но я уверен, что не могу законно использовать изображения эмодзи Apple (или Microsoft, или Google) без разрешения:

Другие вопросы по теме