ndav-magick-image 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf489f7ae5981b5e552d896e8ce0f0696784d914572af0678790464f409f9b16
4
- data.tar.gz: '09e621d161ed19c832229e535a9f9ff3a6864b1f05756ab91c0c2e5a1e3e800b'
3
+ metadata.gz: '0996608a78022414f8bd891b56e9505ae3f0f1784efe2b32e55b158ddfe53fce'
4
+ data.tar.gz: a6e1042355ee3cc29adfe82d1b50d805eefc151d0961e8304fc61f0284eb0fcc
5
5
  SHA512:
6
- metadata.gz: 955db5a60c525d1be3a242c424428a93a71cdec036724684f14c1876741bb56f3de86d0e3be75ced7980f44038573332a7a508b0918df524017f3b3e17c4e666
7
- data.tar.gz: 85d97b041b9153ff193b5348fee2b55257458f76450019307b2a4ff529b726c68d388fb3f1944328aaba12deaf09422d4b6d525c41c5658364b6c7146b30faea
6
+ metadata.gz: 07c973f3747bd2358672c1729700f1a09f0d0d95cf33ee292e133962cf1f54e2158a5189001f2848246678c6e3d49136e05aeb1975f7947546cbbf0f61210c23
7
+ data.tar.gz: b8062885f5f5e2e53ca33cbab91ca36ca1aff098001b66444f3da463e611e20ea951600e7b863eed7b09942604d274bfc97184db8a0a199ed9f06226c1792c35
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 supports only 8-bit depth expression of pixels, which means all channels including grayscale intencity, RGB and alpha are 0-255 values. Therefore, the MemoryView format is always `"C"` and the item size is 1-byte. Currently, HDR images are converted to standard dynamic-range images.
63
+ Currently, this bridge exports `Magick::Image`'s MemoryCiew 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
- Other formats such as float might be supported in the future.
65
+ On the other hand, this bridge can import MemoryViews whose format differs from `NDAV::Magick::Image::MemoryViewable::FORMAT`. Formats that are not currently supported might be supported in the future.
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
- noise = Numo::Int8.new(numo.shape).rand(Numo::Int8::MIN, Numo::Int8::MAX)
86
- noised = Numo::Int16.cast(numo)
87
- noised.inplace + noise
88
- noised.inplace.clip(Numo::UInt8::MIN, Numo::UInt8::MAX)
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(Numo::UInt8.cast(noised))
90
+ noised_image = MagickImage(noised)
91
91
  noised_image.write "noised.png"
92
+
92
93
  ```
93
94
 
94
95
  | Before | After |
95
96
  |--------|-------|
96
- | [![Original image](https://i.gyazo.com/905f541f15c0d57db5fc7ea3f6edaf07.png)](https://gyazo.com/905f541f15c0d57db5fc7ea3f6edaf07) | [![Noized image](https://i.gyazo.com/7ad51507e7a2d2c8c39c15ce71a5175a.png)](https://gyazo.com/7ad51507e7a2d2c8c39c15ce71a5175a) |
97
+ | [![Original image](https://i.gyazo.com/905f541f15c0d57db5fc7ea3f6edaf07.png)](https://gyazo.com/905f541f15c0d57db5fc7ea3f6edaf07) | [![Noised image](https://i.gyazo.com/c8c7191713d97fffaa2509e6b0874aab.png)](https://gyazo.com/c8c7191713d97fffaa2509e6b0874aab) |
97
98
 
98
99
  TODO
99
100
  ----
100
101
 
101
- * Support HDRI
102
102
  * Support zero-copy
103
- * Support float value pixels
103
+ * Support export in non-ImageMagick-native format
104
104
 
105
105
  LICENSE
106
106
  -------
@@ -4,6 +4,16 @@ 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
+ COLORSPACE_TO_MAP = {
9
+ ::Magick::GRAYColorspace => "I",
10
+ ::Magick::LinearGRAYColorspace => "I",
11
+ ::Magick::RGBColorspace => "RGB",
12
+ ::Magick::ScRGBColorspace => "RGB",
13
+ ::Magick::SRGBColorspace => "RGB",
14
+ ::Magick::CMYColorspace => "CMY",
15
+ ::Magick::CMYKColorspace => "CMYK"
16
+ }
7
17
  CHANNELS_TO_MAP = {
8
18
  nil => "I",
9
19
  1 => "I",
@@ -11,11 +21,32 @@ class NDAV
11
21
  3 => "RGB",
12
22
  4 => "RGBA"
13
23
  }
24
+ FORMAT_TO_TYPE = Hash.new {|types, format| types[format] = type_from_format(format)}
25
+
26
+ class << self
27
+ # TODO: Support more formats like "CCC"
28
+ def type_from_format(format)
29
+ item_desc = NDAV::ITEM_DESCS[format]
30
+ return unless item_desc.length == 1
31
+
32
+ component = item_desc[0]
33
+ return unless component.repeat == 1
34
+
35
+ case component.format
36
+ when MemoryViewable::FORMAT then ::Magick::QuantumPixel
37
+ when "C" then ::Magick::CharPixel
38
+ when "S" then ::Magick::ShortPixel
39
+ when "L" then ::Magick::IntegerPixel
40
+ when "f" then ::Magick::FloatPixel
41
+ when "d" then ::Magick::DoublePixel
42
+ else raise "Unsupported format: #{format}"
43
+ end
44
+ end
45
+ end
14
46
 
15
47
  module FromNDAV
16
48
  # TODO: Support more formats
17
49
  def from_ndav(ndav)
18
- raise %|Currently, supports only format "C", but is "#{ndav.format}"| unless ndav.format == "C"
19
50
  raise "Currently, supports only row-major contiguous NDAV" unless ndav.row_major_contiguous?
20
51
  raise "ndim must be 2 or 3 but is #{ndav.ndim}" unless [2, 3].include? ndav.ndim
21
52
 
@@ -24,33 +55,37 @@ class NDAV
24
55
  raise "Unsupported channels: #{channels}" unless map
25
56
 
26
57
  image = ::Magick::Image.new(width, height)
27
- image.import_pixels 0, 0, width, height, map, ndav.to_s
58
+ image.import_pixels 0, 0, width, height, map, ndav.to_s, FORMAT_TO_TYPE[ndav.format]
28
59
  image
29
60
  end
30
61
  end
31
62
 
32
63
  module MemoryViewable
64
+ FORMAT = case [::Magick::MAGICKCORE_QUANTUM_DEPTH, NDAV::Magick::Image::IS_HDRI_SUPPORTED]
65
+ in [ 8, true ] then "f"
66
+ in [ 8, false] then "C"
67
+ in [16, true ] then "f"
68
+ in [16, false] then "S"
69
+ in [32, true ] then "f"
70
+ in [32, false] then "L"
71
+ in [64, true ] then "d"
72
+ end
73
+ ITEM_SIZE = NDAV::ITEM_SIZES[FORMAT]
74
+
33
75
  private
34
76
 
35
- # TODO: Support HDRI
36
77
  def ndav_descriptor(**)
37
- map =
38
- case [gray?, alpha?]
39
- when [true, true] then "IA"
40
- when [true, false] then "I"
41
- when [false, true] then "RGBA"
42
- else "RGB"
43
- end
78
+ map = COLORSPACE_TO_MAP[colorspace]
79
+ Kernel.raise "Unsupported color space: #{colorspace}" unless map
80
+ map += "A" if alpha?
44
81
  shape = [rows, columns, map.length]
45
- format = "C"
46
- item_size = ::NDAV::ITEM_SIZES[format]
47
82
 
48
83
  {
49
- data: export_pixels_to_str(0, 0, columns, rows, map, ::Magick::CharPixel),
84
+ data: export_pixels_to_str(0, 0, columns, rows, map, ::Magick::QuantumPixel),
50
85
  shape:,
51
- strides: ::NDAV.default_strides(shape:, item_size:),
52
- format:,
53
- byte_size: shape.reduce(item_size, :*),
86
+ strides: NDAV.default_strides(shape:, item_size: ITEM_SIZE),
87
+ format: FORMAT,
88
+ byte_size: shape.reduce(ITEM_SIZE, :*),
54
89
  readonly?: true
55
90
  }
56
91
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "ndav-magick-image"
3
- s.version = "0.0.1"
3
+ s.version = "0.0.2"
4
4
  s.authors = ["Kitaiti Makoto"]
5
5
  s.summary = "N-Dimensional Array View for RMagick"
6
6
  s.licenses = ["MIT"]
data/test/helper.rb CHANGED
@@ -3,3 +3,18 @@ require "test/unit"
3
3
  require "test/unit/notify"
4
4
  require "fiddle"
5
5
  require "tmpdir"
6
+
7
+ module Helper
8
+ private
9
+
10
+ def make_image(width, height)
11
+ ratio = (2 ** ::Magick::MAGICKCORE_QUANTUM_DEPTH - 1) / 255
12
+ [
13
+ [[255, 255, 255] * width] * (height / 2),
14
+ [[ 0, 255, 0] * width] * (height / 2)
15
+ # ].flatten.collect {|item| round_trip(item * ratio, NDAV::Magick::Image::MemoryViewable::FORMAT)}
16
+ ].flatten.collect {|item| item * ratio}
17
+ end
18
+ end
19
+
20
+ Test::Unit::TestCase.include Helper
@@ -1,6 +1,9 @@
1
1
  require_relative "helper"
2
2
 
3
3
  class TestMemoryViewable < Test::Unit::TestCase
4
+ FORMAT = NDAV::Magick::Image::MemoryViewable::FORMAT
5
+ ITEM_SIZE = NDAV::ITEM_SIZES[FORMAT]
6
+
4
7
  def setup
5
8
  @width = 3
6
9
  @height = 2
@@ -18,14 +21,10 @@ class TestMemoryViewable < Test::Unit::TestCase
18
21
  Fiddle::MemoryView.export @image do |view|
19
22
  assert_equal 3, view.ndim
20
23
  assert_equal [@height, @width, 3], view.shape
21
- assert_equal 1, view.item_size
22
- assert_equal "C", view.format
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*")
24
+ assert_equal ITEM_SIZE, view.item_size
25
+ assert_equal FORMAT, view.format
26
+ assert_equal @width * @height * 3 * ITEM_SIZE, view.byte_size
27
+ assert_equal make_image(@width, @height), view.to_s.unpack("#{FORMAT}*")
29
28
  end
30
29
  end
31
30
 
@@ -35,44 +34,38 @@ class TestMemoryViewable < Test::Unit::TestCase
35
34
  Fiddle::MemoryView.export @image do |view|
36
35
  assert_equal 3, view.ndim
37
36
  assert_equal [@height, @width, 4], view.shape
38
- assert_equal 1, view.item_size
39
- assert_equal "C", view.format
40
- assert_equal @width * @height * 4, view.byte_size
37
+ assert_equal ITEM_SIZE, view.item_size
38
+ assert_equal FORMAT, view.format
39
+ assert_equal @width * @height * 4* ITEM_SIZE, view.byte_size
41
40
  end
42
41
  end
43
42
 
44
43
  def test_grayscale
45
- image = @image.quantize(256, Magick::GRAYColorspace)
44
+ @image.colorspace = Magick::GRAYColorspace
46
45
 
47
- Fiddle::MemoryView.export image do |view|
46
+ Fiddle::MemoryView.export @image do |view|
48
47
  assert_equal 3, view.ndim
49
48
  assert_equal [@height, @width, 1], view.shape
50
- assert_equal 1, view.item_size
51
- assert_equal "C", view.format
52
- assert_equal @width * @height * 1, view.byte_size
53
- assert_equal [
54
- [[255] * @width] * (@height / 2),
55
- [[182] * @width] * (@height / 2)
56
- ].flatten,
57
- view.to_s.unpack("C*")
49
+ assert_equal ITEM_SIZE, view.item_size
50
+ assert_equal FORMAT, view.format
51
+ assert_equal @width * @height * 1 * ITEM_SIZE, view.byte_size
52
+ assert_equal @image.export_pixels_to_str(0, 0, @width, @height, "I", Magick::QuantumPixel).unpack("#{FORMAT}*"),
53
+ view.to_s.unpack("#{FORMAT}*")
58
54
  end
59
55
  end
60
56
 
61
57
  def test_gray_alpha
62
- image = @image.quantize(256, Magick::GRAYColorspace)
63
- image.alpha Magick::OnAlphaChannel
58
+ @image.colorspace = Magick::GRAYColorspace
59
+ @image.alpha Magick::OnAlphaChannel
64
60
 
65
- Fiddle::MemoryView.export image do |view|
61
+ Fiddle::MemoryView.export @image do |view|
66
62
  assert_equal 3, view.ndim
67
63
  assert_equal [@height, @width, 2], view.shape
68
- assert_equal 1, view.item_size
69
- assert_equal "C", view.format
70
- assert_equal @width * @height * 2, view.byte_size
71
- assert_equal [
72
- [[255, 255] * @width] * (@height / 2),
73
- [[182, 255] * @width] * (@height / 2)
74
- ].flatten,
75
- view.to_s.unpack("C*")
64
+ assert_equal ITEM_SIZE, view.item_size
65
+ assert_equal FORMAT, view.format
66
+ assert_equal @width * @height * 2 * ITEM_SIZE, view.byte_size
67
+ assert_equal @image.export_pixels_to_str(0, 0, @width, @height, "IA", Magick::QuantumPixel).unpack("#{FORMAT}*"),
68
+ view.to_s.unpack("#{FORMAT}*")
76
69
  end
77
70
  end
78
71
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ndav-magick-image
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kitaiti Makoto