tiff 0.1

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.
@@ -0,0 +1,30 @@
1
+ Tiff
2
+ ====
3
+
4
+ This is a simple wrapper around libtiff using FFI. It only implements a small
5
+ subset of libffi's features -- just enough to generate a TIFF image and read
6
+ back some of its data. If you're interested in adding features, you can always
7
+ send me a pull request (please include specs!).
8
+
9
+ Usage
10
+ =====
11
+
12
+ Tiff::Image.open "filename.tif", "w" do |tiff|
13
+
14
+ tiff.set_field :compression, :CCITTFAX4
15
+ # or: tiff.set_field :compression, :CCITTFAX3
16
+
17
+ tiff.set_field :photometric, :min_is_white
18
+ # or: tiff.set_field :photometric, :min_is_black
19
+
20
+ tiff.bits_per_sample = 1
21
+ tiff.width = 200
22
+ tiff.height = 40
23
+
24
+ tiff.data = raw_data
25
+
26
+ end
27
+
28
+ image = Tiff::Image.open "filename.tif", "r"
29
+ image.get_field :width # => 200
30
+ image.get_field :height # => 40
@@ -0,0 +1,8 @@
1
+ require "ffi"
2
+
3
+ module Tiff
4
+ require "tiff/tag"
5
+
6
+ require "tiff/bindings"
7
+ require "tiff/image"
8
+ end
@@ -0,0 +1,99 @@
1
+ module Tiff
2
+ module Bindings
3
+
4
+ extend FFI::Library
5
+
6
+ ffi_lib 'libtiff'
7
+
8
+ attach_function :open, :TIFFOpen,
9
+ [:string, :string], :pointer
10
+
11
+ attach_function :close, :TIFFClose,
12
+ [:pointer], :void
13
+
14
+ attach_function :set_field, :TIFFSetField,
15
+ [:pointer, :uint, :varargs], :int
16
+
17
+ attach_function :get_field, :TIFFGetField,
18
+ [:pointer, :uint, :varargs], :int
19
+
20
+ attach_function :write_raw_strip, :TIFFWriteRawStrip,
21
+ [:pointer, :uint, :pointer, :int], :int
22
+
23
+ @@tags = Hash.new do |hash, key|
24
+ raise KeyError, "Tag #{key.inspect} is unsupported. Available tags: #{hash.keys}"
25
+ end
26
+
27
+ class << self
28
+
29
+ # Returns a hash of tag names to Tag instances. See `lib/tiff/tags.rb`
30
+ # for a list of supported tags.
31
+ def tags
32
+ @@tags
33
+ end
34
+
35
+ end
36
+
37
+ # Initializes the tags hash with the default set of supported tags. See
38
+ # `man libtiff` and `man TIFFGetField` for details.
39
+
40
+ tags[:artist] = Tag.new(:artist, 315, :string)
41
+ tags[:bad_fax_lines] = Tag.new(:bad_fax_lines, 326, :uint)
42
+ tags[:bits_per_sample] = Tag.new(:bits_per_sample, 258, :ushort)
43
+ tags[:clean_fax_data] = Tag.new(:clean_fax_data, 327, :ushort)
44
+ tags[:compression] = Tag.new(:compression, 259, :ushort, CCITTFAX3: 3, CCITTFAX4: 4)
45
+ tags[:consecutive_bad_fax_lines] = Tag.new(:consecutive_bad_fax_lines, 328, :uint)
46
+ tags[:copyright] = Tag.new(:copyright, 33432, :string)
47
+ tags[:data_type] = Tag.new(:data_type, 32996, :ushort)
48
+ tags[:date_time] = Tag.new(:date_time, 306, :string)
49
+ tags[:document_name] = Tag.new(:document_name, 269, :string)
50
+ tags[:fill_order] = Tag.new(:fill_order, 266, :ushort)
51
+ tags[:group3_options] = Tag.new(:group3_options, 292, :uint)
52
+ tags[:group4_options] = Tag.new(:group4_options, 293, :uint)
53
+ tags[:height] = Tag.new(:height, 257, :uint)
54
+ tags[:host_computer] = Tag.new(:host_computer, 316, :string)
55
+ tags[:image_depth] = Tag.new(:image_depth, 32997, :uint)
56
+ tags[:image_description] = Tag.new(:image_description, 270, :string)
57
+ tags[:ink_names] = Tag.new(:ink_names, 333, :string)
58
+ tags[:ink_set] = Tag.new(:ink_set, 332, :ushort)
59
+ tags[:make] = Tag.new(:make, 271, :string)
60
+ tags[:matteing] = Tag.new(:matteing, 32995, :ushort)
61
+ tags[:max_sample_value] = Tag.new(:max_sample_value, 281, :ushort)
62
+ tags[:min_sample_value] = Tag.new(:min_sample_value, 280, :ushort)
63
+ tags[:model] = Tag.new(:model, 272, :string)
64
+ tags[:orientation] = Tag.new(:orientation, 274, :ushort)
65
+ tags[:page_name] = Tag.new(:page_name, 285, :string)
66
+ tags[:photometric] = Tag.new(:photometric, 262, :ushort, min_is_white: 0, min_is_black: 1)
67
+ tags[:predictor] = Tag.new(:predictor, 317, :ushort)
68
+ tags[:resolution_unit] = Tag.new(:resolution_unit, 296, :ushort, none: 1, inch: 2, centimeter: 3)
69
+ tags[:rows_per_strip] = Tag.new(:rows_per_strip, 278, :uint)
70
+ tags[:s_max_sample_value] = Tag.new(:s_max_sample_value, 341, :double)
71
+ tags[:s_min_sample_value] = Tag.new(:s_min_sample_value, 340, :double)
72
+ tags[:sample_format] = Tag.new(:sample_format, 339, :ushort)
73
+ tags[:samples_per_pixel] = Tag.new(:samples_per_pixel, 277, :ushort)
74
+ tags[:software] = Tag.new(:software, 305, :string)
75
+ tags[:sub_file_type] = Tag.new(:sub_file_type, 255, :uint)
76
+ tags[:target_printer] = Tag.new(:target_printer, 337, :string)
77
+ tags[:tile_depth] = Tag.new(:tile_depth, 32998, :uint)
78
+ tags[:tile_length] = Tag.new(:tile_length, 323, :uint)
79
+ tags[:tile_width] = Tag.new(:tile_width, 322, :uint)
80
+ tags[:width] = Tag.new(:width, 256, :uint)
81
+ tags[:x_position] = Tag.new(:x_position, 286, :float)
82
+ tags[:x_resolution] = Tag.new(:x_resolution, 282, :float)
83
+ tags[:y_cb_cr_positioning] = Tag.new(:y_cb_cr_positioning, 531, :ushort)
84
+ tags[:y_position] = Tag.new(:y_position, 286, :float)
85
+ tags[:y_resolution] = Tag.new(:y_resolution, 283, :float)
86
+
87
+ # Array types are not yet supported.
88
+ #
89
+ # tags[:reference_black_white] = Tag.new(:reference_black_white, 532, :float*)
90
+ # tags[:sto_nits] = Tag.new(:sto_nits, 37439, :double*)
91
+ # tags[:strip_byte_counts] = Tag.new(:strip_byte_counts, 279, :uint*)
92
+ # tags[:strip_offsets] = Tag.new(:strip_offsets, 273, :uint*)
93
+ # tags[:tile_byte_counts] = Tag.new(:tile_byte_counts, 324, :uint*)
94
+ # tags[:tile_offsets] = Tag.new(:tile_offsets, 324, :uint*)
95
+ # tags[:white_point] = Tag.new(:white_point, 318, :float*)
96
+ # tags[:y_cb_cr_coefficients] = Tag.new(:y_cb_cr_coefficients, 529, :float*)
97
+
98
+ end
99
+ end
@@ -0,0 +1,91 @@
1
+ module Tiff
2
+
3
+ class Image
4
+
5
+ attr_reader :path, :mode
6
+
7
+ # The file descriptor. This is an FFI::Pointer to the opened TIFF file.
8
+ attr_reader :fd
9
+
10
+ def initialize(path, mode)
11
+ @path = path
12
+ @mode = mode
13
+
14
+ @fd = Bindings::open path, mode
15
+ end
16
+
17
+ def close
18
+ Bindings::close fd
19
+ end
20
+
21
+ # Writes raw data to the image.
22
+ def data=(data)
23
+ Bindings::write_raw_strip fd, 0, data, data.length
24
+ end
25
+
26
+ # Sets a field on the image, using the list of tags in
27
+ # `Tiff::Bindings.tags`
28
+ def set_field(name, value)
29
+ tag = Bindings::tags[name]
30
+ Bindings::set_field fd, tag.id, tag.type, tag.serialize(value)
31
+ end
32
+
33
+ # Gets a field from the image, using the list of tags in #
34
+ # `Tiff::Bindings.tags`
35
+ def get_field(name)
36
+ tag = Bindings::tags[name]
37
+ pointer = FFI::MemoryPointer.new tag.type
38
+ result = Bindings::get_field fd, tag.id, :pointer, pointer
39
+ if result == 1
40
+ tag.deserialize pointer
41
+ else
42
+ nil
43
+ end
44
+ end
45
+
46
+ # Sets the image's width
47
+ def width=(width)
48
+ set_field :width, width
49
+ end
50
+
51
+ # Sets the image's height
52
+ def height=(height)
53
+ set_field :height, height
54
+ end
55
+
56
+ # Sets the image's bits_per_sample
57
+ def bits_per_sample=(bits_per_sample)
58
+ set_field :bits_per_sample, bits_per_sample
59
+ end
60
+
61
+ # Sets the image's compression
62
+ def compression=(compresion)
63
+ set_field :compression, compresion
64
+ end
65
+
66
+ # Sets the image's photometric
67
+ def photometric=(compresion)
68
+ set_field :photometric, compresion
69
+ end
70
+
71
+ class << self
72
+
73
+ # Initializes a new image. If a block is provided, the image is yielded
74
+ # and automatically closed.
75
+ def open(path, mode)
76
+ new(path, mode).tap do |image|
77
+ if block_given?
78
+ begin
79
+ yield image
80
+ ensure
81
+ image.close
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,71 @@
1
+ module Tiff
2
+ class Tag
3
+
4
+ # The name of this tag
5
+ attr_accessor :name
6
+
7
+ # The value for this tag as defined by `tiff.h`
8
+ attr_accessor :id
9
+
10
+ # The FFI type for this tag. See `man TIFFSetField` for the types of each
11
+ # field, and `https://github.com/ffi/ffi/wiki/Types` for it's corresponding
12
+ # value in ruby.
13
+ attr_accessor :type
14
+
15
+ # A hash of ruby to FFI values for serialization and deserialization.
16
+ attr_accessor :map
17
+
18
+ # Creates a new tag.
19
+ #
20
+ # - name: A rubyish name for the tag. Displayed to users for exceptions.
21
+ # - id: The value for this tag as defined by `tiff.h`
22
+ # - type: The FFI type of the tag
23
+ # - map: A hash of ruby to FFI values (optional)
24
+ #
25
+ # Examples:
26
+ #
27
+ # width = Tag.new(:width, 256, :uint)
28
+ # metric = Tag.new(:photometric, 262, :ushort, {
29
+ # min_is_white: 0,
30
+ # min_is_black: 1
31
+ # })
32
+ #
33
+ def initialize(name, id, type, map = nil)
34
+ @name = name
35
+ @id = id
36
+ @type = type
37
+ @map = map
38
+ end
39
+
40
+ # Returns the value for serialization. If the tag does not have a map
41
+ # defined, this simply returns the value provided.
42
+ #
43
+ # If a map was provided for the tag, it will return the value for the
44
+ # mapping. If the mapping isn't found, it will raise an exception.
45
+ def serialize(value)
46
+ return value unless map
47
+
48
+ map.fetch value do
49
+ raise KeyError, "Tag #{name.inspect} does not support value #{value.inspect}. Defined values: #{map.keys}"
50
+ end
51
+ end
52
+
53
+ # Returns the deserialized value from the provided FFI::MemoryPointer.
54
+ #
55
+ # If a map was provided for the tag, it will return the ruby value if it
56
+ # exists. If the mapping isn't found, it will return the raw value.
57
+ def deserialize(pointer)
58
+ case type
59
+ when :string
60
+ string = pointer.read_pointer()
61
+ return string.null? ? nil : string.read_string()
62
+
63
+ else
64
+ value = pointer.send :"read_#{type}"
65
+ value = map.invert[value] if map && map.has_value?(value)
66
+ value
67
+ end
68
+ end
69
+
70
+ end
71
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tiff
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bernerd Schaefer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-25 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ffi
16
+ requirement: &70275682402260 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70275682402260
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70275682428940 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70275682428940
36
+ description: Ruby wrapper for libtiff with FFI
37
+ email:
38
+ - bj.schaefer@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - lib/tiff/bindings.rb
44
+ - lib/tiff/image.rb
45
+ - lib/tiff/tag.rb
46
+ - lib/tiff.rb
47
+ - README.md
48
+ homepage: ''
49
+ licenses: []
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 1.8.6
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Ruby wrapper for libtiff with FFI
72
+ test_files: []