Skip to content

Commit 615d228

Browse files
committed
Generate social images
- Fixes #1723
1 parent 4052f99 commit 615d228

File tree

221 files changed

+183
-23
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

221 files changed

+183
-23
lines changed

Gemfile

+6-1
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,10 @@ gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
3333
# Performance-booster for watching directories on Windows
3434
gem "wdm", "~> 0.1.0" if Gem.win_platform?
3535

36-
3736
gem "webrick", "~> 1.7"
37+
38+
# Used in _plugins/social_images.rb
39+
gem "chunky_png", "~> 1.4.0"
40+
gem 'rsvg2', '~> 4.1.7'
41+
gem "cairo", "~> 1.17.9"
42+
gem "rake", "~> 13.0.1"

Gemfile.lock

+53-21
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
11
GEM
22
remote: https://rubygems.org/
33
specs:
4-
addressable (2.8.0)
5-
public_suffix (>= 2.0.2, < 5.0)
6-
asciidoctor (2.0.15)
4+
addressable (2.8.4)
5+
public_suffix (>= 2.0.2, < 6.0)
6+
asciidoctor (2.0.20)
7+
cairo (1.17.9)
8+
native-package-installer (>= 1.0.3)
9+
pkg-config (>= 1.2.2)
10+
red-colors
11+
cairo-gobject (4.1.7)
12+
cairo (>= 1.16.2)
13+
glib2 (= 4.1.7)
14+
chunky_png (1.4.0)
715
colorator (1.1.0)
8-
concurrent-ruby (1.1.8)
9-
em-websocket (0.5.2)
16+
concurrent-ruby (1.2.2)
17+
em-websocket (0.5.3)
1018
eventmachine (>= 0.12.9)
11-
http_parser.rb (~> 0.6.0)
19+
http_parser.rb (~> 0)
1220
eventmachine (1.2.7)
13-
ffi (1.15.0)
21+
ffi (1.15.5)
22+
fiddle (1.1.1)
1423
forwardable-extended (2.6.0)
15-
http_parser.rb (0.6.0)
16-
i18n (1.8.10)
24+
gdk_pixbuf2 (4.1.7)
25+
gio2 (= 4.1.7)
26+
gio2 (4.1.7)
27+
fiddle
28+
gobject-introspection (= 4.1.7)
29+
glib2 (4.1.7)
30+
native-package-installer (>= 1.0.3)
31+
pkg-config (>= 1.3.5)
32+
gobject-introspection (4.1.7)
33+
glib2 (= 4.1.7)
34+
http_parser.rb (0.8.0)
35+
i18n (1.14.1)
1736
concurrent-ruby (~> 1.0)
1837
jekyll (4.1.1)
1938
addressable (~> 2.4)
@@ -35,57 +54,70 @@ GEM
3554
jekyll-asciidoc (3.0.0)
3655
asciidoctor (>= 1.5.0)
3756
jekyll (>= 3.0.0)
38-
jekyll-feed (0.15.1)
57+
jekyll-feed (0.17.0)
3958
jekyll (>= 3.7, < 5.0)
4059
jekyll-paginate-v2 (3.0.0)
4160
jekyll (>= 3.0, < 5.0)
42-
jekyll-sass-converter (2.1.0)
61+
jekyll-sass-converter (2.2.0)
4362
sassc (> 2.0.1, < 3.0)
44-
jekyll-seo-tag (2.7.1)
63+
jekyll-seo-tag (2.8.0)
4564
jekyll (>= 3.8, < 5.0)
4665
jekyll-watch (2.2.1)
4766
listen (~> 3.0)
48-
kramdown (2.3.1)
67+
kramdown (2.4.0)
4968
rexml
5069
kramdown-parser-gfm (1.1.0)
5170
kramdown (~> 2.0)
52-
liquid (4.0.3)
53-
listen (3.5.1)
71+
liquid (4.0.4)
72+
listen (3.8.0)
5473
rb-fsevent (~> 0.10, >= 0.10.3)
5574
rb-inotify (~> 0.9, >= 0.9.10)
75+
matrix (0.4.2)
5676
mercenary (0.4.0)
5777
minima (2.5.1)
5878
jekyll (>= 3.5, < 5.0)
5979
jekyll-feed (~> 0.9)
6080
jekyll-seo-tag (~> 2.1)
81+
native-package-installer (1.1.5)
6182
pathutil (0.16.2)
6283
forwardable-extended (~> 2.6)
63-
public_suffix (4.0.6)
64-
rb-fsevent (0.11.0)
84+
pkg-config (1.5.1)
85+
public_suffix (5.0.1)
86+
rake (13.0.6)
87+
rb-fsevent (0.11.2)
6588
rb-inotify (0.10.1)
6689
ffi (~> 1.0)
90+
red-colors (0.3.0)
91+
matrix
6792
rexml (3.2.5)
68-
rouge (3.26.0)
93+
rouge (3.30.0)
94+
rsvg2 (4.1.7)
95+
cairo-gobject (= 4.1.7)
96+
gdk_pixbuf2 (= 4.1.7)
6997
safe_yaml (1.0.5)
7098
sassc (2.4.0)
7199
ffi (~> 1.9)
72100
terminal-table (1.8.0)
73101
unicode-display_width (~> 1.1, >= 1.1.1)
74-
unicode-display_width (1.7.0)
75-
webrick (1.7.0)
102+
unicode-display_width (1.8.0)
103+
webrick (1.8.1)
76104

77105
PLATFORMS
78106
ruby
79107

80108
DEPENDENCIES
109+
cairo (~> 1.17.9)
110+
chunky_png (~> 1.4.0)
81111
jekyll (~> 4.1.1)
82112
jekyll-archives
83113
jekyll-asciidoc
84114
jekyll-feed (~> 0.6)
85115
jekyll-paginate-v2
86116
minima (~> 2.0)
117+
rake (~> 13.0.1)
118+
rsvg2 (~> 4.1.7)
87119
tzinfo-data
88120
webrick (~> 1.7)
89121

90122
BUNDLED WITH
91-
2.2.16
123+
2.4.10

_layouts/base.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
<meta property="og:url" content="{{ page.url | prepend: site.url }}" />
3535
<meta property="og:title" content="{{ page.title }}{{ page_title_version_suffix }}" />
3636
<meta property="og:description" content="{% if page.description %}{{ page.description }}{% else %}{{ site.description }}{% endif %}" />
37-
<meta property="og:image" content="{{ '/assets/images/quarkus_card.png' | prepend: site.url }}" />
37+
<meta property="og:image" content="{{ page.social_image | social_image: page.path | prepend: site.url }}" />
3838
{% if page.layout == 'guides' or page.layout == 'guides-index' %}
3939
{%assign canonical_url = page.url | replace_regex: '^/version/[^/]+', '' %}
4040
{% else %}
237 KB

_plugins/social_images.rb

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
require 'chunky_png'
2+
require 'cairo'
3+
require 'rsvg2'
4+
5+
module Jekyll
6+
# Generates social images for blog posts and guides
7+
module SocialImages
8+
def social_image(text, page_path)
9+
# If text is not empty, return it
10+
if text.nil? || text.empty?
11+
# If page_path contains "guides/", return the social image path
12+
if page_path.include?('guides/')
13+
return "/assets/images/social/#{File.basename(page_path, '.adoc')}.png"
14+
else
15+
return "/assets/images/quarkus_card.png"
16+
end
17+
else
18+
text
19+
end
20+
end
21+
end
22+
23+
class GenerateSocialImagesGenerator < Generator
24+
def generate(site)
25+
guides = Dir.glob(File.join(site.source, '_guides', '*.adoc'))
26+
output_dir = 'assets/images/social'
27+
FileUtils.mkdir_p(File.join(site.source, output_dir))
28+
29+
guides.each do |guide_file|
30+
basename = File.basename(guide_file, '.adoc')
31+
if basename.start_with?('_')
32+
next
33+
end
34+
title = extract_title(guide_file)
35+
output_file = File.join(site.source, output_dir, "#{basename}.png")
36+
# Skip if the file already exists
37+
if File.exist?(output_file)
38+
next
39+
end
40+
41+
# Generate the SVG image
42+
svg_image_str = generate_svg_string(title)
43+
44+
# Create a Cairo surface and context for the PNG image (must be smaller than 600x330)
45+
surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, 600, 250)
46+
context = Cairo::Context.new(surface)
47+
48+
# Load and render the SVG onto the Cairo context
49+
svg = RSVG::Handle.new_from_data(svg_image_str)
50+
context.render_rsvg_handle(svg)
51+
52+
# Save the Cairo surface to a PNG file
53+
b = StringIO.new
54+
surface.write_to_png(b)
55+
56+
# Compose the generated image with the template image
57+
png_image = ChunkyPNG::Image.from_file('_plugins/assets/quarkus_card_blank.png')
58+
# Change the last parameters to change the position of the generated image
59+
png_image.compose!(ChunkyPNG::Image.from_blob(b.string), 0, 80)
60+
61+
Jekyll.logger.info("Generating social image to #{output_file}")
62+
# Save the composed image to the output file
63+
png_image.save(output_file)
64+
end
65+
end
66+
67+
def split_text_into_lines(text)
68+
lines = []
69+
words = text.split(' ')
70+
current_line = ''
71+
72+
words.each do |word|
73+
if current_line.length + word.length <= 32
74+
current_line += (current_line == '' ? '' : ' ') + word
75+
else
76+
lines.push(current_line)
77+
current_line = word
78+
end
79+
end
80+
81+
lines.push(current_line) unless current_line.empty?
82+
83+
lines
84+
end
85+
86+
private
87+
88+
def generate_svg_string(title)
89+
idx = 90
90+
font_size = 30
91+
tspan_elements = ''
92+
split_text_into_lines(title).each_with_index do |line, index|
93+
tspan_elements += "<tspan x='50%' y='#{idx}'>#{line}</tspan>"
94+
idx += font_size + 10
95+
end
96+
"
97+
<svg width=\"600\" height=\"330\">
98+
<style>
99+
.title { fill: white; font-size: #{font_size}px; font-weight: bold; font-family:'Open Sans'}
100+
</style>
101+
<text x=\"50%\" y=\"50%\" text-anchor=\"middle\" class=\"title\" >
102+
#{tspan_elements}
103+
</text>
104+
</svg>
105+
"
106+
end
107+
108+
def extract_title(adoc_file)
109+
title = ''
110+
File.open(adoc_file, 'r') do |file|
111+
file.each_line do |line|
112+
if line.start_with? '='
113+
title = line[2..].strip
114+
break
115+
end
116+
end
117+
end
118+
title
119+
end
120+
end
121+
end
122+
123+
Liquid::Template.register_filter(Jekyll::SocialImages)

assets/images/social/README.png

233 KB
230 KB

assets/images/social/all-config.png

233 KB
240 KB
231 KB
236 KB
233 KB
240 KB

assets/images/social/amqp.png

239 KB

assets/images/social/ansible.png

236 KB

assets/images/social/appcds.png

230 KB
240 KB
231 KB
233 KB
233 KB
231 KB

assets/images/social/cache.png

233 KB

assets/images/social/camel.png

233 KB

assets/images/social/capabilities.png

233 KB

assets/images/social/cassandra.png

233 KB
232 KB
234 KB

assets/images/social/cdi.png

237 KB

assets/images/social/cli-tooling.png

238 KB
234 KB
234 KB

assets/images/social/config-yaml.png

232 KB

assets/images/social/config.png

233 KB
232 KB
234 KB
232 KB
233 KB

assets/images/social/datasource.png

231 KB
232 KB
237 KB

assets/images/social/dev-services.png

233 KB

assets/images/social/dev-ui.png

229 KB

assets/images/social/doc-concept.png

235 KB
232 KB
235 KB
235 KB
232 KB
233 KB

assets/images/social/flyway.png

231 KB
233 KB
233 KB

assets/images/social/funqy-http.png

233 KB
233 KB

assets/images/social/funqy.png

229 KB
242 KB
235 KB
234 KB
234 KB
233 KB

assets/images/social/grpc-xds.png

232 KB

assets/images/social/grpc.png

229 KB
235 KB
236 KB
233 KB
231 KB

assets/images/social/ide-tooling.png

234 KB
232 KB

assets/images/social/jms.png

230 KB

assets/images/social/jreleaser.png

236 KB
233 KB

assets/images/social/kafka-dev-ui.png

230 KB
234 KB

assets/images/social/kafka.png

234 KB

assets/images/social/kotlin.png

230 KB
231 KB
232 KB

assets/images/social/lifecycle.png

234 KB
233 KB

assets/images/social/liquibase.png

231 KB

assets/images/social/logging.png

233 KB

assets/images/social/lra.png

234 KB
233 KB

assets/images/social/mailer.png

233 KB
234 KB

assets/images/social/micrometer.png

232 KB
234 KB

assets/images/social/mongodb.png

233 KB
233 KB
234 KB
233 KB
234 KB
232 KB

assets/images/social/opentracing.png

232 KB

assets/images/social/optaplanner.png

238 KB
233 KB

assets/images/social/picocli.png

233 KB

assets/images/social/platform.png

229 KB

assets/images/social/podman.png

233 KB
232 KB

assets/images/social/quartz.png

235 KB
232 KB

assets/images/social/qute.png

233 KB
233 KB
240 KB

assets/images/social/rabbitmq.png

239 KB
232 KB
233 KB
232 KB
234 KB
233 KB
234 KB

assets/images/social/redis.png

232 KB
235 KB
232 KB

assets/images/social/rest-client.png

233 KB
237 KB

assets/images/social/rest-json.png

233 KB
237 KB

assets/images/social/resteasy.png

232 KB
233 KB

assets/images/social/scheduler.png

233 KB

assets/images/social/scripting.png

232 KB
233 KB
236 KB
235 KB

assets/images/social/security-jwt.png

231 KB
234 KB
232 KB
234 KB
232 KB
232 KB
231 KB
231 KB

assets/images/social/spring-cache.png

235 KB
233 KB
234 KB

assets/images/social/spring-di.png

234 KB
236 KB
235 KB

assets/images/social/spring-web.png

235 KB
233 KB
232 KB

assets/images/social/stork.png

235 KB
235 KB

assets/images/social/tooling.png

232 KB

assets/images/social/transaction.png

233 KB
237 KB

assets/images/social/upx.png

236 KB

assets/images/social/validation.png

234 KB
233 KB

assets/images/social/vertx.png

237 KB
240 KB

assets/images/social/websockets.png

232 KB
233 KB

0 commit comments

Comments
 (0)