tdd-attachment_fu 0.9.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.
- data/CHANGELOG +44 -0
- data/LICENSE +20 -0
- data/README +197 -0
- data/Rakefile +22 -0
- data/amazon_s3.yml.tpl +17 -0
- data/init.rb +16 -0
- data/install.rb +7 -0
- data/lib/geometry.rb +96 -0
- data/lib/technoweenie/attachment_fu/backends/cloud_file_backend.rb +211 -0
- data/lib/technoweenie/attachment_fu/backends/db_file_backend.rb +39 -0
- data/lib/technoweenie/attachment_fu/backends/file_system_backend.rb +126 -0
- data/lib/technoweenie/attachment_fu/backends/s3_backend.rb +394 -0
- data/lib/technoweenie/attachment_fu/processors/core_image_processor.rb +65 -0
- data/lib/technoweenie/attachment_fu/processors/gd2_processor.rb +62 -0
- data/lib/technoweenie/attachment_fu/processors/image_science_processor.rb +80 -0
- data/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb +138 -0
- data/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb +65 -0
- data/lib/technoweenie/attachment_fu.rb +514 -0
- data/rackspace_cloudfiles.yml.tpl +14 -0
- data/test/backends/db_file_test.rb +16 -0
- data/test/backends/file_system_test.rb +143 -0
- data/test/backends/remote/cloudfiles_test.rb +102 -0
- data/test/backends/remote/s3_test.rb +119 -0
- data/test/base_attachment_tests.rb +77 -0
- data/test/basic_test.rb +70 -0
- data/test/database.yml +18 -0
- data/test/extra_attachment_test.rb +67 -0
- data/test/fixtures/attachment.rb +249 -0
- data/test/fixtures/files/fake/rails.png +0 -0
- data/test/fixtures/files/foo.txt +1 -0
- data/test/fixtures/files/rails.jpg +0 -0
- data/test/fixtures/files/rails.png +0 -0
- data/test/geometry_test.rb +114 -0
- data/test/processors/core_image_test.rb +50 -0
- data/test/processors/gd2_test.rb +44 -0
- data/test/processors/image_science_test.rb +47 -0
- data/test/processors/mini_magick_test.rb +116 -0
- data/test/processors/rmagick_test.rb +267 -0
- data/test/schema.rb +134 -0
- data/test/test_helper.rb +153 -0
- data/test/validation_test.rb +55 -0
- data/vendor/red_artisan/core_image/filters/color.rb +27 -0
- data/vendor/red_artisan/core_image/filters/effects.rb +31 -0
- data/vendor/red_artisan/core_image/filters/perspective.rb +25 -0
- data/vendor/red_artisan/core_image/filters/quality.rb +25 -0
- data/vendor/red_artisan/core_image/filters/scale.rb +47 -0
- data/vendor/red_artisan/core_image/filters/watermark.rb +32 -0
- data/vendor/red_artisan/core_image/processor.rb +123 -0
- metadata +103 -0
@@ -0,0 +1,25 @@
|
|
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
|
@@ -0,0 +1,47 @@
|
|
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
|
@@ -0,0 +1,32 @@
|
|
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
|
@@ -0,0 +1,123 @@
|
|
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
|
+
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tdd-attachment_fu
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rick Olson
|
8
|
+
- Christophe Porteneuve
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-08-04 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: "This is a fork of Rick Olson\xE2\x80\x99s attachment_fu adding '!' geometry support, JPEG quality control and polymorphic-relation-based thumbnailing."
|
18
|
+
email: tdd@tddsworld.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- README
|
25
|
+
files:
|
26
|
+
- CHANGELOG
|
27
|
+
- LICENSE
|
28
|
+
- README
|
29
|
+
- Rakefile
|
30
|
+
- init.rb
|
31
|
+
- install.rb
|
32
|
+
- amazon_s3.yml.tpl
|
33
|
+
- rackspace_cloudfiles.yml.tpl
|
34
|
+
- lib/geometry.rb
|
35
|
+
- lib/technoweenie/attachment_fu/backends/cloud_file_backend.rb
|
36
|
+
- lib/technoweenie/attachment_fu/backends/db_file_backend.rb
|
37
|
+
- lib/technoweenie/attachment_fu/backends/file_system_backend.rb
|
38
|
+
- lib/technoweenie/attachment_fu/backends/s3_backend.rb
|
39
|
+
- lib/technoweenie/attachment_fu/processors/core_image_processor.rb
|
40
|
+
- lib/technoweenie/attachment_fu/processors/gd2_processor.rb
|
41
|
+
- lib/technoweenie/attachment_fu/processors/image_science_processor.rb
|
42
|
+
- lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb
|
43
|
+
- lib/technoweenie/attachment_fu/processors/rmagick_processor.rb
|
44
|
+
- lib/technoweenie/attachment_fu.rb
|
45
|
+
- test/base_attachment_tests.rb
|
46
|
+
- test/basic_test.rb
|
47
|
+
- test/database.yml
|
48
|
+
- test/extra_attachment_test.rb
|
49
|
+
- test/geometry_test.rb
|
50
|
+
- test/schema.rb
|
51
|
+
- test/test_helper.rb
|
52
|
+
- test/validation_test.rb
|
53
|
+
- test/backends/db_file_test.rb
|
54
|
+
- test/backends/file_system_test.rb
|
55
|
+
- test/backends/remote/cloudfiles_test.rb
|
56
|
+
- test/backends/remote/s3_test.rb
|
57
|
+
- test/fixtures/attachment.rb
|
58
|
+
- test/fixtures/files/foo.txt
|
59
|
+
- test/fixtures/files/rails.jpg
|
60
|
+
- test/fixtures/files/rails.png
|
61
|
+
- test/fixtures/files/fake/rails.png
|
62
|
+
- test/processors/core_image_test.rb
|
63
|
+
- test/processors/gd2_test.rb
|
64
|
+
- test/processors/image_science_test.rb
|
65
|
+
- test/processors/mini_magick_test.rb
|
66
|
+
- test/processors/rmagick_test.rb
|
67
|
+
- vendor/red_artisan/core_image/processor.rb
|
68
|
+
- vendor/red_artisan/core_image/filters/color.rb
|
69
|
+
- vendor/red_artisan/core_image/filters/effects.rb
|
70
|
+
- vendor/red_artisan/core_image/filters/perspective.rb
|
71
|
+
- vendor/red_artisan/core_image/filters/quality.rb
|
72
|
+
- vendor/red_artisan/core_image/filters/scale.rb
|
73
|
+
- vendor/red_artisan/core_image/filters/watermark.rb
|
74
|
+
has_rdoc: true
|
75
|
+
homepage: http://github.com/tdd/attachment_fu
|
76
|
+
licenses:
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options:
|
79
|
+
- --inline-source
|
80
|
+
- --charset=UTF-8
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: "0"
|
88
|
+
version:
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: "0"
|
94
|
+
version:
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project: attachment_fu
|
98
|
+
rubygems_version: 1.3.5
|
99
|
+
signing_key:
|
100
|
+
specification_version: 2
|
101
|
+
summary: attachment_fu with more geometries, polymorphic-based settings and JPEG quality control.
|
102
|
+
test_files: []
|
103
|
+
|