dragonfly_libvips 2.5.0 → 2.6.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/.github/workflows/test.yml +29 -0
- data/.rubocop.yml +6 -0
- data/.ruby-version +1 -1
- data/.tool-versions +1 -1
- data/CHANGELOG.md +13 -0
- data/Gemfile +3 -1
- data/Guardfile +3 -1
- data/Rakefile +4 -2
- data/dragonfly_libvips.gemspec +23 -19
- data/lefthook.yml +5 -0
- data/lib/dragonfly_libvips/analysers/image_properties.rb +13 -10
- data/lib/dragonfly_libvips/dimensions.rb +44 -43
- data/lib/dragonfly_libvips/plugin.rb +10 -10
- data/lib/dragonfly_libvips/processors/encode.rb +27 -18
- data/lib/dragonfly_libvips/processors/extract_area.rb +28 -17
- data/lib/dragonfly_libvips/processors/rotate.rb +28 -17
- data/lib/dragonfly_libvips/processors/thumb.rb +48 -37
- data/lib/dragonfly_libvips/version.rb +3 -1
- data/lib/dragonfly_libvips.rb +40 -15
- metadata +52 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 507faa296ab3057e5b71b9fd85b0c9314ba77b748c2e23983dfb5bfbb46203f2
|
|
4
|
+
data.tar.gz: 47eec77cb209df469e4caf83a6102a4d0af6dc3452799bb441c305c8fe5f5faf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d13cd15073052fcbd5f7de59f5a6462662c98a083c1e348ebb4747a72fece6266261c9bac8ed2af97f693f930a2f3861c9a07d403dad49ec2cf1fa407fa6288b
|
|
7
|
+
data.tar.gz: ed631f529a74d9dbe21ae4810f24e9d237da89fa5495a400c81f7e2b2875f765be3370e10b541f459e5776fafac475f49614eb4d8edbf9712c4fddbb5cd76545
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
on:
|
|
3
|
+
pull_request:
|
|
4
|
+
branches: ["master"]
|
|
5
|
+
push:
|
|
6
|
+
branches: ["master"]
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
strategy:
|
|
11
|
+
matrix:
|
|
12
|
+
ruby: ['2.7', '3.2']
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v2
|
|
15
|
+
- name: Install dependencies
|
|
16
|
+
run: |
|
|
17
|
+
sudo apt-get clean
|
|
18
|
+
sudo apt-get update
|
|
19
|
+
sudo apt-get install -y gobject-introspection libgirepository1.0-dev libglib2.0-dev libpoppler-glib-dev libgif-dev
|
|
20
|
+
curl -OL https://github.com/libvips/libvips/releases/download/v8.13.3/vips-8.13.3.tar.gz
|
|
21
|
+
tar zxvf vips-8.13.3.tar.gz && cd vips-8.13.3 && ./configure $1 && sudo make && sudo make install
|
|
22
|
+
export GI_TYPELIB_PATH=/usr/local/lib/girepository-1.0/
|
|
23
|
+
sudo ldconfig
|
|
24
|
+
- uses: ruby/setup-ruby@v1
|
|
25
|
+
with:
|
|
26
|
+
ruby-version: ${{ matrix.ruby }}
|
|
27
|
+
bundler-cache: true
|
|
28
|
+
- name: Run tests
|
|
29
|
+
run: bundle exec rake
|
data/.rubocop.yml
ADDED
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3.4.5
|
data/.tool-versions
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
ruby
|
|
1
|
+
ruby 3.4.5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 2.6.0
|
|
4
|
+
|
|
5
|
+
* Add auto_profile configuration option by @asgerb
|
|
6
|
+
* Fix output not having the ICC profile embedded by @asgerb
|
|
7
|
+
|
|
8
|
+
## 2.5.1
|
|
9
|
+
|
|
10
|
+
* Update all DragonflyLibvips.symbolize_keys to new syntax by @Bartuz
|
|
11
|
+
* Remove `raw` from supported output formats by @asgerb
|
|
12
|
+
* Add `j2c`, `j2k`, `jp2`, `jpc`, `jpt`, `jxl`, and `szi` to formats without profile support by @asgerb
|
|
13
|
+
* Don't pass `format` output option to `gif` by @asgerb
|
|
14
|
+
* Fix missing parameters in `Dimensions` by @asgerb
|
|
15
|
+
|
|
3
16
|
## 2.5.0
|
|
4
17
|
|
|
5
18
|
* Fix ruby 3.0+ compatibility by @Bartuz
|
data/Gemfile
CHANGED
data/Guardfile
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# A sample Guardfile
|
|
2
4
|
# More info at https://github.com/guard/guard#readme
|
|
3
5
|
|
|
4
6
|
guard :minitest do
|
|
5
7
|
watch(%r{^lib/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
|
|
6
8
|
watch(%r{^test/.+_test\.rb$})
|
|
7
|
-
watch(%r{^test/test_helper\.rb$}) {
|
|
9
|
+
watch(%r{^test/test_helper\.rb$}) { "test" }
|
|
8
10
|
end
|
data/Rakefile
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "bundler/gem_tasks"
|
|
2
4
|
require "rake/testtask"
|
|
3
5
|
|
|
4
6
|
Rake::TestTask.new(:test) do |t|
|
|
5
7
|
t.libs << "test"
|
|
6
8
|
t.libs << "lib"
|
|
7
|
-
t.test_files = FileList[
|
|
9
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
8
10
|
end
|
|
9
11
|
|
|
10
|
-
task :
|
|
12
|
+
task default: :test
|
data/dragonfly_libvips.gemspec
CHANGED
|
@@ -1,31 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
|
|
2
|
-
lib = File.expand_path(
|
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
-
require
|
|
5
|
+
require "dragonfly_libvips/version"
|
|
5
6
|
|
|
6
7
|
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name =
|
|
8
|
+
spec.name = "dragonfly_libvips"
|
|
8
9
|
spec.version = DragonflyLibvips::VERSION
|
|
9
|
-
spec.authors = [
|
|
10
|
-
spec.email = [
|
|
10
|
+
spec.authors = ["Tomas Celizna"]
|
|
11
|
+
spec.email = ["tomas.celizna@gmail.com"]
|
|
11
12
|
|
|
12
|
-
spec.summary =
|
|
13
|
-
spec.homepage =
|
|
14
|
-
spec.license =
|
|
13
|
+
spec.summary = "Dragonfly analysers and processors for libvips image processing library."
|
|
14
|
+
spec.homepage = "https://github.com/tomasc/dragonfly_libvips"
|
|
15
|
+
spec.license = "MIT"
|
|
15
16
|
|
|
16
17
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
17
|
-
spec.bindir =
|
|
18
|
+
spec.bindir = "exe"
|
|
18
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
19
|
-
spec.require_paths = [
|
|
20
|
+
spec.require_paths = ["lib"]
|
|
20
21
|
|
|
21
|
-
spec.add_dependency
|
|
22
|
-
spec.add_dependency
|
|
22
|
+
spec.add_dependency "dragonfly", "~> 1.0"
|
|
23
|
+
spec.add_dependency "ruby-vips", "~> 2.0", ">= 2.0.16"
|
|
24
|
+
spec.add_dependency "base64"
|
|
23
25
|
|
|
24
|
-
spec.add_development_dependency
|
|
25
|
-
spec.add_development_dependency
|
|
26
|
-
spec.add_development_dependency
|
|
27
|
-
spec.add_development_dependency
|
|
28
|
-
spec.add_development_dependency
|
|
29
|
-
spec.add_development_dependency
|
|
30
|
-
spec.add_development_dependency
|
|
26
|
+
spec.add_development_dependency "bundler" # , '~> 2.0'
|
|
27
|
+
spec.add_development_dependency "rb-readline"
|
|
28
|
+
spec.add_development_dependency "guard"
|
|
29
|
+
spec.add_development_dependency "guard-minitest"
|
|
30
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
31
|
+
spec.add_development_dependency "minitest-reporters"
|
|
32
|
+
spec.add_development_dependency "rake"
|
|
33
|
+
spec.add_development_dependency "lefthook"
|
|
34
|
+
spec.add_development_dependency "rubocop-rails_config"
|
|
31
35
|
end
|
data/lefthook.yml
ADDED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "vips"
|
|
2
4
|
|
|
3
5
|
module DragonflyLibvips
|
|
4
6
|
module Analysers
|
|
@@ -10,9 +12,9 @@ module DragonflyLibvips
|
|
|
10
12
|
return {} unless SUPPORTED_FORMATS.include?(content.ext.downcase)
|
|
11
13
|
|
|
12
14
|
input_options = {}
|
|
13
|
-
input_options[
|
|
14
|
-
input_options[
|
|
15
|
-
input_options[
|
|
15
|
+
input_options["access"] = "sequential"
|
|
16
|
+
input_options["autorotate"] = true if content.mime_type == "image/jpeg"
|
|
17
|
+
input_options["dpi"] = DPI if content.mime_type == "application/pdf"
|
|
16
18
|
|
|
17
19
|
img = ::Vips::Image.new_from_file(content.path, **DragonflyLibvips.symbolize_keys(input_options))
|
|
18
20
|
|
|
@@ -22,12 +24,13 @@ module DragonflyLibvips
|
|
|
22
24
|
yres = img.yres
|
|
23
25
|
|
|
24
26
|
{
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
"format" => content.ext.to_s,
|
|
28
|
+
"width" => width,
|
|
29
|
+
"height" => height,
|
|
30
|
+
"xres" => xres,
|
|
31
|
+
"yres" => yres,
|
|
32
|
+
"has_alpha" => img.has_alpha?,
|
|
33
|
+
"progressive" => (content.mime_type == "image/jpeg" && img.get("jpeg-multiscan") != 0)
|
|
31
34
|
}
|
|
32
35
|
end
|
|
33
36
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module DragonflyLibvips
|
|
2
4
|
class Dimensions < Struct.new(:geometry, :orig_w, :orig_h)
|
|
3
5
|
def self.call(*args)
|
|
@@ -10,60 +12,59 @@ module DragonflyLibvips
|
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
private
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
def width
|
|
16
|
+
if landscape?
|
|
17
|
+
dimensions_specified_by_width? ? dimensions.width : dimensions.height / aspect_ratio
|
|
18
|
+
else
|
|
19
|
+
dimensions_specified_by_height? ? dimensions.height / aspect_ratio : dimensions.width
|
|
20
|
+
end
|
|
19
21
|
end
|
|
20
|
-
end
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
def height
|
|
24
|
+
if landscape?
|
|
25
|
+
dimensions_specified_by_width? ? dimensions.width * aspect_ratio : dimensions.height
|
|
26
|
+
else
|
|
27
|
+
dimensions_specified_by_height? ? dimensions.height : dimensions.width * aspect_ratio
|
|
28
|
+
end
|
|
27
29
|
end
|
|
28
|
-
end
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
def scale
|
|
32
|
+
width.to_f / orig_w.to_f
|
|
33
|
+
end
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
def dimensions
|
|
36
|
+
w, h = geometry.scan(/\A(\d*)x(\d*)/).flatten.map(&:to_f)
|
|
37
|
+
OpenStruct.new(width: w, height: h)
|
|
38
|
+
end
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
def aspect_ratio
|
|
41
|
+
orig_h.to_f / orig_w
|
|
42
|
+
end
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
def dimensions_specified_by_width?
|
|
45
|
+
dimensions.width > 0
|
|
46
|
+
end
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
def dimensions_specified_by_height?
|
|
49
|
+
dimensions.height > 0
|
|
50
|
+
end
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
def landscape?
|
|
53
|
+
aspect_ratio <= 1.0
|
|
54
|
+
end
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
def portrait?
|
|
57
|
+
!landscape?
|
|
58
|
+
end
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
def do_not_resize_if_image_smaller_than_requested?
|
|
61
|
+
return false unless geometry.include? ">"
|
|
62
|
+
orig_w < width && orig_h < height
|
|
63
|
+
end
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
def do_not_resize_if_image_larger_than_requested?
|
|
66
|
+
return false unless geometry.include? "<"
|
|
67
|
+
orig_w > width && orig_h > height
|
|
68
|
+
end
|
|
68
69
|
end
|
|
69
70
|
end
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dragonfly_libvips/analysers/image_properties"
|
|
4
|
+
require "dragonfly_libvips/processors/encode"
|
|
5
|
+
require "dragonfly_libvips/processors/extract_area"
|
|
6
|
+
require "dragonfly_libvips/processors/rotate"
|
|
7
|
+
require "dragonfly_libvips/processors/thumb"
|
|
6
8
|
|
|
7
9
|
module DragonflyLibvips
|
|
8
10
|
class Plugin
|
|
@@ -24,11 +26,9 @@ module DragonflyLibvips
|
|
|
24
26
|
app.add_analyser(:landscape) { |c| !c.analyse(:portrait) }
|
|
25
27
|
|
|
26
28
|
app.add_analyser(:image) do |c|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
false
|
|
31
|
-
end
|
|
29
|
+
c.analyse(:image_properties).key?("format")
|
|
30
|
+
rescue ::Vips::Error
|
|
31
|
+
false
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# Aliases
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "vips"
|
|
4
4
|
|
|
5
5
|
module DragonflyLibvips
|
|
6
6
|
module Processors
|
|
@@ -10,40 +10,49 @@ module DragonflyLibvips
|
|
|
10
10
|
raise UnsupportedFormat unless SUPPORTED_FORMATS.include?(content.ext.downcase)
|
|
11
11
|
|
|
12
12
|
format = format.to_s
|
|
13
|
-
format =
|
|
14
|
-
format =
|
|
13
|
+
format = "tif" if format == "tiff"
|
|
14
|
+
format = "jpg" if format == "jpeg"
|
|
15
15
|
|
|
16
16
|
raise UnsupportedOutputFormat unless SUPPORTED_OUTPUT_FORMATS.include?(format.downcase)
|
|
17
17
|
|
|
18
18
|
if content.mime_type == Rack::Mime.mime_type(".#{format}")
|
|
19
19
|
content.ext ||= format
|
|
20
|
-
content.meta[
|
|
20
|
+
content.meta["format"] = format
|
|
21
21
|
return
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
options = DragonflyLibvips.stringify_keys(options)
|
|
25
25
|
|
|
26
|
-
input_options = options.fetch(
|
|
27
|
-
input_options[
|
|
28
|
-
if content.mime_type ==
|
|
29
|
-
input_options[
|
|
26
|
+
input_options = options.fetch("input_options", {})
|
|
27
|
+
input_options["access"] ||= "sequential"
|
|
28
|
+
if content.mime_type == "image/jpeg"
|
|
29
|
+
input_options["autorotate"] = true unless input_options.key?("autorotate")
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
output_options = options.fetch(
|
|
32
|
+
output_options = options.fetch("output_options", {})
|
|
33
33
|
if FORMATS_WITHOUT_PROFILE_SUPPORT.include?(format)
|
|
34
|
-
output_options.delete(
|
|
35
|
-
|
|
36
|
-
output_options[
|
|
34
|
+
output_options.delete("profile")
|
|
35
|
+
elsif DragonflyLibvips.auto_profile
|
|
36
|
+
output_options["profile"] ||= input_options.fetch("profile", EPROFILE_PATH)
|
|
37
37
|
end
|
|
38
|
-
output_options.delete(
|
|
39
|
-
output_options[
|
|
38
|
+
output_options.delete("Q") unless /jpg|jpeg/i.match?(format.to_s)
|
|
39
|
+
output_options["format"] ||= format.to_s if /bmp/i.match?(format.to_s)
|
|
40
40
|
|
|
41
|
-
img = ::Vips::Image.new_from_file(content.path, DragonflyLibvips.symbolize_keys(input_options))
|
|
41
|
+
img = ::Vips::Image.new_from_file(content.path, **DragonflyLibvips.symbolize_keys(input_options))
|
|
42
|
+
|
|
43
|
+
if output_options.include?("profile")
|
|
44
|
+
img = img.icc_transform(
|
|
45
|
+
output_options["profile"],
|
|
46
|
+
embedded: true,
|
|
47
|
+
intent: :relative,
|
|
48
|
+
black_point_compensation: true
|
|
49
|
+
)
|
|
50
|
+
end
|
|
42
51
|
|
|
43
52
|
content.update(
|
|
44
|
-
img.write_to_buffer(".#{format}", DragonflyLibvips.symbolize_keys(output_options)),
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
img.write_to_buffer(".#{format}", **DragonflyLibvips.symbolize_keys(output_options)),
|
|
54
|
+
"name" => "temp.#{format}",
|
|
55
|
+
"format" => format
|
|
47
56
|
)
|
|
48
57
|
content.ext = format
|
|
49
58
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "vips"
|
|
2
4
|
|
|
3
5
|
module DragonflyLibvips
|
|
4
6
|
module Processors
|
|
@@ -8,38 +10,47 @@ module DragonflyLibvips
|
|
|
8
10
|
raise UnsupportedFormat unless SUPPORTED_FORMATS.include?(content.ext.downcase)
|
|
9
11
|
|
|
10
12
|
options = DragonflyLibvips.stringify_keys(options)
|
|
11
|
-
format = options.fetch(
|
|
13
|
+
format = options.fetch("format", content.ext)
|
|
12
14
|
|
|
13
|
-
input_options = options.fetch(
|
|
15
|
+
input_options = options.fetch("input_options", {})
|
|
14
16
|
|
|
15
17
|
# input_options['access'] ||= 'sequential'
|
|
16
|
-
if content.mime_type ==
|
|
17
|
-
input_options[
|
|
18
|
+
if content.mime_type == "image/jpeg"
|
|
19
|
+
input_options["autorotate"] = true unless input_options.has_key?("autorotate")
|
|
18
20
|
end
|
|
19
21
|
|
|
20
|
-
output_options = options.fetch(
|
|
22
|
+
output_options = options.fetch("output_options", {})
|
|
21
23
|
if FORMATS_WITHOUT_PROFILE_SUPPORT.include?(format)
|
|
22
|
-
output_options.delete(
|
|
23
|
-
|
|
24
|
-
output_options[
|
|
24
|
+
output_options.delete("profile")
|
|
25
|
+
elsif DragonflyLibvips.auto_profile
|
|
26
|
+
output_options["profile"] ||= input_options.fetch("profile", EPROFILE_PATH)
|
|
25
27
|
end
|
|
26
|
-
output_options.delete(
|
|
27
|
-
output_options[
|
|
28
|
+
output_options.delete("Q") unless /jpg|jpeg/i.match?(format.to_s)
|
|
29
|
+
output_options["format"] ||= format.to_s if /gif|bmp/i.match?(format.to_s)
|
|
28
30
|
|
|
29
|
-
img = ::Vips::Image.new_from_file(content.path, DragonflyLibvips.symbolize_keys(input_options))
|
|
31
|
+
img = ::Vips::Image.new_from_file(content.path, **DragonflyLibvips.symbolize_keys(input_options))
|
|
30
32
|
img = img.extract_area(x, y, width, height)
|
|
31
33
|
|
|
34
|
+
if output_options.include?("profile")
|
|
35
|
+
img = img.icc_transform(
|
|
36
|
+
output_options["profile"],
|
|
37
|
+
embedded: true,
|
|
38
|
+
intent: :relative,
|
|
39
|
+
black_point_compensation: true
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
|
|
32
43
|
content.update(
|
|
33
|
-
img.write_to_buffer(".#{format}", DragonflyLibvips.symbolize_keys(output_options)),
|
|
34
|
-
|
|
35
|
-
|
|
44
|
+
img.write_to_buffer(".#{format}", **DragonflyLibvips.symbolize_keys(output_options)),
|
|
45
|
+
"name" => "temp.#{format}",
|
|
46
|
+
"format" => format
|
|
36
47
|
)
|
|
37
48
|
content.ext = format
|
|
38
49
|
end
|
|
39
50
|
|
|
40
51
|
def update_url(url_attributes, _, _, _, _, options = {})
|
|
41
|
-
options = options.
|
|
42
|
-
return unless format = options.fetch(
|
|
52
|
+
options = options.transform_keys { |k| k.to_s } # stringify keys
|
|
53
|
+
return unless format = options.fetch("format", nil)
|
|
43
54
|
url_attributes.ext = format
|
|
44
55
|
end
|
|
45
56
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "vips"
|
|
2
4
|
|
|
3
5
|
module DragonflyLibvips
|
|
4
6
|
module Processors
|
|
@@ -8,38 +10,47 @@ module DragonflyLibvips
|
|
|
8
10
|
raise UnsupportedFormat unless SUPPORTED_FORMATS.include?(content.ext.downcase)
|
|
9
11
|
|
|
10
12
|
options = DragonflyLibvips.stringify_keys(options)
|
|
11
|
-
format = options.fetch(
|
|
13
|
+
format = options.fetch("format", content.ext)
|
|
12
14
|
|
|
13
|
-
input_options = options.fetch(
|
|
15
|
+
input_options = options.fetch("input_options", {})
|
|
14
16
|
|
|
15
17
|
# input_options['access'] ||= 'sequential'
|
|
16
|
-
if content.mime_type ==
|
|
17
|
-
input_options[
|
|
18
|
+
if content.mime_type == "image/jpeg"
|
|
19
|
+
input_options["autorotate"] = true unless input_options.has_key?("autorotate")
|
|
18
20
|
end
|
|
19
21
|
|
|
20
|
-
output_options = options.fetch(
|
|
22
|
+
output_options = options.fetch("output_options", {})
|
|
21
23
|
if FORMATS_WITHOUT_PROFILE_SUPPORT.include?(format)
|
|
22
|
-
output_options.delete(
|
|
23
|
-
|
|
24
|
-
output_options[
|
|
24
|
+
output_options.delete("profile")
|
|
25
|
+
elsif DragonflyLibvips.auto_profile
|
|
26
|
+
output_options["profile"] ||= input_options.fetch("profile", EPROFILE_PATH)
|
|
25
27
|
end
|
|
26
|
-
output_options.delete(
|
|
27
|
-
output_options[
|
|
28
|
+
output_options.delete("Q") unless /jpg|jpeg/i.match?(format.to_s)
|
|
29
|
+
output_options["format"] ||= format.to_s if /gif|bmp/i.match?(format.to_s)
|
|
28
30
|
|
|
29
|
-
img = ::Vips::Image.new_from_file(content.path, DragonflyLibvips.symbolize_keys(input_options))
|
|
31
|
+
img = ::Vips::Image.new_from_file(content.path, **DragonflyLibvips.symbolize_keys(input_options))
|
|
30
32
|
img = img.rot("d#{rotate}")
|
|
31
33
|
|
|
34
|
+
if output_options.include?("profile")
|
|
35
|
+
img = img.icc_transform(
|
|
36
|
+
output_options["profile"],
|
|
37
|
+
embedded: true,
|
|
38
|
+
intent: :relative,
|
|
39
|
+
black_point_compensation: true
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
|
|
32
43
|
content.update(
|
|
33
|
-
img.write_to_buffer(".#{format}", DragonflyLibvips.symbolize_keys(output_options)),
|
|
34
|
-
|
|
35
|
-
|
|
44
|
+
img.write_to_buffer(".#{format}", **DragonflyLibvips.symbolize_keys(output_options)),
|
|
45
|
+
"name" => "temp.#{format}",
|
|
46
|
+
"format" => format
|
|
36
47
|
)
|
|
37
48
|
content.ext = format
|
|
38
49
|
end
|
|
39
50
|
|
|
40
51
|
def update_url(url_attributes, _, options = {})
|
|
41
|
-
options = options.
|
|
42
|
-
return unless format = options.fetch(
|
|
52
|
+
options = options.transform_keys { |k| k.to_s } # stringify keys
|
|
53
|
+
return unless format = options.fetch("format", nil)
|
|
43
54
|
url_attributes.ext = format
|
|
44
55
|
end
|
|
45
56
|
end
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dragonfly_libvips/dimensions"
|
|
4
|
+
require "vips"
|
|
3
5
|
|
|
4
6
|
module DragonflyLibvips
|
|
5
7
|
module Processors
|
|
6
8
|
class Thumb
|
|
7
|
-
OPERATORS =
|
|
9
|
+
OPERATORS = "><"
|
|
8
10
|
RESIZE_GEOMETRY = /\A\d*x\d*[#{OPERATORS}]?\z/ # e.g. '300x200>'
|
|
9
11
|
DPI = 300
|
|
10
12
|
|
|
@@ -15,67 +17,76 @@ module DragonflyLibvips
|
|
|
15
17
|
options = DragonflyLibvips.stringify_keys(options)
|
|
16
18
|
|
|
17
19
|
filename = content.path
|
|
18
|
-
format = options.fetch(
|
|
20
|
+
format = options.fetch("format", content.ext).to_s
|
|
19
21
|
|
|
20
|
-
input_options = options.fetch(
|
|
21
|
-
input_options[
|
|
22
|
-
input_options[
|
|
22
|
+
input_options = options.fetch("input_options", {})
|
|
23
|
+
input_options["access"] = input_options.fetch("access", "sequential")
|
|
24
|
+
input_options["autorotate"] = input_options.fetch("autorotate", true) if content.mime_type == "image/jpeg"
|
|
23
25
|
|
|
24
|
-
if content.mime_type ==
|
|
25
|
-
input_options[
|
|
26
|
-
input_options[
|
|
27
|
-
|
|
28
|
-
input_options.delete(
|
|
29
|
-
input_options.delete(
|
|
26
|
+
if content.mime_type == "application/pdf"
|
|
27
|
+
input_options["dpi"] = input_options.fetch("dpi", DPI)
|
|
28
|
+
input_options["page"] = input_options.fetch("page", 0)
|
|
29
|
+
elsif DragonflyLibvips.auto_profile
|
|
30
|
+
input_options.delete("page")
|
|
31
|
+
input_options.delete("dpi")
|
|
30
32
|
end
|
|
31
33
|
|
|
32
|
-
output_options = options.fetch(
|
|
34
|
+
output_options = options.fetch("output_options", {})
|
|
33
35
|
if FORMATS_WITHOUT_PROFILE_SUPPORT.include?(format)
|
|
34
|
-
output_options.delete(
|
|
36
|
+
output_options.delete("profile")
|
|
35
37
|
else
|
|
36
|
-
output_options[
|
|
38
|
+
output_options["profile"] ||= input_options.fetch("profile", EPROFILE_PATH)
|
|
37
39
|
end
|
|
38
|
-
output_options.delete(
|
|
39
|
-
output_options[
|
|
40
|
+
output_options.delete("Q") unless /jpg|jpeg/i.match?(format.to_s)
|
|
41
|
+
output_options["format"] ||= format.to_s if /bmp/i.match?(format.to_s)
|
|
40
42
|
|
|
41
|
-
input_options = input_options.
|
|
42
|
-
img = ::Vips::Image.new_from_file(filename, DragonflyLibvips.symbolize_keys(input_options))
|
|
43
|
+
input_options = input_options.transform_keys { |k| k.to_sym } # symbolize
|
|
44
|
+
img = ::Vips::Image.new_from_file(filename, **DragonflyLibvips.symbolize_keys(input_options))
|
|
43
45
|
|
|
44
46
|
dimensions = case geometry
|
|
45
47
|
when RESIZE_GEOMETRY then Dimensions.call(geometry, img.width, img.height)
|
|
46
48
|
else raise ArgumentError, "Didn't recognise the geometry string: #{geometry}"
|
|
47
49
|
end
|
|
48
50
|
|
|
49
|
-
thumbnail_options = options.fetch(
|
|
51
|
+
thumbnail_options = options.fetch("thumbnail_options", {})
|
|
50
52
|
if Vips.at_least_libvips?(8, 8)
|
|
51
|
-
thumbnail_options[
|
|
53
|
+
thumbnail_options["no_rotate"] = input_options.fetch("no_rotate", false) if content.mime_type == "image/jpeg"
|
|
52
54
|
else
|
|
53
|
-
thumbnail_options[
|
|
55
|
+
thumbnail_options["auto_rotate"] = input_options.fetch("autorotate", true) if content.mime_type == "image/jpeg"
|
|
54
56
|
end
|
|
55
|
-
thumbnail_options[
|
|
56
|
-
thumbnail_options[
|
|
57
|
-
thumbnail_options[
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
thumbnail_options["height"] = thumbnail_options.fetch("height", dimensions.height.ceil)
|
|
58
|
+
thumbnail_options["import_profile"] = CMYK_PROFILE_PATH if img.get("interpretation") == :cmyk
|
|
59
|
+
thumbnail_options["size"] ||= case geometry
|
|
60
|
+
when />\z/ then :down # do_not_resize_if_image_smaller_than_requested
|
|
61
|
+
when /<\z/ then :up # do_not_resize_if_image_larger_than_requested
|
|
62
|
+
else :both
|
|
61
63
|
end
|
|
62
64
|
|
|
63
|
-
filename += "[page=#{input_options[:page]}]" if content.mime_type ==
|
|
65
|
+
filename += "[page=#{input_options[:page]}]" if content.mime_type == "application/pdf"
|
|
64
66
|
|
|
65
|
-
thumbnail_options = thumbnail_options.
|
|
66
|
-
thumb = ::Vips::Image.thumbnail(filename, dimensions.width.ceil, DragonflyLibvips.symbolize_keys(thumbnail_options))
|
|
67
|
+
thumbnail_options = thumbnail_options.transform_keys { |k| k.to_sym } # symbolize
|
|
68
|
+
thumb = ::Vips::Image.thumbnail(filename, dimensions.width.ceil, **DragonflyLibvips.symbolize_keys(thumbnail_options))
|
|
69
|
+
|
|
70
|
+
if output_options.include?("profile")
|
|
71
|
+
thumb = thumb.icc_transform(
|
|
72
|
+
output_options["profile"],
|
|
73
|
+
embedded: true,
|
|
74
|
+
intent: :relative,
|
|
75
|
+
black_point_compensation: true
|
|
76
|
+
)
|
|
77
|
+
end
|
|
67
78
|
|
|
68
79
|
content.update(
|
|
69
|
-
thumb.write_to_buffer(".#{format}", DragonflyLibvips.symbolize_keys(output_options)),
|
|
70
|
-
|
|
71
|
-
|
|
80
|
+
thumb.write_to_buffer(".#{format}", **DragonflyLibvips.symbolize_keys(output_options)),
|
|
81
|
+
"name" => "temp.#{format}",
|
|
82
|
+
"format" => format
|
|
72
83
|
)
|
|
73
84
|
content.ext = format
|
|
74
85
|
end
|
|
75
86
|
|
|
76
87
|
def update_url(url_attributes, _, options = {})
|
|
77
|
-
options = options.
|
|
78
|
-
return unless format = options.fetch(
|
|
88
|
+
options = options.transform_keys { |k| k.to_s } # stringify keys
|
|
89
|
+
return unless format = options.fetch("format", nil)
|
|
79
90
|
url_attributes.ext = format
|
|
80
91
|
end
|
|
81
92
|
end
|
data/lib/dragonfly_libvips.rb
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dragonfly"
|
|
4
|
+
require "dragonfly_libvips/dimensions"
|
|
5
|
+
require "dragonfly_libvips/plugin"
|
|
6
|
+
require "dragonfly_libvips/version"
|
|
7
|
+
require "vips"
|
|
6
8
|
|
|
7
9
|
module DragonflyLibvips
|
|
8
10
|
class UnsupportedFormat < RuntimeError; end
|
|
9
11
|
class UnsupportedOutputFormat < RuntimeError; end
|
|
10
12
|
|
|
11
|
-
CMYK_PROFILE_PATH = File.expand_path(
|
|
12
|
-
EPROFILE_PATH = File.expand_path(
|
|
13
|
+
CMYK_PROFILE_PATH = File.expand_path("../vendor/cmyk.icm", __dir__)
|
|
14
|
+
EPROFILE_PATH = File.expand_path("../vendor/sRGB_v4_ICC_preference.icc", __dir__)
|
|
13
15
|
|
|
14
16
|
SUPPORTED_FORMATS = begin
|
|
15
17
|
output = `vips -l | grep -i ForeignLoad`
|
|
@@ -29,19 +31,42 @@ module DragonflyLibvips
|
|
|
29
31
|
pfm
|
|
30
32
|
pgm
|
|
31
33
|
ppm
|
|
34
|
+
raw
|
|
32
35
|
v
|
|
33
36
|
vips
|
|
34
37
|
]
|
|
35
38
|
|
|
36
|
-
FORMATS_WITHOUT_PROFILE_SUPPORT = %w[
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
FORMATS_WITHOUT_PROFILE_SUPPORT = %w[
|
|
40
|
+
avif
|
|
41
|
+
bmp
|
|
42
|
+
dz
|
|
43
|
+
gif
|
|
44
|
+
hdr
|
|
45
|
+
heic
|
|
46
|
+
heif
|
|
47
|
+
j2c
|
|
48
|
+
j2k
|
|
49
|
+
jp2
|
|
50
|
+
jpc
|
|
51
|
+
jpt
|
|
52
|
+
jxl
|
|
53
|
+
szi
|
|
54
|
+
webp
|
|
55
|
+
]
|
|
39
56
|
|
|
40
|
-
|
|
41
|
-
|
|
57
|
+
class << self
|
|
58
|
+
# Controls whether output images automatically get an ICC profile attached
|
|
59
|
+
attr_accessor :auto_profile
|
|
42
60
|
end
|
|
43
61
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
62
|
+
self.auto_profile ||= true
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
def self.stringify_keys(hash = {})
|
|
66
|
+
hash.transform_keys { |k| k.to_s }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def self.symbolize_keys(hash = {})
|
|
70
|
+
hash.transform_keys { |k| k.to_sym }
|
|
71
|
+
end
|
|
47
72
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dragonfly_libvips
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tomas Celizna
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: dragonfly
|
|
@@ -44,6 +43,20 @@ dependencies:
|
|
|
44
43
|
- - ">="
|
|
45
44
|
- !ruby/object:Gem::Version
|
|
46
45
|
version: 2.0.16
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: base64
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0'
|
|
53
|
+
type: :runtime
|
|
54
|
+
prerelease: false
|
|
55
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '0'
|
|
47
60
|
- !ruby/object:Gem::Dependency
|
|
48
61
|
name: bundler
|
|
49
62
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -132,24 +145,53 @@ dependencies:
|
|
|
132
145
|
name: rake
|
|
133
146
|
requirement: !ruby/object:Gem::Requirement
|
|
134
147
|
requirements:
|
|
135
|
-
- - "
|
|
148
|
+
- - ">="
|
|
136
149
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: '
|
|
150
|
+
version: '0'
|
|
138
151
|
type: :development
|
|
139
152
|
prerelease: false
|
|
140
153
|
version_requirements: !ruby/object:Gem::Requirement
|
|
141
154
|
requirements:
|
|
142
|
-
- - "
|
|
155
|
+
- - ">="
|
|
143
156
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: '
|
|
145
|
-
|
|
157
|
+
version: '0'
|
|
158
|
+
- !ruby/object:Gem::Dependency
|
|
159
|
+
name: lefthook
|
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
|
161
|
+
requirements:
|
|
162
|
+
- - ">="
|
|
163
|
+
- !ruby/object:Gem::Version
|
|
164
|
+
version: '0'
|
|
165
|
+
type: :development
|
|
166
|
+
prerelease: false
|
|
167
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
168
|
+
requirements:
|
|
169
|
+
- - ">="
|
|
170
|
+
- !ruby/object:Gem::Version
|
|
171
|
+
version: '0'
|
|
172
|
+
- !ruby/object:Gem::Dependency
|
|
173
|
+
name: rubocop-rails_config
|
|
174
|
+
requirement: !ruby/object:Gem::Requirement
|
|
175
|
+
requirements:
|
|
176
|
+
- - ">="
|
|
177
|
+
- !ruby/object:Gem::Version
|
|
178
|
+
version: '0'
|
|
179
|
+
type: :development
|
|
180
|
+
prerelease: false
|
|
181
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
182
|
+
requirements:
|
|
183
|
+
- - ">="
|
|
184
|
+
- !ruby/object:Gem::Version
|
|
185
|
+
version: '0'
|
|
146
186
|
email:
|
|
147
187
|
- tomas.celizna@gmail.com
|
|
148
188
|
executables: []
|
|
149
189
|
extensions: []
|
|
150
190
|
extra_rdoc_files: []
|
|
151
191
|
files:
|
|
192
|
+
- ".github/workflows/test.yml"
|
|
152
193
|
- ".gitignore"
|
|
194
|
+
- ".rubocop.yml"
|
|
153
195
|
- ".ruby-version"
|
|
154
196
|
- ".tool-versions"
|
|
155
197
|
- ".travis.yml"
|
|
@@ -162,6 +204,7 @@ files:
|
|
|
162
204
|
- bin/console
|
|
163
205
|
- bin/setup
|
|
164
206
|
- dragonfly_libvips.gemspec
|
|
207
|
+
- lefthook.yml
|
|
165
208
|
- lib/dragonfly_libvips.rb
|
|
166
209
|
- lib/dragonfly_libvips/analysers/image_properties.rb
|
|
167
210
|
- lib/dragonfly_libvips/dimensions.rb
|
|
@@ -187,7 +230,6 @@ homepage: https://github.com/tomasc/dragonfly_libvips
|
|
|
187
230
|
licenses:
|
|
188
231
|
- MIT
|
|
189
232
|
metadata: {}
|
|
190
|
-
post_install_message:
|
|
191
233
|
rdoc_options: []
|
|
192
234
|
require_paths:
|
|
193
235
|
- lib
|
|
@@ -202,8 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
202
244
|
- !ruby/object:Gem::Version
|
|
203
245
|
version: '0'
|
|
204
246
|
requirements: []
|
|
205
|
-
rubygems_version: 3.
|
|
206
|
-
signing_key:
|
|
247
|
+
rubygems_version: 3.6.9
|
|
207
248
|
specification_version: 4
|
|
208
249
|
summary: Dragonfly analysers and processors for libvips image processing library.
|
|
209
250
|
test_files: []
|