winton-attachment_fu 1.0.5 → 1.0.6
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.
- metadata +16 -14
- data/CHANGELOG +0 -35
- data/README +0 -186
- data/Rakefile +0 -22
- data/amazon_s3.yml.tpl +0 -14
- data/init.rb +0 -17
- data/install.rb +0 -5
- data/lib/geometry.rb +0 -93
- data/lib/technoweenie/attachment_fu.rb +0 -473
- data/lib/technoweenie/attachment_fu/backends/db_file_backend.rb +0 -39
- data/lib/technoweenie/attachment_fu/backends/file_system_backend.rb +0 -101
- data/lib/technoweenie/attachment_fu/backends/s3_backend.rb +0 -303
- data/lib/technoweenie/attachment_fu/processors/core_image_processor.rb +0 -59
- data/lib/technoweenie/attachment_fu/processors/gd2_processor.rb +0 -54
- data/lib/technoweenie/attachment_fu/processors/image_science_processor.rb +0 -61
- data/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb +0 -59
- data/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb +0 -54
- data/test/backends/db_file_test.rb +0 -16
- data/test/backends/file_system_test.rb +0 -80
- data/test/backends/remote/s3_test.rb +0 -119
- data/test/base_attachment_tests.rb +0 -77
- data/test/basic_test.rb +0 -70
- data/test/database.yml +0 -18
- data/test/extra_attachment_test.rb +0 -67
- data/test/fixtures/attachment.rb +0 -148
- data/test/fixtures/files/fake/rails.png +0 -0
- data/test/fixtures/files/foo.txt +0 -1
- data/test/fixtures/files/rails.png +0 -0
- data/test/geometry_test.rb +0 -101
- data/test/processors/core_image_test.rb +0 -37
- data/test/processors/gd2_test.rb +0 -31
- data/test/processors/image_science_test.rb +0 -31
- data/test/processors/mini_magick_test.rb +0 -31
- data/test/processors/rmagick_test.rb +0 -255
- data/test/schema.rb +0 -108
- data/test/test_helper.rb +0 -150
- data/test/validation_test.rb +0 -55
- data/vendor/red_artisan/core_image/filters/color.rb +0 -27
- data/vendor/red_artisan/core_image/filters/effects.rb +0 -31
- data/vendor/red_artisan/core_image/filters/perspective.rb +0 -25
- data/vendor/red_artisan/core_image/filters/quality.rb +0 -25
- data/vendor/red_artisan/core_image/filters/scale.rb +0 -47
- data/vendor/red_artisan/core_image/filters/watermark.rb +0 -32
- data/vendor/red_artisan/core_image/processor.rb +0 -123
data/test/test_helper.rb
DELETED
@@ -1,150 +0,0 @@
|
|
1
|
-
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
-
|
3
|
-
ENV['RAILS_ENV'] = 'test'
|
4
|
-
ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '/../../../..'
|
5
|
-
|
6
|
-
require 'test/unit'
|
7
|
-
require File.expand_path(File.join(ENV['RAILS_ROOT'], 'config/environment.rb'))
|
8
|
-
require 'active_record/fixtures'
|
9
|
-
require 'action_controller/test_process'
|
10
|
-
|
11
|
-
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
12
|
-
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
13
|
-
|
14
|
-
db_adapter = ENV['DB']
|
15
|
-
|
16
|
-
# no db passed, try one of these fine config-free DBs before bombing.
|
17
|
-
db_adapter ||=
|
18
|
-
begin
|
19
|
-
require 'rubygems'
|
20
|
-
require 'sqlite'
|
21
|
-
'sqlite'
|
22
|
-
rescue MissingSourceFile
|
23
|
-
begin
|
24
|
-
require 'sqlite3'
|
25
|
-
'sqlite3'
|
26
|
-
rescue MissingSourceFile
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
if db_adapter.nil?
|
31
|
-
raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3."
|
32
|
-
end
|
33
|
-
|
34
|
-
ActiveRecord::Base.establish_connection(config[db_adapter])
|
35
|
-
|
36
|
-
load(File.dirname(__FILE__) + "/schema.rb")
|
37
|
-
|
38
|
-
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures"
|
39
|
-
$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
|
40
|
-
|
41
|
-
class Test::Unit::TestCase #:nodoc:
|
42
|
-
include ActionController::TestProcess
|
43
|
-
def create_fixtures(*table_names)
|
44
|
-
if block_given?
|
45
|
-
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
|
46
|
-
else
|
47
|
-
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def setup
|
52
|
-
Attachment.saves = 0
|
53
|
-
DbFile.transaction { [Attachment, FileAttachment, OrphanAttachment, MinimalAttachment, DbFile].each { |klass| klass.delete_all } }
|
54
|
-
attachment_model self.class.attachment_model
|
55
|
-
end
|
56
|
-
|
57
|
-
def teardown
|
58
|
-
FileUtils.rm_rf File.join(File.dirname(__FILE__), 'files')
|
59
|
-
end
|
60
|
-
|
61
|
-
self.use_transactional_fixtures = true
|
62
|
-
self.use_instantiated_fixtures = false
|
63
|
-
|
64
|
-
def self.attachment_model(klass = nil)
|
65
|
-
@attachment_model = klass if klass
|
66
|
-
@attachment_model
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.test_against_class(test_method, klass, subclass = false)
|
70
|
-
define_method("#{test_method}_on_#{:sub if subclass}class") do
|
71
|
-
klass = Class.new(klass) if subclass
|
72
|
-
attachment_model klass
|
73
|
-
send test_method, klass
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.test_against_subclass(test_method, klass)
|
78
|
-
test_against_class test_method, klass, true
|
79
|
-
end
|
80
|
-
|
81
|
-
protected
|
82
|
-
def upload_file(options = {})
|
83
|
-
use_temp_file options[:filename] do |file|
|
84
|
-
att = attachment_model.create :uploaded_data => fixture_file_upload(file, options[:content_type] || 'image/png')
|
85
|
-
att.reload unless att.new_record?
|
86
|
-
return att
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def upload_merb_file(options = {})
|
91
|
-
use_temp_file options[:filename] do |file|
|
92
|
-
att = attachment_model.create :uploaded_data => {"size" => file.size, "content_type" => options[:content_type] || 'image/png', "filename" => file, 'tempfile' => fixture_file_upload(file, options[:content_type] || 'image/png')}
|
93
|
-
att.reload unless att.new_record?
|
94
|
-
return att
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def use_temp_file(fixture_filename)
|
99
|
-
temp_path = File.join('/tmp', File.basename(fixture_filename))
|
100
|
-
FileUtils.mkdir_p File.join(fixture_path, 'tmp')
|
101
|
-
FileUtils.cp File.join(fixture_path, fixture_filename), File.join(fixture_path, temp_path)
|
102
|
-
yield temp_path
|
103
|
-
ensure
|
104
|
-
FileUtils.rm_rf File.join(fixture_path, 'tmp')
|
105
|
-
end
|
106
|
-
|
107
|
-
def assert_created(num = 1)
|
108
|
-
assert_difference attachment_model.base_class, :count, num do
|
109
|
-
if attachment_model.included_modules.include? DbFile
|
110
|
-
assert_difference DbFile, :count, num do
|
111
|
-
yield
|
112
|
-
end
|
113
|
-
else
|
114
|
-
yield
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def assert_not_created
|
120
|
-
assert_created(0) { yield }
|
121
|
-
end
|
122
|
-
|
123
|
-
def should_reject_by_size_with(klass)
|
124
|
-
attachment_model klass
|
125
|
-
assert_not_created do
|
126
|
-
attachment = upload_file :filename => '/files/rails.png'
|
127
|
-
assert attachment.new_record?
|
128
|
-
assert attachment.errors.on(:size)
|
129
|
-
assert_nil attachment.db_file if attachment.respond_to?(:db_file)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def assert_difference(object, method = nil, difference = 1)
|
134
|
-
initial_value = object.send(method)
|
135
|
-
yield
|
136
|
-
assert_equal initial_value + difference, object.send(method)
|
137
|
-
end
|
138
|
-
|
139
|
-
def assert_no_difference(object, method, &block)
|
140
|
-
assert_difference object, method, 0, &block
|
141
|
-
end
|
142
|
-
|
143
|
-
def attachment_model(klass = nil)
|
144
|
-
@attachment_model = klass if klass
|
145
|
-
@attachment_model
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
require File.join(File.dirname(__FILE__), 'fixtures/attachment')
|
150
|
-
require File.join(File.dirname(__FILE__), 'base_attachment_tests')
|
data/test/validation_test.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
-
|
3
|
-
class ValidationTest < Test::Unit::TestCase
|
4
|
-
def test_should_invalidate_big_files
|
5
|
-
@attachment = SmallAttachment.new
|
6
|
-
assert !@attachment.valid?
|
7
|
-
assert @attachment.errors.on(:size)
|
8
|
-
|
9
|
-
@attachment.size = 2000
|
10
|
-
assert !@attachment.valid?
|
11
|
-
assert @attachment.errors.on(:size), @attachment.errors.full_messages.to_sentence
|
12
|
-
|
13
|
-
@attachment.size = 1000
|
14
|
-
assert !@attachment.valid?
|
15
|
-
assert_nil @attachment.errors.on(:size)
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_should_invalidate_small_files
|
19
|
-
@attachment = BigAttachment.new
|
20
|
-
assert !@attachment.valid?
|
21
|
-
assert @attachment.errors.on(:size)
|
22
|
-
|
23
|
-
@attachment.size = 2000
|
24
|
-
assert !@attachment.valid?
|
25
|
-
assert @attachment.errors.on(:size), @attachment.errors.full_messages.to_sentence
|
26
|
-
|
27
|
-
@attachment.size = 1.megabyte
|
28
|
-
assert !@attachment.valid?
|
29
|
-
assert_nil @attachment.errors.on(:size)
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_should_validate_content_type
|
33
|
-
@attachment = PdfAttachment.new
|
34
|
-
assert !@attachment.valid?
|
35
|
-
assert @attachment.errors.on(:content_type)
|
36
|
-
|
37
|
-
@attachment.content_type = 'foo'
|
38
|
-
assert !@attachment.valid?
|
39
|
-
assert @attachment.errors.on(:content_type)
|
40
|
-
|
41
|
-
@attachment.content_type = 'pdf'
|
42
|
-
assert !@attachment.valid?
|
43
|
-
assert_nil @attachment.errors.on(:content_type)
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_should_require_filename
|
47
|
-
@attachment = Attachment.new
|
48
|
-
assert !@attachment.valid?
|
49
|
-
assert @attachment.errors.on(:filename)
|
50
|
-
|
51
|
-
@attachment.filename = 'foo'
|
52
|
-
assert !@attachment.valid?
|
53
|
-
assert_nil @attachment.errors.on(:filename)
|
54
|
-
end
|
55
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module RedArtisan
|
2
|
-
module CoreImage
|
3
|
-
module Filters
|
4
|
-
module Color
|
5
|
-
|
6
|
-
def greyscale(color = nil, intensity = 1.00)
|
7
|
-
create_core_image_context(@original.extent.size.width, @original.extent.size.height)
|
8
|
-
|
9
|
-
color = OSX::CIColor.colorWithString("1.0 1.0 1.0 1.0") unless color
|
10
|
-
|
11
|
-
@original.color_monochrome :inputColor => color, :inputIntensity => intensity do |greyscale|
|
12
|
-
@target = greyscale
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def sepia(intensity = 1.00)
|
17
|
-
create_core_image_context(@original.extent.size.width, @original.extent.size.height)
|
18
|
-
|
19
|
-
@original.sepia_tone :inputIntensity => intensity do |sepia|
|
20
|
-
@target = sepia
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module RedArtisan
|
2
|
-
module CoreImage
|
3
|
-
module Filters
|
4
|
-
module Effects
|
5
|
-
|
6
|
-
def spotlight(position, points_at, brightness, concentration, color)
|
7
|
-
create_core_image_context(@original.extent.size.width, @original.extent.size.height)
|
8
|
-
|
9
|
-
@original.spot_light :inputLightPosition => vector3(*position), :inputLightPointsAt => vector3(*points_at),
|
10
|
-
:inputBrightness => brightness, :inputConcentration => concentration, :inputColor => color do |spot|
|
11
|
-
@target = spot
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def edges(intensity = 1.00)
|
16
|
-
create_core_image_context(@original.extent.size.width, @original.extent.size.height)
|
17
|
-
|
18
|
-
@original.edges :inputIntensity => intensity do |edged|
|
19
|
-
@target = edged
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def vector3(x, y, w)
|
26
|
-
OSX::CIVector.vectorWithX_Y_Z(x, y, w)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module RedArtisan
|
2
|
-
module CoreImage
|
3
|
-
module Filters
|
4
|
-
module Perspective
|
5
|
-
|
6
|
-
def perspective(top_left, top_right, bottom_left, bottom_right)
|
7
|
-
create_core_image_context(@original.extent.size.width, @original.extent.size.height)
|
8
|
-
|
9
|
-
@original.perspective_transform :inputTopLeft => top_left, :inputTopRight => top_right, :inputBottomLeft => bottom_left, :inputBottomRight => bottom_right do |transformed|
|
10
|
-
@target = transformed
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def perspective_tiled(top_left, top_right, bottom_left, bottom_right)
|
15
|
-
create_core_image_context(@original.extent.size.width, @original.extent.size.height)
|
16
|
-
|
17
|
-
@original.perspective_tile :inputTopLeft => top_left, :inputTopRight => top_right, :inputBottomLeft => bottom_left, :inputBottomRight => bottom_right do |tiled|
|
18
|
-
@target = tiled
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module RedArtisan
|
2
|
-
module CoreImage
|
3
|
-
module Filters
|
4
|
-
module Quality
|
5
|
-
|
6
|
-
def reduce_noise(level = 0.02, sharpness = 0.4)
|
7
|
-
create_core_image_context(@original.extent.size.width, @original.extent.size.height)
|
8
|
-
|
9
|
-
@original.noise_reduction :inputNoiseLevel => level, :inputSharpness => sharpness do |noise_reduced|
|
10
|
-
@target = noise_reduced
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def adjust_exposure(input_ev = 0.5)
|
15
|
-
create_core_image_context(@original.extent.size.width, @original.extent.size.height)
|
16
|
-
|
17
|
-
@original.exposure_adjust :inputEV => input_ev do |adjusted|
|
18
|
-
@target = adjusted
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module RedArtisan
|
2
|
-
module CoreImage
|
3
|
-
module Filters
|
4
|
-
module Scale
|
5
|
-
|
6
|
-
def resize(width, height)
|
7
|
-
create_core_image_context(width, height)
|
8
|
-
|
9
|
-
scale_x, scale_y = scale(width, height)
|
10
|
-
|
11
|
-
@original.affine_clamp :inputTransform => OSX::NSAffineTransform.transform do |clamped|
|
12
|
-
clamped.lanczos_scale_transform :inputScale => scale_x > scale_y ? scale_x : scale_y, :inputAspectRatio => scale_x / scale_y do |scaled|
|
13
|
-
scaled.crop :inputRectangle => vector(0, 0, width, height) do |cropped|
|
14
|
-
@target = cropped
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def thumbnail(width, height)
|
21
|
-
create_core_image_context(width, height)
|
22
|
-
|
23
|
-
transform = OSX::NSAffineTransform.transform
|
24
|
-
transform.scaleXBy_yBy *scale(width, height)
|
25
|
-
|
26
|
-
@original.affine_transform :inputTransform => transform do |scaled|
|
27
|
-
@target = scaled
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def fit(size)
|
32
|
-
original_size = @original.extent.size
|
33
|
-
scale = size.to_f / (original_size.width > original_size.height ? original_size.width : original_size.height)
|
34
|
-
resize (original_size.width * scale).to_i, (original_size.height * scale).to_i
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def scale(width, height)
|
40
|
-
original_size = @original.extent.size
|
41
|
-
return width.to_f / original_size.width.to_f, height.to_f / original_size.height.to_f
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
module RedArtisan
|
2
|
-
module CoreImage
|
3
|
-
module Filters
|
4
|
-
module Watermark
|
5
|
-
|
6
|
-
def watermark(watermark_image, tile = false, strength = 0.1)
|
7
|
-
create_core_image_context(@original.extent.size.width, @original.extent.size.height)
|
8
|
-
|
9
|
-
if watermark_image.respond_to? :to_str
|
10
|
-
watermark_image = OSX::CIImage.from(watermark_image.to_str)
|
11
|
-
end
|
12
|
-
|
13
|
-
if tile
|
14
|
-
tile_transform = OSX::NSAffineTransform.transform
|
15
|
-
tile_transform.scaleXBy_yBy 1.0, 1.0
|
16
|
-
|
17
|
-
watermark_image.affine_tile :inputTransform => tile_transform do |tiled|
|
18
|
-
tiled.crop :inputRectangle => vector(0, 0, @original.extent.size.width, @original.extent.size.height) do |tiled_watermark|
|
19
|
-
watermark_image = tiled_watermark
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
@original.dissolve_transition :inputTargetImage => watermark_image, :inputTime => strength do |watermarked|
|
25
|
-
@target = watermarked
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,123 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'osx/cocoa'
|
3
|
-
require 'active_support'
|
4
|
-
|
5
|
-
require 'red_artisan/core_image/filters/scale'
|
6
|
-
require 'red_artisan/core_image/filters/color'
|
7
|
-
require 'red_artisan/core_image/filters/watermark'
|
8
|
-
require 'red_artisan/core_image/filters/quality'
|
9
|
-
require 'red_artisan/core_image/filters/perspective'
|
10
|
-
require 'red_artisan/core_image/filters/effects'
|
11
|
-
|
12
|
-
# Generic image processor for scaling images based on CoreImage via RubyCocoa.
|
13
|
-
#
|
14
|
-
# Example usage:
|
15
|
-
#
|
16
|
-
# p = Processor.new OSX::CIImage.from(path_to_image)
|
17
|
-
# p.resize(640, 480)
|
18
|
-
# p.render do |result|
|
19
|
-
# result.save('resized.jpg', OSX::NSJPEGFileType)
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# This will resize the image to the given dimensions exactly, if you'd like to ensure that aspect ratio is preserved:
|
23
|
-
#
|
24
|
-
# p = Processor.new OSX::CIImage.from(path_to_image)
|
25
|
-
# p.fit(640)
|
26
|
-
# p.render do |result|
|
27
|
-
# result.save('resized.jpg', OSX::NSJPEGFileType)
|
28
|
-
# end
|
29
|
-
#
|
30
|
-
# fit(size) will attempt its best to resize the image so that the longest width/height (depending on image orientation) will match
|
31
|
-
# the given size. The second axis will be calculated automatically based on the aspect ratio.
|
32
|
-
#
|
33
|
-
# Scaling is performed by first clamping the image so that its external bounds become infinite, this helps when scaling so that any
|
34
|
-
# rounding discrepencies in dimensions don't affect the resultant image. We then perform a Lanczos transform on the image which scales
|
35
|
-
# it to the target size. We then crop the image to the traget dimensions.
|
36
|
-
#
|
37
|
-
# If you are generating smaller images such as thumbnails where high quality rendering isn't as important, an additional method is
|
38
|
-
# available:
|
39
|
-
#
|
40
|
-
# p = Processor.new OSX::CIImage.from(path_to_image)
|
41
|
-
# p.thumbnail(100, 100)
|
42
|
-
# p.render do |result|
|
43
|
-
# result.save('resized.jpg', OSX::NSJPEGFileType)
|
44
|
-
# end
|
45
|
-
#
|
46
|
-
# This will perform a straight affine transform and scale the X and Y boundaries to the requested size. Generally, this will be faster
|
47
|
-
# than a lanczos scale transform, but with a scaling quality trade.
|
48
|
-
#
|
49
|
-
# More than welcome to intregrate any patches, improvements - feel free to mail me with ideas.
|
50
|
-
#
|
51
|
-
# Thanks to
|
52
|
-
# * Satoshi Nakagawa for working out that OCObjWrapper needs inclusion when aliasing method_missing on existing OSX::* classes.
|
53
|
-
# * Vasantha Crabb for general help and inspiration with Cocoa
|
54
|
-
# * Ben Schwarz for example image data and collaboration during performance testing
|
55
|
-
#
|
56
|
-
# Copyright (c) Marcus Crafter <crafterm@redartisan.com> released under the MIT license
|
57
|
-
#
|
58
|
-
module RedArtisan
|
59
|
-
module CoreImage
|
60
|
-
class Processor
|
61
|
-
|
62
|
-
def initialize(original)
|
63
|
-
if original.respond_to? :to_str
|
64
|
-
@original = OSX::CIImage.from(original.to_str)
|
65
|
-
else
|
66
|
-
@original = original
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def render(&block)
|
71
|
-
raise "unprocessed image: #{@original}" unless @target
|
72
|
-
block.call @target
|
73
|
-
end
|
74
|
-
|
75
|
-
include Filters::Scale, Filters::Color, Filters::Watermark, Filters::Quality, Filters::Perspective, Filters::Effects
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
def create_core_image_context(width, height)
|
80
|
-
output = OSX::NSBitmapImageRep.alloc.initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bytesPerRow_bitsPerPixel(nil, width, height, 8, 4, true, false, OSX::NSDeviceRGBColorSpace, 0, 0)
|
81
|
-
context = OSX::NSGraphicsContext.graphicsContextWithBitmapImageRep(output)
|
82
|
-
OSX::NSGraphicsContext.setCurrentContext(context)
|
83
|
-
@ci_context = context.CIContext
|
84
|
-
end
|
85
|
-
|
86
|
-
def vector(x, y, w, h)
|
87
|
-
OSX::CIVector.vectorWithX_Y_Z_W(x, y, w, h)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
module OSX
|
94
|
-
class CIImage
|
95
|
-
include OCObjWrapper
|
96
|
-
|
97
|
-
def method_missing_with_filter_processing(sym, *args, &block)
|
98
|
-
f = OSX::CIFilter.filterWithName("CI#{sym.to_s.camelize}")
|
99
|
-
return method_missing_without_filter_processing(sym, *args, &block) unless f
|
100
|
-
|
101
|
-
f.setDefaults if f.respond_to? :setDefaults
|
102
|
-
f.setValue_forKey(self, 'inputImage')
|
103
|
-
options = args.last.is_a?(Hash) ? args.last : {}
|
104
|
-
options.each { |k, v| f.setValue_forKey(v, k.to_s) }
|
105
|
-
|
106
|
-
block.call f.valueForKey('outputImage')
|
107
|
-
end
|
108
|
-
|
109
|
-
alias_method_chain :method_missing, :filter_processing
|
110
|
-
|
111
|
-
def save(target, format = OSX::NSJPEGFileType, properties = nil)
|
112
|
-
bitmapRep = OSX::NSBitmapImageRep.alloc.initWithCIImage(self)
|
113
|
-
blob = bitmapRep.representationUsingType_properties(format, properties)
|
114
|
-
blob.writeToFile_atomically(target, false)
|
115
|
-
end
|
116
|
-
|
117
|
-
def self.from(filepath)
|
118
|
-
raise Errno::ENOENT, "No such file or directory - #{filepath}" unless File.exists?(filepath)
|
119
|
-
OSX::CIImage.imageWithContentsOfURL(OSX::NSURL.fileURLWithPath(filepath))
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|