smartimage 0.0.1-java → 0.0.2-java

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