Module: Redmine::Thumbnail

Extended by:
Utils::Shell
Defined in:
lib/redmine/thumbnail.rb

Constant Summary collapse

CONVERT_BIN =
(Redmine::Configuration['imagemagick_convert_command'] || 'convert').freeze
GS_BIN =
(
  Redmine::Configuration['gs_command'] ||
  ('gswin64c' if Redmine::Platform.mswin?) ||
  'gs'
).freeze
ALLOWED_TYPES =
%w(image/bmp image/gif image/jpeg image/png image/webp application/pdf)

Class Method Summary collapse

Methods included from Utils::Shell

shell_quote, shell_quote_command

Class Method Details

.convert_available?Boolean

Returns:

  • (Boolean)


75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/redmine/thumbnail.rb', line 75

def self.convert_available?
  return @convert_available if defined?(@convert_available)

  begin
    `#{shell_quote CONVERT_BIN} -version`
    @convert_available = $?.success?
  rescue
    @convert_available = false
  end
  logger.warn("Imagemagick's convert binary (#{CONVERT_BIN}) not available") unless @convert_available
  @convert_available
end

.generate(source, target, size, is_pdf = false) ⇒ Object

Generates a thumbnail for the source image to target



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/redmine/thumbnail.rb', line 36

def self.generate(source, target, size, is_pdf = false)
  return nil unless convert_available?
  return nil if is_pdf && !gs_available?

  unless File.exist?(target)
    # Make sure we only invoke Imagemagick if the file type is allowed
    mime_type = File.open(source) {|f| Marcel::MimeType.for(f)}
    return nil unless ALLOWED_TYPES.include? mime_type
    return nil if is_pdf && mime_type != "application/pdf"

    directory = File.dirname(target)
    FileUtils.mkdir_p directory
    size_option = "#{size}x#{size}>"

    if is_pdf
      cmd = "#{shell_quote CONVERT_BIN} #{shell_quote "#{source}[0]"} -thumbnail #{shell_quote size_option} #{shell_quote "png:#{target}"}"
    else
      cmd = "#{shell_quote CONVERT_BIN} #{shell_quote source} -auto-orient -thumbnail #{shell_quote size_option} #{shell_quote target}"
    end

    pid = nil
    begin
      Timeout.timeout(Redmine::Configuration['thumbnails_generation_timeout'].to_i) do
        pid = Process.spawn(cmd)
        _, status = Process.wait2(pid)
        unless status.success?
          logger.error("Creating thumbnail failed (#{status.exitstatus}):\nCommand: #{cmd}")
          return nil
        end
      end
    rescue Timeout::Error
      Process.kill('KILL', pid)
      logger.error("Creating thumbnail timed out:\nCommand: #{cmd}")
      return nil
    end
  end
  target
end

.gs_available?Boolean

Returns:

  • (Boolean)


88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/redmine/thumbnail.rb', line 88

def self.gs_available?
  return @gs_available if defined?(@gs_available)

  begin
    `#{shell_quote GS_BIN} -version`
    @gs_available = $?.success?
  rescue
    @gs_available = false
  end
  logger.warn("gs binary (#{GS_BIN}) not available") unless @gs_available
  @gs_available
end

.loggerObject



101
102
103
# File 'lib/redmine/thumbnail.rb', line 101

def self.logger
  Rails.logger
end