diff --git a/Gemfile b/Gemfile index af8e1eeab0..c69cf3492a 100644 --- a/Gemfile +++ b/Gemfile @@ -35,3 +35,9 @@ gem "wdm", "~> 0.1.0" if Gem.win_platform? gem "webrick", "~> 1.7" + +# Used in _plugins/social_images.rb +gem "chunky_png", "~> 1.4.0" +gem 'rsvg2', '~> 4.1.7' +gem "cairo", "~> 1.17.9" +gem "rake", "~> 13.0.1" diff --git a/Gemfile.lock b/Gemfile.lock index 0ae6c30f37..7fe8e531f3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,19 +1,38 @@ GEM remote: https://rubygems.org/ specs: - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) - asciidoctor (2.0.15) + addressable (2.8.4) + public_suffix (>= 2.0.2, < 6.0) + asciidoctor (2.0.20) + cairo (1.17.9) + native-package-installer (>= 1.0.3) + pkg-config (>= 1.2.2) + red-colors + cairo-gobject (4.1.7) + cairo (>= 1.16.2) + glib2 (= 4.1.7) + chunky_png (1.4.0) colorator (1.1.0) - concurrent-ruby (1.1.8) - em-websocket (0.5.2) + concurrent-ruby (1.2.2) + em-websocket (0.5.3) eventmachine (>= 0.12.9) - http_parser.rb (~> 0.6.0) + http_parser.rb (~> 0) eventmachine (1.2.7) - ffi (1.15.0) + ffi (1.15.5) + fiddle (1.1.1) forwardable-extended (2.6.0) - http_parser.rb (0.6.0) - i18n (1.8.10) + gdk_pixbuf2 (4.1.7) + gio2 (= 4.1.7) + gio2 (4.1.7) + fiddle + gobject-introspection (= 4.1.7) + glib2 (4.1.7) + native-package-installer (>= 1.0.3) + pkg-config (>= 1.3.5) + gobject-introspection (4.1.7) + glib2 (= 4.1.7) + http_parser.rb (0.8.0) + i18n (1.14.1) concurrent-ruby (~> 1.0) jekyll (4.1.1) addressable (~> 2.4) @@ -35,57 +54,70 @@ GEM jekyll-asciidoc (3.0.0) asciidoctor (>= 1.5.0) jekyll (>= 3.0.0) - jekyll-feed (0.15.1) + jekyll-feed (0.17.0) jekyll (>= 3.7, < 5.0) jekyll-paginate-v2 (3.0.0) jekyll (>= 3.0, < 5.0) - jekyll-sass-converter (2.1.0) + jekyll-sass-converter (2.2.0) sassc (> 2.0.1, < 3.0) - jekyll-seo-tag (2.7.1) + jekyll-seo-tag (2.8.0) jekyll (>= 3.8, < 5.0) jekyll-watch (2.2.1) listen (~> 3.0) - kramdown (2.3.1) + kramdown (2.4.0) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) liquid (4.0.4) - listen (3.5.1) + listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) + matrix (0.4.2) mercenary (0.4.0) minima (2.5.1) jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) + native-package-installer (1.1.5) pathutil (0.16.2) forwardable-extended (~> 2.6) - public_suffix (4.0.6) - rb-fsevent (0.11.0) + pkg-config (1.5.1) + public_suffix (5.0.1) + rake (13.0.6) + rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) + red-colors (0.3.0) + matrix rexml (3.2.5) - rouge (3.26.0) + rouge (3.30.0) + rsvg2 (4.1.7) + cairo-gobject (= 4.1.7) + gdk_pixbuf2 (= 4.1.7) safe_yaml (1.0.5) sassc (2.4.0) ffi (~> 1.9) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) - unicode-display_width (1.7.0) - webrick (1.7.0) + unicode-display_width (1.8.0) + webrick (1.8.1) PLATFORMS ruby DEPENDENCIES + cairo (~> 1.17.9) + chunky_png (~> 1.4.0) jekyll (~> 4.1.1) jekyll-archives jekyll-asciidoc jekyll-feed (~> 0.6) jekyll-paginate-v2 minima (~> 2.0) + rake (~> 13.0.1) + rsvg2 (~> 4.1.7) tzinfo-data webrick (~> 1.7) BUNDLED WITH - 2.2.16 + 2.4.10 diff --git a/_layouts/base.html b/_layouts/base.html index a3a3b40207..9b7e098feb 100755 --- a/_layouts/base.html +++ b/_layouts/base.html @@ -35,7 +35,7 @@ - + {% if page.layout == 'guides' or page.layout == 'guides-index' %} {%assign canonical_url = page.url | replace_regex: '^/version/[^/]+', '' %} {% else %} diff --git a/_plugins/assets/quarkus_card_blank.png b/_plugins/assets/quarkus_card_blank.png new file mode 100644 index 0000000000..4b74b1102e Binary files /dev/null and b/_plugins/assets/quarkus_card_blank.png differ diff --git a/_plugins/social_images.rb b/_plugins/social_images.rb new file mode 100644 index 0000000000..8a97beebba --- /dev/null +++ b/_plugins/social_images.rb @@ -0,0 +1,123 @@ +require 'chunky_png' +require 'cairo' +require 'rsvg2' + +module Jekyll + # Generates social images for blog posts and guides + module SocialImages + def social_image(text, page_path) + # If text is not empty, return it + if text.nil? || text.empty? + # If page_path contains "guides/", return the social image path + if page_path.include?('guides/') + return "/assets/images/social/#{File.basename(page_path, '.adoc')}.png" + else + return "/assets/images/quarkus_card.png" + end + else + text + end + end + end + + class GenerateSocialImagesGenerator < Generator + def generate(site) + guides = Dir.glob(File.join(site.source, '_guides', '*.adoc')) + output_dir = 'assets/images/social' + FileUtils.mkdir_p(File.join(site.source, output_dir)) + + guides.each do |guide_file| + basename = File.basename(guide_file, '.adoc') + if basename.start_with?('_') + next + end + title = extract_title(guide_file) + output_file = File.join(site.source, output_dir, "#{basename}.png") + # Skip if the file already exists + if File.exist?(output_file) + next + end + + # Generate the SVG image + svg_image_str = generate_svg_string(title) + + # Create a Cairo surface and context for the PNG image (must be smaller than 600x330) + surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, 600, 250) + context = Cairo::Context.new(surface) + + # Load and render the SVG onto the Cairo context + svg = RSVG::Handle.new_from_data(svg_image_str) + context.render_rsvg_handle(svg) + + # Save the Cairo surface to a PNG file + b = StringIO.new + surface.write_to_png(b) + + # Compose the generated image with the template image + png_image = ChunkyPNG::Image.from_file('_plugins/assets/quarkus_card_blank.png') + # Change the last parameters to change the position of the generated image + png_image.compose!(ChunkyPNG::Image.from_blob(b.string), 0, 80) + + Jekyll.logger.info("Generating social image to #{output_file}") + # Save the composed image to the output file + png_image.save(output_file) + end + end + + def split_text_into_lines(text) + lines = [] + words = text.split(' ') + current_line = '' + + words.each do |word| + if current_line.length + word.length <= 32 + current_line += (current_line == '' ? '' : ' ') + word + else + lines.push(current_line) + current_line = word + end + end + + lines.push(current_line) unless current_line.empty? + + lines + end + + private + + def generate_svg_string(title) + idx = 90 + font_size = 30 + tspan_elements = '' + split_text_into_lines(title).each_with_index do |line, index| + tspan_elements += "#{line}" + idx += font_size + 10 + end + " + + + + #{tspan_elements} + + + " + end + + def extract_title(adoc_file) + title = '' + File.open(adoc_file, 'r') do |file| + file.each_line do |line| + if line.start_with? '=' + title = line[2..].strip + break + end + end + end + title + end + end +end + +Liquid::Template.register_filter(Jekyll::SocialImages)