smartimage 0.0.1-java → 0.0.2-java

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,164 @@
1
+ SmartImage
2
+ ==========
3
+
4
+ "It's like a Swiss Army Knife for images, but one of those tiny ones you can
5
+ keep on your keychain"
6
+
7
+ SmartImage provides a cross-platform solution for image compositing that works
8
+ on both MRI and JRuby. If using RMagick feels like swatting a fly with a
9
+ nuclear missile, and ImageScience just doesn't get you there, SmartImage is
10
+ hopefully at that sweet spot in the middle.
11
+
12
+ The functionality available in the current version is somewhat limited, but
13
+ should be added easily in the future thanks to a focus on modularity and a
14
+ clear codebase free of lots of platformisms that normally hinder portability.
15
+
16
+ The goal of SmartImage is to support the most common image compositing tasks
17
+ in a Ruby-like API while not becoming bloated and huge like RMagick, and also
18
+ remaining portable across multiple Ruby implementations, including JRuby.
19
+
20
+ Backends
21
+ --------
22
+
23
+ SmartImage works by implementing a platform-specific SmartImage::Canvas class
24
+ that encompasses all of the low level image manipulation primitives. Two such
25
+ canvases are currently available:
26
+
27
+ * SmartImage::RMagickCanvas: a canvas backend based on the RMagick gem
28
+ * SmartImage::JavaCanvas: a canvas backend based on Java AWT/Graphics2D APIs
29
+
30
+ Can it create thumbnails for my Ruby on Rails-based web application?
31
+ --------------------------------------------------------------------
32
+
33
+ Yes, SmartImage *CAN* create thumbnails for your Ruby on Rails-based web
34
+ application! And it can do it in the most cross-platform manner imaginable!
35
+ If you are looking for a thumbnail solution that will allow you to safely
36
+ migrate your web application to JRuby in the future, look no further than
37
+ SmartImage.
38
+
39
+ To use SmartImage in your Rails application, simply add the following to
40
+ config/environment.rb:
41
+
42
+ config.gem 'smartimage'
43
+
44
+ (there is an appropriate place to put this line, BTW. The exact location
45
+ is left as an exercise to the reader)
46
+
47
+ That's it! Now wherever you would like to generate thumbnails, use the
48
+ following:
49
+
50
+ SmartImage.thumbnail_file(
51
+ "path/to/input.jpg",
52
+ "path/to/output.jpg",
53
+ :width => 69,
54
+ :height => 42
55
+ )
56
+
57
+ This will generate a thumbnail which is at most 69 pixels wide (but could be
58
+ smaller) and at most 42 pixels tall (but again, could be smaller). It looks
59
+ at the file extension to determine the output format. We specified a .jpg
60
+ so it will output a JPEG encoded image.
61
+
62
+ Why could it be smaller, you ask? Because SmartImage preserves the aspect
63
+ ratio of the original image by default. SmartImage allows you to set aside
64
+ space of a predetermined width/height, but will ensure images are scaled
65
+ with their aspect ratio preserved.
66
+
67
+ Don't like this behavior? Want to stretch out your thumbnails all weird?
68
+ Just turn it off:
69
+
70
+ SmartImage.thumbnail_file(
71
+ "path/to/input.jpg",
72
+ "path/to/output.jpg",
73
+ :width => 69,
74
+ :height => 42,
75
+ :preserve_aspect_ratio => false
76
+ )
77
+
78
+ Tada! Stretched-out images! Yay!
79
+
80
+ What if I want to work with raw image data instead of files?
81
+ ------------------------------------------------------------
82
+
83
+ SmartImage provides both file-based and data-based methods for every API. All
84
+ the APIs are the same, except file-based APIs have "_file" on the end.
85
+
86
+ For example, above we used the SmartImage.thumbnail_file API. However, there's
87
+ also a SmartImage.thumbnail API that works on raw image data:
88
+
89
+ thumbnail = SmartImage.thumbnail image, :width => 69,
90
+ :height => 42,
91
+ :format => :jpg
92
+
93
+ This API produces a thumbnail in-memory from the given input image, also
94
+ in-memory. We've requested a .jpg thumbnail, with a max width of 69 and
95
+ a max height of 42.
96
+
97
+ If an image format isn't specified, the default is PNG.
98
+
99
+ What other APIs are available?
100
+ ------------------------------
101
+
102
+ SmartImage allows you to successively manipulate an image buffer. Here's an
103
+ example and below is the deconstruction:
104
+
105
+ SmartImage.new(69, 42) do |image|
106
+ image.composite_file 'mongoose.jpg', :width => 115,
107
+ :height => 95,
108
+ :preserve_aspect_ratio => false
109
+
110
+ image.alpha_mask_file 'mask.png'
111
+ image.composite_file 'overlay.png'
112
+ image.write 'output.png'
113
+ end
114
+
115
+ The first thing to notice is that SmartImage.new takes a width, a height, and
116
+ a block. Creating a new SmartImage makes a new image "canvas" that you can
117
+ draw to. However, all the drawing must take place within the block. You
118
+ can't do things with SmartImages outside the block. The block yields you
119
+ a SmartImage object that you can manipulate willy nilly within the block.
120
+ But after the block, it's kaput, sorry. This is because certain silly C
121
+ extensions lack the ability to garbage collect memory safely and require safe
122
+ allocation and deallocation of memory.
123
+
124
+ The first thing we do is composite an image file onto the buffer. Just like
125
+ the SmartImage.thumbnail_file method we give it an options has with a width,
126
+ height, and aspect ratio preservation options.
127
+
128
+ After that an alpha mask is applied. SmartImage supports applying alpha masks
129
+ in the form of grayscale images where white is opaque and black is transparent.
130
+
131
+ After that, a glossy overlay is composited over the top of the canvas.
132
+
133
+ When it's all done, we write to an output file. We've specified 'output.png'
134
+ so it will write a PNG image to the given file.
135
+
136
+ Doesn't RMagick leak memory?
137
+ ----------------------------
138
+
139
+ It does if you use it wrong. There are experimental attempts to safely garbage
140
+ collect RMagick images. However, your best bet is to work with an API which is
141
+ designed so you can't leak memory, which is exactly what SmartImage provides.
142
+
143
+ SmartImage would be over 9000 times better if it...
144
+ ---------------------------------------------------
145
+
146
+ Please fork me! I'm sure there's a whole world of better backends that
147
+ SmartImage could be using on MRI-like interpreters than RMagick. Imagine a
148
+ lightweight FFI wrapper to libfreeimage or something to that effect.
149
+
150
+ If there's something SmartImage doesn't do that you'd like it do to, please
151
+ send me a pull request. Just keep in mind that cross-implementation
152
+ consistency is a major focus of SmartImage, so if you implement a new image
153
+ backend it should implement all methods of SmartImage::BaseCanvas, and if you
154
+ wish to add a new method to either SmartImage or SmartImage::BaseCanvas it
155
+ should work across all implementations.
156
+
157
+ Credits
158
+ -------
159
+
160
+ SmartImage assumes your Ruby interpreter supports the absurdly powerful RMagick
161
+ library, unless you're running JRuby, in which case it uses the absurdly
162
+ powerful Java Graphics2D library and AWT.
163
+
164
+ [Mongoose courtesy Wikimedia Commons](http://en.wikipedia.org/wiki/File:Mongoose.jpg)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
data/lib/smart_image.rb CHANGED
@@ -32,6 +32,71 @@ class SmartImage
32
32
  def file_info(path)
33
33
  info File.read(path)
34
34
  end
35
+
36
+ # Generate a thumbnail from the given image data
37
+ # Options:
38
+ # * width: max width of the image, or explicit width if not preserving
39
+ # aspect ratio
40
+ # * height: ditto, except for height of course
41
+ # * preserve_aspect_ratio: if true, ensure image fits within the given
42
+ # width/height restraints.
43
+ # * format: file extension you'd ordinarily apply to an output file of
44
+ # the type you desire. Supported formats are :jpg, :png, and :gif
45
+ # (default :png)
46
+ def thumbnail(data, options = {})
47
+ source_info = info data
48
+
49
+ opts = {
50
+ :width => source_info.width,
51
+ :height => source_info.height,
52
+ :preserve_aspect_ratio => true,
53
+ :format => :png
54
+ }.merge(options)
55
+
56
+ width, height = calculate_aspect_ratio source_info, opts
57
+
58
+ # Set res so we can assign it within the SmartImage.new block
59
+ res = nil
60
+
61
+ SmartImage.new(width, height) do |image|
62
+ image.composite data, :width => width,
63
+ :height => height,
64
+ :preserve_aspect_ratio => false
65
+
66
+ res = image.encode opts[:format]
67
+ end
68
+
69
+ res
70
+ end
71
+
72
+ # Generate a thumbnail file from a given input file
73
+ # Accepts the same options as SmartImage.thumbnail
74
+ def thumbnail_file(input_path, output_path, options = {})
75
+ opts = {
76
+ :format => File.extname(output_path).sub(/^\./, '')
77
+ }.merge(options)
78
+
79
+ data = SmartImage.thumbnail File.read(input_path), options
80
+ File.open(output_path, 'w') { |file| file << data }
81
+ end
82
+
83
+ # Solve aspect ratio constraints based on source image info and
84
+ # a given options hash. This is mostly an internal method but
85
+ # if you find it useful knock yourself out.
86
+ def calculate_aspect_ratio(info, options)
87
+ if options[:preserve_aspect_ratio]
88
+ composited_size = SmartImage::RatioCalculator.new(
89
+ :source_width => info.width,
90
+ :source_height => info.height,
91
+ :dest_width => Integer(options[:width]),
92
+ :dest_height => Integer(options[:height])
93
+ ).size
94
+
95
+ return composited_size.width, composited_size.height
96
+ else
97
+ return options[:width], options[:height]
98
+ end
99
+ end
35
100
  end
36
101
 
37
102
  # Create a new SmartImage of the given width and height. Always takes a
@@ -55,6 +120,8 @@ class SmartImage
55
120
  @canvas = DeadCanvas.new
56
121
  end
57
122
 
123
+ # After the SmartImage#initialize block completes, the canvas is destroyed
124
+ # and replaced with a DeadCanvas that doesn't let you do anything
58
125
  class DeadCanvas
59
126
  def method_missing(*args)
60
127
  raise ArgumentError, "your image exists only within the SmartImage.new block"
@@ -81,18 +148,7 @@ class SmartImage
81
148
  :preserve_aspect_ratio => true
82
149
  }.merge(options)
83
150
 
84
- if opts[:preserve_aspect_ratio]
85
- composited_size = SmartImage::RatioCalculator.new(
86
- :source_width => info.width,
87
- :source_height => info.height,
88
- :dest_width => Integer(opts[:width]),
89
- :dest_height => Integer(opts[:height])
90
- ).size
91
-
92
- dest_width, dest_height = composited_size.width, composited_size.height
93
- else
94
- dest_width, dest_height = opts[:width], opts[:height]
95
- end
151
+ dest_width, dest_height = self.class.calculate_aspect_ratio info, opts
96
152
 
97
153
  @canvas.composite data, :width => Integer(dest_width),
98
154
  :height => Integer(dest_height),
@@ -28,7 +28,11 @@ class SmartImage
28
28
  }.merge(options)
29
29
 
30
30
  image.thumbnail! opts[:width], opts[:height]
31
- @canvas.composite! image, opts[:x], opts[:y], OverCompositeOp
31
+ begin
32
+ @canvas.composite! image, opts[:x], opts[:y], OverCompositeOp
33
+ ensure
34
+ image.destroy!
35
+ end
32
36
  end
33
37
 
34
38
  # Load the given file as an alpha mask for the image
data/lib/smartimage.rb ADDED
@@ -0,0 +1,15 @@
1
+ # Maybe you want to:
2
+ #
3
+ # require 'smartimage'
4
+ #
5
+ # Instead of:
6
+ #
7
+ # require 'smart_image'
8
+ #
9
+ # Yes SmartImage is CamelCase and smart_image is the String#underscore of
10
+ # that, but seriously, shouldn't require 'smartimage' Just Work?
11
+ #
12
+ # Yes, yes it should...
13
+ #
14
+
15
+ require 'smart_image'
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{smartimage}
8
- s.version = "0.0.1"
8
+ s.version = "0.0.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Tony Arcieri"]
12
- s.date = %q{2010-03-26}
12
+ s.date = %q{2010-03-30}
13
13
  s.description = %q{ SmartImage provides a cross-platform solution for image compositing that works on both MRI and JRuby.
14
14
  If using RMagick feels like swatting a fly with a nucler missile, and ImageScience just doesn't get
15
15
  you there, SmartImage is hopefully at that sweet spot in the middle
@@ -17,13 +17,13 @@ Gem::Specification.new do |s|
17
17
  s.email = %q{tony@medioh.com}
18
18
  s.extra_rdoc_files = [
19
19
  "LICENSE",
20
- "README.textile"
20
+ "README.markdown"
21
21
  ]
22
22
  s.files = [
23
23
  ".document",
24
24
  ".gitignore",
25
25
  "LICENSE",
26
- "README.textile",
26
+ "README.markdown",
27
27
  "Rakefile",
28
28
  "VERSION",
29
29
  "lib/smart_image.rb",
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
31
31
  "lib/smart_image/java_canvas.rb",
32
32
  "lib/smart_image/ratio_calculator.rb",
33
33
  "lib/smart_image/rmagick_canvas.rb",
34
+ "lib/smartimage.rb",
34
35
  "smartimage-java.gemspec",
35
36
  "smartimage.gemspec",
36
37
  "spec/fixtures/mask.png",
data/smartimage.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{smartimage}
8
- s.version = "0.0.1"
8
+ s.version = "0.0.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Tony Arcieri"]
12
- s.date = %q{2010-03-26}
12
+ s.date = %q{2010-03-30}
13
13
  s.description = %q{ SmartImage provides a cross-platform solution for image compositing that works on both MRI and JRuby.
14
14
  If using RMagick feels like swatting a fly with a nucler missile, and ImageScience just doesn't get
15
15
  you there, SmartImage is hopefully at that sweet spot in the middle
@@ -17,13 +17,13 @@ Gem::Specification.new do |s|
17
17
  s.email = %q{tony@medioh.com}
18
18
  s.extra_rdoc_files = [
19
19
  "LICENSE",
20
- "README.textile"
20
+ "README.markdown"
21
21
  ]
22
22
  s.files = [
23
23
  ".document",
24
24
  ".gitignore",
25
25
  "LICENSE",
26
- "README.textile",
26
+ "README.markdown",
27
27
  "Rakefile",
28
28
  "VERSION",
29
29
  "lib/smart_image.rb",
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
31
31
  "lib/smart_image/java_canvas.rb",
32
32
  "lib/smart_image/ratio_calculator.rb",
33
33
  "lib/smart_image/rmagick_canvas.rb",
34
+ "lib/smartimage.rb",
34
35
  "smartimage-java.gemspec",
35
36
  "smartimage.gemspec",
36
37
  "spec/fixtures/mask.png",
@@ -41,4 +41,11 @@ describe SmartImage do
41
41
  image.write @output_dir + 'alpha_mask.png'
42
42
  end
43
43
  end
44
+
45
+ it "generates thumbnails" do
46
+ output = @output_dir + 'thumbnail.jpg'
47
+
48
+ SmartImage.thumbnail_file @mongoose, output, :width => 115,
49
+ :height => 95
50
+ end
44
51
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smartimage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: java
6
6
  authors:
7
7
  - Tony Arcieri
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-03-26 00:00:00 -06:00
12
+ date: 2010-03-30 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -40,12 +40,12 @@ extensions: []
40
40
 
41
41
  extra_rdoc_files:
42
42
  - LICENSE
43
- - README.textile
43
+ - README.markdown
44
44
  files:
45
45
  - .document
46
46
  - .gitignore
47
47
  - LICENSE
48
- - README.textile
48
+ - README.markdown
49
49
  - Rakefile
50
50
  - VERSION
51
51
  - lib/smart_image.rb
@@ -53,6 +53,7 @@ files:
53
53
  - lib/smart_image/java_canvas.rb
54
54
  - lib/smart_image/ratio_calculator.rb
55
55
  - lib/smart_image/rmagick_canvas.rb
56
+ - lib/smartimage.rb
56
57
  - smartimage-java.gemspec
57
58
  - smartimage.gemspec
58
59
  - spec/fixtures/mask.png
data/README.textile DELETED
@@ -1,11 +0,0 @@
1
- h1. SmartImage
2
-
3
- Hi. There will be a real README here soon, I promise.
4
-
5
- h2. Credits
6
-
7
- SmartImage assumes your Ruby interpreter supports the absurdly powerful RMagick
8
- library, unless you're running JRuby, in which case it uses the absurdly
9
- powerful Java Graphics2D library and AWT.
10
-
11
- Mongoose courtesy Wikimedia Commons: http://en.wikipedia.org/wiki/File:Mongoose.jpg