Project

General

Profile

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

patch for r16542 - Go MAEDA, 2017-05-04 11:15

View differences:

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

  
213
  def detect_content_type(attachment)
213
  def detect_content_type(attachment, is_thumb = false)
214 214
    content_type = attachment.content_type
215 215
    if content_type.blank? || content_type == "application/octet-stream"
216 216
      content_type = Redmine::MimeType.of(attachment.filename)
217 217
    end
218
    content_type.to_s
218
    content_type = content_type.to_s
219

  
220
    if is_thumb and content_type == "application/pdf"
221
      # PDF previews are stored in PNG format
222
      content_type = "image/png"
223
    end
224

  
225
    content_type
219 226
  end
220 227

  
221 228
  def disposition(attachment)
app/models/attachment.rb (working copy)
200 200
  end
201 201

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

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

  
222 222
      begin
223
        Redmine::Thumbnail.generate(self.diskfile, target, size)
223
        Redmine::Thumbnail.generate(self.diskfile, target, size, is_pdf?)
224 224
      rescue => e
225 225
        logger.error "An error occured while generating thumbnail for #{disk_filename} to #{target}\nException was: #{e.message}" if logger
226 226
        return nil
config/locales/de.yml (working copy)
1059 1059
  text_caracters_minimum: "Muss mindestens %{count} Zeichen lang sein."
1060 1060
  text_comma_separated: Mehrere Werte erlaubt (durch Komma getrennt).
1061 1061
  text_convert_available: ImageMagick-Konvertierung verfügbar (optional)
1062
  text_gs_available: ImageMagick PDF-Unterstützung verfügbar (optional)
1062 1063
  text_custom_field_possible_values_info: 'Eine Zeile pro Wert'
1063 1064
  text_default_administrator_account_changed: Administrator-Passwort geändert
1064 1065
  text_destroy_time_entries: Gebuchte Aufwände löschen
config/locales/en-GB.yml (working copy)
1090 1090
    current password
1091 1091
  setting_mail_handler_excluded_filenames: Exclude attachments by name
1092 1092
  text_convert_available: ImageMagick convert available (optional)
1093
  text_gs_available: ImageMagick PDF support available (optional)
1093 1094
  label_link: Link
1094 1095
  label_only: only
1095 1096
  label_drop_down_list: drop-down list
config/locales/en.yml (working copy)
1130 1130
  text_plugin_assets_writable: Plugin assets directory writable
1131 1131
  text_rmagick_available: RMagick available (optional)
1132 1132
  text_convert_available: ImageMagick convert available (optional)
1133
  text_gs_available: ImageMagick PDF support available (optional)
1133 1134
  text_destroy_time_entries_question: "%{hours} hours were reported on the issues you are about to delete. What do you want to do?"
1134 1135
  text_destroy_time_entries: Delete reported hours
1135 1136
  text_assign_time_entries_to_project: Assign reported hours to the project
lib/redmine/thumbnail.rb (working copy)
23 23
    extend Redmine::Utils::Shell
24 24

  
25 25
    CONVERT_BIN = (Redmine::Configuration['imagemagick_convert_command'] || 'convert').freeze
26
    ALLOWED_TYPES = %w(image/bmp image/gif image/jpeg image/png)
26
    ALLOWED_TYPES = %w(image/bmp image/gif image/jpeg image/png application/pdf)
27 27

  
28 28
    # Generates a thumbnail for the source image to target
29
    def self.generate(source, target, size)
29
    def self.generate(source, target, size, is_pdf = false)
30 30
      return nil unless convert_available?
31
      return nil if is_pdf && !gs_available?
31 32
      unless File.exists?(target)
33
        mime_type = File.open(source) {|f| MimeMagic.by_magic(f).try(:type) }
34
        return nil if mime_type.nil?
35
        return nil if !ALLOWED_TYPES.include? mime_type
36
        return nil if is_pdf && mime_type != "application/pdf"
37

  
32 38
        # Make sure we only invoke Imagemagick if the file type is allowed
33 39
        unless File.open(source) {|f| ALLOWED_TYPES.include? MimeMagic.by_magic(f).try(:type) }
34 40
          return nil
......
38 44
          FileUtils.mkdir_p directory
39 45
        end
40 46
        size_option = "#{size}x#{size}>"
41
        cmd = "#{shell_quote CONVERT_BIN} #{shell_quote source} -thumbnail #{shell_quote size_option} #{shell_quote target}"
47

  
48
        if is_pdf
49
          cmd = "#{shell_quote CONVERT_BIN} #{shell_quote "#{source}[0]"} -thumbnail #{shell_quote size_option} #{shell_quote "png:#{target}"}"
50
        else
51
          cmd = "#{shell_quote CONVERT_BIN} #{shell_quote source} -thumbnail #{shell_quote size_option} #{shell_quote target}"
52
        end
53

  
42 54
        unless system(cmd)
43 55
          logger.error("Creating thumbnail failed (#{$?}):\nCommand: #{cmd}")
44 56
          return nil
......
54 66
      @convert_available
55 67
    end
56 68

  
69
    def self.gs_available?
70
      return @gs_available if defined?(@gs_available)
71

  
72
      @gs_available = system("gs -version") rescue false
73
      @gs_available ||= system("gswin32 -version") rescue false
74
      @gs_available ||= system("gswin64 -version") rescue false
75

  
76
      @gs_available
77
    end
78

  
57 79
    def self.logger
58 80
      Rails.logger
59 81
    end
(4-4/9)