Defect #32915
openInternal Server Error occurted when exporting gantt chart to png on Windows
0%
Description
Redmine 4.0.4 using RMagick was fine.
However, Redmine 4.1.0 using MiniMagick does not work.
prodution.log of Redmine 4.1.0 is this:
Started GET "/redmine/projects/some_project/issues/gantt.png?..." for (IP) at (date) Processing by GanttsController#show as PNG Parameters: {...} Current user: admin (id=1) Completed 500 Internal Server Error in 290ms (ActiveRecord: 63.0ms) Errno::E2BIG (Arg list too long - convert): lib/redmine/helpers/gantt.rb:381:in `to_image' app/controllers/gantts_controller.rb:44:in `block (2 levels) in show' app/controllers/gantts_controller.rb:42:in `show'
On Windows, the ImageMagick's "convert" command length is too long, and then error occurred.
I want to shorten the command length or split the command if Redmine keeps using Minimagick.
And there should be some exception code as below:
--- a\lib\redmine\helpers\gantt.rb
+++ b\lib\redmine\helpers\gantt.rb
@@ -488,4 +488,15 @@
end
img.to_blob
+ rescue
+ MiniMagick::Tool::Convert.new do |gc|
+ # create error message image
+ gc.size('%dx%d' % [200, 50])
+ gc.xc('white')
+ gc.stroke('transparent').fill('red')
+ # and draw error message
+ gc.draw('text %d,%d %s' % [10, 20, Redmine::Utils::Shell.shell_quote('Gantt size too big.')])
+ gc << img.path
+ end
+ img.to_blob
ensure
img.destroy! if img
For some reason, I have to keep using Redmine on Windows...
Updated by Anonymous almost 5 years ago
To work on Windows, divided the MiniMagick "convert" block.
This patch can display up to about 200 issues.
However, the subjects() and lines() functions create "convert" commands internally, so these could't be divided.
--- a/lib/redmine/helpers/gantt.rb
+++ b/lib/redmine/helpers/gantt.rb
@@ -386,4 +386,11 @@
gc.stroke('transparent')
subjects(:image => gc, :top => (headers_height + 20), :indent => 4, :format => :image)
+ gc << img.path
+ gc.call
+ end
+ # Make blocks smaller for windows
+ MiniMagick::Tool::Convert.new do |gc|
+ gc << img.path
+ gc.font(font_path) if font_path.present?
# Months headers
month_f = @date_from
@@ -472,4 +479,11 @@
0, 0, subject_width + g_width, g_height + headers_height - 1
])
+ gc << img.path
+ gc.call
+ end
+ # Make blocks smaller for windows
+ MiniMagick::Tool::Convert.new do |gc|
+ gc << img.path
+ gc.font(font_path) if font_path.present?
# content
top = headers_height + 20
Updated by Anonymous almost 5 years ago
Changed to split MiniMagick's "convert" command on Windows only.
To do so, changed the "convert" object (gc) to an instance variable (@gc), and added an @minimagick_command_max instance variable for the command splitting.
@@ -90,4 +90,6 @@
@max_rows = Setting.gantt_items_limit.blank? ? nil : Setting.gantt_items_limit.to_i
end
+ @gc = nil
+ @minimagick_command_max = Redmine::Platform.mswin? ? 1000 : -1
end
@@ -379,11 +381,11 @@
font_path = Redmine::Configuration['minimagick_font_path'].presence || Redmine::Configuration['rmagick_font_path'].presence
img = MiniMagick::Image.create(".#{format}", false)
- MiniMagick::Tool::Convert.new do |gc|
- gc.size('%dx%d' % [subject_width + g_width + 1, height])
- gc.xc('white')
- gc.font(font_path) if font_path.present?
+ @gc = MiniMagick::Tool::Convert.new
+ @gc.size('%dx%d' % [subject_width + g_width + 1, height])
+ @gc.xc('white')
+ @gc.font(font_path) if font_path.present?
# Subjects
- gc.stroke('transparent')
- subjects(:image => gc, :top => (headers_height + 20), :indent => 4, :format => :image)
+ @gc.stroke('transparent')
+ subjects(:image => @gc, :top => (headers_height + 20), :indent => 4, :format => :image, :img_path => img.path, :font_path => font_path)
# Months headers
month_f = @date_from
@@ -391,14 +393,14 @@
@months.times do
width = ((month_f >> 1) - month_f) * zoom
- gc.fill('white')
- gc.stroke('grey')
- gc.strokewidth(1)
- gc.draw('rectangle %d,%d %d,%d' % [
+ @gc.fill('white')
+ @gc.stroke('grey')
+ @gc.strokewidth(1)
+ @gc.draw('rectangle %d,%d %d,%d' % [
left, 0, left + width, height
])
- gc.fill('black')
- gc.stroke('transparent')
- gc.strokewidth(1)
- gc.draw('text %d,%d %s' % [
+ @gc.fill('black')
+ @gc.stroke('transparent')
+ @gc.strokewidth(1)
+ @gc.draw('text %d,%d %s' % [
left.round + 8, 14, Redmine::Utils::Shell.shell_quote("#{month_f.year}-#{month_f.month}")
])
@@ -417,8 +419,8 @@
week_f = @date_from + (7 - @date_from.cwday + 1)
width = (7 - @date_from.cwday + 1) * zoom
- gc.fill('white')
- gc.stroke('grey')
- gc.strokewidth(1)
- gc.draw('rectangle %d,%d %d,%d' % [
+ @gc.fill('white')
+ @gc.stroke('grey')
+ @gc.strokewidth(1)
+ @gc.draw('rectangle %d,%d %d,%d' % [
left, header_height, left + width, 2 * header_height + g_height - 1
])
@@ -427,14 +429,14 @@
while week_f <= date_to
width = (week_f + 6 <= date_to) ? 7 * zoom : (date_to - week_f + 1) * zoom
- gc.fill('white')
- gc.stroke('grey')
- gc.strokewidth(1)
- gc.draw('rectangle %d,%d %d,%d' % [
+ @gc.fill('white')
+ @gc.stroke('grey')
+ @gc.strokewidth(1)
+ @gc.draw('rectangle %d,%d %d,%d' % [
left.round, header_height, left.round + width, 2 * header_height + g_height - 1
])
- gc.fill('black')
- gc.stroke('transparent')
- gc.strokewidth(1)
- gc.draw('text %d,%d %s' % [
+ @gc.fill('black')
+ @gc.stroke('transparent')
+ @gc.strokewidth(1)
+ @gc.draw('text %d,%d %s' % [
left.round + 2, header_height + 14, Redmine::Utils::Shell.shell_quote(week_f.cweek.to_s)
])
@@ -450,10 +452,18 @@
(date_to - @date_from + 1).to_i.times do
width = zoom
- gc.fill(non_working_week_days.include?(wday) ? '#eee' : 'white')
- gc.stroke('#ddd')
- gc.strokewidth(1)
- gc.draw('rectangle %d,%d %d,%d' % [
+ @gc.fill(non_working_week_days.include?(wday) ? '#eee' : 'white')
+ @gc.stroke('#ddd')
+ @gc.strokewidth(1)
+ @gc.draw('rectangle %d,%d %d,%d' % [
left, 2 * header_height, left + width, 2 * header_height + g_height - 1
])
+ # Make blocks smaller for windows
+ if (@minimagick_command_max > 0) && (@gc.command.length > @minimagick_command_max)
+ @gc << img.path
+ @gc.call
+ @gc = MiniMagick::Tool::Convert.new
+ @gc << img.path
+ @gc.font(font_path) if font_path.present?
+ end
left = left + width
wday = wday + 1
@@ -462,29 +472,45 @@
end
# border
- gc.fill('transparent')
- gc.stroke('grey')
- gc.strokewidth(1)
- gc.draw('rectangle %d,%d %d,%d' % [
+ @gc.fill('transparent')
+ @gc.stroke('grey')
+ @gc.strokewidth(1)
+ @gc.draw('rectangle %d,%d %d,%d' % [
0, 0, subject_width + g_width, headers_height
])
- gc.stroke('black')
- gc.draw('rectangle %d,%d %d,%d' % [
+ @gc.stroke('black')
+ @gc.draw('rectangle %d,%d %d,%d' % [
0, 0, subject_width + g_width, g_height + headers_height - 1
])
# content
top = headers_height + 20
- gc.stroke('transparent')
- lines(:image => gc, :top => top, :zoom => zoom,
- :subject_width => subject_width, :format => :image)
+ @gc.stroke('transparent')
+ lines(:image => @gc, :top => top, :zoom => zoom,
+ :subject_width => subject_width, :format => :image, :img_path => img.path, :font_path => font_path)
# today red line
if User.current.today >= @date_from and User.current.today <= date_to
- gc.stroke('red')
+ @gc.stroke('red')
x = (User.current.today - @date_from + 1) * zoom + subject_width
- gc.draw('line %g,%g %g,%g' % [
+ @gc.draw('line %g,%g %g,%g' % [
x, headers_height, x, headers_height + g_height - 1
])
end
- gc << img.path
- end
+ @gc << img.path
+ @gc.call
+ img.to_blob
+ rescue
+ @gc = MiniMagick::Tool::Convert.new
+ # create error message image
+ @gc.size('%dx%d' % [600, 120])
+ @gc.xc('white')
+ @gc.stroke('transparent').fill('red')
+ @gc.pointsize(20)
+ # and draw error message
+ err_message = <<"EOS"
+Image geneneration failed.
+There may be too much issues.
+Please decrease the number of issues.
+EOS
+ @gc.draw('text %d,%d %s' % [10, 40, Redmine::Utils::Shell.shell_quote(err_message)])
+ @gc << img.path
img.to_blob
ensure
@@ -803,10 +829,18 @@
def image_subject(params, subject, options={})
- params[:image].fill('black')
- params[:image].stroke('transparent')
- params[:image].strokewidth(1)
- params[:image].draw('text %d,%d %s' % [
+ @gc.fill('black')
+ @gc.stroke('transparent')
+ @gc.strokewidth(1)
+ @gc.draw('text %d,%d %s' % [
params[:indent], params[:top] + 2, Redmine::Utils::Shell.shell_quote(subject)
])
+ # Make blocks smaller for windows
+ if (@minimagick_command_max > 0) && (@gc.command.length > @minimagick_command_max)
+ @gc << params[:img_path]
+ @gc.call
+ @gc = MiniMagick::Tool::Convert.new
+ @gc << params[:img_path]
+ @gc.font(params[:font_path]) if params[:font_path].present?
+ end
end
@@ -992,6 +1026,6 @@
# Renders the task bar, with progress and late
if coords[:bar_start] && coords[:bar_end]
- params[:image].fill('#aaa')
- params[:image].draw('rectangle %d,%d %d,%d' % [
+ @gc.fill('#aaa')
+ @gc.draw('rectangle %d,%d %d,%d' % [
params[:subject_width] + coords[:bar_start],
params[:top],
@@ -1000,6 +1034,6 @@
])
if coords[:bar_late_end]
- params[:image].fill('#f66')
- params[:image].draw('rectangle %d,%d %d,%d' % [
+ @gc.fill('#f66')
+ @gc.draw('rectangle %d,%d %d,%d' % [
params[:subject_width] + coords[:bar_start],
params[:top],
@@ -1009,6 +1043,6 @@
end
if coords[:bar_progress_end]
- params[:image].fill('#00c600')
- params[:image].draw('rectangle %d,%d %d,%d' % [
+ @gc.fill('#00c600')
+ @gc.draw('rectangle %d,%d %d,%d' % [
params[:subject_width] + coords[:bar_start],
params[:top],
@@ -1023,6 +1057,6 @@
x = params[:subject_width] + coords[:start]
y = params[:top] - height / 2
- params[:image].fill('blue')
- params[:image].draw('polygon %d,%d %d,%d %d,%d %d,%d' % [
+ @gc.fill('blue')
+ @gc.draw('polygon %d,%d %d,%d %d,%d %d,%d' % [
x - 4, y,
x, y - 4,
@@ -1034,6 +1068,6 @@
x = params[:subject_width] + coords[:end] + params[:zoom]
y = params[:top] - height / 2
- params[:image].fill('blue')
- params[:image].draw('polygon %d,%d %d,%d %d,%d %d,%d' % [
+ @gc.fill('blue')
+ @gc.draw('polygon %d,%d %d,%d %d,%d %d,%d' % [
x - 4, y,
x, y - 4,
@@ -1045,9 +1079,17 @@
# Renders the label on the right
if label
- params[:image].fill('black')
- params[:image].draw('text %d,%d %s' % [
+ @gc.fill('black')
+ @gc.draw('text %d,%d %s' % [
params[:subject_width] + (coords[:bar_end] || 0) + 5, params[:top] + 1, Redmine::Utils::Shell.shell_quote(label)
])
end
+ # Make blocks smaller for windows
+ if (@minimagick_command_max > 0) && (@gc.command.length > @minimagick_command_max)
+ @gc << params[:img_path]
+ @gc.call
+ @gc = MiniMagick::Tool::Convert.new
+ @gc << params[:img_path]
+ @gc.font(params[:font_path]) if params[:font_path].present?
+ end
end
end
Updated by Go MAEDA almost 5 years ago
- Subject changed from Internal Server Error occurted when exporting gantt chart to png to Internal Server Error occurted when exporting gantt chart to png on Windows
Updated by 春 陈 over 3 years ago
taca tadocolo wrote:
Changed to split MiniMagick's "convert" command on Windows only.
To do so, changed the "convert" object (gc) to an instance variable (@gc), and added an @minimagick_command_max instance variable for the command splitting.[...]
hello, taca tadocolo
"@gc.size('%dx%d' % [subject_width + g_width + 1, height])" build error was occurred.
how to fix it?