Class: Kithe::VipsCliImageToPng
- Inherits:
-
Object
- Object
- Kithe::VipsCliImageToPng
- Defined in:
- app/models/kithe/vips_cli_image_to_png.rb
Overview
Use the [vips](jcupitt.github.io/libvips/) command-line utility (via shell-out) to transform any image type to a PNG, with a specified maximum width (keeping aspect ratio).
Requires vips command line utilities ‘vips` and `vipsthumbnail` and to be installed on your system, eg `brew install vips`, or apt package `vips-tools`.
If thumbnail_mode:true is given, we ALSO apply some additional best practices for minimizing size when used as an image _in a browser_, such as removing color profile information. See eg:
* https://developers.google.com/speed/docs/insights/OptimizeImages
* http://libvips.blogspot.com/2013/11/tips-and-tricks-for-vipsthumbnail.html
* https://github.com/jcupitt/libvips/issues/775
It takes an open ‘File` object in, and returns an open TempFile object. It is built for use with kithe derivatives transformations, eg:
class Asset < KitheAsset
define_derivative(thumb) do |original_file|
Kithe::VipsCliImageToPng.new(max_width: 100, thumbnail_mode: true).call(original_file)
end
end
We use the vips CLI because we know how, and it means we can avoid worrying about ruby memory leaks or the GIL. An alternative that uses vips ruby bindings would also be possible, and might work well, but this is what for us is tried and true.
Instance Attribute Summary collapse
-
#max_width ⇒ Object
readonly
Returns the value of attribute max_width.
-
#png_compression ⇒ Object
readonly
Returns the value of attribute png_compression.
Instance Method Summary collapse
-
#call(original_file) ⇒ Object
Will raise TTY::Command::ExitError if the external Vips command returns non-null.
-
#initialize(max_width: nil, png_compression: 1, thumbnail_mode: false) ⇒ VipsCliImageToPng
constructor
A new instance of VipsCliImageToPng.
Constructor Details
#initialize(max_width: nil, png_compression: 1, thumbnail_mode: false) ⇒ VipsCliImageToPng
Returns a new instance of VipsCliImageToPng.
38 39 40 41 42 43 44 45 46 47 |
# File 'app/models/kithe/vips_cli_image_to_png.rb', line 38 def initialize(max_width: nil, png_compression: 1, thumbnail_mode: false) @max_width = max_width @png_compression = png_compression @thumbnail_mode = !!thumbnail_mode if thumbnail_mode && max_width.nil? # https://github.com/libvips/libvips/issues/1179 raise ArgumentError.new("thumbnail_mode currently requires a non-nil max_width") end end |
Instance Attribute Details
#max_width ⇒ Object (readonly)
Returns the value of attribute max_width.
36 37 38 |
# File 'app/models/kithe/vips_cli_image_to_png.rb', line 36 def max_width @max_width end |
#png_compression ⇒ Object (readonly)
Returns the value of attribute png_compression.
36 37 38 |
# File 'app/models/kithe/vips_cli_image_to_png.rb', line 36 def png_compression @png_compression end |
Instance Method Details
#call(original_file) ⇒ Object
Will raise TTY::Command::ExitError if the external Vips command returns non-null.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'app/models/kithe/vips_cli_image_to_png.rb', line 50 def call(original_file) tempfile = Tempfile.new(["kithe_vips_cli_image_to_png", ".png"]) vips_args = [] # If we are resizing, we use `vipsthumbnail`, if we are not resizing, # `vips copy` works better. if max_width # Due to bug in vips, we need to provide a height constraint, we make # really huge one million pixels so it should not come into play, and # we're constraining proportionally by width. # https://github.com/jcupitt/libvips/issues/781 vips_args.concat [vips_thumbnail_command, original_file.path] vips_args.concat maybe_profile_normalization_args vips_args.concat ["--size", "#{max_width}x65500"] vips_args.concat ["-o", "#{tempfile.path}#{vips_png_params}"] else # If we arne't making a thumbnail, we need to use `vips copy` instead of `vipsthumbnail`, # to avoid it changing height/width on us. There might be another way. # # Yes, this means we can't do thumbnail-mode normalizations. vips_args.concat [vips_command, "copy", original_file.path] vips_args.concat ["#{tempfile.path}#{vips_png_params}"] end TTY::Command.new(printer: :null).run(*vips_args) tempfile end |