rszr 0.4.0 → 0.8.0
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.
- checksums.yaml +4 -4
- data/README.md +129 -12
- data/Rakefile +6 -0
- data/ext/rszr/errors.c +68 -0
- data/ext/rszr/errors.h +15 -0
- data/ext/rszr/extconf.rb +18 -0
- data/ext/rszr/image.c +482 -0
- data/ext/rszr/image.h +12 -0
- data/ext/rszr/rszr.c +17 -0
- data/ext/rszr/rszr.h +11 -0
- data/lib/rszr/batch_transformation.rb +24 -0
- data/lib/rszr/buffered.rb +25 -0
- data/lib/rszr/identification.rb +60 -0
- data/lib/rszr/image.rb +151 -98
- data/lib/rszr/image_processing.rb +82 -0
- data/lib/rszr/orientation.rb +107 -0
- data/lib/rszr/stream.rb +61 -0
- data/lib/rszr/version.rb +1 -1
- data/lib/rszr.rb +21 -7
- metadata +27 -114
- data/lib/rszr/base.rb +0 -29
- data/lib/rszr/errors.rb +0 -42
- data/lib/rszr/handle.rb +0 -37
- data/lib/rszr/lib.rb +0 -73
- data/lib/rszr/lock.rb +0 -23
data/lib/rszr/image.rb
CHANGED
@@ -1,97 +1,161 @@
|
|
1
1
|
module Rszr
|
2
2
|
class Image
|
3
|
-
|
4
|
-
|
3
|
+
extend Identification
|
4
|
+
include Buffered
|
5
|
+
include Orientation
|
6
|
+
|
5
7
|
class << self
|
6
|
-
|
7
|
-
|
8
|
-
protected :instantiate
|
9
|
-
|
10
|
-
def new(width, height)
|
11
|
-
ptr = with_lock { imlib_create_image(width, height) }
|
12
|
-
raise Error, 'Could not instantiate image' if ptr.null?
|
13
|
-
instantiate(ptr)
|
14
|
-
end
|
15
|
-
|
16
|
-
def load(path, options = {})
|
8
|
+
|
9
|
+
def load(path, autorotate: Rszr.autorotate, **opts)
|
17
10
|
path = path.to_s
|
18
11
|
raise FileNotFound unless File.exist?(path)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
imlib_load_image_with_error_return(path, load_error.ptr)
|
23
|
-
end
|
24
|
-
raise load_error, load_error.message if ptr.null?
|
25
|
-
return instantiate(ptr)
|
12
|
+
image = _load(path)
|
13
|
+
autorotate(image, path) if autorotate
|
14
|
+
image
|
26
15
|
end
|
27
16
|
alias :open :load
|
28
17
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
imlib_context_set_image(ptr)
|
34
|
-
imlib_free_image
|
18
|
+
def load_data(data, autorotate: Rszr.autorotate, **opts)
|
19
|
+
raise LoadError, 'Unknown format' unless format = identify(data)
|
20
|
+
with_tempfile(format, data) do |file|
|
21
|
+
load(file.path, autorotate: autorotate, **opts)
|
35
22
|
end
|
36
23
|
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
def initialize(ptr)
|
41
|
-
@handle = Handle.new(self, ptr)
|
42
|
-
end
|
43
|
-
|
44
|
-
def width
|
45
|
-
with_image { imlib_image_get_width }
|
46
|
-
end
|
47
|
-
|
48
|
-
def height
|
49
|
-
with_image { imlib_image_get_height }
|
24
|
+
|
50
25
|
end
|
51
|
-
|
26
|
+
|
52
27
|
def dimensions
|
53
28
|
[width, height]
|
54
29
|
end
|
55
30
|
|
56
31
|
def format
|
57
|
-
|
58
|
-
|
59
|
-
str_ptr.to_s
|
32
|
+
fmt = _format
|
33
|
+
fmt == 'jpg' ? 'jpeg' : fmt
|
60
34
|
end
|
61
35
|
|
62
|
-
def
|
63
|
-
|
36
|
+
def format=(fmt)
|
37
|
+
fmt = fmt.to_s if fmt.is_a?(Symbol)
|
38
|
+
self._format = fmt
|
64
39
|
end
|
65
|
-
|
66
|
-
def
|
67
|
-
|
68
|
-
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
fmt = format
|
43
|
+
fmt = " #{fmt.upcase}" if fmt
|
44
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)} #{width}x#{height}#{fmt}>"
|
69
45
|
end
|
46
|
+
|
47
|
+
module Transformations
|
48
|
+
def resize(*args, **opts)
|
49
|
+
_resize(false, *calculate_size(*args, **opts))
|
50
|
+
end
|
51
|
+
|
52
|
+
def resize!(*args, **opts)
|
53
|
+
_resize(true, *calculate_size(*args, **opts))
|
54
|
+
end
|
55
|
+
|
56
|
+
def crop(x, y, width, height)
|
57
|
+
_crop(false, x, y, width, height)
|
58
|
+
end
|
59
|
+
|
60
|
+
def crop!(x, y, width, height)
|
61
|
+
_crop(true, x, y, width, height)
|
62
|
+
end
|
63
|
+
|
64
|
+
def turn(orientation)
|
65
|
+
dup.turn!(orientation)
|
66
|
+
end
|
67
|
+
|
68
|
+
def turn!(orientation)
|
69
|
+
orientation = orientation.abs + 2 if orientation.negative?
|
70
|
+
_turn!(orientation % 4)
|
71
|
+
end
|
70
72
|
|
71
|
-
|
72
|
-
|
73
|
-
|
73
|
+
def rotate(deg)
|
74
|
+
_rotate(false, deg.to_f * Math::PI / 180.0)
|
75
|
+
end
|
74
76
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
77
|
+
def rotate!(deg)
|
78
|
+
_rotate(true, deg.to_f * Math::PI / 180.0)
|
79
|
+
end
|
80
|
+
|
81
|
+
# horizontal
|
82
|
+
def flop
|
83
|
+
dup.flop!
|
84
|
+
end
|
85
|
+
|
86
|
+
# vertical
|
87
|
+
def flip
|
88
|
+
dup.flip!
|
89
|
+
end
|
79
90
|
|
80
|
-
|
81
|
-
|
82
|
-
format ||= format_from_filename(path) || 'jpg'
|
83
|
-
imlib_image_set_format(format)
|
84
|
-
save_error = SaveError.new
|
85
|
-
imlib_save_image_with_error_return(path, save_error.ptr)
|
86
|
-
raise save_error, save_error.message if save_error.error?
|
87
|
-
true
|
91
|
+
def sharpen(radius)
|
92
|
+
dup.sharpen!(radius)
|
88
93
|
end
|
89
|
-
end
|
90
94
|
|
91
|
-
|
92
|
-
|
95
|
+
def sharpen!(radius)
|
96
|
+
raise ArgumentError, 'illegal radius' if radius < 0
|
97
|
+
_sharpen!(radius)
|
98
|
+
end
|
99
|
+
|
100
|
+
def blur(radius)
|
101
|
+
dup.blur!(radius)
|
102
|
+
end
|
103
|
+
|
104
|
+
def blur!(radius)
|
105
|
+
raise ArgumentError, 'illegal radius' if radius < 0
|
106
|
+
_sharpen!(-radius)
|
107
|
+
end
|
108
|
+
|
109
|
+
def filter(filter_expr)
|
110
|
+
dup.filter!(filter_expr)
|
111
|
+
end
|
112
|
+
|
113
|
+
def brighten!(value, r: nil, g: nil, b: nil, a: nil)
|
114
|
+
raise ArgumentError, 'illegal brightness' if value > 1 || value < -1
|
115
|
+
filter!("colormod(brightness=#{value.to_f});")
|
116
|
+
end
|
117
|
+
|
118
|
+
def brighten(*args, **opts)
|
119
|
+
dup.brighten!(*args, **opts)
|
120
|
+
end
|
121
|
+
|
122
|
+
def contrast!(value, r: nil, g: nil, b: nil, a: nil)
|
123
|
+
raise ArgumentError, 'illegal contrast (must be > 0)' if value < 0
|
124
|
+
filter!("colormod(contrast=#{value.to_f});")
|
125
|
+
end
|
126
|
+
|
127
|
+
def contrast(*args, **opts)
|
128
|
+
dup.contrast!(*args, **opts)
|
129
|
+
end
|
130
|
+
|
131
|
+
def gamma!(value, r: nil, g: nil, b: nil, a: nil)
|
132
|
+
#raise ArgumentError, 'illegal gamma (must be > 0)' if value < 0
|
133
|
+
filter!("colormod(gamma=#{value.to_f});")
|
134
|
+
end
|
135
|
+
|
136
|
+
def gamma(*args, **opts)
|
137
|
+
dup.gamma!(*args, **opts)
|
138
|
+
end
|
93
139
|
end
|
94
140
|
|
141
|
+
include Transformations
|
142
|
+
|
143
|
+
def save(path, format: nil, quality: nil)
|
144
|
+
format ||= format_from_filename(path) || self.format || 'jpg'
|
145
|
+
raise ArgumentError, "invalid quality #{quality.inspect}" if quality && !(0..100).cover?(quality)
|
146
|
+
ensure_path_is_writable(path)
|
147
|
+
_save(path.to_s, format.to_s, quality)
|
148
|
+
end
|
149
|
+
|
150
|
+
def save_data(format: nil, quality: nil)
|
151
|
+
format ||= self.format || 'jpg'
|
152
|
+
with_tempfile(format) do |file|
|
153
|
+
save(file.path, format: format, quality: quality)
|
154
|
+
file.rewind
|
155
|
+
file.read
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
95
159
|
private
|
96
160
|
|
97
161
|
# 0.5 0 < scale < 1
|
@@ -100,16 +164,16 @@ module Rszr
|
|
100
164
|
# :auto, 300 auto width, fit height
|
101
165
|
# 400, 300, crop: :center_middle
|
102
166
|
# 400, 300, background: rgba
|
103
|
-
# 400, 300,
|
167
|
+
# 400, 300, skew: true
|
104
168
|
|
105
|
-
def
|
169
|
+
def calculate_size(*args, crop: nil, skew: nil)
|
106
170
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
107
|
-
assert_valid_keys options, :crop, :background, :skew #:extend, :width, :height, :max_width, :max_height, :box
|
171
|
+
#assert_valid_keys options, :crop, :background, :skew #:extend, :width, :height, :max_width, :max_height, :box
|
108
172
|
original_width, original_height = width, height
|
109
173
|
x, y, = 0, 0
|
110
174
|
if args.size == 1
|
111
175
|
scale = args.first
|
112
|
-
raise ArgumentError, "scale #{scale.inspect} out of range" unless scale > 0 && scale < 1
|
176
|
+
raise ArgumentError, "scale factor #{scale.inspect} out of range" unless scale > 0 && scale < 1
|
113
177
|
new_width = original_width.to_f * scale
|
114
178
|
new_height = original_height.to_f * scale
|
115
179
|
elsif args.size == 2
|
@@ -121,9 +185,9 @@ module Rszr
|
|
121
185
|
new_width = box_width
|
122
186
|
new_height = box_width.to_f / original_width.to_f * original_height.to_f
|
123
187
|
elsif box_width.is_a?(Numeric) && box_height.is_a?(Numeric)
|
124
|
-
if
|
188
|
+
if skew
|
125
189
|
new_width, new_height = box_width, box_height
|
126
|
-
elsif
|
190
|
+
elsif crop
|
127
191
|
# TODO: calculate x, y offset if crop
|
128
192
|
else
|
129
193
|
scale = original_width.to_f / original_height.to_f
|
@@ -142,38 +206,27 @@ module Rszr
|
|
142
206
|
else
|
143
207
|
raise ArgumentError, "wrong number of arguments (#{args.size} for 1..2)"
|
144
208
|
end
|
145
|
-
|
146
|
-
imlib_context_set_anti_alias(1)
|
147
|
-
imlib_create_cropped_scaled_image(x, y, imlib_image_get_width, imlib_image_get_height, new_width.round, new_height.round)
|
148
|
-
end
|
149
|
-
raise TransformationError, "error resizing image" if resized_ptr.null?
|
150
|
-
resized_ptr
|
151
|
-
end
|
152
|
-
|
153
|
-
def create_cropped_image(x, y, width, height)
|
154
|
-
cropped_ptr = with_image { imlib_create_cropped_image(x, y, width, height) }
|
155
|
-
raise TransformationError, 'error cropping image' if cropped_ptr.null?
|
156
|
-
cropped_ptr
|
209
|
+
[x, y, original_width, original_height, new_width.round, new_height.round]
|
157
210
|
end
|
158
|
-
|
211
|
+
|
159
212
|
def format_from_filename(path)
|
160
|
-
File.extname(path)[1..-1]
|
213
|
+
File.extname(path)[1..-1].to_s.downcase
|
161
214
|
end
|
162
215
|
|
163
|
-
def
|
164
|
-
|
216
|
+
def ensure_path_is_writable(path)
|
217
|
+
path = Pathname.new(path)
|
218
|
+
path.dirname.realpath.writable?
|
219
|
+
rescue Errno::ENOENT => e
|
220
|
+
raise SaveError, 'Non-existant path component'
|
221
|
+
rescue SystemCallError => e
|
222
|
+
raise SaveError, e.message
|
165
223
|
end
|
166
|
-
|
167
|
-
def
|
168
|
-
|
169
|
-
|
170
|
-
yield
|
224
|
+
|
225
|
+
def assert_valid_keys(hsh, *valid_keys)
|
226
|
+
if unknown_key = (hsh.keys - valid_keys).first
|
227
|
+
raise ArgumentError.new("Unknown key: #{unknown_key.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}")
|
171
228
|
end
|
172
229
|
end
|
173
230
|
|
174
|
-
def instantiate(ptr)
|
175
|
-
self.class.send(:instantiate, ptr)
|
176
|
-
end
|
177
|
-
|
178
231
|
end
|
179
232
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rszr'
|
2
|
+
require 'image_processing'
|
3
|
+
|
4
|
+
module ImageProcessing
|
5
|
+
module Rszr
|
6
|
+
extend Chainable
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# Returns whether the given image file is processable.
|
11
|
+
def valid_image?(file)
|
12
|
+
::Rszr::Image.load(file).width
|
13
|
+
true
|
14
|
+
rescue ::Rszr::Error
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class Processor < ImageProcessing::Processor
|
21
|
+
accumulator :image, ::Rszr::Image
|
22
|
+
|
23
|
+
class << self
|
24
|
+
|
25
|
+
# Loads the image on disk into a Rszr::Image object
|
26
|
+
def load_image(path_or_image, **options)
|
27
|
+
if path_or_image.is_a?(::Rszr::Image)
|
28
|
+
path_or_image
|
29
|
+
else
|
30
|
+
::Rszr::Image.load(path_or_image)
|
31
|
+
end
|
32
|
+
# TODO: image = image.autorot if autorot && !options.key?(:autorotate)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Writes the image object to disk.
|
36
|
+
# Accepts additional options (quality, format).
|
37
|
+
def save_image(image, destination_path, **options)
|
38
|
+
image.save(destination_path, **options)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Calls the operation to perform the processing. If the operation is
|
42
|
+
# defined on the processor (macro), calls it. Otherwise calls the
|
43
|
+
# bang variant of the method directly on the Rszr image object.
|
44
|
+
def apply_operation(accumulator, (name, args, block))
|
45
|
+
return super if method_defined?(name)
|
46
|
+
accumulator.send("#{name}!", *args, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
# Resizes the image to not be larger than the specified dimensions.
|
52
|
+
def resize_to_limit(width, height, **options)
|
53
|
+
width, height = default_dimensions(width, height)
|
54
|
+
thumbnail(width, height, **options)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Resizes the image to fit within the specified dimensions.
|
58
|
+
def resize_to_fit(width, height, **options)
|
59
|
+
width, height = default_dimensions(width, height)
|
60
|
+
thumbnail(width, height, **options)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Resizes the image to fill the specified dimensions, applying any
|
64
|
+
# necessary cropping.
|
65
|
+
def resize_to_fill(width, height, **options)
|
66
|
+
thumbnail(width, height, crop: :center, **options)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def thumbnail(width, height, **options)
|
72
|
+
image.resize!(width, height, **options)
|
73
|
+
end
|
74
|
+
|
75
|
+
def default_dimensions(width, height)
|
76
|
+
raise Error, 'either width or height must be specified' unless width || height
|
77
|
+
[width || :auto, height || :auto]
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Rszr
|
2
|
+
module Orientation
|
3
|
+
ROTATIONS = { 5 => 1, 6 => 1, 3 => 2, 4 => 2, 7 => 3, 8 => 3 }
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
base.attr_reader :original_orientation
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def autorotate(image, path)
|
15
|
+
return unless %w[jpeg tiff].include?(image.format)
|
16
|
+
File.open(path) do |file|
|
17
|
+
if orientation = send("parse_#{image.format}_orientation", file) and (1..8).member?(orientation)
|
18
|
+
image.instance_variable_set :@original_orientation, orientation
|
19
|
+
image.flop! if [2, 4, 5, 7].include?(orientation)
|
20
|
+
image.turn!(ROTATIONS[orientation]) if ROTATIONS.key?(orientation)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse_tiff_orientation(data)
|
26
|
+
exif_parse_orientation(Stream.new(data))
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_jpeg_orientation(data)
|
30
|
+
stream = Stream.new(data)
|
31
|
+
exif = nil
|
32
|
+
state = nil
|
33
|
+
loop do
|
34
|
+
state = case state
|
35
|
+
when nil
|
36
|
+
stream.skip(2)
|
37
|
+
:started
|
38
|
+
when :started
|
39
|
+
stream.read_byte == 0xFF ? :sof : :started
|
40
|
+
when :sof
|
41
|
+
case stream.read_byte
|
42
|
+
when 0xe1 # APP1
|
43
|
+
skip_chars = stream.read_int - 2
|
44
|
+
app1 = Stream.new(stream.read(skip_chars))
|
45
|
+
if app1.read(4) == 'Exif'
|
46
|
+
app1.skip(2)
|
47
|
+
orientation = exif_parse_orientation(app1.fast_forward)# rescue nil
|
48
|
+
return orientation
|
49
|
+
end
|
50
|
+
:started
|
51
|
+
when 0xe0..0xef
|
52
|
+
:skipframe
|
53
|
+
when 0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF
|
54
|
+
:readsize
|
55
|
+
when 0xFF
|
56
|
+
:sof
|
57
|
+
else
|
58
|
+
:skipframe
|
59
|
+
end
|
60
|
+
when :skipframe
|
61
|
+
skip_chars = stream.read_int - 2
|
62
|
+
stream.skip(skip_chars)
|
63
|
+
:started
|
64
|
+
when :readsize
|
65
|
+
# stream.skip(3)
|
66
|
+
# height = stream.read_int
|
67
|
+
# width = stream.read_int
|
68
|
+
return exif&.orientation
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def exif_byte_order(stream)
|
74
|
+
byte_order = stream.read(2)
|
75
|
+
case byte_order
|
76
|
+
when 'II'
|
77
|
+
%w[v V]
|
78
|
+
when 'MM'
|
79
|
+
%w[n N]
|
80
|
+
else
|
81
|
+
raise LoadError
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def exif_parse_ifd(stream, short)
|
86
|
+
tag_count = stream.read(2).unpack(short)[0]
|
87
|
+
tag_count.downto(1) do
|
88
|
+
type = stream.read(2).unpack(short)[0]
|
89
|
+
stream.read(6)
|
90
|
+
data = stream.read(2).unpack(short)[0]
|
91
|
+
return data if 0x0112 == type
|
92
|
+
stream.read(2)
|
93
|
+
end
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
|
97
|
+
def exif_parse_orientation(stream)
|
98
|
+
short, long = exif_byte_order(stream)
|
99
|
+
stream.read(2) # 42
|
100
|
+
offset = stream.read(4).unpack(long)[0]
|
101
|
+
stream.skip(offset - 8)
|
102
|
+
exif_parse_ifd(stream, short)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
data/lib/rszr/stream.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Rszr
|
2
|
+
class Stream
|
3
|
+
attr_reader :pos, :data
|
4
|
+
protected :data
|
5
|
+
|
6
|
+
def initialize(data, start: 0)
|
7
|
+
raise ArgumentError, 'start must be > 0' if start < 0
|
8
|
+
@data = case data
|
9
|
+
when IO then data
|
10
|
+
when String then StringIO.new(data)
|
11
|
+
when Stream then data.data
|
12
|
+
else
|
13
|
+
raise ArgumentError, "data must be File or String, got #{data.class}"
|
14
|
+
end
|
15
|
+
@data.binmode
|
16
|
+
@data.seek(start, IO::SEEK_CUR)
|
17
|
+
@pos = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def read(n)
|
21
|
+
@data.read(n).tap { @pos += n }
|
22
|
+
end
|
23
|
+
|
24
|
+
def peek(n)
|
25
|
+
old_pos = @data.pos
|
26
|
+
@data.read(n)
|
27
|
+
ensure
|
28
|
+
@data.pos = old_pos
|
29
|
+
end
|
30
|
+
|
31
|
+
def skip(n)
|
32
|
+
@data.seek(n, IO::SEEK_CUR).tap { @pos += n }
|
33
|
+
end
|
34
|
+
|
35
|
+
def substream
|
36
|
+
self.class.new(self, pos)
|
37
|
+
end
|
38
|
+
|
39
|
+
def fast_forward
|
40
|
+
@pos = 0
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def read_byte
|
45
|
+
read(1)[0].ord
|
46
|
+
end
|
47
|
+
|
48
|
+
def read_int
|
49
|
+
read(2).unpack('n')[0]
|
50
|
+
end
|
51
|
+
|
52
|
+
def read_string_int
|
53
|
+
value = []
|
54
|
+
while read(1) =~ /(\d)/
|
55
|
+
value << $1
|
56
|
+
end
|
57
|
+
value.join.to_i
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
data/lib/rszr/version.rb
CHANGED
data/lib/rszr.rb
CHANGED
@@ -1,12 +1,26 @@
|
|
1
|
-
require 'fiddle'
|
2
|
-
require 'fiddle/import'
|
3
1
|
require 'rbconfig'
|
4
2
|
require 'pathname'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'stringio'
|
5
5
|
|
6
|
+
require 'rszr/rszr'
|
6
7
|
require 'rszr/version'
|
7
|
-
require 'rszr/
|
8
|
-
require 'rszr/
|
9
|
-
require 'rszr/
|
10
|
-
require 'rszr/
|
11
|
-
require 'rszr/base'
|
8
|
+
require 'rszr/stream'
|
9
|
+
require 'rszr/identification'
|
10
|
+
require 'rszr/orientation'
|
11
|
+
require 'rszr/buffered'
|
12
12
|
require 'rszr/image'
|
13
|
+
|
14
|
+
module Rszr
|
15
|
+
class << self
|
16
|
+
@@autorotate = nil
|
17
|
+
|
18
|
+
def autorotate
|
19
|
+
@@autorotate
|
20
|
+
end
|
21
|
+
|
22
|
+
def autorotate=(value)
|
23
|
+
@@autorotate = !!value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|