ndav-magick-image 0.0.1 → 0.0.3
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 +10 -10
- data/lib/ndav/magick/image.rb +42 -21
- data/ndav-magick-image.gemspec +1 -1
- data/test/helper.rb +16 -0
- data/test/test_converter.rb +3 -6
- data/test/test_from_ndav.rb +20 -28
- data/test/test_memory_viewable.rb +24 -32
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 96acb84dd6f8a244f0951db50db36caf76cdf29d87804a45cac2fb356b699e28
|
|
4
|
+
data.tar.gz: 5a5c8fce397292d41afa18d60cbdbd6e8948c40a014143ce3a003b88aea66444
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d2dcc5754ad77b221630fde7deb4a6f8b36067bc938e3b0d3a2f3d5623c675d44cfba2c41527cade9e7eb4e5a2acda4dbf7cf53dbfb8c5ee9a62aec5df4825a9
|
|
7
|
+
data.tar.gz: 2b76f5e90698374a5788c212837a6cb466977479e18514606b10061be1da6e43047e712530824a6ca67f51e1e9060ba3a7e170f3e78a404d4a0238ea503cd451
|
data/README.md
CHANGED
|
@@ -60,9 +60,9 @@ The shape is `[height, width, channels]`. Channels vary based on the image attri
|
|
|
60
60
|
|
|
61
61
|
### format and item size ###
|
|
62
62
|
|
|
63
|
-
Currently, this bridge
|
|
63
|
+
Currently, this bridge exports `Magick::Image`'s MemoryView and imports from `NDAV` using `Magick::QuantumPixel`. Therefore, the MemoryView's format and item_size depend on the build options of ImageMagick. You can check the format with `NDAV::Magick::Image::MemoryViewable::FORMAT`.
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
It's under consideration whether other formats should be supported or not.
|
|
66
66
|
|
|
67
67
|
EXAMPLE
|
|
68
68
|
-------
|
|
@@ -82,25 +82,25 @@ image = image_list[0]
|
|
|
82
82
|
numo = NumoNArray(image)
|
|
83
83
|
abort "Use RGB image" unless numo.shape[2] == 3
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
noised
|
|
88
|
-
noised.inplace.clip(
|
|
85
|
+
# Assumes numo is Numo::SFloat here. It depends on your environment.
|
|
86
|
+
noise = Numo::SFloat.new(numo.shape).rand(0, -Magick::QuantumRange / 2)
|
|
87
|
+
noised = numo + noise
|
|
88
|
+
noised.inplace.clip(0, Magick::QuantumRange)
|
|
89
89
|
|
|
90
|
-
noised_image = MagickImage(
|
|
90
|
+
noised_image = MagickImage(noised)
|
|
91
91
|
noised_image.write "noised.png"
|
|
92
|
+
|
|
92
93
|
```
|
|
93
94
|
|
|
94
95
|
| Before | After |
|
|
95
96
|
|--------|-------|
|
|
96
|
-
| [](https://gyazo.com/905f541f15c0d57db5fc7ea3f6edaf07) | [](https://gyazo.com/905f541f15c0d57db5fc7ea3f6edaf07) | [](https://gyazo.com/c8c7191713d97fffaa2509e6b0874aab) |
|
|
97
98
|
|
|
98
99
|
TODO
|
|
99
100
|
----
|
|
100
101
|
|
|
101
|
-
* Support HDRI
|
|
102
102
|
* Support zero-copy
|
|
103
|
-
* Support
|
|
103
|
+
* Support export in non-ImageMagick-native format
|
|
104
104
|
|
|
105
105
|
LICENSE
|
|
106
106
|
-------
|
data/lib/ndav/magick/image.rb
CHANGED
|
@@ -4,6 +4,25 @@ require "rmagick"
|
|
|
4
4
|
class NDAV
|
|
5
5
|
module Magick
|
|
6
6
|
module Image
|
|
7
|
+
IS_HDRI_SUPPORTED = ::Magick::Magick_features.match?(/\bHDRI\b/)
|
|
8
|
+
is_little_endian = IO::Buffer::HOST_ENDIAN == IO::Buffer::LITTLE_ENDIAN
|
|
9
|
+
SUPPORTED_FORMATS =
|
|
10
|
+
case [::Magick::MAGICKCORE_QUANTUM_DEPTH, IS_HDRI_SUPPORTED]
|
|
11
|
+
in [ 8, false] then ["C"]
|
|
12
|
+
in [16, false] then ["S", is_little_endian ? "v" : "n"]
|
|
13
|
+
in [32, false] then ["L", is_little_endian ? "V" : "N"]
|
|
14
|
+
in [ 8, true ] | [16, true] | [32, true] then ["f", is_little_endian ? "e" : "g"]
|
|
15
|
+
in [64, true ] then ["d", is_little_endian ? "E" : "G"]
|
|
16
|
+
end
|
|
17
|
+
COLORSPACE_TO_MAP = {
|
|
18
|
+
::Magick::GRAYColorspace => "I",
|
|
19
|
+
::Magick::LinearGRAYColorspace => "I",
|
|
20
|
+
::Magick::RGBColorspace => "RGB",
|
|
21
|
+
::Magick::ScRGBColorspace => "RGB",
|
|
22
|
+
::Magick::SRGBColorspace => "RGB",
|
|
23
|
+
::Magick::CMYColorspace => "CMY",
|
|
24
|
+
::Magick::CMYKColorspace => "CMYK"
|
|
25
|
+
}
|
|
7
26
|
CHANNELS_TO_MAP = {
|
|
8
27
|
nil => "I",
|
|
9
28
|
1 => "I",
|
|
@@ -14,48 +33,50 @@ class NDAV
|
|
|
14
33
|
|
|
15
34
|
module FromNDAV
|
|
16
35
|
# TODO: Support more formats
|
|
36
|
+
# TODO: Support CMYK
|
|
17
37
|
def from_ndav(ndav)
|
|
18
|
-
raise
|
|
19
|
-
raise "Currently, supports only row-major contiguous NDAV" unless ndav.row_major_contiguous?
|
|
20
|
-
|
|
38
|
+
Kernel.raise "ndim must be 2 or 3 but is #{ndav.ndim}" unless [2, 3].include? ndav.ndim
|
|
39
|
+
Kernel.raise "Currently, supports only row-major contiguous NDAV" unless ndav.row_major_contiguous?
|
|
40
|
+
|
|
41
|
+
item_desc = NDAV::ITEM_DESCS[ndav.format]
|
|
42
|
+
Kernel.raise "Unsupported format: #{ndav.format}. Must be single character" unless item_desc.length == 1
|
|
43
|
+
component = item_desc[0]
|
|
44
|
+
Kernel.raise "Unsupported format: #{ndav.format}. Must not be repeated" unless component.repeat == 1
|
|
45
|
+
Kernel.raise "Unsupported format: #{ndav.format}. Supported chars: #{SUPPORTED_FORMATS.join(', ')}" unless SUPPORTED_FORMATS.include? component.format
|
|
21
46
|
|
|
22
47
|
height, width, channels = ndav.shape
|
|
23
48
|
map = CHANNELS_TO_MAP[channels]
|
|
24
|
-
raise "Unsupported channels: #{channels}" unless map
|
|
49
|
+
Kernel.raise "Unsupported channels: #{channels}" unless map
|
|
25
50
|
|
|
26
51
|
image = ::Magick::Image.new(width, height)
|
|
27
|
-
image.import_pixels 0, 0, width, height, map, ndav.to_s
|
|
52
|
+
image.import_pixels 0, 0, width, height, map, ndav.to_s, ::Magick::QuantumPixel
|
|
28
53
|
image
|
|
29
54
|
end
|
|
30
55
|
end
|
|
31
|
-
|
|
56
|
+
|
|
32
57
|
module MemoryViewable
|
|
58
|
+
FORMAT = SUPPORTED_FORMATS.first
|
|
59
|
+
ITEM_SIZE = NDAV::ITEM_SIZES[FORMAT]
|
|
60
|
+
|
|
33
61
|
private
|
|
34
62
|
|
|
35
|
-
# TODO: Support HDRI
|
|
36
63
|
def ndav_descriptor(**)
|
|
37
|
-
map =
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
when [true, false] then "I"
|
|
41
|
-
when [false, true] then "RGBA"
|
|
42
|
-
else "RGB"
|
|
43
|
-
end
|
|
64
|
+
map = COLORSPACE_TO_MAP[colorspace]
|
|
65
|
+
Kernel.raise "Unsupported color space: #{colorspace}" unless map
|
|
66
|
+
map += "A" if alpha?
|
|
44
67
|
shape = [rows, columns, map.length]
|
|
45
|
-
format = "C"
|
|
46
|
-
item_size = ::NDAV::ITEM_SIZES[format]
|
|
47
68
|
|
|
48
69
|
{
|
|
49
|
-
data: export_pixels_to_str(0, 0, columns, rows, map, ::Magick::
|
|
70
|
+
data: export_pixels_to_str(0, 0, columns, rows, map, ::Magick::QuantumPixel),
|
|
50
71
|
shape:,
|
|
51
|
-
strides:
|
|
52
|
-
format
|
|
53
|
-
byte_size: shape.reduce(
|
|
72
|
+
strides: NDAV.default_strides(shape:, item_size: ITEM_SIZE),
|
|
73
|
+
format: FORMAT,
|
|
74
|
+
byte_size: shape.reduce(ITEM_SIZE, :*),
|
|
54
75
|
readonly?: true
|
|
55
76
|
}
|
|
56
77
|
end
|
|
57
78
|
end
|
|
58
|
-
|
|
79
|
+
|
|
59
80
|
module Converter
|
|
60
81
|
def MagickImage(array, *, **)
|
|
61
82
|
if array.kind_of? ::Magick::Image
|
data/ndav-magick-image.gemspec
CHANGED
data/test/helper.rb
CHANGED
|
@@ -3,3 +3,19 @@ require "test/unit"
|
|
|
3
3
|
require "test/unit/notify"
|
|
4
4
|
require "fiddle"
|
|
5
5
|
require "tmpdir"
|
|
6
|
+
|
|
7
|
+
module Helper
|
|
8
|
+
FORMAT = NDAV::Magick::Image::MemoryViewable::FORMAT
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def make_image(width, height, former = [255, 255, 255], latter = [0, 255, 0])
|
|
13
|
+
ratio = (2 ** ::Magick::MAGICKCORE_QUANTUM_DEPTH - 1) / 255
|
|
14
|
+
[
|
|
15
|
+
[former * width] * (height / 2),
|
|
16
|
+
[latter * width] * (height / 2)
|
|
17
|
+
].flatten.collect {|item| item * ratio}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Test::Unit::TestCase.include Helper
|
data/test/test_converter.rb
CHANGED
|
@@ -18,12 +18,9 @@ class TestConverter < Test::Unit::TestCase
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def test_magick_image_from_ndav
|
|
21
|
-
array =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
]
|
|
25
|
-
ptr = Fiddle::Pointer[array.flatten.pack("C*")]
|
|
26
|
-
ndav = ::NDAV.new(ptr, shape: [@height, @width, 3])
|
|
21
|
+
array = make_image(@width, @height)
|
|
22
|
+
ptr = Fiddle::Pointer[array.flatten.pack("#{FORMAT}*")]
|
|
23
|
+
ndav = ::NDAV.new(ptr, format: FORMAT, shape: [@height, @width, 3])
|
|
27
24
|
|
|
28
25
|
assert_instance_of ::Magick::Image, ::NDAV::Converter::MagickImage(ndav)
|
|
29
26
|
end
|
data/test/test_from_ndav.rb
CHANGED
|
@@ -7,66 +7,58 @@ class TestFromNDAV < Test::Unit::TestCase
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def test_basic
|
|
10
|
-
array =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
]
|
|
14
|
-
ptr = Fiddle::Pointer[array.flatten.pack("C*")]
|
|
15
|
-
ndav = ::NDAV.new(ptr, shape: [@height, @width, 3])
|
|
10
|
+
array = make_image(@width, @height)
|
|
11
|
+
ptr = Fiddle::Pointer[array.flatten.pack("#{FORMAT}*")]
|
|
12
|
+
ndav = ::NDAV.new(ptr, format: FORMAT, shape: [@height, @width, 3])
|
|
16
13
|
image = ::Magick::Image.from_ndav(ndav)
|
|
17
14
|
|
|
18
15
|
assert_equal @width, image.columns
|
|
19
16
|
assert_equal @height, image.rows
|
|
20
17
|
assert_false image.gray?
|
|
21
18
|
assert_false image.alpha?
|
|
22
|
-
assert_equal array.flatten,
|
|
19
|
+
assert_equal array.flatten,
|
|
20
|
+
image.export_pixels_to_str(0, 0, @width, @height, "RGB", ::Magick::QuantumPixel).unpack("#{FORMAT}*")
|
|
23
21
|
end
|
|
24
22
|
|
|
25
23
|
def test_alpha
|
|
26
|
-
array = [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
]
|
|
30
|
-
ptr = Fiddle::Pointer[array.flatten.pack("C*")]
|
|
31
|
-
ndav = ::NDAV.new(ptr, shape: [@height, @width, 4])
|
|
24
|
+
array = make_image(@width, @height, [255, 255, 255, 128], [0, 255, 0, 128])
|
|
25
|
+
ptr = Fiddle::Pointer[array.flatten.pack("#{FORMAT}*")]
|
|
26
|
+
ndav = ::NDAV.new(ptr, format: FORMAT, shape: [@height, @width, 4])
|
|
32
27
|
image = ::Magick::Image.from_ndav(ndav)
|
|
33
28
|
|
|
34
29
|
assert_equal @width, image.columns
|
|
35
30
|
assert_equal @height, image.rows
|
|
36
31
|
assert_false image.gray?
|
|
37
32
|
assert_true image.alpha?
|
|
38
|
-
assert_equal array.flatten,
|
|
33
|
+
assert_equal array.flatten,
|
|
34
|
+
image.export_pixels_to_str(0, 0, @width, @height, "RGBA", ::Magick::QuantumPixel).unpack("#{FORMAT}*")
|
|
39
35
|
end
|
|
40
36
|
|
|
41
37
|
def test_grayscale
|
|
42
|
-
array = [
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
]
|
|
46
|
-
ptr = Fiddle::Pointer[array.flatten.pack("C*")]
|
|
47
|
-
ndav = ::NDAV.new(ptr, shape: [@height, @width, 1])
|
|
38
|
+
array = make_image(@width, @height, [255], [128])
|
|
39
|
+
ptr = Fiddle::Pointer[array.flatten.pack("#{FORMAT}*")]
|
|
40
|
+
ndav = ::NDAV.new(ptr, format: FORMAT, shape: [@height, @width, 1])
|
|
48
41
|
image = ::Magick::Image.from_ndav(ndav)
|
|
49
42
|
|
|
50
43
|
assert_equal @width, image.columns
|
|
51
44
|
assert_equal @height, image.rows
|
|
52
45
|
assert_true image.gray?
|
|
53
46
|
assert_false image.alpha?
|
|
54
|
-
assert_equal array.flatten,
|
|
47
|
+
assert_equal array.flatten,
|
|
48
|
+
image.export_pixels_to_str(0, 0, @width, @height, "R", ::Magick::QuantumPixel).unpack("#{FORMAT}*")
|
|
55
49
|
end
|
|
56
50
|
|
|
57
51
|
def test_gray_alpha
|
|
58
|
-
array = [
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
]
|
|
62
|
-
ptr = Fiddle::Pointer[array.flatten.pack("C*")]
|
|
63
|
-
ndav = ::NDAV.new(ptr, shape: [@height, @width, 2])
|
|
52
|
+
array = make_image(@width, @height, [255, 128], [128, 128])
|
|
53
|
+
ptr = Fiddle::Pointer[array.flatten.pack("#{FORMAT}*")]
|
|
54
|
+
ndav = ::NDAV.new(ptr, format: FORMAT, shape: [@height, @width, 2])
|
|
64
55
|
image = ::Magick::Image.from_ndav(ndav)
|
|
65
56
|
|
|
66
57
|
assert_equal @width, image.columns
|
|
67
58
|
assert_equal @height, image.rows
|
|
68
59
|
assert_true image.gray?
|
|
69
60
|
assert_true image.alpha?
|
|
70
|
-
assert_equal array.flatten,
|
|
61
|
+
assert_equal array.flatten,
|
|
62
|
+
image.export_pixels_to_str(0, 0, @width, @height, "RA", ::Magick::QuantumPixel).unpack("#{FORMAT}*")
|
|
71
63
|
end
|
|
72
64
|
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
require_relative "helper"
|
|
2
2
|
|
|
3
3
|
class TestMemoryViewable < Test::Unit::TestCase
|
|
4
|
+
ITEM_SIZE = NDAV::ITEM_SIZES[FORMAT]
|
|
5
|
+
|
|
4
6
|
def setup
|
|
5
7
|
@width = 3
|
|
6
8
|
@height = 2
|
|
@@ -18,14 +20,10 @@ class TestMemoryViewable < Test::Unit::TestCase
|
|
|
18
20
|
Fiddle::MemoryView.export @image do |view|
|
|
19
21
|
assert_equal 3, view.ndim
|
|
20
22
|
assert_equal [@height, @width, 3], view.shape
|
|
21
|
-
assert_equal
|
|
22
|
-
assert_equal
|
|
23
|
-
assert_equal @width * @height * 3, view.byte_size
|
|
24
|
-
assert_equal
|
|
25
|
-
[[255, 255, 255] * @width] * (@height / 2),
|
|
26
|
-
[[ 0, 255, 0] * @width] * (@height / 2)
|
|
27
|
-
].flatten,
|
|
28
|
-
view.to_s.unpack("C*")
|
|
23
|
+
assert_equal ITEM_SIZE, view.item_size
|
|
24
|
+
assert_equal FORMAT, view.format
|
|
25
|
+
assert_equal @width * @height * 3 * ITEM_SIZE, view.byte_size
|
|
26
|
+
assert_equal make_image(@width, @height), view.to_s.unpack("#{FORMAT}*")
|
|
29
27
|
end
|
|
30
28
|
end
|
|
31
29
|
|
|
@@ -35,44 +33,38 @@ class TestMemoryViewable < Test::Unit::TestCase
|
|
|
35
33
|
Fiddle::MemoryView.export @image do |view|
|
|
36
34
|
assert_equal 3, view.ndim
|
|
37
35
|
assert_equal [@height, @width, 4], view.shape
|
|
38
|
-
assert_equal
|
|
39
|
-
assert_equal
|
|
40
|
-
assert_equal @width * @height * 4, view.byte_size
|
|
36
|
+
assert_equal ITEM_SIZE, view.item_size
|
|
37
|
+
assert_equal FORMAT, view.format
|
|
38
|
+
assert_equal @width * @height * 4* ITEM_SIZE, view.byte_size
|
|
41
39
|
end
|
|
42
40
|
end
|
|
43
41
|
|
|
44
42
|
def test_grayscale
|
|
45
|
-
image =
|
|
43
|
+
@image.colorspace = Magick::GRAYColorspace
|
|
46
44
|
|
|
47
|
-
Fiddle::MemoryView.export image do |view|
|
|
45
|
+
Fiddle::MemoryView.export @image do |view|
|
|
48
46
|
assert_equal 3, view.ndim
|
|
49
47
|
assert_equal [@height, @width, 1], view.shape
|
|
50
|
-
assert_equal
|
|
51
|
-
assert_equal
|
|
52
|
-
assert_equal @width * @height * 1, view.byte_size
|
|
53
|
-
assert_equal
|
|
54
|
-
|
|
55
|
-
[[182] * @width] * (@height / 2)
|
|
56
|
-
].flatten,
|
|
57
|
-
view.to_s.unpack("C*")
|
|
48
|
+
assert_equal ITEM_SIZE, view.item_size
|
|
49
|
+
assert_equal FORMAT, view.format
|
|
50
|
+
assert_equal @width * @height * 1 * ITEM_SIZE, view.byte_size
|
|
51
|
+
assert_equal @image.export_pixels_to_str(0, 0, @width, @height, "I", Magick::QuantumPixel).unpack("#{FORMAT}*"),
|
|
52
|
+
view.to_s.unpack("#{FORMAT}*")
|
|
58
53
|
end
|
|
59
54
|
end
|
|
60
55
|
|
|
61
56
|
def test_gray_alpha
|
|
62
|
-
image =
|
|
63
|
-
image.alpha Magick::OnAlphaChannel
|
|
57
|
+
@image.colorspace = Magick::GRAYColorspace
|
|
58
|
+
@image.alpha Magick::OnAlphaChannel
|
|
64
59
|
|
|
65
|
-
Fiddle::MemoryView.export image do |view|
|
|
60
|
+
Fiddle::MemoryView.export @image do |view|
|
|
66
61
|
assert_equal 3, view.ndim
|
|
67
62
|
assert_equal [@height, @width, 2], view.shape
|
|
68
|
-
assert_equal
|
|
69
|
-
assert_equal
|
|
70
|
-
assert_equal @width * @height * 2, view.byte_size
|
|
71
|
-
assert_equal
|
|
72
|
-
|
|
73
|
-
[[182, 255] * @width] * (@height / 2)
|
|
74
|
-
].flatten,
|
|
75
|
-
view.to_s.unpack("C*")
|
|
63
|
+
assert_equal ITEM_SIZE, view.item_size
|
|
64
|
+
assert_equal FORMAT, view.format
|
|
65
|
+
assert_equal @width * @height * 2 * ITEM_SIZE, view.byte_size
|
|
66
|
+
assert_equal @image.export_pixels_to_str(0, 0, @width, @height, "IA", Magick::QuantumPixel).unpack("#{FORMAT}*"),
|
|
67
|
+
view.to_s.unpack("#{FORMAT}*")
|
|
76
68
|
end
|
|
77
69
|
end
|
|
78
70
|
|