How to efficiently use app.after_build?

I am writing a custom extension that can generate images on the fly while generating middleman site. This is what my code looks like

class GenImage < Middleman::Extension
    def initialize(app, options_hash={}, &block)
        super
        app.after_build do
            image_font = "AvantGarde-Book"
            image_dir = "source/images"
            system("if [ ! -d \"#{image_dir}\" ]; then mkdir #{image_dir}; fi")
            blog.articles.each do |item|
                filename = item.data.baseurl + ".gif"
                output = image_dir + "/" + filename
        
                system("if [ ! -f #{output} ]; then convert -size 260x170 -background black -gravity center -weight 300 -pointsize 20 -font #{image_font} -fill white caption:\"#{item.data.title}\" -bordercolor black -border 20x0 -gravity south -background black -splice 0x10 -font #{image_font} -pointsize 12 -annotate +0+2 '' #{output} && echo \"-> Generating #{output}\"; else echo \"-> identical  #{output}\"; fi")
            end
        end
    end
end

::Middleman::Extensions.register(:generate_images, GenImage)

The code is working pretty good except that I need to use the command middleman build twice. Because when i run the build command, the images get generated at last in the source directory. So I will have to execute the same command again to move newly created images to the build directory.

I tried generating images directly to the build directory but it doesn’t help me because the images are deleted and created again everytime I execute middleman build command.

I tried before_build method. This command generates and replaces them for every single post. i.e If I have 10 posts then every post then image is generated 100 times(by replacing itself).

I am expecting the images to be generated in the source directory and copied to the build directory with one single command.

1 Like

You’ll be fighting against Middleman if those images aren’t in the sitemap. Either generate files in the source directory beforehand, or create resources—

class TitleImages < Middleman::Extension
  # Create a title image for each blog article.
  def manipulate_resource_list(resources)
    title_images = app.blog.articles.map do |article|
      path = "title_images/#{ article.slug }.png"

      RenderedTextResource.new(app.sitemap, path, article.data.title)
    end

    resources + title_images
  end
end

TitleImages.register

—that will dynamically render the images:

# Resource that renders an image of text
class RenderedTextResource < Middleman::Sitemap::Resource
  def initialize(store, path, text)
    super(store, path, '')

    @text = text
  end

  def binary?
    false
  end

  def render
    IO.popen(['convert', "label:#{ @text }", 'png:-']).read
  end
end

Note that I’ve used 'title_images' rather than images_dir in this example so as not to conflict with Sprockets, which I don’t have a good understanding of.