Project

General

Profile

Defect #44358 » 0003-Defect-44358-Add-image-placeholder-mode.patch

Florian Walchshofer, 2026-08-29 22:12

View differences:

config/configuration.yml.example
264 264
  # Larger output is truncated to this limit.
265 265
  # Default: 102400 (100 kilobytes)
266 266
  #markdownized_preview_max_output_size: 102400
267

  
267
  #
268
  # Controls how embedded images in Office document previews are handled.
269
  #
270
  # Available values:
271
  # render  - Extract embedded images and render them in the preview (default)
272
  # replace - Replace images with a markdown placeholder generated by the
273
  #           Pandoc Lua filter
274
  #
275
  #markdownized_preview_images: render
276
  
268 277
# specific configuration options for production environment
269 278
# that overrides the default ones
270 279
production:
extra/pandoc_filter/markdownized_preview.lua
1
image_count = 0
2

  
3
function Image(el)
4
  image_count = image_count + 1
5

  
6
  local alt = pandoc.utils.stringify(el.caption)
7

  
8
  if alt == "" then
9
    local ext = el.src:match("%.([^.]+)$") or "img"
10
    alt = image_count .. "." .. ext
11
  end
12

  
13
  return pandoc.Str("[🖼️ " .. alt .. "] ")
14
end
lib/redmine/configuration.rb
31 31
      'thumbnails_generation_timeout' => 10,
32 32
      'markdownized_preview_generation_timeout' => 10,
33 33
      'markdownized_preview_max_source_size' => 10.megabytes,
34
      'markdownized_preview_max_output_size' => 100.kilobytes
34
      'markdownized_preview_max_output_size' => 100.kilobytes,
35
      'markdownized_preview_images' => 'render'
35 36
    }
36 37

  
37 38
    @config = nil
lib/redmine/markdownizer.rb
30 30
    PREVIEW_GENERATION_TIMEOUT = Redmine::Configuration['markdownized_preview_generation_timeout'].to_i
31 31
    MAX_SOURCE_SIZE = Redmine::Configuration['markdownized_preview_max_source_size'].to_i
32 32
    MAX_OUTPUT_SIZE = Redmine::Configuration['markdownized_preview_max_output_size'].to_i
33
    IMAGES_MODE = Redmine::Configuration['markdownized_preview_images'].to_s
34
    LUA_FILTER = Rails.root.join("extra", "pandoc_filter", "markdownized_preview.lua").freeze
33 35

  
34 36
    def self.supports?(filename)
35 37
      markdownizable_extensions.include?(File.extname(filename.to_s).downcase)
......
47 49
      directory = File.dirname(target)
48 50
      basedir = File.dirname(Attachment.markdownized_previews_storage_path)
49 51
      FileUtils.mkdir_p(directory)
50
      args = [COMMAND, source, "-t", "gfm", "--extract-media=markdownized_previews/#{attachment_id}/"]
52
      args = [COMMAND, source, "-t", "gfm"]
53

  
54
      if IMAGES_MODE == 'placeholder'
55
        args << "--lua-filter=#{LUA_FILTER}"
56
      else
57
        args << "--extract-media=markdownized_previews/#{attachment_id}/"
58
      end
59

  
51 60
      pid = nil
52 61
      output = Tempfile.new('markdownized-preview')
53 62

  
test/functional/attachments_controller_test.rb
380 380
    assert_response :not_found
381 381
  end
382 382

  
383
  def test_show_msword_with_replaced_images
384
    skip unless Redmine::Markdownizer.available?
385

  
386
    old = Redmine::Markdownizer::IMAGES_MODE
387
    Redmine::Markdownizer.send(:remove_const, :IMAGES_MODE)
388
    Redmine::Markdownizer.const_set(:IMAGES_MODE, 'placeholder')
389

  
390
    begin
391
      set_tmp_attachments_directory
392

  
393
      a = Attachment.new(
394
        :container => Issue.find(1),
395
        :file => uploaded_test_file(
396
          'msword.docx',
397
          'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
398
        ),
399
        :author => User.find(1)
400
      )
401
      assert a.save
402

  
403
      get(:show, :params => {:id => a.id})
404

  
405
      assert_response :success
406
      assert_equal 'text/html', @response.media_type
407

  
408
      assert_select 'div.filecontent.wiki', :text => /Redmine is a flexible project management web application/
409
      assert_select 'div.filecontent.wiki img', 0
410
      assert_select 'div.filecontent.wiki', :text => /\[🖼️ 1\.png\]/
411
      children = Dir.children(a.markdownized_preview_directory)
412
      assert_equal ['preview.md'], children
413
    ensure
414
      Redmine::Markdownizer.send(:remove_const, :IMAGES_MODE)
415
      Redmine::Markdownizer.const_set(:IMAGES_MODE, old)
416
    end
417
  end
418

  
419
  def test_show_libreoffice_with_replaced_images
420
    skip unless Redmine::Markdownizer.available?
421

  
422
    old = Redmine::Markdownizer::IMAGES_MODE
423
    Redmine::Markdownizer.send(:remove_const, :IMAGES_MODE)
424
    Redmine::Markdownizer.const_set(:IMAGES_MODE, 'placeholder')
425

  
426
    begin
427
      set_tmp_attachments_directory
428
      a = Attachment.new(
429
        :container => Issue.find(1),
430
        :file => uploaded_test_file(
431
          'libreoffice-writer.odt',
432
          'application/vnd.oasis.opendocument.text'
433
        ),
434
        :author => User.find(1)
435
      )
436
      assert a.save
437

  
438
      get(:show, :params => {:id => a.id})
439

  
440
      assert_response :success
441
      assert_equal 'text/html', @response.media_type
442
      assert_select 'div.filecontent.wiki', :text => /Redmine is a flexible project management web application/
443
      assert_select 'div.filecontent.wiki img', 0
444
      assert_select 'div.filecontent.wiki', :text => /\[🖼️ 1\.png\]/
445
      children = Dir.children(a.markdownized_preview_directory)
446
      assert_equal ['preview.md'], children
447
    ensure
448
      Redmine::Markdownizer.send(:remove_const, :IMAGES_MODE)
449
      Redmine::Markdownizer.const_set(:IMAGES_MODE, old)
450
    end
451
  end
452

  
383 453
  def test_show_other_with_no_preview
384 454
    @request.session[:user_id] = 2
385 455
    get(:show, :params => {:id => 6})
(5-5/5)