Don't regenerate smaller images so often.
authorNick Bowler <nbowler@draconx.ca>
Tue, 7 Jul 2020 01:16:36 +0000 (21:16 -0400)
committerNick Bowler <nbowler@draconx.ca>
Tue, 7 Jul 2020 01:26:10 +0000 (21:26 -0400)
It is a bit annoying how nanoc always runs the rule to regenerate
resized images, even if none of the inputs are changed at all.

Since the imgresize filter is quite expensive to run, let's try hacking
around the problem by passing in the final output filename and just
re-using that if it exists and its mtime is newer than the source image.

This is definitely not the most accurate as it will not automatically
regenerate images if the rules change, but I expect any problems due to
this will waste less of my time than regenerating dozens of redundant
images every single time the site is compiled.

Rules
lib/imgresize.rb

diff --git a/Rules b/Rules
index a881607f9b3211cd296780c97a8bdf4678883a61..e00c5f3593813fe9e9f2d39edc02263703aea310 100644 (file)
--- a/Rules
+++ b/Rules
@@ -149,8 +149,9 @@ compile '/license/cc*.xhtml' do
 end
 
 compile '/images/*.jpg', rep: :large do
-    filter :imgresize, width: 1200, height: 1200
-    write item.identifier.without_ext + '-t1200.' + item.identifier.ext
+    filename = item.identifier.without_ext + '-t1200.' + item.identifier.ext
+    filter :imgresize, width: 1200, height: 1200, cache: filename
+    write filename
 end
 
 compile '/images/*.jpg', rep: :info do
index e539f371b0c22a23368bcc2d3db8c5756f17b38e..b14530bc5278e0e2c4821206f1dc289a263550c8 100644 (file)
@@ -20,6 +20,27 @@ class ImgResize < Nanoc::Filter
     identifier :imgresize
     type       :binary
 
+    def fetch_from_cache(filename, params)
+        return unless params[:cache]
+
+        cachefile = File.join(@config[:output_dir], params[:cache])
+        begin
+            s = File.stat(cachefile)
+        rescue Errno::ENOENT
+            return
+        end
+
+        return unless s.mtime >= File.stat(filename).mtime
+
+        begin
+            File.link(cachefile, output_filename)
+        rescue
+            FileUtils.copy_file(cachefile, output_filename)
+        end
+
+        return true
+    end
+
     def run(filename, params = {})
         w = if params[:width] then params[:width].to_i end
         h = if params[:height] then params[:height].to_i end
@@ -32,6 +53,8 @@ class ImgResize < Nanoc::Filter
         end
         args << output_filename
 
-        system('gm', 'convert', *args)
+        unless fetch_from_cache(filename, params)
+            system('gm', 'convert', *args)
+        end
     end
 end