zena 0.16.3 → 0.16.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/History.txt +11 -0
- data/app/controllers/nodes_controller.rb +1 -1
- data/app/controllers/versions_controller.rb +1 -1
- data/app/controllers/virtual_classes_controller.rb +29 -2
- data/app/models/cached_page.rb +3 -3
- data/app/models/document.rb +1 -20
- data/app/models/iformat.rb +4 -4
- data/app/models/image.rb +1 -1
- data/app/models/image_content.rb +5 -5
- data/app/models/node.rb +25 -0
- data/app/models/text_document_version.rb +11 -3
- data/app/models/virtual_class.rb +50 -0
- data/app/views/{nodes → sites}/404.html +0 -0
- data/app/views/templates/edit_tabs/_image.rhtml +1 -1
- data/app/views/versions/_list.rhtml +3 -1
- data/app/views/virtual_classes/_li.erb +2 -2
- data/app/views/virtual_classes/index.erb +9 -1
- data/bricks/tags/patch/node.rb +1 -1
- data/config/bricks.yml +1 -1
- data/config/gems.yml +4 -2
- data/db/migrate/047_change_default_link_id_to_zero.rb +1 -1
- data/db/migrate/20090825201159_insert_zero_link.rb +1 -1
- data/lib/bricks.rb +2 -2
- data/lib/bricks/requirements_validation.rb +13 -8
- data/lib/gettext_strings.rb +1 -0
- data/lib/tasks/zena.rake +15 -6
- data/lib/zena.rb +9 -3
- data/lib/{base_additions.rb → zena/base_additions.rb} +0 -0
- data/lib/{core_ext → zena/core_ext}/date_time.rb +0 -0
- data/lib/{core_ext → zena/core_ext}/dir.rb +0 -0
- data/lib/zena/core_ext/file_utils.rb +13 -0
- data/lib/{core_ext → zena/core_ext}/fixnum.rb +0 -0
- data/lib/{core_ext → zena/core_ext}/string.rb +0 -0
- data/lib/zena/deploy.rb +1 -1
- data/lib/zena/deploy/start.html +1 -1
- data/lib/zena/deploy/template.rb +5 -1
- data/lib/{fix_rails_layouts.rb → zena/fix_rails_layouts.rb} +0 -0
- data/lib/zena/info.rb +2 -2
- data/lib/zena/routes.rb +1 -1
- data/lib/zena/use/fixtures.rb +1 -1
- data/lib/zena/use/html_tags.rb +3 -3
- data/lib/zena/use/image_builder.rb +329 -0
- data/lib/zena/use/query_comment.rb +96 -0
- data/lib/zena/use/query_node.rb +408 -0
- data/lib/zena/use/query_node_finders.rb +91 -0
- data/lib/zena/use/rendering.rb +2 -2
- data/lib/{webdav_adapter.rb → zena/webdav_adapter.rb} +0 -0
- data/locale/de/LC_MESSAGES/zena.mo +0 -0
- data/locale/de/zena.po +1456 -0
- data/locale/en/LC_MESSAGES/zena.mo +0 -0
- data/locale/en/zena.po +626 -1197
- data/locale/fr/LC_MESSAGES/zena.mo +0 -0
- data/locale/fr/zena.po +895 -1221
- data/locale/zena.pot +527 -1027
- data/public/calendar/lang/calendar-de-utf8.js +128 -0
- data/public/calendar/menuarrow.gif +0 -0
- data/public/stylesheets/admin.css +2 -1
- data/test/custom_queries/complex.host.yml +1 -1
- data/test/fixtures/files/vclasses.yml +12 -0
- data/test/functional/virtual_classes_controller_test.rb +9 -0
- data/test/helpers/{node_query → query_node}/basic.yml +0 -0
- data/test/helpers/{node_query → query_node}/comments.yml +0 -0
- data/test/helpers/{node_query → query_node}/complex.yml +0 -0
- data/test/helpers/{node_query → query_node}/filters.yml +0 -0
- data/test/helpers/{node_query → query_node}/relations.yml +0 -0
- data/test/helpers/{node_query_test.rb → query_node_test.rb} +1 -2
- data/test/integration/navigation_test.rb +2 -0
- data/test/test_helper.rb +1 -1
- data/test/test_zena.rb +1 -1
- data/test/unit/core_ext_test.rb +3 -3
- data/test/unit/iformat_test.rb +3 -3
- data/test/unit/image_builder_test.rb +34 -34
- data/test/unit/node_test.rb +15 -1
- data/test/unit/virtual_class_test.rb +106 -0
- data/test/unit/zena/use/upload_test.rb +3 -3
- data/vendor/plugins/gettext_i18n_rails/tasks/gettext_rails_i18n.rake +3 -3
- data/zena.gemspec +36 -29
- data/zena_console.rb +33 -0
- metadata +30 -23
- data/lib/comment_query.rb +0 -92
- data/lib/image_builder.rb +0 -325
- data/lib/zena/use/node_query_finders.rb +0 -494
- data/vendor/bricks/20070122-172926.txt +0 -282
data/lib/bricks.rb
CHANGED
|
@@ -3,17 +3,20 @@ require 'yaml'
|
|
|
3
3
|
module Bricks
|
|
4
4
|
module RequirementsValidation
|
|
5
5
|
def requirement_errors(brick, requirements)
|
|
6
|
+
current_stderr = $stderr
|
|
7
|
+
$stderr = StringIO.new
|
|
6
8
|
errors = []
|
|
7
9
|
requirements.each do |k,v|
|
|
8
10
|
case k
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
# bad idea, this is run before gem version configuration
|
|
12
|
+
# when 'gem'
|
|
13
|
+
# v.split(',').each do |name|
|
|
14
|
+
# begin
|
|
15
|
+
# require name.strip
|
|
16
|
+
# rescue LoadError => err
|
|
17
|
+
# errors << "'#{name}' missing"
|
|
18
|
+
# end
|
|
19
|
+
# end
|
|
17
20
|
when 'file'
|
|
18
21
|
v.split(',').each do |name|
|
|
19
22
|
unless File.exist?("#{RAILS_ROOT}/#{name}")
|
|
@@ -28,6 +31,7 @@ module Bricks
|
|
|
28
31
|
end
|
|
29
32
|
end
|
|
30
33
|
end
|
|
34
|
+
$stderr = current_stderr
|
|
31
35
|
errors.empty? ? nil : errors
|
|
32
36
|
end
|
|
33
37
|
|
|
@@ -37,6 +41,7 @@ module Bricks
|
|
|
37
41
|
else
|
|
38
42
|
raw_config = YAML.load_file("#{Zena::ROOT}/config/bricks.yml")[RAILS_ENV] || {}
|
|
39
43
|
end
|
|
44
|
+
|
|
40
45
|
config = {}
|
|
41
46
|
|
|
42
47
|
raw_config.each do |brick, opts|
|
data/lib/gettext_strings.rb
CHANGED
data/lib/tasks/zena.rake
CHANGED
|
@@ -30,14 +30,14 @@ def symlink_assets(from, to)
|
|
|
30
30
|
if File.exist?(trg) || File.symlink?(trg)
|
|
31
31
|
File.unlink(trg)
|
|
32
32
|
end
|
|
33
|
-
FileUtils.
|
|
33
|
+
FileUtils.symlink_or_copy(src, trg)
|
|
34
34
|
end
|
|
35
35
|
else
|
|
36
36
|
# ignore
|
|
37
37
|
puts "Cannot install assets in #{to}/public/#{dir} (not a directory)"
|
|
38
38
|
end
|
|
39
39
|
else
|
|
40
|
-
FileUtils.
|
|
40
|
+
FileUtils.symlink_or_copy("#{from}/public/#{dir}", "#{to}/public/#{dir}")
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
end
|
|
@@ -440,11 +440,20 @@ namespace :zena do
|
|
|
440
440
|
puts cmd
|
|
441
441
|
system(cmd)
|
|
442
442
|
|
|
443
|
-
|
|
443
|
+
if RUBY_PLATFORM =~ /mswin32/
|
|
444
|
+
puts "\n\nOnce the server has started, you can open your web browser at:\n\n\n ====> http://localhost:3000 <====\n\n\n"
|
|
445
|
+
cmd = "ruby script/server -e #{ENV['RAILS_ENV']} -p 3000"
|
|
446
|
+
puts cmd
|
|
447
|
+
system cmd
|
|
448
|
+
else
|
|
449
|
+
cmd = "open #{File.join(Zena::ROOT, 'lib/zena/deploy/start.html').inspect}"
|
|
450
|
+
puts cmd
|
|
451
|
+
system(cmd)
|
|
444
452
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
453
|
+
cmd = "ruby script/server -e #{ENV['RAILS_ENV']} -p 3000"
|
|
454
|
+
puts cmd
|
|
455
|
+
exec cmd
|
|
456
|
+
end
|
|
448
457
|
end
|
|
449
458
|
|
|
450
459
|
end
|
data/lib/zena.rb
CHANGED
|
@@ -5,6 +5,7 @@ require 'fileutils'
|
|
|
5
5
|
require File.join(File.dirname(__FILE__), 'zena', 'info')
|
|
6
6
|
|
|
7
7
|
def has_executable(*list)
|
|
8
|
+
return false if RUBY_PLATFORM =~ /mswin32/
|
|
8
9
|
list.inject(true) do |s,e|
|
|
9
10
|
s && !(`which #{e} || echo 'no #{e}'` =~ /^no #{e}/)
|
|
10
11
|
end
|
|
@@ -50,7 +51,7 @@ module Zena
|
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
# FIXME: make this explicit in models
|
|
53
|
-
ActiveRecord::Base.send :include, Zena::Use::
|
|
54
|
+
ActiveRecord::Base.send :include, Zena::Use::QueryNodeFinders::AddUseQueryNodeMethod
|
|
54
55
|
ActiveRecord::Base.send :include, Zena::Acts::Secure
|
|
55
56
|
ActionController::Base.send :include, Zena::Acts::Secure
|
|
56
57
|
|
|
@@ -87,6 +88,11 @@ module Zena
|
|
|
87
88
|
gem_configuration.each do |gem_name, gem_config|
|
|
88
89
|
if gem_config
|
|
89
90
|
if gem_config['optional']
|
|
91
|
+
if brick_name = gem_config['brick']
|
|
92
|
+
unless Bricks::CONFIG[brick_name]
|
|
93
|
+
next
|
|
94
|
+
end
|
|
95
|
+
end
|
|
90
96
|
begin
|
|
91
97
|
gem gem_name, gem_config['version']
|
|
92
98
|
rescue LoadError
|
|
@@ -132,7 +138,7 @@ module Zena
|
|
|
132
138
|
|
|
133
139
|
def load_custom_extensions
|
|
134
140
|
#FIXME: cleanup all these hacks !
|
|
135
|
-
lib_path = File.join(Zena::ROOT, 'lib')
|
|
141
|
+
lib_path = File.join(Zena::ROOT, 'lib/zena')
|
|
136
142
|
Dir.foreach(File.join(lib_path, 'core_ext')) do |f|
|
|
137
143
|
next unless f =~ /\.rb\Z/
|
|
138
144
|
require File.join(lib_path, 'core_ext', f)
|
|
@@ -178,7 +184,6 @@ module Zena
|
|
|
178
184
|
add_load_paths(config)
|
|
179
185
|
config_gems(config)
|
|
180
186
|
load_plugins if RAILS_ROOT != Zena::ROOT
|
|
181
|
-
load_custom_extensions
|
|
182
187
|
include_modules
|
|
183
188
|
load_bricks
|
|
184
189
|
set_default_timezone(config)
|
|
@@ -407,4 +412,5 @@ end
|
|
|
407
412
|
Zena::EXT_TO_TYPE, Zena::TYPE_TO_EXT = make_hashes(EXT_TYPE)
|
|
408
413
|
Zena.add_load_paths
|
|
409
414
|
Zena.gems_setup
|
|
415
|
+
Zena.load_custom_extensions
|
|
410
416
|
require 'rubyless'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# This file provides a portable way to symlink, reverting to copy if symlinks are not supported.
|
|
2
|
+
|
|
3
|
+
FileUtils
|
|
4
|
+
|
|
5
|
+
if RUBY_PLATFORM =~ /mswin32/
|
|
6
|
+
class << FileUtils
|
|
7
|
+
alias symlink_or_copy cp_r
|
|
8
|
+
end
|
|
9
|
+
else
|
|
10
|
+
class << FileUtils
|
|
11
|
+
alias symlink_or_copy ln_s
|
|
12
|
+
end
|
|
13
|
+
end
|
|
File without changes
|
|
File without changes
|
data/lib/zena/deploy.rb
CHANGED
|
@@ -121,7 +121,7 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
|
121
121
|
end
|
|
122
122
|
|
|
123
123
|
#========================== MANAGE HOST =========================#
|
|
124
|
-
desc "create a new site"
|
|
124
|
+
desc "create a new site [-s host='...' -s pass='...' -s lang='...']"
|
|
125
125
|
task :mksite, :roles => :app do
|
|
126
126
|
run "#{in_current} rake zena:mksite HOST='#{self[:host]}' PASSWORD='#{self[:pass]}' RAILS_ENV='production' LANG='#{self[:lang] || 'en'}'"
|
|
127
127
|
create_vhost
|
data/lib/zena/deploy/start.html
CHANGED
|
@@ -32,7 +32,7 @@ new PeriodicalExecuter(function(pe) {
|
|
|
32
32
|
counter -= 1;
|
|
33
33
|
if (counter == 0) {
|
|
34
34
|
pe.stop();
|
|
35
|
-
window.location.href = 'http://localhost:
|
|
35
|
+
window.location.href = 'http://localhost:3000';
|
|
36
36
|
} else {
|
|
37
37
|
$('counter').update(counter);
|
|
38
38
|
$('counter').show();
|
data/lib/zena/deploy/template.rb
CHANGED
|
@@ -2,7 +2,11 @@ require 'digest/sha1'
|
|
|
2
2
|
require 'zena/info'
|
|
3
3
|
# This is a rails template to generate a basic zena application
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
if RUBY_PLATFORM =~ /mswin32/
|
|
6
|
+
run "del public\\index.html"
|
|
7
|
+
else
|
|
8
|
+
run "rm public/index.html"
|
|
9
|
+
end
|
|
6
10
|
|
|
7
11
|
gem 'zena', :version => Zena::VERSION
|
|
8
12
|
route 'map.zen_routes'
|
|
File without changes
|
data/lib/zena/info.rb
CHANGED
|
@@ -5,11 +5,11 @@ end
|
|
|
5
5
|
|
|
6
6
|
AUTHENTICATED_PREFIX = "oo"
|
|
7
7
|
PASSWORD_SALT = "jf93jfnvnas09093nas0923" # type anything here (but change this line !)
|
|
8
|
-
ZENA_CALENDAR_LANGS = ["en", "fr"] # FIXME: build this dynamically from existing files
|
|
8
|
+
ZENA_CALENDAR_LANGS = ["en", "fr", "de"] # FIXME: build this dynamically from existing files
|
|
9
9
|
ENABLE_XSENDFILE = false
|
|
10
10
|
|
|
11
11
|
module Zena
|
|
12
|
-
VERSION = '0.16.
|
|
12
|
+
VERSION = '0.16.4'
|
|
13
13
|
REVISION = 1336
|
|
14
14
|
ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
|
15
15
|
end
|
data/lib/zena/routes.rb
CHANGED
data/lib/zena/use/fixtures.rb
CHANGED
|
@@ -131,7 +131,7 @@ module Zena
|
|
|
131
131
|
unless File.exist?("#{SITES_ROOT}/test.host/public")
|
|
132
132
|
FileUtils::mkpath("#{SITES_ROOT}/test.host/public")
|
|
133
133
|
['images', 'calendar', 'stylesheets', 'javascripts'].each do |dir|
|
|
134
|
-
FileUtils.
|
|
134
|
+
FileUtils.symlink_or_copy("../../../public/#{dir}", "#{SITES_ROOT}/test.host/public/#{dir}")
|
|
135
135
|
end
|
|
136
136
|
end
|
|
137
137
|
|
data/lib/zena/use/html_tags.rb
CHANGED
|
@@ -163,7 +163,7 @@ module Zena
|
|
|
163
163
|
|
|
164
164
|
if opts[:mode] && (format = Iformat[opts[:mode]]) && format[:size] != :keep
|
|
165
165
|
# resize image
|
|
166
|
-
img = ImageBuilder.new(:path=>"#{RAILS_ROOT}/public#{res[:src]}", :width=>32, :height=>32)
|
|
166
|
+
img = Zena::Use::ImageBuilder.new(:path=>"#{RAILS_ROOT}/public#{res[:src]}", :width=>32, :height=>32)
|
|
167
167
|
img.transform!(format)
|
|
168
168
|
if (img.width == res[:width] && img.height == res[:height])
|
|
169
169
|
# ignore mode
|
|
@@ -377,10 +377,10 @@ module Zena
|
|
|
377
377
|
# else
|
|
378
378
|
# "<a href='/login'>#{_('login')}</a>"
|
|
379
379
|
# end
|
|
380
|
-
link_to "login", login_url
|
|
380
|
+
link_to _("login"), login_url
|
|
381
381
|
else
|
|
382
382
|
# "<a href='/logout'>#{_('logout')}</a>"
|
|
383
|
-
link_to "logout", logout_url
|
|
383
|
+
link_to _("logout"), logout_url
|
|
384
384
|
end
|
|
385
385
|
end
|
|
386
386
|
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
require 'tempfile'
|
|
2
|
+
require 'digest/sha1'
|
|
3
|
+
unless defined?(Magick)
|
|
4
|
+
begin
|
|
5
|
+
# this works on the deb box
|
|
6
|
+
require 'RMagick'
|
|
7
|
+
rescue LoadError
|
|
8
|
+
begin
|
|
9
|
+
# this works on my Mac
|
|
10
|
+
require 'rmagick'
|
|
11
|
+
rescue LoadError
|
|
12
|
+
puts "ImageMagick not found. Using dummy."
|
|
13
|
+
require 'ftools'
|
|
14
|
+
# Create a dummy magick module
|
|
15
|
+
module Magick
|
|
16
|
+
CenterGravity = OverCompositeOp = MaxRGB = NorthGravity = SouthGravity = nil
|
|
17
|
+
class << self
|
|
18
|
+
end
|
|
19
|
+
class ZenaDummy
|
|
20
|
+
def initialize(*a)
|
|
21
|
+
end
|
|
22
|
+
def method_missing(meth, *args)
|
|
23
|
+
# do nothing
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
class Image < ZenaDummy
|
|
27
|
+
end
|
|
28
|
+
class ImageList < ZenaDummy
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
module Zena
|
|
36
|
+
module Use
|
|
37
|
+
class ImageBuilder
|
|
38
|
+
DEFAULT_FORMATS = {
|
|
39
|
+
'tiny' => { :name=>'tiny', :size=>:force, :width=>16, :height=>16 , :gravity=>Magick::CenterGravity },
|
|
40
|
+
'mini' => { :name=>'mini', :size=>:force, :width=>32, :height=>32 , :gravity=>Magick::CenterGravity },
|
|
41
|
+
'square' => { :name=>'square', :size=>:limit, :width=>180, :height=>180, :gravity=>Magick::CenterGravity },
|
|
42
|
+
'med' => { :name=>'med', :size=>:limit, :width=>280, :height=>186, :gravity=>Magick::CenterGravity },
|
|
43
|
+
'top' => { :name=>'top', :size=>:force, :width=>280, :height=>186, :gravity => Magick::NorthGravity },
|
|
44
|
+
'low' => { :name=>'low', :size=>:force, :width=>280, :height=>186, :gravity => Magick::SouthGravity },
|
|
45
|
+
'side' => { :name=>'side', :size=>:force, :width=>220, :height=>500, :gravity=>Magick::CenterGravity },
|
|
46
|
+
'std' => { :name=>'std', :size=>:limit, :width=>600, :height=>400, :gravity=>Magick::CenterGravity },
|
|
47
|
+
'pv' => { :name=>'pv', :size=>:force, :width=>70, :height=>70 , :gravity=>Magick::CenterGravity },
|
|
48
|
+
'edit' => { :name=>'edit', :size=>:limit, :width=>400, :height=>400, :gravity=>Magick::CenterGravity },
|
|
49
|
+
'full' => { :name=>'full', :size=>:keep , :gravity=>Magick::CenterGravity },
|
|
50
|
+
nil => { :name=>'full', :size=>:keep , :gravity=>Magick::CenterGravity },
|
|
51
|
+
}.freeze
|
|
52
|
+
# 'sepia'=> { :size=>:limit, :width=>280, :ratio=>2/3.0, :post=>Proc.new {|img| img.sepiatone(Magick::MaxRGB * 0.8)}},
|
|
53
|
+
|
|
54
|
+
class << self
|
|
55
|
+
def image_content_type?(content_type)
|
|
56
|
+
content_type =~ /image/
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def dummy?
|
|
60
|
+
Magick.const_defined?(:ZenaDummy)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def hash_id(format)
|
|
64
|
+
Digest::SHA1.hexdigest("#{format[:name]}#{format[:size]}#{format[:width]}#{format[:height]}#{format[:gravity]}")[0..9].to_i(16)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
DEFAULT_FORMATS.each do |k, v|
|
|
68
|
+
v[:hash_id] = Zena::Use::ImageBuilder.hash_id(v)
|
|
69
|
+
v.freeze
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def initialize(h)
|
|
74
|
+
params = {:height=>nil, :width=>nil, :path=>nil, :file=>nil, :actions=>[]}.merge(h)
|
|
75
|
+
|
|
76
|
+
params.each do |k,v|
|
|
77
|
+
case k
|
|
78
|
+
when :height
|
|
79
|
+
@height = v if v
|
|
80
|
+
when :width
|
|
81
|
+
@width = v if v
|
|
82
|
+
when :path
|
|
83
|
+
@path = v if v
|
|
84
|
+
when :file
|
|
85
|
+
@file = v if v
|
|
86
|
+
when :actions
|
|
87
|
+
if v.kind_of?(Array)
|
|
88
|
+
@actions = v
|
|
89
|
+
else
|
|
90
|
+
raise StandardError, "Bad actions format"
|
|
91
|
+
end
|
|
92
|
+
else
|
|
93
|
+
raise StandardError, "Bad parameter (#{k})"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
unless @width && @height || dummy?
|
|
97
|
+
if @img = build_image_from_file_or_path
|
|
98
|
+
@width = @img.columns
|
|
99
|
+
@height = @img.rows
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def dummy?
|
|
105
|
+
Zena::Use::ImageBuilder.dummy? || (!@path && !@img && !@file)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def read
|
|
109
|
+
return nil if dummy?
|
|
110
|
+
render_img
|
|
111
|
+
@img.to_blob
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def write(path)
|
|
115
|
+
return false if dummy?
|
|
116
|
+
render_img
|
|
117
|
+
@img.write(path)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def rows
|
|
121
|
+
return nil unless @height || !dummy?
|
|
122
|
+
(@height ||= render_img.rows).round
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def columns
|
|
126
|
+
return nil unless @width || !dummy?
|
|
127
|
+
(@width ||= render_img.columns).round
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
alias height rows
|
|
131
|
+
alias width columns
|
|
132
|
+
|
|
133
|
+
def resize!(s)
|
|
134
|
+
# we do not zoom pixels
|
|
135
|
+
return unless s < 1.0
|
|
136
|
+
@img = nil # reset current rendered image
|
|
137
|
+
@width *= s
|
|
138
|
+
@height *= s
|
|
139
|
+
@actions << Proc.new {|img| img.resize!(s) }
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def crop!(x,y,w,h)
|
|
143
|
+
@img = nil # reset current rendered image
|
|
144
|
+
@width = [@width -x, w].min
|
|
145
|
+
@height = [@height-y, h].min
|
|
146
|
+
@actions << Proc.new {|img| img.crop!(x,y,[@img.columns-x, w].min,[@img.rows-y, h].min, true) }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def format=(fmt)
|
|
150
|
+
return unless !dummy? && Magick.formats[fmt.upcase] =~ /w/
|
|
151
|
+
@actions << Proc.new {|img| img.format = fmt.upcase; img }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def format
|
|
155
|
+
render_img.format
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def exif
|
|
159
|
+
@exif ||= ExifData.new(render_img.get_exif_by_entry)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def max_filesize=(size)
|
|
163
|
+
@actions << Proc.new {|img| do_limit!(size) }
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def do_limit!(size)
|
|
167
|
+
return @img if @filesize <= size
|
|
168
|
+
|
|
169
|
+
# Check real size
|
|
170
|
+
tmp_path = Tempfile.new('tmp_img').path
|
|
171
|
+
@img.write('jpeg:' + tmp_path)
|
|
172
|
+
|
|
173
|
+
return @img if File.stat(tmp_path).size <= size
|
|
174
|
+
|
|
175
|
+
# Change type to JPG and quality to 80
|
|
176
|
+
if (@img.format == 'JPG' || @img.format == 'JPEG') && @img.quality > 80
|
|
177
|
+
@img.write('jpeg:' + tmp_path) { self.quality = 80 }
|
|
178
|
+
else
|
|
179
|
+
@img.format = 'JPG'
|
|
180
|
+
@img.write('jpeg:' + tmp_path) { self.quality = 80 }
|
|
181
|
+
end
|
|
182
|
+
ratio = File.stat(tmp_path).size.to_f / size
|
|
183
|
+
|
|
184
|
+
return @img = Magick::ImageList.new(tmp_path) if ratio <= 1.0
|
|
185
|
+
|
|
186
|
+
# Not enough ? Resize.
|
|
187
|
+
ratio = 1.0 / Math.sqrt(ratio)
|
|
188
|
+
@width *= ratio
|
|
189
|
+
@height *= ratio
|
|
190
|
+
@img.resize!(ratio)
|
|
191
|
+
@img
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def crop_min!(w,h,gravity=Magick::CenterGravity)
|
|
195
|
+
@img = nil # reset current rendered image
|
|
196
|
+
@width = [@width ,w].min
|
|
197
|
+
@height = [@height,h].min
|
|
198
|
+
@actions << Proc.new {|img| img.crop!(gravity,[@img.columns,w].min,[@img.rows,h].min, true) }
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def set_background!(opacity,w,h)
|
|
202
|
+
@img = nil # reset current rendered image
|
|
203
|
+
@width = [@width ,w].max
|
|
204
|
+
@height = [@height,h].max
|
|
205
|
+
@actions << Proc.new do |img|
|
|
206
|
+
bg = Magick::Image.new(w,h)
|
|
207
|
+
bg.opacity = opacity
|
|
208
|
+
bg.format = img.format
|
|
209
|
+
img = bg.composite(img, Magick::CenterGravity, Magick::OverCompositeOp)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Transform into another format. If nil : do nothing.
|
|
214
|
+
def transform!(tformat=nil)
|
|
215
|
+
return self unless tformat
|
|
216
|
+
@img = nil
|
|
217
|
+
format = { :size=>:limit, :gravity=>Magick::CenterGravity }.merge(tformat)
|
|
218
|
+
@pre, @post = format[:pre], format[:post]
|
|
219
|
+
|
|
220
|
+
if format[:size] == :keep
|
|
221
|
+
h,w = @height, @width
|
|
222
|
+
else
|
|
223
|
+
h,w = format[:height], format[:width]
|
|
224
|
+
end
|
|
225
|
+
if format[:scale]
|
|
226
|
+
if h || w
|
|
227
|
+
# scale is a pre-zoom before crop
|
|
228
|
+
scale = format[:scale]
|
|
229
|
+
else
|
|
230
|
+
# we resize to scale
|
|
231
|
+
h,w = @height*format[:scale], @width*format[:scale]
|
|
232
|
+
# but we do not zoom
|
|
233
|
+
scale = 1.0
|
|
234
|
+
# ignore ':size' format if not height nor width was given
|
|
235
|
+
format[:size] = :force
|
|
236
|
+
end
|
|
237
|
+
else
|
|
238
|
+
scale = 1.0
|
|
239
|
+
end
|
|
240
|
+
if format[:ratio] && h && !w
|
|
241
|
+
w = h / format[:ratio]
|
|
242
|
+
elsif format[:ratio] && w && !h
|
|
243
|
+
h = w * format[:ratio]
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
pw,ph = @width, @height
|
|
247
|
+
if [w,h,pw,ph].include?(nil) || [w,h,pw,ph].min <= 0
|
|
248
|
+
# image size or thumb size is null (no image processing tool used, no idea on image size)
|
|
249
|
+
if format[:size] == :keep
|
|
250
|
+
@height, @width = nil, nil
|
|
251
|
+
else
|
|
252
|
+
@height, @width = h, w
|
|
253
|
+
end
|
|
254
|
+
return self
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
case format[:size]
|
|
258
|
+
when :force
|
|
259
|
+
crop_scale = [w.to_f/pw, h.to_f/ph].max
|
|
260
|
+
if crop_scale > 1.0
|
|
261
|
+
# we do not zoom. Fill with transparent background.
|
|
262
|
+
crop_min!(w,h,format[:gravity])
|
|
263
|
+
set_background!(Magick::MaxRGB, w, h)
|
|
264
|
+
else
|
|
265
|
+
resize!(crop_scale * scale)
|
|
266
|
+
crop_min!(w, h,format[:gravity])
|
|
267
|
+
end
|
|
268
|
+
when :force_no_crop
|
|
269
|
+
crop_scale = [w.to_f/pw, h.to_f/ph].min
|
|
270
|
+
resize!(crop_scale * scale)
|
|
271
|
+
crop_min!(w, h,format[:gravity])
|
|
272
|
+
set_background!(Magick::MaxRGB, w, h)
|
|
273
|
+
when :limit
|
|
274
|
+
crop_scale = [w.to_f/pw, h.to_f/ph].min
|
|
275
|
+
resize!(crop_scale * scale)
|
|
276
|
+
crop_min!(w, h,format[:gravity])
|
|
277
|
+
when :keep
|
|
278
|
+
end
|
|
279
|
+
self
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def render_img
|
|
283
|
+
raise IOError, 'MagickDummy cannot render image' if Zena::Use::ImageBuilder.dummy?
|
|
284
|
+
unless @img
|
|
285
|
+
unless @img = build_image_from_file_or_path
|
|
286
|
+
raise IOError, 'Cannot render image without path or file'
|
|
287
|
+
end
|
|
288
|
+
if @pre
|
|
289
|
+
@pre = [@pre].flatten
|
|
290
|
+
@pre.each do |a|
|
|
291
|
+
@img = a.call(@img)
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
if @actions
|
|
296
|
+
@actions.each do |a|
|
|
297
|
+
@img = a.call(@img)
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
if @post
|
|
302
|
+
@post = [@post].flatten
|
|
303
|
+
@post.each do |a|
|
|
304
|
+
@img = a.call(@img)
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
@img
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def build_image_from_file_or_path
|
|
312
|
+
if @file || @path
|
|
313
|
+
if @file.kind_of?(StringIO)
|
|
314
|
+
img = Magick::ImageList.new
|
|
315
|
+
@file.rewind
|
|
316
|
+
img.from_blob(@file.read)
|
|
317
|
+
@file.rewind
|
|
318
|
+
@filesize = @file.size
|
|
319
|
+
img
|
|
320
|
+
else
|
|
321
|
+
img = Magick::ImageList.new(@file ? @file.path : @path)
|
|
322
|
+
@filesize = img.filesize
|
|
323
|
+
img
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end # ImageBuilder
|
|
328
|
+
end # Use
|
|
329
|
+
end # Zena
|