tiff 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []