Project

General

Profile

Feature #22481 » 0001-Render-PDF-thumbnail-using-ImageMagick-GhostScript.patch

Updated to r15429 - Gregor Schmidt, 2016-05-30 10:56

View differences:

app/controllers/admin_controller.rb
78 78
      [:text_file_repository_writable, File.writable?(Attachment.storage_path)],
79 79
      ["#{l :text_plugin_assets_writable} (./public/plugin_assets)",   File.writable?(Redmine::Plugin.public_directory)],
80 80
      [:text_rmagick_available,        Object.const_defined?(:Magick)],
81
      [:text_convert_available,        Redmine::Thumbnail.convert_available?]
81
      [:text_convert_available,        Redmine::Thumbnail.convert_available?],
82
      [:text_gs_available,             Redmine::Thumbnail.gs_available?]
82 83
    ]
83 84
  end
84 85
end
app/controllers/attachments_controller.rb
68 68
      if stale?(:etag => tbnail)
69 69
        send_file tbnail,
70 70
          :filename => filename_for_content_disposition(@attachment.filename),
71
          :type => detect_content_type(@attachment),
71
          :type => detect_content_type(@attachment, true),
72 72
          :disposition => 'inline'
73 73
      end
74 74
    else
......
184 184
    @attachment.deletable? ? true : deny_access
185 185
  end
186 186

  
187
  def detect_content_type(attachment)
187
  def detect_content_type(attachment, is_thumb = false)
188 188
    content_type = attachment.content_type
189 189
    if content_type.blank? || content_type == "application/octet-stream"
190 190
      content_type = Redmine::MimeType.of(attachment.filename)
191 191
    end
192
    content_type.to_s
192
    content_type = content_type.to_s
193

  
194
    if is_thumb and content_type == "application/pdf"
195
      # PDF previews are stored in PNG format
196
      content_type = "image/png"
197
    end
198

  
199
    content_type
193 200
  end
194 201

  
195 202
  def disposition(attachment)
app/models/attachment.rb
198 198
  end
199 199

  
200 200
  def thumbnailable?
201
    image?
201
    image? || (is_pdf? && Redmine::Thumbnail.gs_available?)
202 202
  end
203 203

  
204 204
  # Returns the full path the attachment thumbnail, or nil
......
218 218
      target = File.join(self.class.thumbnails_storage_path, "#{id}_#{digest}_#{size}.thumb")
219 219

  
220 220
      begin
221
        Redmine::Thumbnail.generate(self.diskfile, target, size)
221
        Redmine::Thumbnail.generate(self.diskfile, target, size, is_pdf?)
222 222
      rescue => e
223 223
        logger.error "An error occured while generating thumbnail for #{disk_filename} to #{target}\nException was: #{e.message}" if logger
224 224
        return nil
config/locales/de.yml
1063 1063
  text_caracters_minimum: "Muss mindestens %{count} Zeichen lang sein."
1064 1064
  text_comma_separated: Mehrere Werte erlaubt (durch Komma getrennt).
1065 1065
  text_convert_available: ImageMagick-Konvertierung verfügbar (optional)
1066
  text_gs_available: ImageMagick PDF-Unterstützung verfügbar (optional)
1066 1067
  text_custom_field_possible_values_info: 'Eine Zeile pro Wert'
1067 1068
  text_default_administrator_account_changed: Administrator-Passwort geändert
1068 1069
  text_destroy_time_entries: Gebuchte Aufwände löschen
config/locales/en-GB.yml
1098 1098
    current password
1099 1099
  setting_mail_handler_excluded_filenames: Exclude attachments by name
1100 1100
  text_convert_available: ImageMagick convert available (optional)
1101
  text_gs_available: ImageMagick PDF support available (optional)
1101 1102
  label_link: Link
1102 1103
  label_only: only
1103 1104
  label_drop_down_list: drop-down list
config/locales/en.yml
1107 1107
  text_plugin_assets_writable: Plugin assets directory writable
1108 1108
  text_rmagick_available: RMagick available (optional)
1109 1109
  text_convert_available: ImageMagick convert available (optional)
1110
  text_gs_available: ImageMagick PDF support available (optional)
1110 1111
  text_destroy_time_entries_question: "%{hours} hours were reported on the issues you are about to delete. What do you want to do?"
1111 1112
  text_destroy_time_entries: Delete reported hours
1112 1113
  text_assign_time_entries_to_project: Assign reported hours to the project
lib/redmine/thumbnail.rb
25 25
    CONVERT_BIN = (Redmine::Configuration['imagemagick_convert_command'] || 'convert').freeze
26 26

  
27 27
    # Generates a thumbnail for the source image to target
28
    def self.generate(source, target, size)
28
    def self.generate(source, target, size, is_pdf = false)
29 29
      return nil unless convert_available?
30
      return nil if is_pdf && !gs_available?
30 31
      unless File.exists?(target)
31
        # Make sure we only invoke Imagemagick if this is actually an image
32
        unless File.open(source) {|f| MimeMagic.by_magic(f).try(:image?)}
33
          return nil
34
        end
32
        # Make sure we only invoke Imagemagick if assumed type matches content
33
        mime_magic = File.open(source) {|f| MimeMagic.by_magic(f) }
34
        return nil if mime_magic.nil?
35
        return nil if  is_pdf &&  mime_magic.type != "application/pdf"
36
        return nil if !is_pdf && !mime_magic.image?
37

  
35 38
        directory = File.dirname(target)
36 39
        unless File.exists?(directory)
37 40
          FileUtils.mkdir_p directory
38 41
        end
39 42
        size_option = "#{size}x#{size}>"
40
        cmd = "#{shell_quote CONVERT_BIN} #{shell_quote source} -thumbnail #{shell_quote size_option} #{shell_quote target}"
43

  
44
        if is_pdf
45
          cmd = "#{shell_quote CONVERT_BIN} #{shell_quote "#{source}[0]"} -thumbnail #{shell_quote size_option} #{shell_quote "png:#{target}"}"
46
        else
47
          cmd = "#{shell_quote CONVERT_BIN} #{shell_quote source} -thumbnail #{shell_quote size_option} #{shell_quote target}"
48
        end
49

  
41 50
        unless system(cmd)
42 51
          logger.error("Creating thumbnail failed (#{$?}):\nCommand: #{cmd}")
43 52
          return nil
......
53 62
      @convert_available
54 63
    end
55 64

  
65
    def self.gs_available?
66
      return @gs_available if defined?(@gs_available)
67

  
68
      @gs_available = system("gs -version") rescue false
69
      @gs_available ||= system("gswin32 -version") rescue false
70
      @gs_available ||= system("gswin64 -version") rescue false
71

  
72
      @gs_available
73
    end
74

  
56 75
    def self.logger
57 76
      Rails.logger
58 77
    end
(3-3/9)