rubyshop 0.0.1 → 0.0.2
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/lib/rubyshop.rb +2 -31
- data/lib/rubyshop/adjustmentlayer.rb +44 -0
- data/lib/rubyshop/canvas.rb +5 -67
- data/lib/rubyshop/filllayer.rb +40 -0
- data/lib/rubyshop/layer.rb +65 -10
- data/lib/rubyshop/layermask.rb +16 -0
- data/lib/rubyshop/layerset.rb +91 -5
- data/lib/rubyshop/rubyshop.rb +7 -0
- metadata +4 -2
data/lib/rubyshop.rb
CHANGED
@@ -1,37 +1,8 @@
|
|
1
1
|
require 'rmagick'
|
2
2
|
|
3
|
-
require 'rubyshop/canvas'
|
4
3
|
require 'rubyshop/layerset'
|
5
4
|
require 'rubyshop/layer'
|
5
|
+
require 'rubyshop/canvas'
|
6
6
|
require 'rubyshop/filllayer'
|
7
7
|
require 'rubyshop/adjustmentlayer'
|
8
|
-
|
9
|
-
module Rubyshop
|
10
|
-
# Layer mode constants
|
11
|
-
# some of photoshops layer modes are directly equvilent to RMagick
|
12
|
-
# some are not, and some arent supported at all.
|
13
|
-
|
14
|
-
Normal = Magick::OverCompositeOp # PS equivilent
|
15
|
-
Dissolve = Magick::DissolveCompositeOp
|
16
|
-
Darken = Magick::DarkenCompositeOp # PS equivilent
|
17
|
-
Multiply = Magick::MultiplyCompositeOp # PS equivilent
|
18
|
-
#ColorBurn
|
19
|
-
#LinearBurn
|
20
|
-
Lighten = Magick::LightenCompositeOp # PS equivilent
|
21
|
-
Screen = Magick::ScreenCompositeOp # PS equivilent
|
22
|
-
#ColorDodge
|
23
|
-
#LinearDodge
|
24
|
-
Overlay = Magick::OverlayCompositeOp # PS equivilent
|
25
|
-
#SoftLight
|
26
|
-
#HardLight
|
27
|
-
#VividLight
|
28
|
-
#LinearLight
|
29
|
-
#PinLight
|
30
|
-
#HardMix
|
31
|
-
Difference = Magick::DifferenceCompositeOp # PS equivilent
|
32
|
-
#Exclusion
|
33
|
-
Hue = Magick::HueCompositeOp
|
34
|
-
Saturation = Magick::SaturateCompositeOp
|
35
|
-
Color = Magick::ColorizeCompositeOp
|
36
|
-
Luminosity = Magick::LuminizeCompositeOp
|
37
|
-
end
|
8
|
+
require 'rubyshop/layermask'
|
@@ -1,4 +1,48 @@
|
|
1
1
|
module Rubyshop
|
2
|
+
Levels = 1
|
3
|
+
Curves = 2
|
4
|
+
ColorBalance = 3
|
5
|
+
BrightnessContrast = 4
|
6
|
+
HueSaturation = 5
|
7
|
+
SelectiveColor = 6
|
8
|
+
ChannelMixer = 7
|
9
|
+
GradientMap = 8
|
10
|
+
PhotoFilter = 9
|
11
|
+
Invert = 10 # negate
|
12
|
+
Threshold = 11 # threshold
|
13
|
+
Polarize = 12 #
|
14
|
+
Blur = 13
|
15
|
+
|
2
16
|
class AdjustmentLayer < Layer
|
17
|
+
attr_reader :type, :args
|
18
|
+
|
19
|
+
def initialize(type, *args, &block)
|
20
|
+
@type = type
|
21
|
+
@args = args
|
22
|
+
@mode = Normal
|
23
|
+
@offset_x = 0
|
24
|
+
@offset_y = 0
|
25
|
+
@opacity_percent = 100
|
26
|
+
@layer_mask = nil
|
27
|
+
|
28
|
+
case type
|
29
|
+
when Invert
|
30
|
+
@proc = proc { negate }
|
31
|
+
when Threshold
|
32
|
+
@proc = proc { threshold *args }
|
33
|
+
when Levels
|
34
|
+
@proc = proc { level *args }
|
35
|
+
when Blur
|
36
|
+
@proc = proc { gaussian_blur *args }
|
37
|
+
end
|
38
|
+
@proc = proc { |*args| @proc }.call(*@args)
|
39
|
+
end
|
40
|
+
|
41
|
+
def merge_down(image)
|
42
|
+
@image = image.clone.instance_eval &@proc
|
43
|
+
@image.matte = true
|
44
|
+
|
45
|
+
super(image)
|
46
|
+
end
|
3
47
|
end
|
4
48
|
end
|
data/lib/rubyshop/canvas.rb
CHANGED
@@ -1,78 +1,16 @@
|
|
1
1
|
module Rubyshop
|
2
|
-
class Canvas
|
2
|
+
class Canvas < LayerSet
|
3
3
|
attr_reader :width, :height
|
4
|
+
attr_accessor :image
|
4
5
|
|
5
6
|
def initialize(width, height, &block)
|
6
7
|
@image = Magick::Image.new width, height
|
7
8
|
@width = width
|
8
9
|
@height = height
|
9
|
-
|
10
|
-
|
10
|
+
$RubyshopCanvasWidth = @width
|
11
|
+
$RubyshopCanvasHeight = @height
|
11
12
|
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
def layer_set(name, &block)
|
16
|
-
if name.is_a? Rubyshop::LayerSet
|
17
|
-
set = name
|
18
|
-
@layers << set
|
19
|
-
@sets[set.name] = set
|
20
|
-
elsif @sets[name]
|
21
|
-
set = @sets[name]
|
22
|
-
else
|
23
|
-
set = LayerSet.new name
|
24
|
-
@layers << set
|
25
|
-
@sets[name] = set
|
26
|
-
end
|
27
|
-
|
28
|
-
set.instance_eval &block if block_given?
|
29
|
-
|
30
|
-
return set
|
31
|
-
end
|
32
|
-
|
33
|
-
def layer(filename, &block)
|
34
|
-
layer = Layer.new filename
|
35
|
-
@layers << layer
|
36
|
-
|
37
|
-
layer.instace_eval &block if block_given?
|
38
|
-
|
39
|
-
return layer
|
40
|
-
end
|
41
|
-
|
42
|
-
def flatten
|
43
|
-
layers = @layers
|
44
|
-
layers.reverse.each do |layer|
|
45
|
-
if layer.is_a? Rubyshop::Layer
|
46
|
-
@image.composite!(layer.image, layer.offset_x, layer.offset_y, layer.mode)
|
47
|
-
elsif layer.is_a? Rubyshop::LayerSet
|
48
|
-
layer.layers.reverse.each do |set_layer|
|
49
|
-
image.composite!(set_layer.image, set_layer.offset_x, set_layer.offset_y, set_layer.mode)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
@layers.delete(layer)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def render
|
57
|
-
image = @image
|
58
|
-
@layers.reverse.each do |layer|
|
59
|
-
if layer.is_a? Rubyshop::Layer
|
60
|
-
image.composite!(layer.image, layer.offset_x, layer.offset_y, layer.mode)
|
61
|
-
elsif layer.is_a? Rubyshop::LayerSet
|
62
|
-
layer.layers.reverse.each do |set_layer|
|
63
|
-
image.composite!(set_layer.image, set_layer.offset_x, set_layer.offset_y, set_layer.mode)
|
64
|
-
end
|
65
|
-
elsif layer.is_a? Rubyshop::AdjustmentLayer
|
66
|
-
# nothing to do
|
67
|
-
elsif layer.is_a? Rubyshop::FillLayer
|
68
|
-
# nother to do
|
69
|
-
end
|
70
|
-
end
|
71
|
-
return image
|
72
|
-
end
|
73
|
-
|
74
|
-
def save_as(filename)
|
75
|
-
render.write(filename)
|
13
|
+
super(:canvas, &block)
|
76
14
|
end
|
77
15
|
end
|
78
16
|
end
|
data/lib/rubyshop/filllayer.rb
CHANGED
@@ -1,4 +1,44 @@
|
|
1
1
|
module Rubyshop
|
2
|
+
# Fill layer types
|
3
|
+
|
4
|
+
SolidColor = 0
|
5
|
+
Gradient = 1
|
6
|
+
Pattern = 2
|
7
|
+
|
2
8
|
class FillLayer < Layer
|
9
|
+
attr_accessor :image
|
10
|
+
attr_reader :offset_x, :offset_y
|
11
|
+
|
12
|
+
def initialize(type, *args, &block)
|
13
|
+
case type
|
14
|
+
when SolidColor
|
15
|
+
color = args[0]
|
16
|
+
|
17
|
+
fill = Magick::GradientFill.new(0, 0, 0, 0, color, color)
|
18
|
+
|
19
|
+
when Gradient
|
20
|
+
x1 = args[0]
|
21
|
+
y1 = args[1]
|
22
|
+
x2 = args[2]
|
23
|
+
y2 = args[3]
|
24
|
+
color1 = args[4]
|
25
|
+
color2 = args[5]
|
26
|
+
|
27
|
+
fill = Magick::GradientFill.new(x1, y1, x2, y2, color1, color2)
|
28
|
+
|
29
|
+
when Pattern
|
30
|
+
image = args[0]
|
31
|
+
|
32
|
+
fill = Magick::TextureFill.new(image)
|
33
|
+
end
|
34
|
+
|
35
|
+
@image = Magick::Image.new($RubyshopCanvasWidth, $RubyshopCanvasHeight, fill)
|
36
|
+
|
37
|
+
@image.matte = true
|
38
|
+
@mode = Normal
|
39
|
+
@offset_x = 0
|
40
|
+
@offset_y = 0
|
41
|
+
@opacity_percent = 100
|
42
|
+
end
|
3
43
|
end
|
4
44
|
end
|
data/lib/rubyshop/layer.rb
CHANGED
@@ -1,17 +1,70 @@
|
|
1
1
|
module Rubyshop
|
2
|
+
# Layer mode constants
|
3
|
+
# some of photoshops layer modes are directly equvilent to RMagick
|
4
|
+
# some are not, and some arent supported at all.
|
5
|
+
|
6
|
+
Normal = Magick::OverCompositeOp # PS equivilent
|
7
|
+
Dissolve = Magick::DissolveCompositeOp
|
8
|
+
Darken = Magick::DarkenCompositeOp # PS equivilent
|
9
|
+
Multiply = Magick::MultiplyCompositeOp # PS equivilent
|
10
|
+
#ColorBurn
|
11
|
+
#LinearBurn
|
12
|
+
Lighten = Magick::LightenCompositeOp # PS equivilent
|
13
|
+
Screen = Magick::ScreenCompositeOp # PS equivilent
|
14
|
+
#ColorDodge
|
15
|
+
#LinearDodge
|
16
|
+
Overlay = Magick::OverlayCompositeOp # PS equivilent
|
17
|
+
#SoftLight
|
18
|
+
#HardLight
|
19
|
+
#VividLight
|
20
|
+
#LinearLight
|
21
|
+
#PinLight
|
22
|
+
#HardMix
|
23
|
+
Difference = Magick::DifferenceCompositeOp # PS equivilent
|
24
|
+
#Exclusion
|
25
|
+
Hue = Magick::HueCompositeOp
|
26
|
+
Saturation = Magick::SaturateCompositeOp
|
27
|
+
Color = Magick::ColorizeCompositeOp
|
28
|
+
Luminosity = Magick::LuminizeCompositeOp
|
29
|
+
|
2
30
|
class Layer
|
3
|
-
attr_accessor :image
|
31
|
+
attr_accessor :image
|
4
32
|
attr_reader :offset_x, :offset_y
|
5
33
|
|
6
|
-
def initialize(
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
34
|
+
def initialize(options = {})
|
35
|
+
if options[:file]
|
36
|
+
@image = Magick::Image.read(options[:file]).first
|
37
|
+
@image.background_color = 'transparent'
|
38
|
+
elsif options[:blob]
|
39
|
+
@image = Magick::Image.from_blob(options[:blob]).first
|
40
|
+
@image.background_color = 'transparent'
|
41
|
+
elsif options[:image]
|
42
|
+
if options[:image].is_a? Magick::Image
|
43
|
+
@image = options[:image]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if @image
|
48
|
+
@image.matte = true
|
49
|
+
@mode = Normal
|
50
|
+
@offset_x = 0
|
51
|
+
@offset_y = 0
|
52
|
+
@opacity_percent = 100
|
53
|
+
@layer_mask = nil
|
54
|
+
else
|
55
|
+
raise "Layer not created -- no layer source."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def layer_mask(options, &block)
|
60
|
+
@layer_mask = LayerMask.new options
|
61
|
+
|
62
|
+
@layer_mask.instance_eval &block if block_given?
|
63
|
+
end
|
64
|
+
|
65
|
+
def merge_down(image)
|
66
|
+
@layer_mask.apply self if @layer_mask
|
67
|
+
image.composite!(@image, @offset_x, @offset_y, @mode)
|
15
68
|
end
|
16
69
|
|
17
70
|
def width
|
@@ -39,6 +92,7 @@ module Rubyshop
|
|
39
92
|
return true
|
40
93
|
end
|
41
94
|
|
95
|
+
|
42
96
|
def mode(mode = nil)
|
43
97
|
return @mode if mode.nil?
|
44
98
|
@mode = mode
|
@@ -55,5 +109,6 @@ module Rubyshop
|
|
55
109
|
def leave_set(set)
|
56
110
|
set.remove_layer(self)
|
57
111
|
end
|
112
|
+
|
58
113
|
end
|
59
114
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rubyshop
|
2
|
+
class LayerMask < Layer
|
3
|
+
def apply(layer)
|
4
|
+
# apply layer mask to layer before merging down
|
5
|
+
fill = Magick::GradientFill.new(0,0,0,0, '#000', '#000')
|
6
|
+
mask = Magick::Image.new(layer.width, layer.height, fill)
|
7
|
+
mask.composite!(@image, @offset_x, @offset_y, Magick::OverCompositeOp)
|
8
|
+
|
9
|
+
alpha_channel = layer.image.channel(Magick::AlphaChannel).negate
|
10
|
+
alpha_channel.composite!(mask, 0, 0, Magick::MultiplyCompositeOp)
|
11
|
+
alpha_channel.matte = false
|
12
|
+
layer.image.composite!(alpha_channel, 0, 0, Magick::CopyOpacityCompositeOp)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
data/lib/rubyshop/layerset.rb
CHANGED
@@ -3,22 +3,108 @@ module Rubyshop
|
|
3
3
|
attr_accessor :layers
|
4
4
|
attr_reader :min_x, :min_y, :max_x, :max_y, :bounding_width, :bounding_height, :name
|
5
5
|
|
6
|
-
def initialize(name)
|
6
|
+
def initialize(name, &block)
|
7
7
|
@layers = []
|
8
|
+
@layer_sets = {}
|
9
|
+
|
8
10
|
bounding_box
|
9
11
|
@name = name
|
10
|
-
|
12
|
+
|
13
|
+
self.instance_eval &block if block_given?
|
11
14
|
end
|
12
15
|
|
13
|
-
def
|
14
|
-
|
16
|
+
def layer_set(set_or_name, &block)
|
17
|
+
if set_or_name.is_a? Rubyshop::LayerSet
|
18
|
+
# referencing a previously instanstiated LayerSet and adding to Canvas.
|
19
|
+
set = set_or_name
|
20
|
+
@layers << set
|
21
|
+
@layer_sets[set.name] = set
|
22
|
+
|
23
|
+
elsif @layer_sets[set_or_name]
|
24
|
+
# referencing a previously added LayerSet.
|
25
|
+
set = @layer_sets[set_or_name]
|
26
|
+
|
27
|
+
else
|
28
|
+
# creating a new LayerSet and adding to Canvas.
|
29
|
+
set = LayerSet.new set_or_name
|
30
|
+
@layers << set
|
31
|
+
@layer_sets[set_or_name] = set
|
32
|
+
end
|
33
|
+
|
34
|
+
# tie floating block methods (layer, rotate, offset, etc) to LayerSet object.
|
35
|
+
set.instance_eval &block if block_given?
|
36
|
+
|
37
|
+
return set
|
38
|
+
end
|
39
|
+
|
40
|
+
def layer(options, &block)
|
41
|
+
if options.is_a? Rubyshop::Layer
|
42
|
+
layer = options
|
43
|
+
else
|
44
|
+
layer = Layer.new options
|
45
|
+
end
|
46
|
+
@layers << layer
|
47
|
+
|
48
|
+
# tie floating block methods (opacity, mode, offset, etc) to Layer object.
|
49
|
+
layer.instance_eval &block if block_given?
|
50
|
+
|
51
|
+
return layer
|
52
|
+
end
|
53
|
+
|
54
|
+
def fill_layer(type, *args, &block)
|
55
|
+
layer = FillLayer.new type, *args
|
15
56
|
@layers << layer
|
16
57
|
|
17
|
-
|
58
|
+
# tie floating block methods (opacity, mode, offset, etc) to Layer object.
|
59
|
+
layer.instance_eval &block if block_given?
|
18
60
|
|
19
61
|
return layer
|
20
62
|
end
|
21
63
|
|
64
|
+
def adjustment_layer(type, *args, &block)
|
65
|
+
layer = AdjustmentLayer.new type, *args
|
66
|
+
@layers << layer
|
67
|
+
|
68
|
+
# tie floating block methods (opacity, mode, offset, etc) to Layer object.
|
69
|
+
layer.instance_eval &block if block_given?
|
70
|
+
|
71
|
+
return layer
|
72
|
+
end
|
73
|
+
|
74
|
+
def flatten
|
75
|
+
flattened_image = render
|
76
|
+
|
77
|
+
# clear layers and sets
|
78
|
+
@layers.clear
|
79
|
+
@layer_sets.clear
|
80
|
+
|
81
|
+
# only 1 flattened layer now
|
82
|
+
@layers << Layer.new(flattened_image)
|
83
|
+
end
|
84
|
+
|
85
|
+
def render
|
86
|
+
return composite_layers(@image.clone, @layers)
|
87
|
+
end
|
88
|
+
|
89
|
+
def composite_layers(image, layers)
|
90
|
+
layers.reverse.each do |layer|
|
91
|
+
case layer
|
92
|
+
when Rubyshop::LayerSet
|
93
|
+
image = composite_layers image, layer.layers
|
94
|
+
when Rubyshop::Layer
|
95
|
+
layer.merge_down image
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
return image
|
100
|
+
end
|
101
|
+
|
102
|
+
def save_as(filename)
|
103
|
+
render.write(filename)
|
104
|
+
end
|
105
|
+
|
106
|
+
################################################################################################################################
|
107
|
+
|
22
108
|
def add_layer(layer)
|
23
109
|
@layers << layer
|
24
110
|
bounding_box
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: rubyshop
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2006-11-
|
6
|
+
version: 0.0.2
|
7
|
+
date: 2006-11-10 00:00:00 -05:00
|
8
8
|
summary: Powerful layer based image compositing made easy as pie.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -34,7 +34,9 @@ files:
|
|
34
34
|
- lib/rubyshop/canvas.rb
|
35
35
|
- lib/rubyshop/filllayer.rb
|
36
36
|
- lib/rubyshop/layer.rb
|
37
|
+
- lib/rubyshop/layermask.rb
|
37
38
|
- lib/rubyshop/layerset.rb
|
39
|
+
- lib/rubyshop/rubyshop.rb
|
38
40
|
- LICENSE
|
39
41
|
test_files: []
|
40
42
|
|