Class: Kithe::VipsCliImageToJpeg
- Inherits:
-
Object
- Object
- Kithe::VipsCliImageToJpeg
- Defined in:
- app/derivative_transformers/kithe/vips_cli_image_to_jpeg.rb
Overview
Use the [vips](jcupitt.github.io/libvips/) command-line utility (via shell-out) to transform any image type to a JPG, 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
Attacher.define_derivative(:thumb) do |original_file, add_metadata:|
Kithe::VipsCliImageToJpeg.new(max_width: 100, thumbnail_mode: true).call(original_file, add_metadata: )
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.
Some usage suggestions at www.libvips.org/API/current/Using-vipsthumbnail.html
Instance Attribute Summary collapse
-
#jpeg_q ⇒ Object
readonly
Returns the value of attribute jpeg_q.
-
#max_width ⇒ Object
readonly
Returns the value of attribute max_width.
Instance Method Summary collapse
-
#call(original_file, add_metadata: nil) ⇒ Object
Will raise TTY::Command::ExitError if the external Vips command returns non-null.
-
#initialize(max_width: nil, jpeg_q: 85, thumbnail_mode: false) ⇒ VipsCliImageToJpeg
constructor
A new instance of VipsCliImageToJpeg.
Constructor Details
#initialize(max_width: nil, jpeg_q: 85, thumbnail_mode: false) ⇒ VipsCliImageToJpeg
Returns a new instance of VipsCliImageToJpeg.
41 42 43 44 45 46 47 48 49 50 |
# File 'app/derivative_transformers/kithe/vips_cli_image_to_jpeg.rb', line 41 def initialize(max_width:nil, jpeg_q: 85, thumbnail_mode: false) @max_width = max_width @jpeg_q = jpeg_q @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
#jpeg_q ⇒ Object (readonly)
Returns the value of attribute jpeg_q.
39 40 41 |
# File 'app/derivative_transformers/kithe/vips_cli_image_to_jpeg.rb', line 39 def jpeg_q @jpeg_q end |
#max_width ⇒ Object (readonly)
Returns the value of attribute max_width.
39 40 41 |
# File 'app/derivative_transformers/kithe/vips_cli_image_to_jpeg.rb', line 39 def max_width @max_width end |
Instance Method Details
#call(original_file, add_metadata: nil) ⇒ Object
Will raise TTY::Command::ExitError if the external Vips command returns non-null.
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 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'app/derivative_transformers/kithe/vips_cli_image_to_jpeg.rb', line 53 def call(original_file, add_metadata: nil) tempfile = Tempfile.new(["kithe_vips_cli_image_to_jpeg", ".jpg"]) 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, "--version", original_file.path] vips_args.concat maybe_profile_normalization_args vips_args.concat ["--size", "#{max_width}x65500"] vips_args.concat ["-o", "#{tempfile.path}#{vips_jpg_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_jpg_params}"] end out, err = TTY::Command.new(printer: :null).run(*vips_args) if [:vips_command] = vips_args.join(" ") out =~ /vips[ \-](\d+\.\d+\.\d+.*$)/ if $1 [:vips_version] = $1 end end return tempfile end |