dimension 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 144828daa18cf773b80abb57606d047917fea1f7
4
- data.tar.gz: a4310e48fc02af5b1899c2bdb6822e51c3ff35e3
3
+ metadata.gz: 193039197b19c73705300522aaf23f6ae3b07aee
4
+ data.tar.gz: c741743c6dfd4ab233832a46cc97e2b77f8b3901
5
5
  SHA512:
6
- metadata.gz: 6eddc9393524c095d2a7a9a6f9af0a05b741bff3147d2b346738364109f985716359a23b5436b6fe7b42ac19abc60f1c34269f376afaa5675d7deadfc68e036f
7
- data.tar.gz: af4ac2e3807547a92113983ceada7d5f51c0e8b18d09b7b0650cb32844a33bff8a31fbe792a759043646052b6019fd8f1d197e27eddd28b74eff8e6eaabeee96
6
+ metadata.gz: 6660d273e74e9772aac18cf4d29c585b517ec4e117f933015c5d0b81c82f9986af371c1c8d10c9c25cced1624db8ea2eeae519d5694ea6b50d0d47ababab371b
7
+ data.tar.gz: a3b939d1c3d5d10b022d71cbfc1ab04549e278ba396b9424448e058e77a5a69f814d5e1920b7e77634f6a5cb524a8a62c40615a80727e4a00943cbf5489e8228
data/README.md CHANGED
@@ -5,7 +5,7 @@ Fast, simplified image resizing for Ruby. No ImageMagick.
5
5
 
6
6
  ``` rb
7
7
  require 'dimension'
8
-
8
+
9
9
  thumb = Dimension.open('tux.png')
10
10
  thumb.generate('100x100') # => { :width => 100, :height => 100 }
11
11
  thumb.save('resized.png')
@@ -33,7 +33,7 @@ You can also pass a block, which will ensure the original image is closed after
33
33
  ``` rb
34
34
  get '/resize/:file' do
35
35
  thumb = Dimension.open(params[:file])
36
- thumb.generate('200x300#') do
36
+ thumb.generate('200x300@') do
37
37
  thumb.to_response
38
38
  end
39
39
  end
data/examples/sinatra.rb CHANGED
@@ -3,11 +3,27 @@ ROOT = File.expand_path(File.dirname(__FILE__))
3
3
  require 'sinatra'
4
4
  require ROOT + '/../lib/dimension'
5
5
 
6
+ if processor = ARGV[0]
7
+ puts "Using #{processor} as processor"
8
+ Dimension.processor = processor
9
+ end
10
+
11
+ geometries = [
12
+ '200x200',
13
+ '300x200!',
14
+ '200x300#',
15
+ '20x50:ne'
16
+ ]
17
+
6
18
  get '/' do
7
19
  images = Dir.glob(File.join(ROOT, 'assets') + '/*')
20
+ index = 0
8
21
  links = images.map do |i|
9
22
  name = File.basename(i)
10
- "<a href='/images/#{name}'>#{name}</a>"
23
+ geom = geometries[index]
24
+ index += 1
25
+ index = 0 unless geometries[index]
26
+ "<a href='/images/#{name}?geometry=#{geom}'>#{name}</a>"
11
27
  end
12
28
  '<ul><li>' + links.join('</li><li>') + '</li></ul>'
13
29
  end
data/lib/dimension.rb CHANGED
@@ -6,6 +6,7 @@ module Dimension
6
6
  ROOT = File.expand_path(File.dirname(__FILE__))
7
7
 
8
8
  PROCESSORS = {
9
+ 'vips' => 'VipsProcessor',
9
10
  'imlib2' => 'Imlib2Processor',
10
11
  'image_magick' => 'ImageMagickProcessor'
11
12
  }
@@ -27,14 +28,23 @@ module Dimension
27
28
 
28
29
  end
29
30
 
30
- begin
31
- require 'imlib2'
32
- Dimension.processor = 'imlib2'
33
- rescue LoadError
34
- out = `which convert`
35
- if $?.success?
36
- Dimension.processor = 'image_magick'
37
- else
38
- puts "No available processors found. Please install ruby-imlib2 or ImageMagick."
31
+ def load_processor(name)
32
+ # puts "Loading #{name}"
33
+ require name
34
+ Dimension.processor = name
35
+ true
36
+ rescue LoadError => e
37
+ # puts "#{name} not found."
38
+ nil
39
+ end
40
+
41
+ unless load_processor 'vips'
42
+ unless load_processor 'imlib2'
43
+ out = `which convert`
44
+ if $?.success?
45
+ Dimension.processor = 'image_magick'
46
+ else
47
+ puts "No available processors found. Please install ruby-vips, ruby-imlib2 or ImageMagick."
48
+ end
39
49
  end
40
50
  end
@@ -18,7 +18,7 @@ class Image
18
18
 
19
19
  # Geometry string patterns
20
20
  RESIZE_GEOMETRY = /^(\d+)?x(\d+)?[><%^!]?$|^\d+@$/ # e.g. '300x200!'
21
- CROPPED_RESIZE_GEOMETRY = /^(\d+)x(\d+)[:|#](\w{1,2})?$/ # e.g. '20x50:ne'
21
+ CROPPED_RESIZE_GEOMETRY = /^(\d+)x(\d+)[:|@](\w{1,2})?$/ # e.g. '20x50:ne'
22
22
  CROP_GEOMETRY = /^(\d+)x(\d+)([+-]\d+)?([+-]\d+)?(\w{1,2})?$/ # e.g. '30x30+10+10'
23
23
 
24
24
  attr_reader :file
@@ -46,13 +46,14 @@ class Image
46
46
  end
47
47
 
48
48
  def generate!(geometry, output_file = nil)
49
+ @geometry_string = geometry # for saving as [file]-[geometry].[ext]
49
50
  resize_to(geometry)
50
51
  save(output_file) && self
51
52
  end
52
53
 
53
54
  def resize_to(geometry)
54
55
  case geometry
55
- when RESIZE_GEOMETRY
56
+ when RESIZE_GEOMETRY
56
57
  log "Resize -- #{$1}x#{$2}"
57
58
  resize($1, $2)
58
59
  when CROPPED_RESIZE_GEOMETRY
@@ -71,7 +72,6 @@ class Image
71
72
 
72
73
  def save(out_file)
73
74
  new_geometry = get_new_geometry
74
-
75
75
  path = @path
76
76
 
77
77
  if out_file and File.directory?(out_file)
@@ -80,7 +80,7 @@ class Image
80
80
  end
81
81
 
82
82
  if out_file.nil?
83
- out_file = File.join(path, @name.sub(File.extname(file), '-' + new_geometry.join('x') + File.extname(file)))
83
+ out_file = File.join(path, @name.sub(File.extname(file), '-' + @geometry_string + File.extname(file)))
84
84
  end
85
85
 
86
86
  log "Writing file: #{out_file}"
@@ -98,6 +98,17 @@ class Image
98
98
  to_response
99
99
  end
100
100
 
101
+ def to_rgba
102
+ bytes = image_data.bytes
103
+ (1..bytes.length).step(4).map { |i| bytes[i..i+2] << bytes[i-1] }.flatten
104
+ end
105
+
106
+ # transforms data (RGBA buffer) into a array of RGB values
107
+ def to_rgb
108
+ bytes = image_data.bytes
109
+ (1..bytes.length).step(4).map { |i| [bytes[i-1],bytes[i],bytes[i+1]] }.flatten
110
+ end
111
+
101
112
  def inspect
102
113
  geometry = get_new_geometry
103
114
  "#<Dimension::Image:#{object_id} @width=#{geometry[0]}, @height=#{geometry[1]}>"
@@ -9,13 +9,14 @@ module ImageMagickProcessor
9
9
  end
10
10
 
11
11
  def image_data
12
- IO.read(@temp_file)
12
+ @current_path = path if @current_path.nil?
13
+ IO.read(@current_path)
13
14
  end
14
15
 
15
16
  def save_as(new_file_path)
16
17
  return if new_file_path == @temp_file
17
18
  FileUtils.mv(@temp_file, new_file_path)
18
- @temp_file = new_file_path # otherwise we'd get a ENOENT error when reading its data
19
+ @current_path = new_file_path
19
20
  end
20
21
 
21
22
  def get_new_geometry
@@ -16,17 +16,6 @@ module Imlib2Processor
16
16
  File.extname(file).sub('.', '')
17
17
  end
18
18
 
19
- def to_rgba
20
- bytes = data.bytes
21
- (1..bytes.length).step(4).map { |i| bytes[i..i+2] << bytes[i-1] }.flatten
22
- end
23
-
24
- # transforms data (RGBA buffer) into a array of RGB values
25
- def to_rgb
26
- bytes = data.bytes
27
- (1..bytes.length).step(4).map { |i| [bytes[i-1],bytes[i],bytes[i+1]] }.flatten
28
- end
29
-
30
19
  def image_data
31
20
  unless @temp_file
32
21
  @temp_file = "/tmp/#{$$}.#{File.basename(file)}"
@@ -0,0 +1,142 @@
1
+ # from examples at
2
+ # - https://github.com/eltiare/carrierwave-vips/blob/master/lib/carrierwave/vips.rb
3
+ # - https://github.com/jcupitt/ruby-vips/tree/master/examples
4
+
5
+ require 'vips'
6
+
7
+ module VipsProcessor
8
+
9
+ FORMAT_OPTS = {
10
+ 'jpeg' => { :quality => 0.9 },
11
+ 'png' => { :compression => 6, :interlace => false }
12
+ }
13
+
14
+ SHARPEN_MASK = begin
15
+ conv_mask = [
16
+ [ -1, -1, -1 ],
17
+ [ -1, 24, -1 ],
18
+ [ -1, -1, -1 ]
19
+ ]
20
+ ::VIPS::Mask.new conv_mask, 16
21
+ end
22
+
23
+ def image
24
+ @image ||= if format == 'jpeg'
25
+ VIPS::Image.jpeg(@file, :sequential => true)
26
+ elsif format == 'png'
27
+ VIPS::Image.png(@file, :sequential => true)
28
+ else
29
+ VIPS::Image.new(@file)
30
+ end
31
+ end
32
+
33
+ def geometry
34
+ [image.x_size, image.y_size]
35
+ end
36
+
37
+ def format
38
+ file[/.png$/] ? 'png' : file[/jpe?g$/] ? 'jpeg' : File.extname(file).sub('.', '')
39
+ end
40
+
41
+ def image_data
42
+ writer.to_memory
43
+ end
44
+
45
+ def save_as(new_file_path)
46
+ save(new_file_path)
47
+ end
48
+
49
+ def save!
50
+ save(file)
51
+ end
52
+
53
+ def close
54
+ log "Closing image and cutting thread..."
55
+ @image = nil
56
+ VIPS::thread_shutdown
57
+ # image.delete!(true) # free image, and de-cache it too
58
+ end
59
+
60
+ def get_new_geometry
61
+ geometry
62
+ end
63
+
64
+ private
65
+
66
+ def resize(width, height, min_or_max = :min)
67
+ ratio = get_ratio(width, height, min_or_max)
68
+ if ratio == 1
69
+ return log "Same ratio as original."
70
+ end
71
+ if ratio > 1
72
+ @image = image.affinei_resize :nearest, ratio
73
+ else
74
+ if ratio <= 0.5
75
+ factor = (1.0 / ratio).floor
76
+ @image = image.shrink(factor)
77
+ @image = image.tile_cache(image.x_size, 1, 30)
78
+ ratio = get_ratio(width, height, min_or_max)
79
+ end
80
+ @image = image.affinei_resize :bicubic, ratio
81
+ @image = image.conv SHARPEN_MASK
82
+ end
83
+ end
84
+
85
+ def resize_and_crop(new_width, new_height, gravity)
86
+ resize(new_width, new_height, :max)
87
+
88
+ if image.x_size > new_width.to_i
89
+ top = 0
90
+ left = (image.x_size - new_width.to_i) / 2
91
+ elsif image.y_size > new_height.to_i
92
+ left = 0
93
+ top = (image.y_size - new_height.to_i) / 2
94
+ else
95
+ left = 0
96
+ top = 0
97
+ end
98
+
99
+ @image = image.extract_area(left, top, new_width.to_i, new_height.to_i)
100
+ end
101
+
102
+ def crop(width, height, x, y, gravity)
103
+ raise "TODO"
104
+ end
105
+
106
+ def crop_scaled(x, y, new_w, new_h)
107
+ raise "TODO"
108
+ end
109
+
110
+ def get_ratio(width, height, min_or_max = :min)
111
+ width_ratio = width.to_f / image.x_size
112
+ height_ratio = height.to_f / image.y_size
113
+ if height.nil?
114
+ width_ratio
115
+ elsif width.nil?
116
+ height_ratio
117
+ else
118
+ [width_ratio, height_ratio].send(min_or_max)
119
+ end
120
+ end
121
+
122
+ def write(filename, strip = false)
123
+ if strip
124
+ writer.remove_exif
125
+ writer.remove_icc
126
+ end
127
+ writer.write(filename)
128
+ end
129
+
130
+ def writer
131
+ @writer ||= writer_class.send(:new, @image, FORMAT_OPTS[format] || {})
132
+ end
133
+
134
+ def writer_class
135
+ case format
136
+ when 'jpeg' then VIPS::JPEGWriter
137
+ when 'png' then VIPS::PNGWriter
138
+ else VIPS::Writer
139
+ end
140
+ end
141
+
142
+ end
@@ -1,7 +1,7 @@
1
1
  module Dimension
2
2
  MAJOR = 0
3
- MINOR = 1
4
- PATCH = 4
3
+ MINOR = 2
4
+ PATCH = 0
5
5
 
6
6
  VERSION = [MAJOR, MINOR, PATCH].join('.')
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dimension
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomás Pollak
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-04 00:00:00.000000000 Z
11
+ date: 2015-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack-throttle
@@ -49,6 +49,7 @@ files:
49
49
  - lib/dimension/middleware.rb
50
50
  - lib/dimension/processors/image_magick.rb
51
51
  - lib/dimension/processors/imlib2.rb
52
+ - lib/dimension/processors/vips.rb
52
53
  - lib/dimension/version.rb
53
54
  homepage: https://github.com/tomas/dimension
54
55
  licenses: []