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 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