rubyshop 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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
- @layers = []
10
- @sets = {}
10
+ $RubyshopCanvasWidth = @width
11
+ $RubyshopCanvasHeight = @height
11
12
 
12
- self.instance_eval &block if block_given?
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
@@ -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
@@ -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, :name
31
+ attr_accessor :image
4
32
  attr_reader :offset_x, :offset_y
5
33
 
6
- def initialize(filename)
7
- @image = Magick::Image.read(filename).first
8
- @image.background_color = 'transparent'
9
- @image.matte = true
10
- @mode = Normal
11
- @offset_x = 0
12
- @offset_y = 0
13
- @opacity_percent = 100
14
- @name = filename
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
@@ -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
- yield self if block_given?
12
+
13
+ self.instance_eval &block if block_given?
11
14
  end
12
15
 
13
- def layer(filename, &block)
14
- layer = Layer.new(filename)
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
- layer.instance_eval &block
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
@@ -0,0 +1,7 @@
1
+ require 'rmagick'
2
+
3
+ require 'rubyshop/canvas'
4
+ require 'rubyshop/layerset'
5
+ require 'rubyshop/layer'
6
+ require 'rubyshop/filllayer'
7
+ require 'rubyshop/adjustmentlayer'
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.1
7
- date: 2006-11-06 00:00:00 -05:00
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